Skip to content

Commit

Permalink
Initial Otto Chat Bot code
Browse files Browse the repository at this point in the history
  • Loading branch information
Bentlybro committed Jan 14, 2025
1 parent 0b9c0c9 commit c3fe0a5
Show file tree
Hide file tree
Showing 6 changed files with 372 additions and 6 deletions.
1 change: 1 addition & 0 deletions autogpt_platform/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"next": "^14.2.13",
"next-themes": "^0.4.4",
"react": "^18",
"react-chat-widget": "^3.1.4",
"react-day-picker": "^9.4.4",
"react-dom": "^18",
"react-hook-form": "^7.54.0",
Expand Down
2 changes: 2 additions & 0 deletions autogpt_platform/frontend/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Navbar } from "@/components/agptui/Navbar";

import "./globals.css";
import TallyPopupSimple from "@/components/TallyPopup";
import OttoChatWidget from "@/components/OttoChatWidget";
import { GoogleAnalytics } from "@next/third-parties/google";
import { Toaster } from "@/components/ui/toaster";
import { IconType } from "@/components/ui/icons";
Expand Down Expand Up @@ -93,6 +94,7 @@ export default async function RootLayout({
/>
<main className="flex-1">{children}</main>
<TallyPopupSimple />
<OttoChatWidget />
</div>
<Toaster />
</Providers>
Expand Down
103 changes: 103 additions & 0 deletions autogpt_platform/frontend/src/components/OttoChatWidget.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
.custom-launcher-button {
background-color: #8b5cf6 !important;
border: none !important;
border-radius: 50% !important;
color: white !important;
cursor: pointer !important;
height: 60px !important;
padding: 18px !important;
position: fixed !important;
right: 35px !important;
bottom: 15px !important;
transition: all 0.2s ease-in-out !important;
width: 60px !important;
z-index: 999 !important;
}

.custom-launcher-button:hover {
background-color: #7c3aed !important;
transform: scale(1.1) !important;
}

.rcw-launcher {
display: none !important;
}

.rcw-widget-container {
height: 65vh !important;
margin-bottom: 50px !important;
border-radius: 10px !important;
max-width: 610px !important;
width: 100% !important;
}

.rcw-conversation-container {
border-radius: 10px !important;
background-color: white !important;
border: none !important;
}

.rcw-header {
background-color: #8b5cf6 !important;
border-radius: 10px 10px 0 0 !important;
padding: 0px !important;
min-height: 0px !important;
}

.rcw-messages-container {
background-color: white !important;
padding: 12px 8px !important;
max-width: 100% !important;
overflow-x: hidden !important;
font-size: 0.9rem !important;
}

.rcw-message {
padding: 4px 8px !important;
width: auto !important;
max-width: 100% !important;
display: flex !important;
flex-direction: column !important;
margin: 4px 0 !important;
}

.rcw-message-text {
background-color: #f3f4f6 !important;
color: #1f2937 !important;
border-radius: 8px !important;
padding: 8px !important;
max-width: 100% !important;
word-wrap: break-word !important;
white-space: pre-wrap !important;
overflow-wrap: break-word !important;
line-height: 1.4 !important;
overflow-x: auto !important;
margin: 0 !important;
}

.rcw-message-text pre {
max-width: 100% !important;
overflow-x: auto !important;
white-space: pre-wrap !important;
word-wrap: break-word !important;
margin: 8px 0 !important;
}

.rcw-message-text code {
word-wrap: break-word !important;
white-space: pre-wrap !important;
display: block !important;
width: 100% !important;
}

.rcw-client .rcw-message-text {
background-color: #8b5cf6 !important;
color: white !important;
}

.rcw-sender {
background-color: white !important;
padding: 10px !important;
border-radius: 0 0 10px 10px !important;
border-top: 1px solid #e5e7eb !important;
}
145 changes: 145 additions & 0 deletions autogpt_platform/frontend/src/components/OttoChatWidget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
"use client";

import React, { useEffect, useState, useRef } from 'react';
import { Widget, addResponseMessage, addLinkSnippet, deleteMessages } from 'react-chat-widget';
import 'react-chat-widget/lib/styles.css';
import './OttoChatWidget.css';
import useSupabase from '../hooks/useSupabase';

interface Document {
url: string;
relevance_score: number;
}

interface ApiResponse {
answer: string;
documents: Document[];
success: boolean;
}

interface Message {
query: string;
response: string;
}

interface ChatPayload {
query: string;
conversation_history: { query: string; response: string }[];
user_id: string;
message_id: string;
}

const OttoChatWidget = () => {
const [chatWindowOpen, setChatWindowOpen] = useState(false);
const [messages, setMessages] = useState<Message[]>([]);
const welcomeMessageSent = useRef(false);
const processingMessageId = useRef<number | null>(null);
const { user } = useSupabase();

useEffect(() => {
if (!welcomeMessageSent.current) {
addResponseMessage('Hello im Otto! Ask me anything about AutoGPT!');
welcomeMessageSent.current = true;
}
}, []);

const formatResponse = (data: ApiResponse): void => {
const cleanedResponse = data.answer.replace(/####|###|\*|-/g, '');
addResponseMessage(cleanedResponse);
};

const handleNewUserMessage = async (newMessage: string) => {

// Generate a message ID with timestamp and 'web' suffix, this is used to identify the message in the database
const messageId = `${Date.now()}-web`;

setMessages(prev => [...prev, { query: newMessage, response: '' }]);

addResponseMessage('Processing your question...');

try {
const payload: ChatPayload = {
query: newMessage,
conversation_history: messages.map(msg => ({
query: msg.query,
response: msg.response
})),
user_id: user?.id || 'anonymous',
message_id: messageId
};

const response = await fetch('http://192.168.0.39:2344/ask', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
mode: 'cors',
credentials: 'omit',
body: JSON.stringify(payload)
});

if (!response.ok) {
throw new Error(`API request failed with status ${response.status}`);
}

const data: ApiResponse = await response.json();

deleteMessages(1);

if (data.success) {
formatResponse(data);
setMessages(prev => {
const newMessages = [...prev];
newMessages[newMessages.length - 1].response = data.answer;
return newMessages;
});
} else {
throw new Error('API request was not successful');
}

} catch (error) {
deleteMessages(1);

console.error('Error calling API:', error);
addResponseMessage('Sorry, there was an error processing your message. Please try again.');
}
};

const handleToggle = () => {
setChatWindowOpen(prev => !prev);
};

return (
<Widget
handleNewUserMessage={handleNewUserMessage}
title="Otto Assistant"
subtitle=""
handleToggle={handleToggle}
autofocus={true}
emojis={true}
launcher={(handleToggle: () => void) => (
<button
onClick={handleToggle}
className="custom-launcher-button"
aria-label="Open chat widget"
>
<svg
viewBox="0 0 24 24"
width="24"
height="24"
stroke="currentColor"
strokeWidth="2"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
</svg>
</button>
)}
/>
);
};

export default OttoChatWidget;
2 changes: 1 addition & 1 deletion autogpt_platform/frontend/src/components/TallyPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const TallyPopupSimple = () => {
};

return (
<div className="fixed bottom-1 right-6 z-50 hidden select-none items-center gap-4 p-3 transition-all duration-300 ease-in-out md:flex">
<div className="fixed bottom-1 right-24 z-50 hidden select-none items-center gap-4 p-3 transition-all duration-300 ease-in-out md:flex">
{show_tutorial && (
<Button
variant="default"
Expand Down
Loading

0 comments on commit c3fe0a5

Please sign in to comment.