feat: 抓取任务队列 + 媒体机直传 + 向量回填

crawl(品牌抓取任务队列)
- /admin/internal/crawl/tasks 领取 / :id/result 回报,spider 可常驻拉任务
- 后台品牌列表支持「加入抓取队列」,队列页可看状态与重试
- 租约超时的 running 自动回收为 queued,避免 worker 崩溃后任务卡死

media(媒体机直传)
- ingest 载荷新增 main_key/detail_keys/main_size/detail_sizes:
  有 key 就直接落库,跳过下载与上传;与 URL 形态可逐图混用
- 细节图按 Details/DetailKeys 两者较长者遍历(只给 key 时不再丢图)
- 媒体机上传的 key 不进失败回滚清单(内容寻址、可能与他人共享)
- /admin/internal/upload-url 签发 S4 PUT 预签名(spider 不持有 AK/SK)

embeddings(向量回填)
- GET /admin/internal/embeddings/pending 派发缺向量的图(含可直接下载的 url)
- POST /admin/internal/embeddings 回写向量并重算近邻;失败项计入
  image_embedding_failures,连续失败到上限后退出队列(坏图不占位)
- 近邻重算改为异步串行:同步会让 100 张的批次 POST 超时(实测 >60s)
- 新增 key 分支单测:混用 key/url、细节图只给 key、字节数、回滚清单、向量占位
This commit is contained in:
toom1996
2026-10-25 00:37:13 +08:00
parent e18c5a0815
commit 151e09ab30
22 changed files with 1535 additions and 28 deletions

View File

@ -37,7 +37,22 @@ type RunwayIngest struct {
// RunwayLook 一场秀中的一个 look:1 张主图 + 0..N 张细节图。
// 主图即对外默认展示的走秀图;细节图挂靠到对应主图,由「细节入口」按需展开。
//
// 图片有两种来源,二选一(同一条 payload 内可混用):
//
// ① 旧路径:Main / Details 给原始 URL,worker 自己下载 + 上传存储(默认行为);
// ② 新路径(媒体机直传):MainKey / DetailKeys 给「已上传到 S4 的对象 key」,
// worker 直接落库,不再下载、不再上传。
//
// 新路径的意义:抓取与入库分离后,下载/上传这类带宽密集的活由部署在快网络里的
// spider 完成,后端只做业务写库,吞吐不再被后端机器的出口带宽卡住。
// key 由 spider 按内容 sha1 生成(runway/<sha1>.jpg),因此重复上传天然幂等。
type RunwayLook struct {
Main string `json:"main"` // 主图(look)原始 URL
Details []string `json:"details"` // 细节图原始 URL 列表
MainKey string `json:"main_key,omitempty"` // 主图已上传的存储 key(新路径)
DetailKeys []string `json:"detail_keys,omitempty"` // 细节图已上传的存储 key(新路径)
MainSize int64 `json:"main_size,omitempty"` // 主图字节数(新路径,0=未知)
DetailSizes []int64 `json:"detail_sizes,omitempty"` // 细节图字节数(与 DetailKeys 对齐,0=未知)
}