""" Hugging Face Spaces 超简版 - 直接内联数据加载 """ from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse from pathlib import Path import pandas as pd app = FastAPI( title="海关数据查询系统", description="巴西海关贸易数据查询服务", version="1.0.0" ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) BASE_DIR = Path(__file__).resolve().parent.parent.parent STATIC_DIR = BASE_DIR / "apps" / "api" / "static" # 挂载静态文件 app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static") @app.get("/") async def serve_ui(): """返回前端页面""" return FileResponse(str(STATIC_DIR / "index.html")) @app.get("/api/v1/health") async def health_check(): """健康检查""" return {"status": "ok", "service": "Customs Data API"} @app.post("/api/v1/trade/search") async def search_trade_records(request: Request): """ 查询贸易记录 - 直接从CSV读取 """ try: body = await request.json() except: body = {} # 提取参数 source_country = body.get('source_country') trade_direction = body.get('trade_direction') hs_code = body.get('hs_code') product_name = body.get('product_name') importer_name = body.get('importer_name') exporter_name = body.get('exporter_name') page = int(body.get('page', 1)) limit = int(body.get('limit', 20)) # 加载CSV csv_path = BASE_DIR / "data" / "standard_trade_records_sample.csv" df = pd.read_csv(csv_path) # 过滤 filtered_df = df.copy() if source_country: filtered_df = filtered_df[filtered_df['source_country'] == source_country] if trade_direction: filtered_df = filtered_df[filtered_df['trade_direction'] == trade_direction] if hs_code: filtered_df = filtered_df[filtered_df['hs_code'].astype(str).str.startswith(str(hs_code))] if product_name: filtered_df = filtered_df[filtered_df['product_name'].str.contains(product_name, na=False, case=False)] if importer_name: filtered_df = filtered_df[filtered_df['importer_name'].str.contains(importer_name, na=False, case=False)] if exporter_name: filtered_df = filtered_df[filtered_df['exporter_name'].str.contains(exporter_name, na=False, case=False)] total = len(filtered_df) # 分页 offset = (page - 1) * limit page_df = filtered_df.iloc[offset:offset + limit] # 构建响应 items = [] for _, row in page_df.iterrows(): trade_date_str = str(row['trade_date']).split()[0] if pd.notna(row['trade_date']) else '2023-01-01' items.append({ 'record_id': str(row['record_id']), 'source_record_id': str(row['source_record_id']), 'source_country': str(row['source_country']), 'trade_direction': str(row['trade_direction']), 'trade_date': trade_date_str, 'importer_name': str(row['importer_name']) if pd.notna(row['importer_name']) else "", 'exporter_name': str(row['exporter_name']) if pd.notna(row['exporter_name']) else "", 'hs_code': str(row['hs_code']) if pd.notna(row['hs_code']) else None, 'product_name': str(row['product_name']) if pd.notna(row['product_name']) else None, 'amount': float(row['amount']) if pd.notna(row['amount']) else None, 'currency': str(row['currency']) if pd.notna(row['currency']) else None, 'weight': float(row['weight']) if pd.notna(row['weight']) else None, 'weight_unit': str(row['weight_unit']) if pd.notna(row['weight_unit']) else None, 'origin_country': str(row['origin_country']) if pd.notna(row['origin_country']) else None, 'destination_country': str(row['destination_country']) if pd.notna(row['destination_country']) else None, 'departure_port': str(row['departure_port']) if pd.notna(row['departure_port']) else None, 'arrival_port': str(row['arrival_port']) if pd.notna(row['arrival_port']) else None, 'transport_mode': str(row['transport_mode']) if pd.notna(row['transport_mode']) else None }) return {'total': total, 'items': items} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=7860)