Auto-mode commit 7aa33cd accidentally deleted 78 files (14,814 lines) during M005
execution. Subsequent commits rebuilt some frontend files but backend/, alembic/,
tests/, whisper/, docker configs, and prompts were never restored in this repo.
This commit restores the full project tree by syncing from ub01's working directory,
which has all M001-M007 features running in production containers.
Restored: backend/ (config, models, routers, database, redis, search_service, worker),
alembic/ (6 migrations), docker/ (Dockerfiles, nginx, compose), prompts/ (4 stages),
tests/, whisper/, README.md, .env.example, chrysopedia-spec.md
46 lines
1.5 KiB
Python
46 lines
1.5 KiB
Python
"""Search endpoint for semantic + keyword search with graceful fallback."""
|
||
|
||
from __future__ import annotations
|
||
|
||
import logging
|
||
from typing import Annotated
|
||
|
||
from fastapi import APIRouter, Depends, Query
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
||
from config import get_settings
|
||
from database import get_session
|
||
from schemas import SearchResponse, SearchResultItem
|
||
from search_service import SearchService
|
||
|
||
logger = logging.getLogger("chrysopedia.search.router")
|
||
|
||
router = APIRouter(prefix="/search", tags=["search"])
|
||
|
||
|
||
def _get_search_service() -> SearchService:
|
||
"""Build a SearchService from current settings."""
|
||
return SearchService(get_settings())
|
||
|
||
|
||
@router.get("", response_model=SearchResponse)
|
||
async def search(
|
||
q: Annotated[str, Query(max_length=500)] = "",
|
||
scope: Annotated[str, Query()] = "all",
|
||
limit: Annotated[int, Query(ge=1, le=100)] = 20,
|
||
db: AsyncSession = Depends(get_session),
|
||
) -> SearchResponse:
|
||
"""Semantic search with keyword fallback.
|
||
|
||
- **q**: Search query (max 500 chars). Empty → empty results.
|
||
- **scope**: ``all`` | ``topics`` | ``creators``. Invalid → defaults to ``all``.
|
||
- **limit**: Max results (1–100, default 20).
|
||
"""
|
||
svc = _get_search_service()
|
||
result = await svc.search(query=q, scope=scope, limit=limit, db=db)
|
||
return SearchResponse(
|
||
items=[SearchResultItem(**item) for item in result["items"]],
|
||
total=result["total"],
|
||
query=result["query"],
|
||
fallback_used=result["fallback_used"],
|
||
)
|