routes.py 5.7 KB

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