3v324v23 commited on
Commit
4f1a9f4
·
1 Parent(s): 5090e69

Ultra-simple version: direct CSV loading, no database

Browse files
Files changed (2) hide show
  1. Dockerfile +9 -30
  2. apps/api/main_hf_simple.py +115 -0
Dockerfile CHANGED
@@ -1,47 +1,26 @@
1
- # Hugging Face Spaces Dockerfile
2
  FROM python:3.11-slim
3
 
4
  WORKDIR /app
5
 
6
- # 安装系统依赖
7
- RUN apt-get update && apt-get install -y \
8
- sqlite3 \
9
- && rm -rf /var/lib/apt/lists/*
10
-
11
- # 安装Python依赖(精简版)
12
  RUN pip install --no-cache-dir \
13
  fastapi==0.111.0 \
14
  uvicorn[standard]==0.30.0 \
15
- sqlalchemy==2.0.30 \
16
- aiosqlite==0.20.0 \
17
- pydantic==2.7.4 \
18
- pydantic-settings==2.3.0 \
19
- python-multipart==0.0.9
20
-
21
- # 复制配置文件(使用HF版本)
22
- COPY packages/core/config_hf.py ./packages/core/config.py
23
- COPY packages/core/__init__.py ./packages/core/
24
- COPY packages/core/models.py ./packages/core/
25
- COPY packages/core/database.py ./packages/core/
26
- COPY packages/core/logger.py ./packages/core/
27
-
28
- # 复制API路由(使用精简版trade路由)
29
- COPY apps/api/routers/__init__.py ./apps/api/routers/
30
- COPY apps/api/routers/trade_hf.py ./apps/api/routers/trade.py
31
- COPY apps/api/schemas/ ./apps/api/schemas/
32
 
33
- # 复制主文件和静态文件
34
- COPY apps/api/main_hf.py ./apps/api/main.py
35
  COPY apps/api/static/ ./apps/api/static/
36
 
37
  # 复制数据文件
38
  COPY data/standard_trade_records_sample.csv ./data/
39
 
40
- # 创建SQLite数据库脚本(不在构建时运行)
41
- COPY init_sqlite.py .
42
 
43
  # 暴露端口
44
  EXPOSE 7860
45
 
46
- # 启动命令(Hugging Face Spaces使用7860端口)
47
- CMD ["sh", "-c", "ls -la data/ && uvicorn apps.api.main:app --host 0.0.0.0 --port 7860"]
 
1
+ # Hugging Face Spaces Dockerfile - 超简版
2
  FROM python:3.11-slim
3
 
4
  WORKDIR /app
5
 
6
+ # 安装必要的Python依赖
 
 
 
 
 
7
  RUN pip install --no-cache-dir \
8
  fastapi==0.111.0 \
9
  uvicorn[standard]==0.30.0 \
10
+ pandas>=2.0.0 \
11
+ pydantic==2.7.4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
+ # 复制静态文件
 
14
  COPY apps/api/static/ ./apps/api/static/
15
 
16
  # 复制数据文件
17
  COPY data/standard_trade_records_sample.csv ./data/
18
 
19
+ # 复制超简版主文件
20
+ COPY apps/api/main_hf_simple.py ./apps/api/main.py
21
 
22
  # 暴露端口
23
  EXPOSE 7860
24
 
25
+ # 启动命令
26
+ CMD ["uvicorn", "apps.api.main:app", "--host", "0.0.0.0", "--port", "7860"]
apps/api/main_hf_simple.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Hugging Face Spaces 超简版 - 直接内联数据加载
3
+ """
4
+ from fastapi import FastAPI, Request
5
+ from fastapi.middleware.cors import CORSMiddleware
6
+ from fastapi.staticfiles import StaticFiles
7
+ from fastapi.responses import FileResponse
8
+ from pathlib import Path
9
+ import pandas as pd
10
+
11
+ app = FastAPI(
12
+ title="海关数据查询系统",
13
+ description="巴西海关贸易数据查询服务",
14
+ version="1.0.0"
15
+ )
16
+
17
+ app.add_middleware(
18
+ CORSMiddleware,
19
+ allow_origins=["*"],
20
+ allow_credentials=True,
21
+ allow_methods=["*"],
22
+ allow_headers=["*"],
23
+ )
24
+
25
+ BASE_DIR = Path(__file__).resolve().parent.parent.parent
26
+ STATIC_DIR = BASE_DIR / "apps" / "api" / "static"
27
+
28
+ # 挂载静态文件
29
+ app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
30
+
31
+ @app.get("/")
32
+ async def serve_ui():
33
+ """返回前端页面"""
34
+ return FileResponse(str(STATIC_DIR / "index.html"))
35
+
36
+ @app.get("/api/v1/health")
37
+ async def health_check():
38
+ """健康检查"""
39
+ return {"status": "ok", "service": "Customs Data API"}
40
+
41
+ @app.post("/api/v1/trade/search")
42
+ async def search_trade_records(request: Request):
43
+ """
44
+ 查询贸易记录 - 直接从CSV读取
45
+ """
46
+ try:
47
+ body = await request.json()
48
+ except:
49
+ body = {}
50
+
51
+ # 提取参数
52
+ source_country = body.get('source_country')
53
+ trade_direction = body.get('trade_direction')
54
+ hs_code = body.get('hs_code')
55
+ product_name = body.get('product_name')
56
+ importer_name = body.get('importer_name')
57
+ exporter_name = body.get('exporter_name')
58
+ page = int(body.get('page', 1))
59
+ limit = int(body.get('limit', 20))
60
+
61
+ # 加载CSV
62
+ csv_path = BASE_DIR / "data" / "standard_trade_records_sample.csv"
63
+ df = pd.read_csv(csv_path)
64
+
65
+ # 过滤
66
+ filtered_df = df.copy()
67
+ if source_country:
68
+ filtered_df = filtered_df[filtered_df['source_country'] == source_country]
69
+ if trade_direction:
70
+ filtered_df = filtered_df[filtered_df['trade_direction'] == trade_direction]
71
+ if hs_code:
72
+ filtered_df = filtered_df[filtered_df['hs_code'].astype(str).str.startswith(str(hs_code))]
73
+ if product_name:
74
+ filtered_df = filtered_df[filtered_df['product_name'].str.contains(product_name, na=False, case=False)]
75
+ if importer_name:
76
+ filtered_df = filtered_df[filtered_df['importer_name'].str.contains(importer_name, na=False, case=False)]
77
+ if exporter_name:
78
+ filtered_df = filtered_df[filtered_df['exporter_name'].str.contains(exporter_name, na=False, case=False)]
79
+
80
+ total = len(filtered_df)
81
+
82
+ # 分页
83
+ offset = (page - 1) * limit
84
+ page_df = filtered_df.iloc[offset:offset + limit]
85
+
86
+ # 构建响应
87
+ items = []
88
+ for _, row in page_df.iterrows():
89
+ trade_date_str = str(row['trade_date']).split()[0] if pd.notna(row['trade_date']) else '2023-01-01'
90
+ items.append({
91
+ 'record_id': str(row['record_id']),
92
+ 'source_record_id': str(row['source_record_id']),
93
+ 'source_country': str(row['source_country']),
94
+ 'trade_direction': str(row['trade_direction']),
95
+ 'trade_date': trade_date_str,
96
+ 'importer_name': str(row['importer_name']) if pd.notna(row['importer_name']) else "",
97
+ 'exporter_name': str(row['exporter_name']) if pd.notna(row['exporter_name']) else "",
98
+ 'hs_code': str(row['hs_code']) if pd.notna(row['hs_code']) else None,
99
+ 'product_name': str(row['product_name']) if pd.notna(row['product_name']) else None,
100
+ 'amount': float(row['amount']) if pd.notna(row['amount']) else None,
101
+ 'currency': str(row['currency']) if pd.notna(row['currency']) else None,
102
+ 'weight': float(row['weight']) if pd.notna(row['weight']) else None,
103
+ 'weight_unit': str(row['weight_unit']) if pd.notna(row['weight_unit']) else None,
104
+ 'origin_country': str(row['origin_country']) if pd.notna(row['origin_country']) else None,
105
+ 'destination_country': str(row['destination_country']) if pd.notna(row['destination_country']) else None,
106
+ 'departure_port': str(row['departure_port']) if pd.notna(row['departure_port']) else None,
107
+ 'arrival_port': str(row['arrival_port']) if pd.notna(row['arrival_port']) else None,
108
+ 'transport_mode': str(row['transport_mode']) if pd.notna(row['transport_mode']) else None
109
+ })
110
+
111
+ return {'total': total, 'items': items}
112
+
113
+ if __name__ == "__main__":
114
+ import uvicorn
115
+ uvicorn.run(app, host="0.0.0.0", port=7860)