forked from erp-dev/erp
214 lines
7.7 KiB
Markdown
214 lines
7.7 KiB
Markdown
# 腾讯云 TIIA 图库(PlateOrder 图片上传 & 搜图)说明
|
||
|
||
## 背景与目标
|
||
|
||
本项目接入腾讯云 TIIA(Image and Video AI)的“图库”能力,用于:
|
||
|
||
- 将 `printing.PlateOrder` 的图片(通过 **ImageUrl**)上传到 TIIA 图库(CreateImage)
|
||
- 通过输入图片(URL 或 Base64)在图库中做相似图检索(SearchImage)
|
||
|
||
---
|
||
|
||
## 一、配置(settings + .env)
|
||
|
||
配置集中在 `flower/settings.py`,建议通过 `.env` 注入:
|
||
|
||
- `TENCENTCLOUD_SECRET_ID`
|
||
- `TENCENTCLOUD_SECRET_KEY`
|
||
- `TENCENTCLOUD_TOKEN`(可选,STS)
|
||
- `TENCENTCLOUD_TIIA_GROUP_ID`(当前默认 `168`)
|
||
- `TENCENTCLOUD_TIIA_REGION`(默认 `ap-guangzhou`)
|
||
- `TENCENTCLOUD_TIIA_ENDPOINT`(默认 `tiia.tencentcloudapi.com`)
|
||
- `TENCENTCLOUD_TIIA_PIC_NAME_PREFIX`(默认 `plate_order`)
|
||
- `TENCENTCLOUD_TIIA_QPS`(默认 `10`,用于限速)
|
||
|
||
说明:
|
||
|
||
- 本项目通过 `django-environ` 读取 `.env`(`Env.read_env(BASE_DIR / '.env')`)
|
||
- 本项目依赖 `tencentcloud-sdk-python`;在容器/服务启动方式不同的情况下,请确保运行使用的是同一套依赖环境(推荐 `uv run ...`)。
|
||
|
||
---
|
||
|
||
## 二、上传到图库(CreateImage)
|
||
|
||
### 2.1 基础上传函数(上传单张 ImageUrl)
|
||
|
||
位置:`api_v1/utils/tencentcloud_tiia.py`
|
||
|
||
- `upload_image_url_to_tencent_tiia(image_url, entity_id, tags=None, custom_content=None)`
|
||
|
||
行为(当前约定):
|
||
|
||
- `GroupId` 固定从 settings 读取
|
||
- `EntityId` 由调用方传入(在 PlateOrder 场景中= `str(plate_order_id)`)
|
||
- `PicName` 自动生成(带 `TENCENTCLOUD_TIIA_PIC_NAME_PREFIX`)
|
||
- `ImageUrl` 使用传入的 `image_url`
|
||
- **`CustomContent` 默认写入完整 `image_url`**
|
||
- **`Tags` 默认不写入**(避免触发“标签值长度过长”)
|
||
|
||
> 注意:腾讯云 `SearchImage` 的返回结构默认不包含 `ImageUrl`;如果你希望在搜图结果里拿到可访问 URL,建议依赖 `CustomContent`(前提是腾讯云搜图返回里会回传该字段)。
|
||
|
||
### 2.2 PlateOrder 批量上传(读取 plate_image)
|
||
|
||
位置:`api_v1/utils/tencentcloud_tiia.py`
|
||
|
||
- `upload_plate_order_images_to_tencent_tiia(plate_order_id, rate_limiter=None)`
|
||
|
||
行为:
|
||
|
||
- 查询 `printing.PlateOrder(id=plate_order_id)`
|
||
- 从 `plate_image(JSONField)` 提取所有图片 URL/Path(兼容多种字段名与格式),并标准化为公网可访问 URL
|
||
- 对每张图片调用 `upload_image_url_to_tencent_tiia(...)`
|
||
- 单张失败不抛出,返回每张图片的结果列表(便于落库/排查)
|
||
|
||
---
|
||
|
||
## 三、定时任务(Celery Beat:每天 03:00 上传“昨天创建的订单”)
|
||
|
||
### 3.1 Task 本体
|
||
|
||
位置:`printing/tasks.py`
|
||
|
||
- `upload_yesterday_plate_order_images_to_tencent_tiia`
|
||
|
||
行为:
|
||
|
||
- 计算“昨天”的日期范围 `[start, end)`
|
||
- 遍历 `created_at` 落在该范围内的所有 `PlateOrder`
|
||
- 逐单上传 `plate_image` 中所有图片
|
||
- 遇错:记录失败并继续处理下一个订单
|
||
- 使用 `SimpleRateLimiter(qps=TENCENTCLOUD_TIIA_QPS)` 控制 QPS(默认 10)
|
||
|
||
### 3.2 Beat 调度配置
|
||
|
||
位置:`flower/settings.py`
|
||
|
||
- `CELERY_BEAT_SCHEDULE['daily_plate_order_tiia_image_upload']`
|
||
- `task = 'printing.tasks.upload_yesterday_plate_order_images_to_tencent_tiia'`
|
||
- `schedule = crontab(hour=3, minute=0)`
|
||
|
||
说明:
|
||
|
||
- 仅配置 schedule 不代表一定在跑;需要线上同时运行 **celery worker** + **celery beat**。
|
||
|
||
---
|
||
|
||
## 四、失败记录(可追踪/可重试)
|
||
|
||
位置:`printing/models.py`
|
||
|
||
- `PlateOrderTiiaUploadFailure`
|
||
- `run_date / plate_order_id / error / details / attempts / last_attempt_at`
|
||
- 唯一约束:`(run_date, plate_order_id)`,同日重复失败会累加 `attempts`
|
||
|
||
可在 Django Admin 中查看(`printing/admin.py` 已注册)。
|
||
|
||
---
|
||
|
||
## 四点五、MDY 开版暂存(MDYPlateOrderStaging)图片上传到图库(CreateImage)
|
||
|
||
### 4.5.1 目标数据源与字段(明道云暂存)
|
||
|
||
数据源:
|
||
|
||
- 模型:`api_v1.models.MDYPlateOrderStaging`
|
||
- 图片字段:`raw["62d52f4b8d2972284492dd27"]`(明道云开版主表字段“开版图”,Attachment)
|
||
|
||
单个附件项的 URL 取值策略(当前约定):
|
||
|
||
- **优先**:`original_file_full_path`(你确认的主用字段)
|
||
- **候补**:`DownloadUrl`
|
||
- 不再使用:`preview_url`(通常带 token/过期参数,不适合作为长期回显 URL)
|
||
|
||
### 4.5.2 Service(上传单条暂存记录)
|
||
|
||
位置:`api_v1/mdy_plate_order_staging_tiia_upload.py`
|
||
|
||
- `upload_mdy_plate_order_staging_plate_images_to_tencent_tiia(staging, rate_limiter=None, dry_run=False)`
|
||
- `EntityId`:使用 `staging.mdy_rowid`
|
||
- 每张图调用:`api_v1.utils.tencentcloud_tiia.upload_image_url_to_tencent_tiia(image_url, entity_id, custom_content=image_url)`
|
||
- 限流:`SimpleRateLimiter(qps=settings.TENCENTCLOUD_TIIA_QPS)`(默认 10)
|
||
- 单张失败不影响其它图片,返回 `successes/failures` 明细
|
||
|
||
### 4.5.3 定时任务(Celery Beat)
|
||
|
||
位置:`api_v1/tasks.py`
|
||
|
||
- task:`upload_mdy_plate_order_staging_images_to_tencent_tiia(batch_size=200, dry_run=False)`
|
||
- **游标**:`api_v1.models.DataSync`(`table_name=mdy_plate_order_staging_tiia_upload`),用 `last_rowid` 存储 staging 表自增 `id`
|
||
- **失败落库**:`api_v1.models.MDYPlateOrderStagingTiiaUploadFailure`(同日同 rowid 去重,attempts 累加)
|
||
|
||
Beat 配置位置:`flower/settings.py`
|
||
|
||
- `CELERY_BEAT_SCHEDULE['daily_mdy_plate_order_staging_tiia_image_upload']`
|
||
- 默认:**03:20** 运行
|
||
- kwargs 默认值:
|
||
- `batch_size=500`
|
||
- `dry_run=False`
|
||
|
||
手动触发(示例):
|
||
|
||
- `uv run python manage.py shell -c "from api_v1.tasks import upload_mdy_plate_order_staging_images_to_tencent_tiia; r=upload_mdy_plate_order_staging_images_to_tencent_tiia.delay(batch_size=50, dry_run=True); print(r.id)"`
|
||
|
||
### 4.5.4 迁移与 Admin
|
||
|
||
- 迁移:`api_v1/migrations/0010_mdy_plate_order_staging_tiia_upload_failure.py`
|
||
- Admin:`api_v1/admin.py` 已注册 `MDYPlateOrderStagingTiiaUploadFailure`
|
||
|
||
---
|
||
|
||
## 五、手动跑批(推荐:management command)
|
||
|
||
位置:`printing/management/commands/tiia_upload_plate_order_images.py`
|
||
|
||
常用:
|
||
|
||
- 全量跑批:`uv run python manage.py tiia_upload_plate_order_images --all`
|
||
- 跑昨天:`uv run python manage.py tiia_upload_plate_order_images --yesterday`
|
||
- 跑某天:`uv run python manage.py tiia_upload_plate_order_images --date 2026-01-15`
|
||
- 跑单个:`uv run python manage.py tiia_upload_plate_order_images --plate-order-id 123`
|
||
- 小批量验证:`uv run python manage.py tiia_upload_plate_order_images --all --limit 20`
|
||
- Dry-run:`uv run python manage.py tiia_upload_plate_order_images --all --dry-run`
|
||
|
||
说明:
|
||
|
||
- 同样遵守 `TENCENTCLOUD_TIIA_QPS` 的限速,并会落库失败记录。
|
||
|
||
---
|
||
|
||
## 六、搜图 API(简化版:SearchImage)
|
||
|
||
### 6.1 接口
|
||
|
||
- `POST /api/v1/tiia/search-image/`
|
||
|
||
参数(JSON body):
|
||
|
||
- `imageUrl`:图片 URL(优先)
|
||
- `imageBase64`:Base64(可选,若无 imageUrl)
|
||
- `limit`:可选,1~100(默认腾讯云 10;本项目已透传)
|
||
- `offset`:可选,>=0
|
||
- `matchThreshold`:可选,0~100
|
||
|
||
### 6.2 返回
|
||
|
||
- 直接返回腾讯云 `SearchImage` 的原始响应 JSON
|
||
|
||
### 6.3 已知限制/注意点
|
||
|
||
- 腾讯云 `SearchImage` 返回结果通常以 `EntityId/PicName/Score/Tags/CustomContent` 为主,不一定直接提供可访问 `ImageUrl`
|
||
- 如果期望在搜图结果里拿到可访问 URL,请优先依赖上传时写入的 `CustomContent`
|
||
|
||
---
|
||
|
||
## 七、排障清单(常见问题)
|
||
|
||
- SDK 导入失败(`No module named 'tencentcloud'`):
|
||
- 确认使用 `uv run python ...`(确保解释器与依赖一致)
|
||
- 腾讯云返回“标签值长度过长”:
|
||
- 不要默认写入 `Tags`;本项目已改为默认不写 `Tags`
|
||
- 任务未触发:
|
||
- 检查是否同时运行 celery worker + celery beat
|
||
- 检查 `CELERY_BROKER_URL / CELERY_RESULT_BACKEND` 是否可用
|
||
|