Migrated to Qdrant

This commit is contained in:
Pratik Narola 2025-09-09 12:54:46 +05:30
parent 28a8953ac5
commit f625f8f556
6 changed files with 78 additions and 111 deletions

View file

@ -10,18 +10,16 @@ class Settings(BaseSettings):
"""Application settings loaded from environment variables."""
# API Configuration
openai_api_key: str = Field(..., env="OPENAI_API_KEY")
openai_base_url: str = Field(..., env="OPENAI_BASE_URL")
openai_api_key: str = Field(..., env="OPENAI_COMPAT_API_KEY")
openai_base_url: str = Field(..., env="OPENAI_COMPAT_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")
postgres_db: str = Field("mem0_db", env="POSTGRES_DB")
postgres_user: str = Field("mem0_user", env="POSTGRES_USER")
postgres_password: str = Field("mem0_password", env="POSTGRES_PASSWORD")
qdrant_host: str = Field("localhost", env="QDRANT_HOST")
qdrant_port: int = Field(6333, env="QDRANT_PORT")
qdrant_collection_name: str = Field("mem0", env="QDRANT_COLLECTION_NAME")
# Neo4j Configuration
neo4j_uri: str = Field("bolt://localhost:7687", env="NEO4J_URI")
@ -35,10 +33,6 @@ class Settings(BaseSettings):
# Model Configuration - Ultra-minimal (single model)
default_model: str = Field("claude-sonnet-4", env="DEFAULT_MODEL")
@property
def postgres_url(self) -> str:
"""Build PostgreSQL connection URL."""
return f"postgresql://{self.postgres_user}:{self.postgres_password}@{self.postgres_host}:{self.postgres_port}/{self.postgres_db}"
@property
def cors_origins_list(self) -> List[str]:

View file

@ -39,14 +39,13 @@ class Mem0Manager:
}
},
"vector_store": {
"provider": "pgvector",
"provider": "qdrant",
"config": {
"dbname": settings.postgres_db,
"user": settings.postgres_user,
"password": settings.postgres_password,
"host": settings.postgres_host,
"port": settings.postgres_port,
"embedding_model_dims": 2560
"collection_name": settings.qdrant_collection_name,
"host": settings.qdrant_host,
"port": settings.qdrant_port,
"embedding_model_dims": 2560,
"on_disk": True
}
},
"graph_store": {

View file

@ -9,8 +9,7 @@ openai
google-genai
# Database
psycopg2-binary
pgvector
qdrant-client
neo4j
langchain-neo4j
rank-bm25

View file

@ -1,66 +0,0 @@
-- Initialize PostgreSQL database for Mem0 with pgvector extension
-- Create the pgvector extension for vector operations
CREATE EXTENSION IF NOT EXISTS vector;
-- Create user if not exists (in case it's needed)
DO
$do$
BEGIN
IF NOT EXISTS (
SELECT FROM pg_catalog.pg_roles
WHERE rolname = 'mem0_user') THEN
CREATE ROLE mem0_user LOGIN PASSWORD 'mem0_password';
END IF;
END
$do$;
-- Grant necessary permissions
GRANT ALL PRIVILEGES ON DATABASE mem0_db TO mem0_user;
GRANT ALL ON SCHEMA public TO mem0_user;
-- Create table for vector embeddings (if needed by Mem0's pgvector implementation)
CREATE TABLE IF NOT EXISTS embeddings (
id SERIAL PRIMARY KEY,
user_id VARCHAR(255),
content TEXT,
embedding VECTOR(2560), -- OpenAI embedding dimension
metadata JSONB,
created_at TIMESTAMP DEFAULT NOW()
);
-- Create index for efficient vector similarity search
CREATE INDEX IF NOT EXISTS embeddings_embedding_idx ON embeddings
USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
-- Create index for user_id lookups
CREATE INDEX IF NOT EXISTS embeddings_user_id_idx ON embeddings (user_id);
-- Create index for metadata queries
CREATE INDEX IF NOT EXISTS embeddings_metadata_idx ON embeddings USING GIN (metadata);
-- Grant permissions on the table
GRANT ALL PRIVILEGES ON TABLE embeddings TO mem0_user;
GRANT USAGE, SELECT ON SEQUENCE embeddings_id_seq TO mem0_user;
-- Create table for memory history tracking
CREATE TABLE IF NOT EXISTS memory_history (
id SERIAL PRIMARY KEY,
memory_id VARCHAR(255),
user_id VARCHAR(255),
action VARCHAR(50),
previous_value TEXT,
new_value TEXT,
metadata JSONB,
created_at TIMESTAMP DEFAULT NOW()
);
-- Create indexes for memory history
CREATE INDEX IF NOT EXISTS memory_history_memory_id_idx ON memory_history (memory_id);
CREATE INDEX IF NOT EXISTS memory_history_user_id_idx ON memory_history (user_id);
CREATE INDEX IF NOT EXISTS memory_history_created_at_idx ON memory_history (created_at);
-- Grant permissions
GRANT ALL PRIVILEGES ON TABLE memory_history TO mem0_user;
GRANT USAGE, SELECT ON SEQUENCE memory_history_id_seq TO mem0_user;

View file

@ -1,20 +1,17 @@
services:
# PostgreSQL with pgvector extension for vector storage
postgres:
image: pgvector/pgvector:pg17-trixie
container_name: mem0-postgres
environment:
POSTGRES_DB: ${POSTGRES_DB:-mem0_db}
POSTGRES_USER: ${POSTGRES_USER:-mem0_user}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-mem0_password}
# Qdrant vector database for vector storage
qdrant:
image: qdrant/qdrant:latest
container_name: mem0-qdrant
expose:
- "5432"
- "6333"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./config/postgres-init.sql:/docker-entrypoint-initdb.d/init.sql
- qdrant_data:/qdrant/storage
command: >
sh -c "apt-get update && apt-get install -y curl && ./entrypoint.sh"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-mem0_user} -d ${POSTGRES_DB:-mem0_db}"]
interval: 5s
test: ["CMD", "curl", "-f", "http://localhost:6333/"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
@ -57,11 +54,9 @@ services:
OPENAI_API_KEY: ${OPENAI_COMPAT_API_KEY}
OPENAI_BASE_URL: ${OPENAI_COMPAT_BASE_URL}
EMBEDDER_API_KEY: ${EMBEDDER_API_KEY:-AIzaSyA_}
POSTGRES_HOST: postgres
POSTGRES_PORT: 5432
POSTGRES_DB: ${POSTGRES_DB:-mem0_db}
POSTGRES_USER: ${POSTGRES_USER:-mem0_user}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-mem0_password}
QDRANT_HOST: qdrant
QDRANT_PORT: 6333
QDRANT_COLLECTION_NAME: ${QDRANT_COLLECTION_NAME:-mem0}
NEO4J_URI: bolt://neo4j:7687
NEO4J_USERNAME: ${NEO4J_USERNAME:-neo4j}
NEO4J_PASSWORD: ${NEO4J_PASSWORD:-mem0_neo4j_password}
@ -71,7 +66,7 @@ services:
ports:
- "${BACKEND_PORT:-8000}:8000"
depends_on:
postgres:
qdrant:
condition: service_healthy
neo4j:
condition: service_healthy
@ -81,7 +76,7 @@ services:
command: ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
volumes:
postgres_data:
qdrant_data:
neo4j_data:
neo4j_logs:
neo4j_import:

View file

@ -37,7 +37,14 @@
padding: 20px;
background: #fafafa;
border-bottom: 1px solid #e0e0e0;
display: flex;
justify-content: space-between;
align-items: center;
}
.chat-header-content {
text-align: center;
flex: 1;
}
.chat-header h1 {
@ -51,6 +58,31 @@
font-size: 14px;
}
.clear-chat-btn {
background: #f8f9fa;
color: #666;
border: 1px solid #e0e0e0;
padding: 8px 12px;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
font-weight: 500;
display: flex;
align-items: center;
gap: 5px;
transition: all 0.2s ease;
}
.clear-chat-btn:hover {
background: #e9ecef;
border-color: #ced4da;
color: #495057;
}
.clear-chat-btn:active {
background: #dee2e6;
}
.chat-messages {
flex: 1;
overflow-y: auto;
@ -242,8 +274,13 @@
<!-- Chat Section -->
<div class="chat-section">
<div class="chat-header">
<h1>What can I help you with?</h1>
<p>Chat with your memories - User: pratik</p>
<div class="chat-header-content">
<h1>What can I help you with?</h1>
<p>Chat with your memories - User: pratik</p>
</div>
<button class="clear-chat-btn" id="clearChatBtn" title="Clear chat history">
🗑️ Clear Chat
</button>
</div>
<div class="chat-messages" id="chatMessages">
@ -281,6 +318,7 @@
const memoriesList = document.getElementById('memoriesList');
const memoryCount = document.getElementById('memoryCount');
const refreshButton = document.getElementById('refreshMemories');
const clearChatBtn = document.getElementById('clearChatBtn');
// Chat history in localStorage
let chatHistory = JSON.parse(localStorage.getItem('chatHistory') || '[]');
@ -296,6 +334,7 @@
if (e.key === 'Enter') sendMessage();
});
refreshButton.addEventListener('click', loadMemories);
clearChatBtn.addEventListener('click', clearChatWithConfirmation);
});
// Load chat history from localStorage
@ -493,6 +532,13 @@
}, 5000);
}
// Clear chat history with confirmation
function clearChatWithConfirmation() {
if (confirm('Are you sure you want to clear the chat history? This action cannot be undone.')) {
clearChatHistory();
}
}
// Clear chat history (for debugging)
function clearChatHistory() {
chatHistory = [];