Add search history with saved results

Saves each mood search and its recommendations to SQLite per user.
Recent searches appear below the results area with mood text, top
movie titles, and timestamp. Click any entry to reload those results.
Entries can be deleted individually. History toggleable via show/hide.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-14 19:57:50 -07:00
parent 3d5de06b44
commit d8c8b473ad
4 changed files with 178 additions and 10 deletions
+69 -10
View File
@@ -1,11 +1,12 @@
import json
import logging
import time
from datetime import datetime, timezone
from fastapi import APIRouter, HTTPException, Request
from app.config import settings
from app.database import get_unwatched_movies
from app.database import get_db, get_unwatched_movies
from app.models import MoodRequest, MoodResponse, Recommendation
from app.routers.auth import get_current_user
from app.services.jellyfin import get_deep_link, get_poster_url
@@ -89,12 +90,70 @@ async def get_mood_recommendations(request: Request, body: MoodRequest):
elapsed_ms = int((time.time() - start_time) * 1000)
return MoodResponse(
recommendations=recommendations,
meta={
"total_unwatched": total_unwatched,
"candidates_evaluated": len(candidates),
"processing_time_ms": elapsed_ms,
"mood": body.mood,
},
)
meta = {
"total_unwatched": total_unwatched,
"candidates_evaluated": len(candidates),
"processing_time_ms": elapsed_ms,
"mood": body.mood,
}
# Save to search history
try:
db = await get_db()
try:
await db.execute(
"INSERT INTO search_history (user_id, mood, results, meta, created_at) VALUES (?, ?, ?, ?, ?)",
(
user["id"],
body.mood,
json.dumps([r.model_dump() for r in recommendations]),
json.dumps(meta),
datetime.now(timezone.utc).isoformat(),
),
)
await db.commit()
finally:
await db.close()
except Exception as e:
logger.warning(f"Failed to save search history: {e}")
return MoodResponse(recommendations=recommendations, meta=meta)
@router.get("/history")
async def get_search_history(request: Request):
user = await get_current_user(request)
db = await get_db()
try:
cursor = await db.execute(
"SELECT id, mood, results, meta, created_at FROM search_history WHERE user_id = ? ORDER BY created_at DESC LIMIT 20",
(user["id"],),
)
rows = await cursor.fetchall()
return [
{
"id": row["id"],
"mood": row["mood"],
"results": json.loads(row["results"]),
"meta": json.loads(row["meta"]) if row["meta"] else {},
"created_at": row["created_at"],
}
for row in rows
]
finally:
await db.close()
@router.delete("/history/{entry_id}")
async def delete_history_entry(entry_id: int, request: Request):
user = await get_current_user(request)
db = await get_db()
try:
await db.execute(
"DELETE FROM search_history WHERE id = ? AND user_id = ?",
(entry_id, user["id"]),
)
await db.commit()
return {"ok": True}
finally:
await db.close()