| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- """
- 文档上传接口实现
- 模拟文件上传功能,返回文件ID和回调任务ID
- """
- import ast
- import uuid
- import time
- from datetime import datetime
- from fastapi import APIRouter, UploadFile, File, Form, HTTPException
- from pydantic import BaseModel
- from typing import Optional,List
- from core.construction_review.workflows.document_ans import DocumentParse
- from foundation.logger.loggering import server_logger as logger
- from foundation.base.config import config_handler
- from .schemas.error_schemas import FileUploadErrors
- file_upload_router = APIRouter(prefix="/sgsc", tags=["文档上传"])
- uploaded_files = {}
- class FileUploadResponse(BaseModel):
- code: int
- data: dict
- def validate_file(file: UploadFile) -> None:
- """验证文件格式和大小"""
- # 检查文件是否存在
- if not file or not file.filename:
- raise FileUploadErrors.file_missing()
- # 检查文件大小(Mock中假设文件大小合理,实际应该读取文件内容)
- # 这里可以添加文件大小检查逻辑
- file_size = getattr(file, 'size', None)
- if file_size is not None and file_size == 0:
- raise FileUploadErrors.file_rejected("文件为空")
- # 支持的文件类型
- allowed_mime_types = {
- 'application/pdf',
- 'application/msword',
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
- }
- # 检查文件格式
- if file.content_type not in allowed_mime_types:
- raise FileUploadErrors.file_format_unsupported()
- @file_upload_router.post("/file_upload", response_model=FileUploadResponse)
- async def file_upload(
- file: List[UploadFile] = File([]), # 改为文件列表,支持多文件检测
- callback_url: str = Form(None),
- project_plan_type: str = Form(None),
- user: str = Form(None) # 用户参数从表单获取,不从配置获取
- ):
- """
- 文件上传接口
- """
- # 调试日志信息
- logger.info(f"文件上传请求 - 用户: {user}, 文件数量: {len(file) if file else 0}",
- log_type="upload", trace_id=f"upload-{int(time.time())}")
- # 记录每个文件的信息
- if file:
- for i, f in enumerate(file):
- file_size = getattr(f, 'size', 0) # 安全获取文件大小,避免属性不存在错误
- logger.info(f"文件 {i+1}: {f.filename}, 大小: {file_size}, 类型: {f.content_type}", log_type="upload")
- logger.info(f"请求参数 - 回调URL: {callback_url}, 工程类型: {project_plan_type}",
- log_type="upload")
- logger.info(f"用户标识: {user}")
- try:
- # 验证工程方案类型
- valid_project_types = {
- 'bridge_up_part', # 桥梁上部结构
- 'tunnel_construction', # 隧道施工
- 'road_repair' # 道路维修
- }
- valid_users = ast.literal_eval(config_handler.get("user_lists", "USERS"))
-
- # 验证文件上传
- if not file or len(file) == 0:
- raise FileUploadErrors.file_missing()
- elif len(file) > 1:
- raise FileUploadErrors.file_multiple()
-
-
- # 验证文件格式和大小(只验证第一个文件)
- if file and len(file) > 0:
- validate_file(file[0])
- # 验证回调地址
- if callback_url is '':
- raise FileUploadErrors.callback_url_missing()
-
- # 验证用户标识
- if user is None or user not in valid_users:
- raise FileUploadErrors.invalid_user()
-
- # 工程方案类型校验
- if project_plan_type not in valid_project_types:
- raise FileUploadErrors.project_plan_type_invalid()
- # 生成文件ID和回调任务ID
- file_id = str(uuid.uuid4())
- created_at = int(time.time())
- callback_task_id = f"{file_id}-{created_at}"
- # 保存文件信息
- file_info = {
- "id": file_id,
- "name": file[0].filename,
- "size": 1024 * 1024, # 文件大小 1MB
- "created_at": created_at,
- "status": "success",
- "callback_task_id": callback_task_id,
- "callback_url": callback_url,
- "project_plan_type": project_plan_type,
- "user": user,
- "upload_time": datetime.now().isoformat()
- }
- # 文档处理(暂时注释,等文件保存逻辑实现后再启用)
- # DocumentParse.document_parse(file_path)
- uploaded_files[file_id] = file_info
- uploaded_files[callback_task_id] = {
- "file_id": file_id,
- "user": user,
- "review_task_status": "processing",
- "overall_progress": 0,
- "stages": [
- {"stage_name": "文件上传", "progress": 100, "stage_status": "completed"},
- {"stage_name": "格式校验", "progress": 0, "stage_status": "pending"},
- {"stage_name": "内容提取", "progress": 0, "stage_status": "pending"},
- {"stage_name": "智能审查", "progress": 0, "stage_status": "pending"}
- ],
- "updated_at": int(time.time()),
- "estimated_remaining": 1800 # 预计30分钟
- }
- return FileUploadResponse(
- code=200,
- data={
- "id": file_id,
- "name": file[0].filename,
- "size": file_info["size"],
- "created_at": file_info["created_at"],
- "status": "success",
- "callback_task_id": callback_task_id
- }
- )
- except HTTPException:
- raise
- except Exception as e:
- raise FileUploadErrors.internal_error(e)
|