Add support for Mem0 REST API Server in OSS package (#2240)
This commit is contained in:
16
server/Dockerfile
Normal file
16
server/Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt .
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY .env .
|
||||
COPY . .
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
|
||||
7
server/Makefile
Normal file
7
server/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
build:
|
||||
docker build -t mem0-api-server .
|
||||
|
||||
run_local:
|
||||
docker run -p 8000:8000 -v $(shell pwd):/app mem0-api-server
|
||||
|
||||
.PHONY: build run_local
|
||||
63
server/README.md
Normal file
63
server/README.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Mem0 REST API Server
|
||||
|
||||
Mem0 provides a REST API server (written using FastAPI). Users can perform all operations through REST endpoints. The API also includes OpenAPI documentation, accessible at `/docs` when the server is running.
|
||||
|
||||
## Features
|
||||
|
||||
- **Create memories:** Create memories based on messages for a user, agent, or run.
|
||||
- **Retrieve memories:** Get all memories for a given user, agent, or run.
|
||||
- **Search memories:** Search stored memories based on a query.
|
||||
- **Update memories:** Update an existing memory.
|
||||
- **Delete memories:** Delete a specific memory or all memories for a user, agent, or run.
|
||||
- **Reset memories:** Reset all memories for a user, agent, or run.
|
||||
- **OpenAPI Documentation:** Accessible via `/docs` endpoint.
|
||||
|
||||
## Running Locally
|
||||
|
||||
### With Docker
|
||||
|
||||
1. Create a `.env` file in the root directory of the project and set your environment variables. For example:
|
||||
|
||||
```env
|
||||
OPENAI_API_KEY=your-openai-api-key
|
||||
```
|
||||
|
||||
2. Build the Docker image:
|
||||
|
||||
```bash
|
||||
docker build -t mem0-api-server .
|
||||
```
|
||||
|
||||
3. Run the Docker container:
|
||||
|
||||
``` bash
|
||||
docker run -p 8000:8000 mem0-api-server
|
||||
```
|
||||
|
||||
4. Access the API at http://localhost:8000.
|
||||
|
||||
### Without Docker
|
||||
|
||||
1. Create a `.env` file in the root directory of the project and set your environment variables. For example:
|
||||
|
||||
```env
|
||||
OPENAI_API_KEY=your-openai-api-key
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
3. Start the FastAPI server:
|
||||
|
||||
```bash
|
||||
uvicorn main:app --reload
|
||||
```
|
||||
|
||||
4. Access the API at http://localhost:8000.
|
||||
|
||||
### Usage
|
||||
|
||||
Once the server is running (locally or via Docker), you can interact with it using any REST client or through your preferred programming language (e.g., Go, Java, etc.). You can test out the APIs using the OpenAPI documentation at [`http://localhost:8000/docs`](http://localhost:8000/docs) endpoint.
|
||||
158
server/main.py
Normal file
158
server/main.py
Normal file
@@ -0,0 +1,158 @@
|
||||
import os
|
||||
from fastapi import FastAPI, HTTPException, Query, Path
|
||||
from fastapi.responses import JSONResponse, RedirectResponse
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional, List, Any, Dict
|
||||
from mem0 import Memory
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load environment variables
|
||||
load_dotenv()
|
||||
|
||||
MEMORY_INSTANCE = Memory()
|
||||
|
||||
app = FastAPI(
|
||||
title="Mem0 REST APIs",
|
||||
description="A REST API for managing and searching memories for your AI Agents and Apps.",
|
||||
version="1.0.0",
|
||||
)
|
||||
|
||||
|
||||
class Message(BaseModel):
|
||||
role: str = Field(..., description="Role of the message (user or assistant).")
|
||||
content: str = Field(..., description="Message content.")
|
||||
|
||||
|
||||
class MemoryCreate(BaseModel):
|
||||
messages: List[Message] = Field(..., description="List of messages to store.")
|
||||
user_id: Optional[str] = None
|
||||
agent_id: Optional[str] = None
|
||||
run_id: Optional[str] = None
|
||||
metadata: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
class SearchRequest(BaseModel):
|
||||
query: str = Field(..., description="Search query.")
|
||||
user_id: Optional[str] = None
|
||||
run_id: Optional[str] = None
|
||||
agent_id: Optional[str] = None
|
||||
|
||||
|
||||
@app.post("/configure", summary="Configure Mem0")
|
||||
def set_config(config: Dict[str, Any]):
|
||||
"""Set memory configuration."""
|
||||
global MEMORY_INSTANCE
|
||||
MEMORY_INSTANCE = Memory.from_config(config)
|
||||
return {"message": "Configuration set successfully"}
|
||||
|
||||
|
||||
@app.post("/memories", summary="Create memories")
|
||||
def add_memory(memory_create: MemoryCreate):
|
||||
"""Store new memories."""
|
||||
if not any([memory_create.user_id, memory_create.agent_id, memory_create.run_id]):
|
||||
raise HTTPException(
|
||||
status_code=400, detail="At least one identifier (user_id, agent_id, run_id) is required."
|
||||
)
|
||||
|
||||
params = {k: v for k, v in memory_create.model_dump().items() if v is not None and k != "messages"}
|
||||
try:
|
||||
response = MEMORY_INSTANCE.add(messages=[m.model_dump() for m in memory_create.messages], **params)
|
||||
return JSONResponse(content=response)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@app.get("/memories", summary="Get memories")
|
||||
def get_all_memories(
|
||||
user_id: Optional[str] = None,
|
||||
run_id: Optional[str] = None,
|
||||
agent_id: Optional[str] = None,
|
||||
):
|
||||
"""Retrieve stored memories."""
|
||||
if not any([user_id, run_id, agent_id]):
|
||||
raise HTTPException(status_code=400, detail="At least one identifier is required.")
|
||||
try:
|
||||
params = {k: v for k, v in {"user_id": user_id, "run_id": run_id, "agent_id": agent_id}.items() if v is not None}
|
||||
return MEMORY_INSTANCE.get_all(**params)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@app.get("/memories/{memory_id}", summary="Get a memory")
|
||||
def get_memory(memory_id: str):
|
||||
"""Retrieve a specific memory by ID."""
|
||||
try:
|
||||
return MEMORY_INSTANCE.get(memory_id)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@app.post("/search", summary="Search memories")
|
||||
def search_memories(search_req: SearchRequest):
|
||||
"""Search for memories based on a query."""
|
||||
try:
|
||||
params = {k: v for k, v in search_req.model_dump().items() if v is not None and k != "query"}
|
||||
return MEMORY_INSTANCE.search(query=search_req.query, **params)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@app.put("/memories/{memory_id}", summary="Update a memory")
|
||||
def update_memory(memory_id: str, updated_memory: Dict[str, Any]):
|
||||
"""Update an existing memory."""
|
||||
try:
|
||||
return MEMORY_INSTANCE.update(memory_id=memory_id, data=updated_memory)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@app.get("/memories/{memory_id}/history", summary="Get memory history")
|
||||
def memory_history(memory_id: str):
|
||||
"""Retrieve memory history."""
|
||||
try:
|
||||
return MEMORY_INSTANCE.history(memory_id=memory_id)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@app.delete("/memories/{memory_id}", summary="Delete a memory")
|
||||
def delete_memory(memory_id: str):
|
||||
"""Delete a specific memory by ID."""
|
||||
try:
|
||||
MEMORY_INSTANCE.delete(memory_id=memory_id)
|
||||
return {"message": "Memory deleted successfully"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@app.delete("/memories", summary="Delete all memories")
|
||||
def delete_all_memories(
|
||||
user_id: Optional[str] = None,
|
||||
run_id: Optional[str] = None,
|
||||
agent_id: Optional[str] = None,
|
||||
):
|
||||
"""Delete all memories for a given identifier."""
|
||||
if not any([user_id, run_id, agent_id]):
|
||||
raise HTTPException(status_code=400, detail="At least one identifier is required.")
|
||||
try:
|
||||
params = {k: v for k, v in {"user_id": user_id, "run_id": run_id, "agent_id": agent_id}.items() if v is not None}
|
||||
MEMORY_INSTANCE.delete_all(**params)
|
||||
return {"message": "All relevant memories deleted"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@app.post("/reset", summary="Reset all memories")
|
||||
def reset_memory():
|
||||
"""Completely reset stored memories."""
|
||||
try:
|
||||
MEMORY_INSTANCE.reset()
|
||||
return {"message": "All memories reset"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@app.get("/", summary="Redirect to the OpenAPI documentation", include_in_schema=False)
|
||||
def home():
|
||||
"""Redirect to the OpenAPI documentation."""
|
||||
return RedirectResponse(url='/docs')
|
||||
5
server/requirements.txt
Normal file
5
server/requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
fastapi==0.115.8
|
||||
uvicorn==0.34.0
|
||||
pydantic==2.10.4
|
||||
mem0ai>=0.1.48
|
||||
python-dotenv==1.0.1
|
||||
Reference in New Issue
Block a user