search.py 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. from __future__ import annotations
  2. import logging
  3. from fastapi import APIRouter, Query
  4. from app.core.response import ApiResponse, BusinessError, ResponseCode
  5. from app.schemas import SearchData, SearchRequest
  6. from app.services.cache import get_snapshot
  7. from app.services.zendesk_client import ZendeskError, search_articles
  8. logger = logging.getLogger(__name__)
  9. router = APIRouter(prefix="/faq",tags=["search"])
  10. async def _do_search(req: SearchRequest) -> ApiResponse[SearchData]:
  11. """共享的搜索逻辑:从 Redis 共享缓存读 sec_ids,调用 Zendesk。"""
  12. snapshot = await get_snapshot()
  13. sec_ids: list[int] = snapshot["sec_ids"]
  14. if not sec_ids:
  15. logger.warning("FAQ sec_ids 缓存为空,本次搜索不带 section 过滤")
  16. try:
  17. data = await search_articles(
  18. query=req.query,
  19. section_ids=sec_ids,
  20. locale=req.locale,
  21. page=req.page,
  22. per_page=req.per_page,
  23. )
  24. except ZendeskError as exc:
  25. raise BusinessError(ResponseCode.UPSTREAM_ERROR) from exc
  26. return ApiResponse.ok(
  27. data=SearchData(
  28. count=int(data.get("count", 0)),
  29. page=req.page,
  30. per_page=req.per_page,
  31. is_next_page=bool(data.get("next_page")),
  32. results=data.get("results", []),
  33. )
  34. )
  35. @router.post(
  36. "/search",
  37. response_model=ApiResponse[SearchData],
  38. summary="按 QUERY 搜索 FAQ 文章 (POST)",
  39. )
  40. async def search_post(req: SearchRequest) -> ApiResponse[SearchData]:
  41. """POST 版本,请求体:{"query": "...", "locale": "...", ...}。"""
  42. return await _do_search(req)
  43. # @router.get(
  44. # "/search",
  45. # response_model=ApiResponse[SearchData],
  46. # summary="按 QUERY 搜索 FAQ 文章",
  47. # )
  48. # async def search_get(
  49. # query: str = Query(..., min_length=1, description="搜索关键词"),
  50. # locale: str | None = Query(default=None),
  51. # page: int = Query(default=1, ge=1),
  52. # per_page: int = Query(default=25, ge=1, le=100),
  53. # ) -> ApiResponse[SearchData]:
  54. # return await _do_search(
  55. # SearchRequest(
  56. # query=query, locale=locale, page=page, per_page=per_page
  57. # )
  58. # )