web_api.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. """前端取数接口:从 app.db 分页/筛选返回 query 与真实搜索结果。
  2. 挂到现有 FastAPI(creation_knowledge/api.py)。前端从「读死 json」改成调这些接口:
  3. GET /api/runs 有哪些批次
  4. GET /api/methods?table=queries|search 某表的打法清单(筛选下拉)
  5. GET /api/queries?method=&run_id=&page=&size=
  6. GET /api/search?platform=&method=&ok=&run_id=&page=&size=
  7. 每个请求开一个 sqlite 连接(轻、够用);连接出错时接口照常返回空集,不 500。
  8. """
  9. from __future__ import annotations
  10. from pathlib import Path
  11. from typing import Optional
  12. from fastapi import APIRouter, Query
  13. from acquisition import store
  14. from acquisition.query import (
  15. ACTIONS, CARRIER_POS_GROUPED, DEMAND, KTYPE_SUFFIX, MODALITIES, STAGES,
  16. )
  17. router = APIRouter(prefix="/api")
  18. _ROOT = Path(__file__).resolve().parent.parent
  19. # 分类「创作知识 / 非创作知识」用的真实判断提示词(图文 / 视频),前端弹窗展示。读 is_empty 为判据。
  20. _JUDGE_PROMPTS = [
  21. ("图文(小红书 / 微信公众号)", "classify_imgtext.txt"),
  22. ("视频(抖音)", "classify_video.txt"),
  23. ]
  24. # 各方法里【人工定义】的轴及其全部取值(实质/形式/作用来自分类树,不在此)。单一来源 = query.py。
  25. MANUAL_AXES = {
  26. "实质 × 创作阶段 × 需求": {"创作阶段": STAGES, "需求点": DEMAND},
  27. "形式 + 载体位置": {"载体位置": CARRIER_POS_GROUPED},
  28. "多轴正交组合": {"阶段": STAGES, "动作": ACTIONS, "知识类型": KTYPE_SUFFIX, "模态": MODALITIES},
  29. }
  30. @router.get("/judge-prompts")
  31. def judge_prompts() -> dict:
  32. """分类创作知识用的真实提示词(图文 / 视频),原样返回供前端展示。"""
  33. out = []
  34. for label, fn in _JUDGE_PROMPTS:
  35. try:
  36. text = (_ROOT / "prompts" / fn).read_text("utf-8")
  37. except Exception as exc:
  38. text = f"(读取失败: {exc})"
  39. out.append({"name": label, "file": fn, "text": text})
  40. return {"prompts": out}
  41. @router.get("/filter-prompt")
  42. def filter_prompt() -> dict:
  43. """机械正交出 query 后做 keep/排除 的【创作筛选提示词】(acquisition/query_filter.txt),原样返回供前端弹窗。"""
  44. try:
  45. text = (_ROOT / "acquisition" / "query_filter.txt").read_text("utf-8")
  46. except Exception as exc:
  47. text = f"(读取失败: {exc})"
  48. return {"name": "创作 query 筛选器(命中 A–E 即排除)", "file": "acquisition/query_filter.txt", "text": text}
  49. @router.get("/runs")
  50. def runs() -> dict:
  51. conn = store.connect()
  52. try:
  53. return {"runs": store.list_runs(conn)}
  54. finally:
  55. conn.close()
  56. @router.get("/manual-axes")
  57. def manual_axes() -> dict:
  58. """各方法人工定义轴的全部取值(前端「查看人工定义的轴」弹窗用)。"""
  59. return {"axes": MANUAL_AXES}
  60. @router.get("/methods")
  61. def methods(table: str = Query("queries")) -> dict:
  62. conn = store.connect()
  63. try:
  64. tbl = "search_results" if table == "search" else "queries"
  65. return {"methods": store.list_methods(conn, tbl)}
  66. finally:
  67. conn.close()
  68. @router.get("/queries")
  69. def queries(method: Optional[str] = None, run_id: Optional[str] = None,
  70. page: int = 1, size: int = 30) -> dict:
  71. conn = store.connect()
  72. try:
  73. return store.list_queries(conn, method=method, run_id=run_id, page=page, size=size)
  74. finally:
  75. conn.close()
  76. @router.get("/search")
  77. def search(platform: Optional[str] = None, method: Optional[str] = None,
  78. ok: Optional[bool] = None, run_id: Optional[str] = None,
  79. query: Optional[str] = None, page: int = 1, size: int = 30) -> dict:
  80. conn = store.connect()
  81. try:
  82. return store.list_search(conn, platform=platform, method=method, ok=ok,
  83. run_id=run_id, query=query, page=page, size=size)
  84. finally:
  85. conn.close()
  86. @router.get("/search/summary")
  87. def search_summary() -> dict:
  88. """{query文本: {total, ok}}——列表页据此给每条 query 显示「搜索结果」按钮与计数。"""
  89. conn = store.connect()
  90. try:
  91. return {"summary": store.search_summary(conn)}
  92. finally:
  93. conn.close()
  94. @router.get("/creation-search/summary")
  95. def creation_search_summary(run_id: Optional[str] = None) -> dict:
  96. """430 query 真实采集状态:{query: {platforms, done, failed, display_count}}。"""
  97. conn = store.connect()
  98. try:
  99. return store.creation_search_summary(conn, run_id=run_id)
  100. finally:
  101. conn.close()
  102. @router.get("/creation-search/query")
  103. def creation_search_query(query: str, run_id: Optional[str] = None,
  104. display_limit: int = 5) -> dict:
  105. """单条 query 的三平台详情,每个平台最多 display_limit 条可展示内容。"""
  106. conn = store.connect()
  107. try:
  108. return store.get_creation_query_detail(
  109. conn, query, run_id=run_id, display_limit=display_limit
  110. )
  111. finally:
  112. conn.close()