from fastapi import APIRouter, File, Form, Query, UploadFile from app.api.analysis_schemas import AnalysisChartResponse, AnalysisReportResponse from app.api.capital_image_schemas import ( CapitalImageListResponse, CapitalImageRecordDetail, CapitalImageUploadResponse, ) from app.api.main_capital_flow_schemas import ( MainCapitalFlowCreateRequest, MainCapitalFlowCreateResponse, MainCapitalFlowDeleteResponse, MainCapitalFlowListResponse, MainCapitalFlowRecognizeResponse, MainCapitalFlowRecordDetail, ) from app.api.schemas import ( AShareIndexFlowResponse, AShareSectorFlowResponse, EtfRealtimeResponse, HealthResponse, HistoryResponse, MetaResponse, OverviewResponse, PushRecord, PushRecordsResponse, RulesResponse, SourceDiagnosticsResponse, ) from app.services.analysis_service import analysis_service from app.services.ashare_flow_service import ashare_flow_service from app.services.alert_service import alert_service from app.services.capital_image_service import capital_image_service from app.services.etf_monitor_service import etf_monitor_service from app.services.main_capital_flow_service import main_capital_flow_service from app.services.monitoring_service import monitoring_service router = APIRouter() @router.get("/health", response_model=HealthResponse) def health() -> HealthResponse: return HealthResponse(status="ok") @router.get("/capital-images", response_model=CapitalImageListResponse) def capital_image_list( trade_date: str | None = Query(default=None), subject: str | None = Query(default=None), ) -> CapitalImageListResponse: return CapitalImageListResponse(**capital_image_service.list_records(trade_date, subject)) @router.get("/capital-images/{record_id}", response_model=CapitalImageRecordDetail) def capital_image_detail(record_id: str) -> CapitalImageRecordDetail: return CapitalImageRecordDetail(**capital_image_service.get_record(record_id)) @router.post("/capital-images/upload", response_model=CapitalImageUploadResponse) async def capital_image_upload( image: UploadFile = File(...), trade_date: str | None = Form(default=None), subject: str | None = Form(default=None), ) -> CapitalImageUploadResponse: return CapitalImageUploadResponse( **await capital_image_service.create_record(image, trade_date=trade_date, subject=subject) ) @router.get("/main-capital-flows", response_model=MainCapitalFlowListResponse) def main_capital_flow_list() -> MainCapitalFlowListResponse: return MainCapitalFlowListResponse(**main_capital_flow_service.list_records()) @router.get("/main-capital-flows/{record_id}", response_model=MainCapitalFlowRecordDetail) def main_capital_flow_detail(record_id: str) -> MainCapitalFlowRecordDetail: return MainCapitalFlowRecordDetail(**main_capital_flow_service.get_record(record_id)) @router.post("/main-capital-flows/recognize", response_model=MainCapitalFlowRecognizeResponse) async def main_capital_flow_recognize( image: UploadFile = File(...), trade_date: str | None = Form(default=None), subject: str | None = Form(default=None), ) -> MainCapitalFlowRecognizeResponse: return MainCapitalFlowRecognizeResponse( **await main_capital_flow_service.recognize_image(image, trade_date=trade_date, subject=subject) ) @router.post("/main-capital-flows", response_model=MainCapitalFlowCreateResponse) def main_capital_flow_create(payload: MainCapitalFlowCreateRequest) -> MainCapitalFlowCreateResponse: return MainCapitalFlowCreateResponse(**main_capital_flow_service.create_record(payload.model_dump())) @router.delete("/main-capital-flows/{record_id}", response_model=MainCapitalFlowDeleteResponse) def main_capital_flow_delete(record_id: str) -> MainCapitalFlowDeleteResponse: return MainCapitalFlowDeleteResponse(**main_capital_flow_service.delete_record(record_id)) @router.get("/analysis/report", response_model=AnalysisReportResponse) def analysis_report(q: str = Query(..., min_length=2)) -> AnalysisReportResponse: return analysis_service.build_report(q) @router.get("/analysis/chart", response_model=AnalysisChartResponse) def analysis_chart( q: str = Query(..., min_length=2), cycle: str = Query(default="day"), ) -> AnalysisChartResponse: return analysis_service.build_chart(q, cycle) @router.get("/meta", response_model=MetaResponse) def meta() -> MetaResponse: return monitoring_service.get_meta() @router.get("/overview", response_model=OverviewResponse) def overview() -> OverviewResponse: return monitoring_service.get_overview() @router.get("/history", response_model=HistoryResponse) def history() -> HistoryResponse: return monitoring_service.get_history() @router.get("/push-records", response_model=PushRecordsResponse) def push_records() -> PushRecordsResponse: return monitoring_service.get_push_records() @router.post("/push-records/test", response_model=PushRecord) def send_test_push_record() -> PushRecord: return PushRecord(**alert_service.send_test_alert()) @router.get("/rules", response_model=RulesResponse) def rules() -> RulesResponse: return monitoring_service.get_rules() @router.get("/source-diagnostics", response_model=SourceDiagnosticsResponse) def source_diagnostics() -> SourceDiagnosticsResponse: return monitoring_service.get_source_diagnostics() @router.get("/ashare/index-flows/realtime", response_model=AShareIndexFlowResponse) def ashare_index_realtime() -> AShareIndexFlowResponse: return AShareIndexFlowResponse(**ashare_flow_service.get_index_realtime()) @router.get("/ashare/index-flows/daily", response_model=AShareIndexFlowResponse) def ashare_index_daily(trade_date: str | None = Query(default=None)) -> AShareIndexFlowResponse: return AShareIndexFlowResponse(**ashare_flow_service.get_index_daily(trade_date)) @router.get("/ashare/sector-flows/realtime", response_model=AShareSectorFlowResponse) def ashare_sector_realtime() -> AShareSectorFlowResponse: return AShareSectorFlowResponse(**ashare_flow_service.get_sector_realtime()) @router.get("/ashare/sector-flows/daily", response_model=AShareSectorFlowResponse) def ashare_sector_daily(trade_date: str | None = Query(default=None)) -> AShareSectorFlowResponse: return AShareSectorFlowResponse(**ashare_flow_service.get_sector_daily(trade_date)) @router.get("/etf/broad/realtime", response_model=EtfRealtimeResponse) def etf_broad_realtime() -> EtfRealtimeResponse: return EtfRealtimeResponse(**etf_monitor_service.get_group_realtime("broad")) @router.get("/etf/sector/realtime", response_model=EtfRealtimeResponse) def etf_sector_realtime() -> EtfRealtimeResponse: return EtfRealtimeResponse(**etf_monitor_service.get_group_realtime("sector")) @router.get("/etf/broad/daily", response_model=EtfRealtimeResponse) def etf_broad_daily(trade_date: str | None = Query(default=None)) -> EtfRealtimeResponse: return EtfRealtimeResponse(**etf_monitor_service.get_group_daily("broad", trade_date)) @router.get("/etf/sector/daily", response_model=EtfRealtimeResponse) def etf_sector_daily(trade_date: str | None = Query(default=None)) -> EtfRealtimeResponse: return EtfRealtimeResponse(**etf_monitor_service.get_group_daily("sector", trade_date))