update: upload fix
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"""Screenshot upload and extraction API."""
|
||||
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File
|
||||
@@ -84,18 +85,105 @@ async def extract_transactions(
|
||||
if not full_path.exists():
|
||||
raise HTTPException(status_code=404, detail="File not found on disk")
|
||||
image_bytes = full_path.read_bytes()
|
||||
started_at = datetime.utcnow()
|
||||
# 每次开始新一轮识别都重置计时,确保耗时是“本次分析”而不是历史累计
|
||||
screenshot.started_at = started_at
|
||||
screenshot.finished_at = None
|
||||
screenshot.duration_ms = None
|
||||
screenshot.error_message = None
|
||||
screenshot.progress_step = "starting"
|
||||
screenshot.progress_percent = 0
|
||||
screenshot.progress_detail = "准备开始识别"
|
||||
await db.commit()
|
||||
|
||||
async def update_progress(step: str, percent: int, detail: str):
|
||||
screenshot.status = "processing"
|
||||
screenshot.progress_step = step
|
||||
screenshot.progress_percent = percent
|
||||
screenshot.progress_detail = detail
|
||||
await db.commit()
|
||||
|
||||
try:
|
||||
transactions = await extract_and_save(case_id, screenshot_id, image_bytes)
|
||||
await update_progress("file_loaded", 10, "截图读取完成")
|
||||
transactions = await extract_and_save(
|
||||
case_id,
|
||||
screenshot_id,
|
||||
image_bytes,
|
||||
progress_hook=update_progress,
|
||||
)
|
||||
except Exception as e:
|
||||
error_detail = _classify_error(e)
|
||||
r = await db.execute(select(Screenshot).where(Screenshot.id == screenshot_id))
|
||||
sc = r.scalar_one_or_none()
|
||||
if sc:
|
||||
sc.status = "failed"
|
||||
sc.progress_step = "failed"
|
||||
sc.progress_percent = 100
|
||||
sc.progress_detail = "识别失败"
|
||||
sc.finished_at = datetime.utcnow()
|
||||
if sc.started_at:
|
||||
sc.duration_ms = int((sc.finished_at - sc.started_at).total_seconds() * 1000)
|
||||
sc.error_message = error_detail
|
||||
await db.commit()
|
||||
raise HTTPException(status_code=502, detail=f"Extraction failed: {e!s}")
|
||||
raise HTTPException(status_code=502, detail=error_detail)
|
||||
r = await db.execute(select(Screenshot).where(Screenshot.id == screenshot_id))
|
||||
sc = r.scalar_one_or_none()
|
||||
if sc:
|
||||
sc.status = "extracted"
|
||||
sc.progress_step = "completed"
|
||||
sc.progress_percent = 100
|
||||
sc.progress_detail = "识别完成"
|
||||
sc.finished_at = datetime.utcnow()
|
||||
if sc.started_at:
|
||||
sc.duration_ms = int((sc.finished_at - sc.started_at).total_seconds() * 1000)
|
||||
sc.error_message = None
|
||||
await db.commit()
|
||||
return TransactionListResponse(items=transactions)
|
||||
|
||||
|
||||
def _classify_error(e: Exception) -> str:
|
||||
"""Produce a human-readable, categorized error message."""
|
||||
name = type(e).__name__
|
||||
msg = str(e)
|
||||
|
||||
if isinstance(e, ValueError):
|
||||
return f"配置错误: {msg}"
|
||||
|
||||
# OpenAI SDK errors
|
||||
try:
|
||||
from openai import AuthenticationError, RateLimitError, APIConnectionError, BadRequestError, APIStatusError, APITimeoutError
|
||||
if isinstance(e, AuthenticationError):
|
||||
return f"API Key 无效或已过期 ({name}): {msg}"
|
||||
if isinstance(e, RateLimitError):
|
||||
return f"API 调用频率超限,请稍后重试 ({name}): {msg}"
|
||||
if isinstance(e, APITimeoutError):
|
||||
return f"模型服务响应超时,请检查 BaseURL/模型可用性或稍后重试 ({name}): {msg}"
|
||||
if isinstance(e, APIConnectionError):
|
||||
return f"无法连接到模型服务,请检查网络或 BaseURL ({name}): {msg}"
|
||||
if isinstance(e, BadRequestError):
|
||||
return f"请求被模型服务拒绝(可能模型名错误或不支持图片) ({name}): {msg}"
|
||||
if isinstance(e, APIStatusError):
|
||||
return f"模型服务返回错误 (HTTP {e.status_code}): {msg}"
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Anthropic SDK errors
|
||||
try:
|
||||
from anthropic import AuthenticationError as AnthAuthError, RateLimitError as AnthRateError
|
||||
from anthropic import APIConnectionError as AnthConnError, BadRequestError as AnthBadReq
|
||||
if isinstance(e, AnthAuthError):
|
||||
return f"Anthropic API Key 无效或已过期: {msg}"
|
||||
if isinstance(e, AnthRateError):
|
||||
return f"Anthropic API 调用频率超限: {msg}"
|
||||
if isinstance(e, AnthConnError):
|
||||
return f"无法连接到 Anthropic 服务: {msg}"
|
||||
if isinstance(e, AnthBadReq):
|
||||
return f"Anthropic 请求被拒绝: {msg}"
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Connection / network
|
||||
if "connect" in msg.lower() or "timeout" in msg.lower():
|
||||
return f"网络连接失败或超时: {msg}"
|
||||
|
||||
return f"识别失败 ({name}): {msg}"
|
||||
|
||||
@@ -9,7 +9,10 @@ router = APIRouter()
|
||||
|
||||
|
||||
class SettingsUpdate(BaseModel):
|
||||
llm_provider: str | None = None
|
||||
ocr_provider: str | None = None
|
||||
ocr_model: str | None = None
|
||||
inference_provider: str | None = None
|
||||
inference_model: str | None = None
|
||||
openai_api_key: str | None = None
|
||||
anthropic_api_key: str | None = None
|
||||
deepseek_api_key: str | None = None
|
||||
|
||||
Reference in New Issue
Block a user