from fastapi import FastAPI, UploadFile, File
from fastapi.responses import HTMLResponse
import ollama
import chromadb
from faster_whisper import WhisperModel
import os
import uuid
app = FastAPI()
UPLOAD_DIR = "uploads"
os.makedirs(UPLOAD_DIR, exist_ok=True)
Local embedding database
client = chromadb.PersistentClient(path="./memory.db")
collection = client.get_or_create_collection(
name="memories"
)
Local speech-to-text model
whisper = WhisperModel(
"base",
device="cpu",
compute_type="int8"
)
def ask_ai(prompt):
response = ollama.chat(
model="qwen3:4b",
messages=[
{
"role": "system",
"content": """
You are OpenMemo, a private personal memory assistant.
Use only the information provided by the user.
Do not invent memories.
Be concise and helpful.
"""
},
{
"role": "user",
"content": prompt
}
]
)
return response["message"]["content"]
@app.post("/upload")
async def upload(file: UploadFile = File(...)):
file_id = str(uuid.uuid4())
path = f"{UPLOAD_DIR}/{file_id}_{file.filename}"
with open(path, "wb") as f:
f.write(await file.read())
segments, info = whisper.transcribe(path)
text = " ".join(
segment.text for segment in segments
)
collection.add(
documents=[text],
ids=[file_id],
metadatas=[
{
"filename": file.filename
}
]
)
return {
"success": True,
"transcription": text
}
@app.get("/ask")
def ask(question: str):
results = collection.query(
query_texts=[question],
n_results=5
)
memories = "\n".join(
results["documents"][0]
)
answer = ask_ai(
f"""
Relevant memories:
{memories}
Question:
{question}
Answer using only the relevant memories.
"""
)
return {
"answer": answer,
"memories": results["documents"][0]
}
@app.get("/")
def home():
return HTMLResponse("""
<!DOCTYPE html>
<style>
body {
font-family: Arial;
max-width: 800px;
margin: 50px auto;
padding: 20px;
background: #f5f5f5;
}
.card {
background: white;
padding: 25px;
border-radius: 15px;
margin-bottom: 20px;
}
button {
padding: 12px 20px;
border: none;
border-radius: 8px;
cursor: pointer;
}
input {
padding: 12px;
width: 70%;
}
#answer {
margin-top: 20px;
white-space: pre-wrap;
}
</style>
🧠OpenMemo
Add a memory
Upload
Ask your memories
Ask AI
async function upload() {
const file =
document.getElementById("audio").files[0];
if (!file) {
alert("Choose an audio file first.");
return;
}
const form = new FormData();
form.append("file", file);
const response =
await fetch("/upload", {
method: "POST",
body: form
});
const data = await response.json();
document.getElementById("result").innerText =
"Saved memory:\\n" + data.transcription;
}
async function ask() {
const question =
document.getElementById("question").value;
const response =
await fetch(
"/ask?question=" +
encodeURIComponent(question)
);
const data = await response.json();
document.getElementById("answer").innerText =
data.answer;
}
""")
Top comments (0)