feat: 支持ZIP压缩包上传(含密码保护)

This commit is contained in:
CHE LIANG ZHAO
2026-01-23 13:46:45 +08:00
parent 49e3176e6b
commit a97a8d6a20
22 changed files with 973 additions and 72 deletions

View File

@@ -24,6 +24,7 @@ if sys.stdout.encoding != 'utf-8':
from cleaners.base import compute_date_range_from_values
from cleaners import AlipayCleaner, WechatCleaner
from category import infer_category, get_all_categories, get_all_income_categories
from converter import convert_bill_file
# 应用版本
APP_VERSION = "0.0.1"
@@ -72,6 +73,14 @@ class HealthResponse(BaseModel):
version: str
class ConvertResponse(BaseModel):
"""文件转换响应"""
success: bool
bill_type: str
output_path: str
message: str
# =============================================================================
# 辅助函数
# =============================================================================
@@ -85,7 +94,7 @@ def detect_bill_type(filepath: str) -> str | None:
"""
try:
with open(filepath, "r", encoding="utf-8") as f:
for _ in range(20):
for _ in range(50): # 支付宝账单可能有较多的头部信息行
line = f.readline()
if not line:
break
@@ -337,6 +346,43 @@ async def detect_bill_type_api(file: UploadFile = File(...)):
os.unlink(tmp_path)
@app.post("/convert", response_model=ConvertResponse)
async def convert_bill_file_api(file: UploadFile = File(...)):
"""
转换账单文件格式
支持:
- xlsx -> csv 转换
- GBK/GB2312 -> UTF-8 编码转换
返回转换后的文件路径和检测到的账单类型
"""
# 保存上传的文件到临时位置
suffix = Path(file.filename).suffix or ".csv"
with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp:
shutil.copyfileobj(file.file, tmp)
input_path = tmp.name
try:
# 调用转换函数
success, bill_type, output_path, message = convert_bill_file(input_path)
if not success:
raise HTTPException(status_code=400, detail=message)
return ConvertResponse(
success=True,
bill_type=bill_type,
output_path=output_path,
message=message
)
finally:
# 清理输入临时文件(转换后的输出文件由调用方负责清理)
if os.path.exists(input_path):
os.unlink(input_path)
# =============================================================================
# 启动入口
# =============================================================================