From 28a8953ac581679dc606f3c3de605eb4d2917109 Mon Sep 17 00:00:00 2001 From: Pratik Narola Date: Thu, 4 Sep 2025 17:07:49 +0530 Subject: [PATCH] Stable checkpoint with chat interface --- backend/config.py | 4 +- backend/main.py | 16 +- backend/mem0_manager.py | 68 +++-- config/postgres-init.sql | 2 +- frontend/README.md | 60 +++++ frontend/graph.html | 545 +++++++++++++++++++++++++++++++++++++++ frontend/index.html | 508 ++++++++++++++++++++++++++++++++++++ 7 files changed, 1181 insertions(+), 22 deletions(-) create mode 100644 frontend/README.md create mode 100644 frontend/graph.html create mode 100644 frontend/index.html diff --git a/backend/config.py b/backend/config.py index 8ce3a3b..ca34492 100644 --- a/backend/config.py +++ b/backend/config.py @@ -13,7 +13,9 @@ class Settings(BaseSettings): openai_api_key: str = Field(..., env="OPENAI_API_KEY") openai_base_url: str = Field(..., env="OPENAI_BASE_URL") embedder_api_key: str = Field(..., env="EMBEDDER_API_KEY") - + + # ollama_base_url: str = Field(..., env="OLLAMA_BASE_URL") + # Database Configuration postgres_host: str = Field("localhost", env="POSTGRES_HOST") postgres_port: int = Field(5432, env="POSTGRES_PORT") diff --git a/backend/main.py b/backend/main.py index 28f96f9..381f022 100644 --- a/backend/main.py +++ b/backend/main.py @@ -71,11 +71,11 @@ app = FastAPI( lifespan=lifespan ) -# Add CORS middleware +# Add CORS middleware - Allow all origins for development app.add_middleware( CORSMiddleware, - allow_origins=settings.cors_origins_list, - allow_credentials=True, + allow_origins=["*"], # Allow all origins for development + allow_credentials=False, # Must be False when allow_origins=["*"] allow_methods=["*"], allow_headers=["*"], ) @@ -203,11 +203,17 @@ async def chat_with_memory(request: ChatRequest): try: logger.info(f"Processing chat request for user: {request.user_id}") + # Convert ChatMessage objects to dict format if context provided + context_dict = None + if request.context: + context_dict = [{"role": msg.role, "content": msg.content} for msg in request.context] + result = await mem0_manager.chat_with_memory( message=request.message, user_id=request.user_id, agent_id=request.agent_id, run_id=request.run_id, + context=context_dict ) return result @@ -341,7 +347,7 @@ async def get_graph_relationships(user_id: str): """Get graph relationships - pure Mem0 passthrough.""" try: logger.info(f"Retrieving graph relationships for user: {user_id}") - result = await mem0_manager.get_graph_relationships(user_id=user_id, agent_id=None, run_id=None) + result = await mem0_manager.get_graph_relationships(user_id=user_id, agent_id=None, run_id=None, limit=10000) return result @@ -473,4 +479,4 @@ if __name__ == "__main__": port=8000, log_level=settings.log_level.lower(), reload=True - ) \ No newline at end of file + ) diff --git a/backend/mem0_manager.py b/backend/mem0_manager.py index a256355..f8e1143 100644 --- a/backend/mem0_manager.py +++ b/backend/mem0_manager.py @@ -32,10 +32,10 @@ class Mem0Manager: "embedder": { "provider": "ollama", "config": { - "model": "hf.co/Qwen/Qwen3-Embedding-8B-GGUF:Q8_0", + "model": "hf.co/Qwen/Qwen3-Embedding-4B-GGUF:Q8_0", # "api_key": settings.embedder_api_key, "ollama_base_url": "http://host.docker.internal:11434", - "embedding_dims": 4096 + "embedding_dims": 2560 } }, "vector_store": { @@ -46,7 +46,7 @@ class Mem0Manager: "password": settings.postgres_password, "host": settings.postgres_host, "port": settings.postgres_port, - "embedding_model_dims": 4096 + "embedding_model_dims": 2560 } }, "graph_store": { @@ -196,7 +196,7 @@ class Mem0Manager: raise e - async def get_graph_relationships(self, user_id: Optional[str], agent_id: Optional[str], run_id: Optional[str]) -> Dict[str, Any]: + async def get_graph_relationships(self, user_id: Optional[str], agent_id: Optional[str], run_id: Optional[str], limit: int = 50) -> Dict[str, Any]: """Get graph relationships - using correct Mem0 get_all() method.""" try: # Use get_all() to retrieve memories with graph relationships @@ -204,7 +204,7 @@ class Mem0Manager: user_id=user_id, agent_id=agent_id, run_id=run_id, - limit=50 + limit=limit ) # Extract relationships from Mem0's response structure @@ -256,30 +256,68 @@ class Mem0Manager: user_id: Optional[str] = None, agent_id: Optional[str] = None, run_id: Optional[str] = None, - # context: Optional[List[Dict[str, str]]] = None, + context: Optional[List[Dict[str, str]]] = None, # metadata: Optional[Dict[str, Any]] = None ) -> Dict[str, Any]: - """Chat with memory - native Mem0 pattern (15 lines vs 95).""" + """Chat with memory - native Mem0 pattern with detailed timing.""" + import time + try: - # Retrieve relevant memories using direct Mem0 search + total_start_time = time.time() + print(f"\nšŸš€ Starting chat request for user: {user_id}") + + # Stage 1: Memory Search + search_start_time = time.time() search_result = self.memory.search(query=message, user_id=user_id, agent_id=agent_id, run_id=run_id, limit=10, threshold=0.3) relevant_memories = search_result.get("results", []) memories_str = "\n".join(f"- {entry['memory']}" for entry in relevant_memories) + search_time = time.time() - search_start_time + print(f"šŸ” Memory search took: {search_time:.2f}s (found {len(relevant_memories)} memories)") - # Generate Assistant response using Mem0's standard pattern + # Stage 2: Prepare LLM messages + prep_start_time = time.time() system_prompt = f"You are a helpful AI. Answer the question based on query and memories.\nUser Memories:\n{memories_str}" - messages = [{"role": "system", "content": system_prompt}, {"role": "user", "content": message}] + messages = [{"role": "system", "content": system_prompt}] + + # Add conversation context if provided (last 50 messages) + if context: + messages.extend(context) + print(f"šŸ“ Added {len(context)} context messages") + + # Add current user message + messages.append({"role": "user", "content": message}) + prep_time = time.time() - prep_start_time + print(f"šŸ“‹ Message preparation took: {prep_time:.3f}s") + + # Stage 3: LLM Call + llm_start_time = time.time() response = self.openai_client.chat.completions.create(model=settings.default_model, messages=messages) assistant_response = response.choices[0].message.content + llm_time = time.time() - llm_start_time + print(f"šŸ¤– LLM call took: {llm_time:.2f}s (model: {settings.default_model})") - # Create new memories from the conversation - messages.append({"role": "assistant", "content": assistant_response}) - self.memory.add(messages, user_id=user_id) + # Stage 4: Memory Add + add_start_time = time.time() + memory_messages = [{"role": "user", "content": message}, {"role": "assistant", "content": assistant_response}] + self.memory.add(memory_messages, user_id=user_id) + add_time = time.time() - add_start_time + print(f"šŸ’¾ Memory add took: {add_time:.2f}s") + + # Total timing summary + total_time = time.time() - total_start_time + print(f"ā±ļø TOTAL: {total_time:.2f}s | Search: {search_time:.2f}s | LLM: {llm_time:.2f}s | Add: {add_time:.2f}s | Prep: {prep_time:.3f}s") + print(f"šŸ“Š Breakdown: Search {(search_time/total_time)*100:.1f}% | LLM {(llm_time/total_time)*100:.1f}% | Add {(add_time/total_time)*100:.1f}%\n") return { "response": assistant_response, "memories_used": len(relevant_memories), - "model_used": settings.default_model + "model_used": settings.default_model, + "timing": { + "total": round(total_time, 2), + "search": round(search_time, 2), + "llm": round(llm_time, 2), + "add": round(add_time, 2) + } } except Exception as e: @@ -313,4 +351,4 @@ class Mem0Manager: # Global instance -mem0_manager = Mem0Manager() \ No newline at end of file +mem0_manager = Mem0Manager() diff --git a/config/postgres-init.sql b/config/postgres-init.sql index 471efc8..21a3ee9 100644 --- a/config/postgres-init.sql +++ b/config/postgres-init.sql @@ -25,7 +25,7 @@ CREATE TABLE IF NOT EXISTS embeddings ( id SERIAL PRIMARY KEY, user_id VARCHAR(255), content TEXT, - embedding VECTOR(4096), -- OpenAI embedding dimension + embedding VECTOR(2560), -- OpenAI embedding dimension metadata JSONB, created_at TIMESTAMP DEFAULT NOW() ); diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..07a66ce --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,60 @@ +# Mem0 Chat Frontend + +A simple, clean frontend for chatting with your Mem0 memories. + +## Features + +- **Chat Interface**: Send messages and get AI responses with memory context +- **Memory Sidebar**: View all your memories with timestamps +- **Memory Management**: Delete individual memories with confirmation +- **Persistent Chat**: Chat history saved in localStorage (survives page refresh) +- **Real-time Updates**: Memories automatically refresh after each chat +- **Simple & Clean**: No fancy animations, just working functionality + +## Setup + +1. **Make sure the backend is running** on `http://localhost:8000` + +2. **Open the frontend** by simply opening `index.html` in your browser: + ```bash + open frontend/index.html + ``` + Or serve it with a simple HTTP server: + ```bash + cd frontend + python3 -m http.server 8080 + # Then open http://localhost:8080 + ``` + +## Usage + +1. **Start chatting** - Type messages in the input field and press Enter or click Send +2. **View memories** - All extracted memories appear in the right sidebar +3. **Delete memories** - Click the "Delete" button on any memory (with confirmation) +4. **Refresh memories** - Click the šŸ”„ button to manually refresh the memories list +5. **Persistent history** - Your chat history is saved and will reload when you refresh the page + +## Configuration + +- **User ID**: Hardcoded as "pratik" in the JavaScript +- **Backend URL**: `http://localhost:8000` (change in the JavaScript if needed) +- **Memory Limit**: Loads up to 50 memories + +## Debugging + +Open browser console and use: +- `clearChatHistory()` - Clear all stored chat history + +## Files + +- `index.html` - Complete frontend (HTML + CSS + JavaScript all in one file) +- `README.md` - This file + +## API Integration + +The frontend uses these backend endpoints: +- `POST /chat` - Send messages and get responses +- `GET /memories/pratik` - Load user memories +- `DELETE /memories/{id}` - Delete specific memory + +Simple, functional, and clean - exactly as requested! diff --git a/frontend/graph.html b/frontend/graph.html new file mode 100644 index 0000000..e382267 --- /dev/null +++ b/frontend/graph.html @@ -0,0 +1,545 @@ + + + + + + Memory Graph Visualization + + + + +
+
+

Memory Graph Visualization

+
+
+ Memories: 0 +
+
+ Relationships: 0 +
+
+ Entities: 0 +
+
+
+ + + +
+
+ +
+
+ Loading graph data... +
+
Connecting...
+
+ +
+
+ + + + diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..40bf99f --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,508 @@ + + + + + + Mem0 Chat Interface + + + +
+ +
+
+

What can I help you with?

+

Chat with your memories - User: pratik

+
+ +
+ +
+ +
+ + +
+
+ + +
+
+

Your Memories (0)

+ +
+ +
+
Loading memories...
+
+
+
+ + + +