Spaces:
Running
Running
| """ | |
| 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") | |
| async def serve_ui(): | |
| """返回前端页面""" | |
| return FileResponse(str(STATIC_DIR / "index.html")) | |
| async def health_check(): | |
| """健康检查""" | |
| return {"status": "ok", "service": "Customs Data API"} | |
| 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) | |