from pathlib import Path from fastapi import FastAPI, HTTPException from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from app.market import MarketService from app.market.models import InquiryRequest from app.mock_data import LocalMockDataService, MockBatchRequest from app.repository import RDFRepository app = FastAPI(title="格士立全球运输与AI市场接口") ROOT = Path(__file__).resolve().parents[1] QUERIES = ROOT / "queries" STATIC = ROOT / "app" / "static" repository = RDFRepository(ROOT) market_service = MarketService(ROOT, repository) mock_data_service = LocalMockDataService(ROOT, repository, market_service) app.mount("/static", StaticFiles(directory=STATIC), name="static") @app.get("/health") def health(): return { "status": "ok", "data_backend": "local", "triple_count": repository.triple_count, "in_memory_triple_count": repository.in_memory_triple_count, "loaded_files": repository.loaded_file_names, } @app.get("/") def index(): return FileResponse(STATIC / "index.html") @app.get("/api/orders") def orders(): return query_file("order-status.rq") @app.get("/api/risks") def risks(): return query_file("risk-orders.rq") @app.get("/api/flow") def flow(): return query_file("operation-flow.rq") @app.get("/api/node-times") def node_times(): return query_file("node-time-status.rq") @app.get("/api/order-cutoffs") def order_cutoffs(): return query_file("order-cutoff-times.rq") @app.get("/api/exception-map") def exception_map(): return query_file("exception-risk-map.rq") @app.get("/api/market/customers") def market_customers(): return {"rows": market_service.customers()} @app.get("/api/market/form-options") def market_form_options(): return market_service.form_options() @app.post("/api/market/recommend") def market_recommend(inquiry: InquiryRequest): try: return market_service.recommend(inquiry) except ValueError as exc: raise HTTPException(status_code=422, detail=str(exc)) from exc @app.get("/api/market/recommendations/{run_id}") def market_recommendation(run_id: str): result = market_service.get_run(run_id) if not result: raise HTTPException(status_code=404, detail="推荐任务不存在或服务已经重启") return result @app.get("/api/market/recommendations/{run_id}/audit") def market_recommendation_audit(run_id: str): result = market_service.get_audit(run_id) if not result: raise HTTPException(status_code=404, detail="推荐任务审计记录不存在") return result @app.get("/api/mock/catalog") def mock_catalog(): return mock_data_service.catalog() @app.post("/api/mock/generate") def mock_generate(request: MockBatchRequest): try: return mock_data_service.generate(request) except ValueError as exc: raise HTTPException(status_code=422, detail=str(exc)) from exc @app.post("/api/mock/reset") def mock_reset(): return mock_data_service.reset() def query_file(filename: str): path = QUERIES / filename if not path.exists(): raise HTTPException(status_code=404, detail=f"Query file not found: {filename}") try: return repository.query_file(path) except Exception as exc: raise HTTPException( status_code=500, detail=f"本地RDF查询执行失败: {filename}", ) from exc