forked from Rockachopa/Timmy-time-dashboard
123 lines
3.3 KiB
Python
123 lines
3.3 KiB
Python
"""Memory (vector store) routes for browsing and searching memories."""
|
|
|
|
from fastapi import APIRouter, Form, HTTPException, Request
|
|
from fastapi.responses import HTMLResponse, JSONResponse
|
|
|
|
from dashboard.templating import templates
|
|
from timmy.memory_system import (
|
|
delete_memory,
|
|
get_memory_stats,
|
|
recall_personal_facts_with_ids,
|
|
search_memories,
|
|
store_personal_fact,
|
|
update_personal_fact,
|
|
)
|
|
|
|
router = APIRouter(prefix="/memory", tags=["memory"])
|
|
|
|
|
|
@router.get("", response_class=HTMLResponse)
|
|
async def memory_page(
|
|
request: Request,
|
|
query: str | None = None,
|
|
context_type: str | None = None,
|
|
agent_id: str | None = None,
|
|
):
|
|
"""Memory browser and search page."""
|
|
results = []
|
|
if query:
|
|
results = search_memories(
|
|
query=query,
|
|
context_type=context_type,
|
|
agent_id=agent_id,
|
|
limit=20,
|
|
)
|
|
|
|
stats = get_memory_stats()
|
|
facts = recall_personal_facts_with_ids()[:10]
|
|
|
|
return templates.TemplateResponse(
|
|
request,
|
|
"memory.html",
|
|
{
|
|
"page_title": "Memory Browser",
|
|
"query": query,
|
|
"results": results,
|
|
"stats": stats,
|
|
"facts": facts,
|
|
"filter_type": context_type,
|
|
"filter_agent": agent_id,
|
|
},
|
|
)
|
|
|
|
|
|
@router.post("/search", response_class=HTMLResponse)
|
|
async def memory_search(
|
|
request: Request,
|
|
query: str = Form(...),
|
|
context_type: str | None = Form(None),
|
|
):
|
|
"""Search memories (form submission)."""
|
|
query = query.strip()
|
|
if not query:
|
|
raise HTTPException(status_code=400, detail="Search query cannot be empty")
|
|
|
|
results = search_memories(
|
|
query=query,
|
|
context_type=context_type,
|
|
limit=20,
|
|
)
|
|
|
|
# Return partial for HTMX
|
|
return templates.TemplateResponse(
|
|
request,
|
|
"partials/memory_results.html",
|
|
{
|
|
"query": query,
|
|
"results": results,
|
|
},
|
|
)
|
|
|
|
|
|
@router.post("/fact", response_class=HTMLResponse)
|
|
async def add_fact(
|
|
request: Request,
|
|
fact: str = Form(...),
|
|
agent_id: str | None = Form(None),
|
|
):
|
|
"""Add a personal fact to memory."""
|
|
fact = fact.strip()
|
|
if not fact:
|
|
raise HTTPException(status_code=400, detail="Fact content cannot be empty")
|
|
|
|
store_personal_fact(fact, agent_id=agent_id)
|
|
|
|
facts = recall_personal_facts_with_ids()[:10]
|
|
return templates.TemplateResponse(
|
|
request,
|
|
"partials/memory_facts.html",
|
|
{"facts": facts},
|
|
)
|
|
|
|
|
|
@router.put("/fact/{fact_id}", response_class=JSONResponse)
|
|
async def edit_fact(fact_id: str, request: Request):
|
|
"""Update a personal fact."""
|
|
body = await request.json()
|
|
new_content = body.get("content", "").strip()
|
|
if not new_content:
|
|
raise HTTPException(400, "Content cannot be empty")
|
|
ok = update_personal_fact(fact_id, new_content)
|
|
if not ok:
|
|
raise HTTPException(404, "Fact not found")
|
|
return {"success": True, "id": fact_id, "content": new_content}
|
|
|
|
|
|
@router.delete("/fact/{fact_id}", response_class=JSONResponse)
|
|
async def delete_fact(fact_id: str):
|
|
"""Delete a personal fact."""
|
|
ok = delete_memory(fact_id)
|
|
if not ok:
|
|
raise HTTPException(404, "Fact not found")
|
|
return {"success": True, "id": fact_id}
|