routes.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. from fastapi import APIRouter, HTTPException, Query
  2. from app.core.config import settings
  3. from app.scheduler.manager import scheduler
  4. from app.services.demand_pool_service import (
  5. query_demand_pool_records,
  6. query_strategy_options,
  7. )
  8. from app.services.element_search_service import (
  9. query_monthly_element_demands,
  10. query_same_period_last_year_element_demands,
  11. query_same_period_last_year_lunar_element_demands,
  12. query_video_decode_url2_for_today,
  13. )
  14. router = APIRouter()
  15. @router.get("/health")
  16. async def health_check() -> dict[str, str]:
  17. return {"status": "ok", "service": settings.app_name, "env": settings.app_env}
  18. @router.get("/scheduler/status")
  19. async def scheduler_status() -> dict[str, object]:
  20. jobs = scheduler.get_jobs()
  21. return {
  22. "running": scheduler.running,
  23. "job_count": len(jobs),
  24. "jobs": [job.id for job in jobs],
  25. }
  26. @router.get("/demand-pool")
  27. async def query_demand_pool(
  28. strategy: list[str] | None = Query(default=None, description="策略,支持多选"),
  29. start_dt: str | None = Query(default=None, description="开始日期: yyyymmdd 或 yyyy-mm-dd"),
  30. end_dt: str | None = Query(default=None, description="结束日期: yyyymmdd 或 yyyy-mm-dd"),
  31. demand_name: str | None = Query(
  32. default=None,
  33. description="需求名称包含该子串则保留;空或未传则不筛选",
  34. ),
  35. min_weight: float | None = Query(default=None, description="最小权重"),
  36. max_weight: float | None = Query(default=None, description="最大权重"),
  37. sort_by: str | None = Query(default="weight", description="排序字段"),
  38. sort_order: str | None = Query(default="desc", description="排序方向: asc 或 desc"),
  39. page: int = Query(default=1, ge=1, description="页码,从 1 开始"),
  40. page_size: int = Query(default=20, ge=1, le=200, description="每页条数"),
  41. ) -> dict[str, object]:
  42. return query_demand_pool_records(
  43. strategies=strategy,
  44. start_dt=start_dt,
  45. end_dt=end_dt,
  46. demand_name=demand_name,
  47. min_weight=min_weight,
  48. max_weight=max_weight,
  49. sort_by=sort_by,
  50. sort_order=sort_order,
  51. page=page,
  52. page_size=page_size,
  53. )
  54. @router.get("/element-demands/solar-calendar")
  55. async def get_element_demands_solar_calendar(
  56. period_days: int = Query(
  57. ...,
  58. ge=0,
  59. description="区间天数(含去年阳历今日);0 表示仅当日分区",
  60. ),
  61. view_pv_count: int = Query(
  62. ...,
  63. ge=0,
  64. description="当日分发曝光 pv 下限(video_dimension_detail_add_column)",
  65. ),
  66. min_contribution_score: float = Query(
  67. ...,
  68. description="贡献分下限(dwd_topic_decode_result_detail_di)",
  69. ),
  70. rov_avg: float = Query(
  71. ...,
  72. description="按原始元素分组后的平均 ROV 下限(HAVING)",
  73. ),
  74. ) -> dict[str, object]:
  75. items = query_same_period_last_year_element_demands(
  76. period_days=period_days,
  77. view_pv_count=view_pv_count,
  78. min_contribution_score=min_contribution_score,
  79. rov_avg=rov_avg,
  80. )
  81. return {"items": items}
  82. @router.get("/element-demands/lunar-calendar")
  83. async def get_element_demands_lunar_calendar(
  84. period_days: int = Query(
  85. ...,
  86. ge=0,
  87. description="区间天数(含去年阴历今日);0 表示仅当日分区",
  88. ),
  89. view_pv_count: int = Query(
  90. ...,
  91. ge=0,
  92. description="当日分发曝光 pv 下限(video_dimension_detail_add_column)",
  93. ),
  94. min_contribution_score: float = Query(
  95. ...,
  96. description="贡献分下限(dwd_topic_decode_result_detail_di)",
  97. ),
  98. rov_avg: float = Query(
  99. ...,
  100. description="按原始元素分组后的平均 ROV 下限(HAVING)",
  101. ),
  102. ) -> dict[str, object]:
  103. items = query_same_period_last_year_lunar_element_demands(
  104. period_days=period_days,
  105. view_pv_count=view_pv_count,
  106. min_contribution_score=min_contribution_score,
  107. rov_avg=rov_avg,
  108. )
  109. return {"items": items}
  110. @router.get("/element-demands/monthly")
  111. async def get_element_demands_monthly(
  112. view_pv_count: int = Query(
  113. ...,
  114. ge=0,
  115. description="当日分发曝光 pv 下限(video_dimension_detail_add_column 单日行)",
  116. ),
  117. month_total_pv_threshold: float = Query(
  118. ...,
  119. ge=0,
  120. description="视频单月累计分发曝光 PV 和的下限(严格大于该值才保留)",
  121. ),
  122. min_contribution_score: float = Query(
  123. ...,
  124. description="贡献分下限(dwd_topic_decode_result_detail_di)",
  125. ),
  126. rov_avg: float = Query(
  127. ...,
  128. description="元素单月平均 ROV 下限(按月聚合后再汇总)",
  129. ),
  130. min_frequency: int = Query(
  131. ...,
  132. ge=0,
  133. description="元素在回溯窗口内满足条件的月份数下限",
  134. ),
  135. ) -> dict[str, object]:
  136. items = query_monthly_element_demands(
  137. view_pv_count=view_pv_count,
  138. month_total_pv_threshold=month_total_pv_threshold,
  139. min_contribution_score=min_contribution_score,
  140. rov_avg=rov_avg,
  141. min_frequency=min_frequency,
  142. )
  143. return {"items": items}
  144. @router.get("/videos/decode-url")
  145. async def get_video_decode_page_url(
  146. vid: str = Query(
  147. ...,
  148. min_length=1,
  149. max_length=128,
  150. description="视频 id,对应 dwd_topic_decode_result_di.vid(当天上海分区)",
  151. ),
  152. ) -> dict[str, str | None]:
  153. try:
  154. url2 = query_video_decode_url2_for_today(vid)
  155. except ValueError as exc:
  156. raise HTTPException(status_code=400, detail=str(exc)) from exc
  157. return {"url2": url2}
  158. @router.get("/demand-pool/strategies")
  159. async def get_demand_pool_strategies(
  160. start_dt: str | None = Query(default=None, description="开始日期: yyyymmdd 或 yyyy-mm-dd"),
  161. end_dt: str | None = Query(default=None, description="结束日期: yyyymmdd 或 yyyy-mm-dd"),
  162. min_weight: float | None = Query(default=None, description="最小权重"),
  163. max_weight: float | None = Query(default=None, description="最大权重"),
  164. ) -> dict[str, object]:
  165. return query_strategy_options(
  166. start_dt=start_dt,
  167. end_dt=end_dt,
  168. min_weight=min_weight,
  169. max_weight=max_weight,
  170. )