jiachenlong/docs/IMAGE_PROCESSING_FLOW.md

8.7 KiB
Raw Blame History

图片处理流程文档

版本: v1.0.0
更新日期: 2026-03-16
作者: 菜鸟小 D 🤖


📊 完整流程图

用户上传图片
    ↓
[1] 前端上传组件
    ↓
[2] 后端接收验证
    ↓
[3] 文件命名处理
    ↓
[4] 保存到服务器
    ↓
[5] 数据库记录
    ↓
[6] 返回图片 URL

1 前端上传组件

上传页面

文件: frontend/src/pages/Add.jsx

上传逻辑:

// 选择图片后自动上传
const handleImageSelect = async (e) => {
  const file = e.target.files[0]
  if (!file) return
  
  const formData = new FormData()
  formData.append('file', file)
  formData.append('collection_id', collectionId)
  
  const res = await fetch('/api/ocr/recognize', {
    method: 'POST',
    body: formData
  })
  
  const data = await res.json()
  // 处理 OCR 识别结果
}

图片显示

文件: frontend/src/pages/Detail.jsx

显示逻辑:

<img 
  src={`/uploads/${img.path}`} 
  alt={img.originalName}
  onError={(e) => { 
    // 加载失败显示"无图片"占位符
    e.target.style.display = 'none';
    e.target.parentElement.innerHTML = '<div>无图片</div>';
  }}
/>

2 后端接收验证

API 端点

文件: backend/app/routers/collections.py

路由: POST /api/collections/upload-image

验证流程

@router.post("/upload-image")
async def upload_image(
    collection_id: str = None,
    file: UploadFile = File(...),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):

验证步骤

  1. 验证藏品是否存在

    collection = db.query(Collection).filter(
        Collection.f99_90_id == collection_id
    ).first()
    
    if not collection:
        raise HTTPException(status_code=404, detail="E00033: 藏品不存在")
    
  2. 获取用户信息

    owner = db.query(User).filter(
        User.f99_90_id == collection.f99_91_user_id
    ).first()
    username = owner.f01_01_name if owner else "unknown"
    
  3. 获取藏品信息

    code = collection.f01_02_code or "0000"
    prefix_serial = collection.f02_10_prefix_serial or ""
    
  4. 验证文件类型

    if not file.content_type.startswith('image/'):
        raise HTTPException(status_code=400, 
                           detail="E00038: 只能上传图片文件")
    
  5. 验证文件大小

    file_size = len(content)
    if file_size > 10 * 1024 * 1024:  # 10MB
        raise HTTPException(status_code=400, 
                           detail=f"图片大小不能超过 10MB")
    

3 文件命名处理

命名规则

格式: 用户名 - 藏品编号 - 冠字号。扩展名

示例:

  • admin-0001-J051963351.jpeg
  • admin-0002-J035161361.JPG
  • testuser-0015.jpeg (无冠字号)

命名代码

# 清理特殊字符,只保留字母、数字、中文、横杠
import re
clean_username = re.sub(r'[^\w\u4e00-\u9fff\-]', '', username)
clean_serial = re.sub(r'[^\w\u4e00-\u9fff\-]', '', prefix_serial)

# 生成文件名
file_extension = file.filename.split('.')[-1] if '.' in file.filename else 'jpg'

if clean_serial:
    filename = f"{clean_username}-{code}-{clean_serial}.{file_extension}"
else:
    filename = f"{clean_username}-{code}.{file_extension}"

避免重名

# 如果文件已存在,添加时间戳
file_path = os.path.join(upload_dir, filename)
if os.path.exists(file_path):
    import time
    timestamp = int(time.time())
    base_name = filename.rsplit('.', 1)[0]
    filename = f"{base_name}-{timestamp}.{file_extension}"
    file_path = os.path.join(upload_dir, filename)

4 保存到服务器

存储路径

目录: backend/uploads/collections/

完整路径: /opt/jiachenlong-backend/uploads/collections/

保存代码

# 创建上传目录
upload_dir = "uploads/collections"
os.makedirs(upload_dir, exist_ok=True)

# 保存文件
with open(file_path, "wb") as buffer:
    buffer.write(content)

文件权限

  • 所有者: root
  • 权限: 644 (rw-r--r--)
  • : root

5 数据库记录

数据表

表名: collection_images

表结构

CREATE TABLE collection_images (
    id VARCHAR(36) PRIMARY KEY,           -- UUID
    collection_id VARCHAR(36),            -- 关联藏品 ID
    filename VARCHAR(255),                -- 文件名
    original_name VARCHAR(255),           -- 原始文件名
    path VARCHAR(500),                    -- 存储路径
    created_at TIMESTAMP DEFAULT NOW()    -- 创建时间
);

插入记录

from app.models.models import CollectionImage
import uuid

image = CollectionImage(
    id=str(uuid.uuid4()),
    collection_id=collection_id,
    filename=filename,
    original_name=file.filename,
    path=file_path
)

db.add(image)
db.commit()
db.refresh(image)

返回数据

return {
    "message": "上传成功",
    "image_id": image.id,
    "filename": filename
}

6 图片访问

Nginx 代理配置

文件: /etc/nginx/conf.d/jiachenlong.conf

# 图片上传文件代理
location /uploads {
    proxy_pass http://47.110.37.129:3000/uploads;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    client_max_body_size 20M;
}

访问 URL 格式

http://8.149.137.26/uploads/collections/admin-0001-J051963351.jpeg

后端静态文件服务

文件: backend/app/main.py

# 挂载静态文件目录(图片上传)
uploads_dir = "uploads"
os.makedirs(uploads_dir, exist_ok=True)
app.mount("/uploads", StaticFiles(directory=uploads_dir), name="uploads")

🔍 OCR 识别流程

API 端点

路由: POST /api/ocr/recognize

文件: backend/app/routers/ocr.py

识别步骤

  1. 读取图片并转 Base64

    image_data = await image.read()
    image_base64 = base64.b64encode(image_data).decode('utf-8')
    
  2. 调用阿里云 DashScope API

    payload = {
        "model": "qwen-vl-max",
        "messages": [{
            "role": "user",
            "content": [
                {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{image_base64}"}},
                {"type": "text", "text": PROFESSIONAL_PROMPT}
            ]
        }]
    }
    
  3. 提取识别结果

    def extract_fields(text: str) -> dict:
        patterns = {
            'version': r'✅.*?2.*?发行版别.*?[:]\s*(.+?)(?:\n|$)',
            'prefix_serial': r'✅.*?6.*?冠字序号.*?[:]\s*(.+?)(?:\n|$)',
            'grading_score': r'✅.*?8.*?评级分数.*?[:]\s*(.+?)(?:\n|$)',
            # ... 更多字段
        }
    
  4. 返回结构化数据

    return {
        "success": True,
        "text": text_content,
        "fields": fields
    }
    

📋 完整示例

用户上传流程

  1. 用户选择图片 → 前端显示预览
  2. 点击上传 → 发送到 /api/ocr/recognize
  3. OCR 识别 → 提取藏品信息
  4. 填写表单 → 用户确认/修改信息
  5. 保存藏品 → 创建藏品记录
  6. 上传图片 → 发送到 /api/collections/upload-image
  7. 保存成功 → 返回图片 URL

文件命名示例

输入:

  • 用户名:admin
  • 藏品编号:0001
  • 冠字号:J051963351
  • 原始文件名:001.JPG

输出:

  • 文件名:admin-0001-J051963351.JPG
  • 路径:uploads/collections/admin-0001-J051963351.JPG
  • URLhttp://8.149.137.26/uploads/collections/admin-0001-J051963351.JPG

⚠️ 注意事项

安全限制

  1. 文件大小: 最大 10MB
  2. 文件类型: 仅支持图片image/*
  3. 认证要求: 必须登录才能上传
  4. 权限控制: 只能上传到自己的藏品

性能优化

  1. 图片压缩: 建议前端先压缩再上传
  2. CDN 加速: 生产环境建议使用 CDN
  3. 缓存策略: Nginx 配置静态资源缓存

备份策略

  1. 定期备份: 备份 uploads/collections/ 目录
  2. 数据库备份: 定期导出 collection_images
  3. 异地备份: 重要图片建议异地备份

🔧 故障排查

图片不显示

  1. 检查文件是否存在:ls -lh /opt/jiachenlong-backend/uploads/collections/
  2. 检查数据库记录:SELECT * FROM collection_images;
  3. 检查 Nginx 日志:tail -f /var/log/nginx/error.log
  4. 检查后端日志:tail -f /tmp/uvicorn.log

上传失败

  1. 检查文件大小是否超限
  2. 检查文件类型是否正确
  3. 检查藏品 ID 是否存在
  4. 检查磁盘空间是否充足

最后更新: 2026-03-16
维护人员: 菜鸟小 D 🤖