Skip to content

Commit

Permalink
building out conversations / multiple chats
Browse files Browse the repository at this point in the history
  • Loading branch information
danXyu committed Dec 11, 2024
1 parent d611dc0 commit e5d7f5c
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 67 deletions.
12 changes: 12 additions & 0 deletions submodules/moragents_dockers/agents/src/models/messages.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from typing import List, Optional
from pydantic import BaseModel


Expand All @@ -10,3 +11,14 @@ class ChatRequest(BaseModel):
prompt: ChatMessage
chain_id: str
wallet_address: str


class ChatMessage(BaseModel):
role: str
content: str
agentName: Optional[str] = None


class Conversation(BaseModel):
messages: List[ChatMessage]
has_uploaded_file: bool = False
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import logging
from fastapi import APIRouter
from fastapi import APIRouter, Query
from src.stores import chat_manager_instance

logger = logging.getLogger(__name__)
Expand All @@ -8,15 +8,33 @@


@router.get("/messages")
async def get_messages():
"""Get all chat messages"""
logger.info("Received get_messages request")
return {"messages": chat_manager_instance.get_messages()}
async def get_messages(conversation_id: str = Query(default="default")):
"""Get all chat messages for a conversation"""
logger.info(f"Received get_messages request for conversation {conversation_id}")
return {"messages": chat_manager_instance.get_messages(conversation_id)}


@router.get("/clear")
async def clear_messages():
"""Clear chat message history"""
logger.info("Clearing message history")
chat_manager_instance.clear_messages()
async def clear_messages(conversation_id: str = Query(default="default")):
"""Clear chat message history for a conversation"""
logger.info(f"Clearing message history for conversation {conversation_id}")
chat_manager_instance.clear_messages(conversation_id)
return {"response": "successfully cleared message history"}


@router.post("/conversations")
async def create_conversation():
"""Create a new conversation"""
# The conversation will be created automatically when first accessed
new_id = f"conversation_{len(chat_manager_instance.get_all_conversation_ids())}"
chat_manager_instance.get_messages(new_id) # This creates the conversation
logger.info(f"Created new conversation with ID: {new_id}")
return {"conversation_id": new_id}


@router.delete("/conversations/{conversation_id}")
async def delete_conversation(conversation_id: str):
"""Delete a conversation"""
logger.info(f"Deleting conversation {conversation_id}")
chat_manager_instance.delete_conversation(conversation_id)
return {"response": f"successfully deleted conversation {conversation_id}"}
108 changes: 70 additions & 38 deletions submodules/moragents_dockers/agents/src/stores/chat_manager.py
Original file line number Diff line number Diff line change
@@ -1,52 +1,84 @@
import logging
from typing import Dict, List
from src.models.messages import ChatMessage, Conversation

logger = logging.getLogger(__name__)


class ChatManager:
def __init__(self):
self.has_uploaded_file = False
self.messages: List[Dict[str, str]] = [
{
"role": "assistant",
"agentName": "Morpheus AI",
"content": """This highly experimental chatbot is not intended for making important decisions,
and its responses are generated based on incomplete data and algorithms that may evolve rapidly.
By using this chatbot, you acknowledge that you use it at your own discretion
and assume all risks associated with its limitations and potential errors.""",
}
]

def add_message(self, message: Dict[str, str]):
self.messages.append(message)
logger.info(f"Added message: {message}")

def get_messages(self) -> List[Dict[str, str]]:
return self.messages

def set_uploaded_file(self, has_file: bool):
self.has_uploaded_file = has_file
logger.info(f"Set uploaded file status to: {has_file}")

def get_uploaded_file_status(self) -> bool:
return self.has_uploaded_file

def clear_messages(self):
self.messages = [self.messages[0]] # Keep the initial message
logger.info("Cleared message history")

def get_last_message(self) -> Dict[str, str]:
return self.messages[-1] if self.messages else {}

def add_response(self, response: Dict[str, str], agent_name: str):
self.conversations: Dict[str, Conversation] = {}
self.default_message = ChatMessage(
role="assistant",
agentName="Morpheus AI",
content="""This highly experimental chatbot is not intended for making important decisions. Its
responses are generated using AI models and may not always be accurate.
By using this chatbot, you acknowledge that you use it at your own discretion
and assume all risks associated with its limitations and potential errors.""",
)

def _get_or_create_conversation(self, conversation_id: str) -> Conversation:
if conversation_id not in self.conversations:
self.conversations[conversation_id] = Conversation(
messages=[self.default_message], has_uploaded_file=False
)
return self.conversations[conversation_id]

def add_message(self, message: Dict[str, str], conversation_id: str):
conversation = self._get_or_create_conversation(conversation_id)
chat_message = ChatMessage(**message)
conversation.messages.append(chat_message)
logger.info(f"Added message to conversation {conversation_id}: {message}")

def get_messages(self, conversation_id: str) -> List[Dict[str, str]]:
conversation = self._get_or_create_conversation(conversation_id)
return [msg.dict() for msg in conversation.messages]

def set_uploaded_file(self, has_file: bool, conversation_id: str):
conversation = self._get_or_create_conversation(conversation_id)
conversation.has_uploaded_file = has_file
logger.info(f"Set uploaded file status to {has_file} for conversation {conversation_id}")

def get_uploaded_file_status(self, conversation_id: str) -> bool:
conversation = self._get_or_create_conversation(conversation_id)
return conversation.has_uploaded_file

def clear_messages(self, conversation_id: str):
conversation = self._get_or_create_conversation(conversation_id)
conversation.messages = [self.default_message] # Keep the initial message
logger.info(f"Cleared message history for conversation {conversation_id}")

def get_last_message(self, conversation_id: str) -> Dict[str, str]:
conversation = self._get_or_create_conversation(conversation_id)
return conversation.messages[-1].dict() if conversation.messages else {}

def add_response(self, response: Dict[str, str], agent_name: str, conversation_id: str):
response_with_agent = response.copy()
response_with_agent["agentName"] = agent_name
self.add_message(response_with_agent)
logger.info(f"Added response from agent {agent_name}: {response_with_agent}")
chat_message = ChatMessage(**response_with_agent)
self.add_message(chat_message.dict(), conversation_id)
logger.info(
f"Added response from agent {agent_name} to conversation {conversation_id}: {response_with_agent}"
)

def get_chat_history(self, conversation_id: str) -> str:
conversation = self._get_or_create_conversation(conversation_id)
return "\n".join([f"{msg.role}: {msg.content}" for msg in conversation.messages])

def get_all_conversation_ids(self) -> List[str]:
"""Get a list of all conversation IDs"""
return list(self.conversations.keys())

def delete_conversation(self, conversation_id: str):
"""Delete a conversation by ID"""
if conversation_id in self.conversations:
del self.conversations[conversation_id]
logger.info(f"Deleted conversation {conversation_id}")

def get_chat_history(self) -> str:
return "\n".join([f"{msg['role']}: {msg['content']}" for msg in self.messages])
def create_conversation(self, conversation_id: str) -> Dict:
"""Create a new conversation with the given ID"""
conversation = self._get_or_create_conversation(conversation_id)
return conversation.dict()


# Create an instance to act as a singleton store
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,68 @@
import React, { FC } from 'react';
import {
Box,
VStack,
Text,
Link
} from "@chakra-ui/react";
import { ConnectButton } from '@rainbow-me/rainbowkit';
import React, { FC, useEffect, useState } from "react";
import { Box, VStack, Text, Button } from "@chakra-ui/react";
import { getHttpClient } from "@/services/constants";

export type LeftSidebarProps = {};

export type LeftSidebarProps = {
export const LeftSidebar: FC<LeftSidebarProps> = () => {
const [conversations, setConversations] = useState<string[]>([]);

};
const fetchConversations = async () => {
try {
const response = await getHttpClient().get("/chat/conversations");
setConversations(response.data.conversation_ids);
} catch (error) {
console.error("Failed to fetch conversations:", error);
}
};

export const LeftSidebar: FC<LeftSidebarProps> = () => {
return (
<Box bg="#020804" p={4}>
<VStack align="stretch" height="85%">
const createNewConversation = async () => {
try {
await getHttpClient().post("/chat/conversations");
fetchConversations();
} catch (error) {
console.error("Failed to create new conversation:", error);
}
};

{/* Dynamic chat list can be added here */}
</VStack>
</Box>
);
}
const deleteConversation = async (conversationId: string) => {
try {
await getHttpClient().delete(`/chat/conversations/${conversationId}`);
fetchConversations();
} catch (error) {
console.error("Failed to delete conversation:", error);
}
};

useEffect(() => {
fetchConversations();
}, []);

return (
<Box bg="#020804" p={4}>
<VStack align="stretch" height="85%" spacing={4}>
<Button onClick={createNewConversation}>New Chat</Button>
{conversations.map((conversationId) => (
<Box
key={conversationId}
p={3}
bg="#1A1A1A"
borderRadius="md"
display="flex"
justifyContent="space-between"
alignItems="center"
>
<Text color="white">{conversationId}</Text>
<Button
size="sm"
colorScheme="red"
onClick={() => deleteConversation(conversationId)}
>
Delete
</Button>
</Box>
))}
</VStack>
</Box>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ type LoadingIndicatorProps = {
export const LoadingIndicator: FC<LoadingIndicatorProps> = ({
selectedAgent,
}) => {
const agentName = availableAgents[selectedAgent]?.name || "Finding an agent";
const agentName =
availableAgents[selectedAgent]?.name || "Finding the best agent";

return (
<Grid
Expand Down

0 comments on commit e5d7f5c

Please sign in to comment.