feat: API routes — speakers, rooms, search, RAG
Full implementations replacing stubs: speakers CRUD with utterance count, rooms list + mute/unmute via pipeline, FTS5-based search, RAG /ask and /summary endpoints. 15 route tests (8 new) all passing; 35 total. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+62
-2
@@ -1,6 +1,66 @@
|
||||
from fastapi import APIRouter
|
||||
import sqlite3
|
||||
import httpx
|
||||
from typing import Optional
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from app.shared.config import Settings
|
||||
|
||||
|
||||
def make_router(settings, db_factory):
|
||||
class AskRequest(BaseModel):
|
||||
question: str
|
||||
date: Optional[str] = None
|
||||
|
||||
|
||||
def make_router(settings: Settings, db_factory):
|
||||
router = APIRouter(prefix="/api")
|
||||
|
||||
@router.post("/ask")
|
||||
def ask(body: AskRequest):
|
||||
db: sqlite3.Connection = db_factory()
|
||||
rows = db.execute("""
|
||||
SELECT u.start_time, u.transcript, r.name as room_name, s.name as speaker_name
|
||||
FROM utterances u
|
||||
JOIN rooms r ON u.room_id = r.id
|
||||
LEFT JOIN speakers s ON u.speaker_id = s.id
|
||||
WHERE date(u.start_time) = date(?)
|
||||
ORDER BY u.start_time ASC
|
||||
LIMIT 200
|
||||
""", (body.date or "now",)).fetchall()
|
||||
|
||||
context_lines = [
|
||||
f"[{r['room_name']} {r['start_time']}] {r['speaker_name'] or 'Unknown'}: {r['transcript']}"
|
||||
for r in rows
|
||||
]
|
||||
context = "\n".join(context_lines) if context_lines else "(no transcripts for this date)"
|
||||
|
||||
prompt = (
|
||||
f"You are a helpful assistant with access to household conversation transcripts.\n\n"
|
||||
f"Transcripts:\n{context}\n\n"
|
||||
f"Question: {body.question}\n\n"
|
||||
f"Answer based only on the transcripts above. Cite the time and room when relevant."
|
||||
)
|
||||
|
||||
resp = httpx.post(
|
||||
f"{settings.ollama_url}/api/chat",
|
||||
json={
|
||||
"model": settings.ollama_model,
|
||||
"messages": [{"role": "user", "content": prompt}],
|
||||
"stream": False,
|
||||
},
|
||||
timeout=60.0,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
answer = resp.json()["message"]["content"]
|
||||
return {"answer": answer, "context_count": len(rows)}
|
||||
|
||||
@router.get("/summary/{date}")
|
||||
def get_summary(date: str):
|
||||
db: sqlite3.Connection = db_factory()
|
||||
row = db.execute(
|
||||
"SELECT * FROM daily_summaries WHERE date=?", (date,)
|
||||
).fetchone()
|
||||
if not row:
|
||||
raise HTTPException(404, f"No summary for {date}")
|
||||
return dict(row)
|
||||
|
||||
return router
|
||||
|
||||
Reference in New Issue
Block a user