bugfix
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
|
||||
- **用户体系**:微信小程序登录(code2session,首次自动注册并初始化免费额度)、JWT 双 token(access/refresh)、个人资料维护。
|
||||
- **衣物管理**:图片上传(扩展名 + magic bytes 双重校验)→ 异步 AI 流水线(抠图 → 15 维分类)→ 衣物 CRUD 与处理状态查询。
|
||||
- **穿搭与 AI 推荐**:自建穿搭(含社区公开与审核)、基于星座运势 + 衣橱衣物的 AI 穿搭推荐(大模型生成,落库为"待用户保存")。
|
||||
- **穿搭与 AI 推荐**:自建穿搭(含社区公开与审核)、基于星座运势 + 衣橱衣物的 AI 穿搭推荐(**异步提交 + 轮询结果**,前端断开不中断生成;落库为"待用户保存",超期未保存自动清理)。
|
||||
- **运势**:每日 0 点定时生成十二星座运势,Redis 分布式锁保证多实例下仅执行一次,查询时支持按需兜底生成。
|
||||
- **社区互动**:衣柜分享(部分衣物 / 全量快照)、穿搭点赞与收藏(Redis 集合 + MySQL 双写)、站内通知(未读计数)。
|
||||
- **额度体系**:四类额度(上传 / AI 推荐 / 穿搭分享 / 衣柜分享)的扣减、回退、发放、回收;上传为**永久额度**,AI 推荐 / 穿搭分享 / 衣柜分享为**每日额度**(每天 0 点重置);购买赠送额度以**凭证**(`quota_grants`)发放——会员包随 VIP 有效期、加量包独立有效期(`goods.valid_days`)、广告激励当天有效;Cos 消费先扣即将过期凭证再扣免费额度,全部走事务 + 幂等流水。
|
||||
@@ -234,7 +234,7 @@ flowchart TD
|
||||
3. **穿搭与社区**:创建穿搭 → 公开(审核自动通过 + 扣分享额度)→ 其他用户点赞/收藏 → 触发通知。
|
||||
4. **衣柜分享**:部分衣物或全量快照分享 → 扣额度 → 属主/访客查看(访客访问即记录接收关系)→ 取消或到期懒过期;"分享给我的"列表联表查询接收关系。
|
||||
5. **交易与权益**:选购商品 → 下单(15 分钟有效)→ 微信支付回调发放权益 → 超时过期 / 退款回收,发放失败自动补偿。
|
||||
6. **AI 推荐**:扣 AI 额度 → 结合星座运势与衣橱生成 → 落库"待用户保存" → 保存转正式穿搭(公开仍需扣分享额度)。
|
||||
6. **AI 推荐**:异步提交(抢占活跃位 + 扣 AI 额度 + 秒回 `task_id`)→ 后台生成 → 前端轮询结果 → 落库"待用户保存" → 保存转正式穿搭(公开仍需扣分享额度);超期未保存的由定时任务自动清理。
|
||||
7. **通知**:点赞、支付成功、退款成功等业务动作触发站内通知,未读计数实时维护。
|
||||
|
||||
### 2. 衣物生命周期
|
||||
@@ -360,26 +360,33 @@ stateDiagram-v2
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["发起推荐请求"] --> B{"Redis 锁 180s<br/>(防并发重复生成)"}
|
||||
B -- 抢锁失败 --> X["返回「请求过于频繁」"]
|
||||
B -- 成功 --> C["扣 AI 额度 1 点<br/>(生成前权威扣减)"]
|
||||
C --> D["组装输入:<br/>处理成功的全部衣物 + 星座 + 今日运势"]
|
||||
D --> E["调用大模型生成<br/>(tokenhub)"]
|
||||
E --> F{"校验结果<br/>(过滤模型幻觉衣物 ID)"}
|
||||
F -- 有效 --> G["落库:source=2 AI、status=3 待用户保存"]
|
||||
F -- 无效 / 任一步失败 --> Y["回退 AI 额度 + 写失败流水"]
|
||||
G --> H["用户确认 Save:<br/>status 3→1 转正式穿搭(不扣额)"]
|
||||
H --> I["公开到社区仍需 Public<br/>(扣搭配分享额度)"]
|
||||
A["POST /ai-recommend<br/>(异步提交)"] --> B{"抢占用户活跃位<br/>(已有任务则返回原 task_id)"}
|
||||
B -- 已有任务 --> X["幂等返回该 task_id<br/>(不重复扣额度)"]
|
||||
B -- 抢占成功 --> C["扣 AI 额度 1 点"]
|
||||
C --> D["写任务快照 status=1<br/>立即返回 {task_id, status:1}"]
|
||||
D --> E["后台 goroutine 生成<br/>(独立 ctx,前端断开不中断)"]
|
||||
E --> F["组装输入:处理成功的全部衣物 + 星座 + 今日运势"]
|
||||
F --> G["调用大模型生成<br/>(tokenhub)"]
|
||||
G --> H{"校验结果<br/>(过滤模型幻觉衣物 ID)"}
|
||||
H -- 有效 --> I["落库:source=2 AI、status=3 待用户保存<br/>任务快照置 status=2 + result"]
|
||||
H -- 无效 / 任一步失败 --> Y["回退 AI 额度 + 写失败流水<br/>任务快照置 status=3 + error"]
|
||||
I --> J["前端轮询 GET /ai-recommend/status<br/>拿到 result"]
|
||||
J --> K["用户确认 Save:<br/>status 3→1 转正式穿搭(不扣额)"]
|
||||
K --> L["公开到社区仍需 Public<br/>(扣搭配分享额度)"]
|
||||
I -. "超过 7 天未保存" .-> M["定时任务自动清理<br/>(软删除穿搭 + 明细)"]
|
||||
```
|
||||
|
||||
处理流程:
|
||||
|
||||
1. **输入**:当前用户**处理成功(4)** 的全部衣物(分页遍历)+ 由生日推算的星座 + 今日运势(无生日/运势时降级为仅星座或空)。
|
||||
2. **扣额与回退**:**生成前**扣减 AI 额度 1 点;衣橱为空、模型调用失败、无有效单品、落库失败等任一情况均**统一回退额度**并写失败流水。
|
||||
3. **结果校验**:校正模型返回的衣物 ID(过滤幻觉),无有效单品则失败回退。
|
||||
4. **落库**:生成穿搭以 `source=2 AI`、`status=3 待用户保存` 入库(私有、待审核);明细落库失败则删除穿搭 + 回退额度。
|
||||
5. **保存转正**:仅 `status=3` 可保存(重复保存幂等),保存仅将状态 3→1,**不扣分享额度**;后续公开到社区仍走 Public 流程扣搭配分享额度。
|
||||
6. **实现备注**:不保存的"待保存"穿搭无自动清理任务;同用户并发请求由 Redis 锁(180s)拦截。
|
||||
1. **异步提交**:`POST /ai-recommend` 只做「抢占活跃位 → 扣额度 → 写任务快照」三步,**秒级返回 `task_id`**;生成在后台 goroutine 完成,使用独立 context,前端退出、切页面或断网都不会中断。
|
||||
2. **提交幂等**:同一用户已有任务在执行时直接返回该任务的 `task_id`,不会重复扣额度;活跃位 TTL 4 分钟,略长于任务超时 3 分钟,避免任务未收尾就被放行重复提交。
|
||||
3. **输入**:当前用户**处理成功(4)** 的全部衣物(分页遍历)+ 由生日推算的星座 + 今日运势(无生日/运势时降级为仅星座或空)。
|
||||
4. **扣额与回退**:**提交时**扣减 AI 额度 1 点;衣橱为空、模型调用失败、无有效单品、落库失败、任务超时等任一情况均**统一回退额度**并写失败流水(回退与写流水使用不受任务取消影响的 context,避免断连时收尾失败)。
|
||||
5. **结果校验**:校正模型返回的衣物 ID(过滤幻觉),无有效单品则失败回退。
|
||||
6. **落库**:生成穿搭以 `source=2 AI`、`status=3 待用户保存` 入库(私有、待审核);明细落库失败则删除穿搭 + 回退额度。
|
||||
7. **结果获取**:前端轮询 `GET /ai-recommend/status?task_id=...`(建议 2 秒一次、上限 90 次);`status=2` 取 `result` 渲染,`status=3` 读 `error_msg` 提示用户。任务快照在 Redis 保留 15 分钟,过期返回 `90402`。
|
||||
8. **保存转正**:仅 `status=3` 可保存(重复保存幂等),保存仅将状态 3→1,**不扣分享额度**;后续公开到社区仍走 Public 流程扣搭配分享额度。
|
||||
9. **自动清理**:未被保存的 `status=3` 穿搭超过 **7 天**,由后台定时任务(启动即执行一次,之后每小时一次,单批 500 条)连同明细一起软删除,避免长期堆积;清理后列表与详情立即不可见。
|
||||
|
||||
### 7. 通知触发规则
|
||||
|
||||
@@ -1213,7 +1220,9 @@ multipart 上传,字段名 `file`;仅支持图片(jpeg/png/gif/webp),
|
||||
|
||||
#### 11. AI 推荐模块
|
||||
|
||||
**POST `/ai-recommend` —— 发起 AI 穿搭推荐(需鉴权)**
|
||||
**POST `/ai-recommend` —— 提交 AI 穿搭推荐任务(需鉴权)**
|
||||
|
||||
> AI 推荐为**异步接口**:提交后立即返回 `task_id`,需轮询 `GET /ai-recommend/status` 获取结果。生成在后台执行,前端退出、切页面、断网都不会中断。
|
||||
|
||||
请求(json):
|
||||
|
||||
@@ -1224,6 +1233,29 @@ multipart 上传,字段名 `file`;仅支持图片(jpeg/png/gif/webp),
|
||||
|
||||
响应 `data`:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| task_id | string | 任务 ID,用于轮询状态接口 |
|
||||
| status | int | 1=生成中 |
|
||||
|
||||
相关错误码:90401 AI 推荐次数已达上限、19002 缓存错误。
|
||||
|
||||
**GET `/ai-recommend/status` —— 查询 AI 推荐任务状态(需鉴权)**
|
||||
|
||||
请求(query):`task_id`(必填,由上一个接口返回)
|
||||
|
||||
响应 `data`:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| task_id | string | 任务 ID |
|
||||
| status | int | 1=生成中 2=成功 3=失败 |
|
||||
| result | object | 仅 status=2 时存在,结构见下表 |
|
||||
| error_code | int | 仅 status=3 时存在(通常 90400) |
|
||||
| error_msg | string | 仅 status=3 时存在 |
|
||||
|
||||
推荐结果 `result`:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| outfit_uuid | string | 生成结果 UUID |
|
||||
@@ -1234,7 +1266,7 @@ multipart 上传,字段名 `file`;仅支持图片(jpeg/png/gif/webp),
|
||||
| status | int | 1=正常 2=封禁 3=待用户保存 |
|
||||
| outfit_item | array | 衣物列表,元素:`{"clothes_uuid": string}` |
|
||||
|
||||
相关错误码:90400 AI 推荐失败、90401 AI 推荐次数已达上限、80000 额度不足。
|
||||
相关错误码:90400 AI 推荐失败、90402 AI 推荐任务不存在或已过期。
|
||||
|
||||
**POST `/ai-recommend/save` —— 保存 AI 推荐为我的穿搭(需鉴权)**
|
||||
|
||||
@@ -1242,7 +1274,7 @@ multipart 上传,字段名 `file`;仅支持图片(jpeg/png/gif/webp),
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| outfit_uuid | string | 是 | AI 推荐结果 UUID(由 `/ai-recommend` 返回) |
|
||||
| outfit_uuid | string | 是 | AI 推荐结果 UUID(由 `GET /ai-recommend/status` 的 `result.outfit_uuid` 返回) |
|
||||
|
||||
响应:`data` 为空对象 `{}`。
|
||||
|
||||
@@ -1337,23 +1369,35 @@ sequenceDiagram
|
||||
sequenceDiagram
|
||||
participant F as 小程序前端
|
||||
participant B as 后端服务
|
||||
participant R as Redis
|
||||
participant L as 大模型网关(Tokenhub)
|
||||
|
||||
F->>B: POST /ai-recommend {scene_type, scene?}
|
||||
B->>R: 抢占用户活跃位 + 写入任务快照(status=1)
|
||||
B->>B: 校验并扣减 AI 额度
|
||||
B->>L: 结合星座运势 + 衣橱衣物生成推荐
|
||||
L-->>B: 推荐结果
|
||||
B->>B: 落库(status=3 待用户保存)
|
||||
B-->>F: {outfit_uuid, outfit_name, outfit_item...}
|
||||
B-->>F: {task_id, status: 1} · 秒级返回
|
||||
|
||||
par 后台生成(独立 ctx,前端退出不中断)
|
||||
B->>L: 结合星座运势 + 衣橱衣物生成推荐
|
||||
L-->>B: 推荐结果
|
||||
B->>B: 落库(status=3 待用户保存)
|
||||
B->>R: 任务快照 status=2 + result
|
||||
and 前端轮询
|
||||
loop 每 2 秒,上限 90 次
|
||||
F->>B: GET /ai-recommend/status?task_id
|
||||
B-->>F: {status, result?}
|
||||
end
|
||||
end
|
||||
|
||||
F->>F: 用户预览、确认
|
||||
F->>B: POST /ai-recommend/save {outfit_uuid}
|
||||
B-->>F: 保存成功,转入我的穿搭
|
||||
```
|
||||
|
||||
1. 请求必带 `scene_type`(1=每日推荐 2=个性化场景),每次调用扣减一次 AI 额度,不足返回 80000 / 90401。
|
||||
2. 推荐结果先落库为"待用户保存"状态(status=3),响应中返回完整推荐内容供预览。
|
||||
3. 用户确认后调用 `/ai-recommend/save`,结果转为用户正式穿搭;未保存的结果不进入穿搭列表。
|
||||
1. 请求必带 `scene_type`(1=每日推荐 2=个性化场景),提交时扣减一次 AI 额度,不足返回 90401。
|
||||
2. 接口**秒级返回** `task_id`,不等大模型;生成在后台执行,前端退出、切页面或断网都不会中断。
|
||||
3. 前端轮询 `GET /ai-recommend/status`(建议 2 秒一次),直到 `status` 为 2(成功)或 3(失败);失败时额度已自动回退。
|
||||
4. 成功后结果先落库为"待用户保存"状态(status=3),用户确认后调用 `/ai-recommend/save` 转为正式穿搭;未保存的结果不进入穿搭列表。
|
||||
|
||||
#### 流程 4:创建订单到支付完成
|
||||
|
||||
|
||||
Reference in New Issue
Block a user