feat: 支持ZIP压缩包上传(含密码保护)
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 启动入口
|
||||
# =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user