app.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. """FastAPI application — category tree API on port 8080."""
  2. from __future__ import annotations
  3. from contextlib import asynccontextmanager
  4. from pathlib import Path
  5. from fastapi import FastAPI, HTTPException, Query
  6. from fastapi.middleware.cors import CORSMiddleware
  7. from fastapi.staticfiles import StaticFiles
  8. from api.services.category_tree import build_category_tree
  9. from api.services.demand_belong_category import list_demand_belong_categories
  10. from api.services.demand_grade import list_demand_grades
  11. from api.services.demand_grade_videos import list_videos_for_demand_grade
  12. from api.services.demand_videos import list_videos_for_demand_belong
  13. from api.services.oss_logs import list_demand_belong_oss_logs
  14. from supply_infra.db import init_db
  15. from supply_infra.scheduler import get_scheduler_status, start_scheduler, stop_scheduler
  16. @asynccontextmanager
  17. async def lifespan(_app: FastAPI):
  18. init_db()
  19. start_scheduler()
  20. yield
  21. stop_scheduler()
  22. app = FastAPI(title="SupplyAgent API", version="0.1.0", lifespan=lifespan)
  23. app.add_middleware(
  24. CORSMiddleware,
  25. allow_origins=[
  26. "http://localhost:5173",
  27. "http://127.0.0.1:5173",
  28. "http://localhost:4173",
  29. "http://127.0.0.1:4173",
  30. ],
  31. allow_credentials=True,
  32. allow_methods=["*"],
  33. allow_headers=["*"],
  34. )
  35. @app.get("/health")
  36. def health() -> dict[str, str]:
  37. return {"status": "ok"}
  38. @app.get("/api/scheduler/status")
  39. def scheduler_status() -> dict:
  40. """Return scheduler enabled/running state and next run times."""
  41. return get_scheduler_status()
  42. @app.get("/api/category-tree")
  43. def category_tree(
  44. biz_dt: str | None = Query(
  45. default=None,
  46. description="业务日 YYYYMMDD;省略则取 category_tree_weight 最新一日",
  47. ),
  48. ) -> dict:
  49. """Return nested global_tree_category with per-dim avg score."""
  50. return build_category_tree(biz_dt=biz_dt)
  51. @app.get("/api/demand-belong-category")
  52. def demand_belong_category() -> dict:
  53. """Return all active demand_belong_category rows in one response."""
  54. items = list_demand_belong_categories()
  55. return {"items": items}
  56. @app.get("/api/demand-belong-category/{belong_id}/videos")
  57. def demand_belong_videos(belong_id: int) -> dict:
  58. """Return videos linked to a demand_belong_category row (vid + title + points JSON)."""
  59. result = list_videos_for_demand_belong(belong_id)
  60. if result is None:
  61. raise HTTPException(status_code=404, detail="demand_belong_category not found")
  62. return result
  63. @app.get("/api/demand-grade")
  64. def demand_grade(
  65. biz_dt: str | None = Query(
  66. default=None,
  67. description="业务日 YYYYMMDD;省略则取 demand_grade 最新一日",
  68. ),
  69. ) -> dict:
  70. """Return demand_grade rows (one per category_id) for the given/latest biz_dt."""
  71. items = list_demand_grades(biz_dt=biz_dt)
  72. return {"items": items}
  73. @app.get("/api/demand-grade/{demand_grade_id}/videos")
  74. def demand_grade_videos(demand_grade_id: int) -> dict:
  75. """Return videos linked to a demand_grade row (vid + title + points JSON)."""
  76. result = list_videos_for_demand_grade(demand_grade_id)
  77. if result is None:
  78. raise HTTPException(status_code=404, detail="demand_grade not found")
  79. return result
  80. @app.get("/api/demand-belong-oss-logs")
  81. def demand_belong_oss_logs() -> dict:
  82. """Return demand_belong_category_agent oss_logs ordered by create_time desc."""
  83. items = list_demand_belong_oss_logs()
  84. return {"items": items}
  85. _web_dist = Path(__file__).resolve().parent.parent / "web" / "dist"
  86. if _web_dist.is_dir():
  87. app.mount("/", StaticFiles(directory=_web_dist, html=True), name="web")