Compare commits

...

55 Commits

Author SHA1 Message Date
Xiaoxia Agent e2de75c9f6 fix(test): 适配#2200/#2207 V2图片分析批处理架构(移除_analyze_single_image断言)
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m4s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m53s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m28s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m8s
AI Code Review / AI Code Review (pull_request) Successful in 7m1s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 11m5s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 11m47s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 10m53s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 14m20s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 18m44s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 27m47s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 1s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 30s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 2m58s
2026-10-05 21:55:57 +08:00
Xiaoxia Agent d949e90051 fix(style): E741 模糊变量名 l -> lpos(vision JSON定位)
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 3s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m54s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m5s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m25s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m14s
AI Code Review / AI Code Review (pull_request) Successful in 7m6s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 9m10s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 12m13s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 12m37s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 10m56s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 16m53s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 23m24s
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 2s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
2026-10-05 21:29:04 +08:00
Xiaoxia Agent 8624896379 feat: 功能计费DB化(爆款读配置+对口型/智能剪辑计费)
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 53s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m52s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m29s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m4s
AI Code Review / AI Code Review (pull_request) Successful in 7m0s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 10m9s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 12m9s
CI/CD Pipeline / Validate - Style (pull_request) Failing after 13m18s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 11m27s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 20m25s
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
2026-10-05 21:02:35 +08:00
CI Bot d7fa9d9e8d style: auto-format with black + isort + ruff + prettier [skip ci-format-check]
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 3s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 10s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 9s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 30s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 59s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 40s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m55s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 23s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 36s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 4s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m3s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m25s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m18s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 2m9s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m42s
AI Code Review / AI Code Review (pull_request) Successful in 7m14s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 2m56s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m49s
CI/CD Pipeline / Integration Tests (push) Successful in 9m41s
CI/CD Pipeline / Validate - Style (push) Failing after 11m10s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 12m38s
CI/CD Pipeline / Unit Tests (push) Failing after 19m36s
CI/CD Pipeline / Validate - Security (push) Successful in 28m3s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
2026-10-05 12:18:41 +00:00
xiaoxia 90004cced4 refactor(vision): dashscope-only (#2207)
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 3s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 16s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m20s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m58s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 7m1s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 51s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 54s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m57s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m45s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 38s
CI/CD Pipeline / CI Gate (pull_request) Successful in 4s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m15s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 2m7s
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
2026-10-05 20:03:30 +08:00
CI Bot e672c17eb2 style: auto-format with black + isort + ruff + prettier [skip ci-format-check]
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 7s
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 9s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 9s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 31s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m33s
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 46s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m34s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m13s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 32s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m27s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m17s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m13s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m45s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m57s
CI/CD Pipeline / Validate - Style (push) Failing after 6m42s
AI Code Review / AI Code Review (pull_request) Successful in 7m6s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m10s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m3s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m33s
CI/CD Pipeline / Validate - Security (push) Successful in 12m14s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 5m10s
CI/CD Pipeline / Unit Tests (push) Failing after 13m40s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
2026-10-05 10:20:33 +00:00
xiaoxia fb0e4989cd Merge pull request 'fix(vision): #2204 lite VLM关闭thinking模式,响应从10-12s降到<3s' (#2204) from fix/vision-v2-disable-thinking into develop
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / Check push changed paths (push) Successful in 10s
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m22s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m5s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m10s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m9s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 6m48s
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m34s
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m38s
CI/CD Pipeline / Build Staging API Image (push) Successful in 2m41s
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
2026-10-05 18:13:07 +08:00
xiaoxia 702f09e6b7 fix(vision): #2204 lite VLM关闭thinking模式,响应从10-12s降到<3s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 50s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m8s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 23s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m44s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 47s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m2s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 5m25s
CI/CD Pipeline / Validate - Style (pull_request) Failing after 5m38s
AI Code Review / AI Code Review (pull_request) Successful in 6m54s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 7m28s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m28s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 12m32s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 17m32s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 6s
根因定位:staging直连测试发现 doubao-seed-2-1-lite-260915 是思考模型,
单次调用产生~520 reasoning_tokens,耗时10-12s,导致fast路径必超时。

修复:
1. vlm_fast_json.py 直接用 httpx 发最小 payload(不走 ai_client 包装),
   显式设置 thinking={"type":"disabled"} + reasoning_effort="low" 关闭思考链,
   期望响应降至 <3s;若API不支持thinking参数返回400,自动降级重试一次。
2. 超时恢复合理值:lite JSON 8s、OCR 6s、fast总超时8s(关闭thinking后预计<3s,余量充足)。
3. vlm_fallback.py 保持单次pro调用,pro走原ai_client路径(兜底场景对延迟不敏感,45s足够)。

预期:3图<10s/8图<15s目标可达。
2026-10-05 18:11:19 +08:00
xiaoxia 12b0d15473 Merge pull request 'fix(vision): #2203 V2快速路径TimeoutError未捕获+max_retries=0不生效' (#2203) from fix/vision-v2-timeout-bugs into develop
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / Check push changed paths (push) Successful in 15s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 2m27s
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 4m56s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m16s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m20s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m2s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m32s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m13s
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m42s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m16s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m28s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m23s
AI Code Review / AI Code Review (pull_request) Successful in 6m29s
CI/CD Pipeline / Validate - Style (push) Failing after 9m24s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m40s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m47s
CI/CD Pipeline / Validate - Security (push) Successful in 11m51s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m18s
CI/CD Pipeline / Unit Tests (push) Failing after 14m17s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
2026-10-05 17:51:27 +08:00
xiaoxia 9344314eac fix(vision): #2203 V2快速路径两个P0 bug修复
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m0s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m21s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 44s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m16s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 14s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m22s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m25s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 5m53s
AI Code Review / AI Code Review (pull_request) Successful in 6m57s
CI/CD Pipeline / Validate - Style (pull_request) Failing after 7m39s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m35s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 13m20s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 15m11s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 1s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
E2E发现两个P0 bug:
1. as_completed(timeout=...)抛TimeoutError时未被捕获,异常直接冒泡到外层,
   跳过了pro VLM兜底路径,导致3/3返回空结果。
   修复:包裹try/except TimeoutError,cancel未完成futures,继续走pro兜底。

2. 外层_step_image_analysis设置client.max_retries=0不生效(ThreadPool线程
   里可能被其他任务覆盖/共享单例状态),实际仍重试1次(2次调用×6s=12s超时)。
   修复:在vlm_fast_json/vlm_fallback内部强制max_retries=0并在finally里恢复。

3. 收紧超时:fast总超时8→6s、lite JSON 6→5s、OCR 8→5s,让lite不够快时
   尽快走pro兜底(pro单次45s足够)。

本地mock验证:fast命中1.5s返回有效portrait_prompt;fast超时6s正确触发pro fallback。
2026-10-05 17:50:13 +08:00
xiaoxia 3f49867384 fix(viral-video): 时长选择恢复原生Select,仅改选项为15-30秒每秒一档 (#2202)
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 4s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 3s
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 6s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 35s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 56s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m6s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m10s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m1s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m22s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m16s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 4m16s
CI/CD Pipeline / Integration Tests (push) Successful in 4m45s
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m21s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m31s
CI/CD Pipeline / Validate - Style (push) Failing after 5m50s
AI Code Review / AI Code Review (pull_request) Successful in 7m7s
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
2026-10-05 17:43:15 +08:00
CI Bot dd420c556f style: auto-format with black + isort + ruff + prettier [skip ci-format-check]
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 3s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 17s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 51s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m0s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m8s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 34s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m16s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m58s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m6s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m16s
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
2026-10-05 09:38:17 +00:00
xiaoxia 2d823a9255 Merge pull request 'refactor(vision): #2201 代码精简 — 删lite/pro竞速/#2194临时止血/V1V2双分支' (#2201) from refactor/vision-v2-clean into develop
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 3s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m59s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m15s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m3s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m21s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m56s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 17s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 6m26s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m22s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m1s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m30s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 6m25s
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
2026-10-05 17:27:02 +08:00
xiaoxia ed24c7cd68 fix(vision): assembler portrait_prompt 拼接自然化 + 清死代码三元
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 4s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 18s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 37s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 38s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 10s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m11s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m10s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Failing after 4m23s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m35s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 5m44s
AI Code Review / AI Code Review (pull_request) Successful in 6m50s
CI/CD Pipeline / Validate - Style (pull_request) Failing after 6m28s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 48s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 12m44s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 1s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
- _AGE_PREFIX 去掉儿童/青少年死代码(已在 _person_subject 里单独按性别处理)
- 风格段(style/mood/scene)之间不用逗号,改为紧凑拼接(休闲阳光街拍风格而非'休闲,阳光,街拍风格')
2026-10-05 17:26:04 +08:00
xiaoxia 69f88434bd refactor(vision): #2201 代码精简 — 删lite/pro竞速/#2194临时止血/V1V2双分支
按灵应要求清理冗余:
1. _step_image_analysis 直接走V2主路径,去掉V1/V2 if/else分支
2. 删除 _analyze_single_image 整个函数(450行lite/pro竞速/_xml_to_product复杂解析)
3. VLM兜底抽到vision/vlm_fallback.py:单次pro调用,简化版XML/JSON解析,无竞速/无复杂超时
4. _normalize_image_url 删除#2194临时加的GET+Range:0-1024可达性检查
5. fast_path.py 去掉VISION_V2_ENABLED判断,简化默认超时(fast=8s/lite=6s/ocr=6s)
6. 删掉未使用的_is_vision_result_usable、ThreadPoolExecutor/as_completed import
7. viral_video.py从2583行精简到2031行(净删552行),结构清爽

代码只有一条主力路径:OCR+lite JSON并行 → 失败单次pro兜底。
2026-10-05 17:26:03 +08:00
CI Bot 599388d9e0 style: auto-format with black + isort + ruff + prettier [skip ci-format-check]
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 6s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 5s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 5s
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 16s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m6s
CI/CD Pipeline / Build Staging API Image (push) Successful in 52s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 26s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m36s
CI/CD Pipeline / CI Gate (pull_request) Successful in 1s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 30s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m56s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m13s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m45s
CI/CD Pipeline / Integration Tests (push) Successful in 4m27s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m36s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (push) Failing after 6m22s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 6m20s
AI Code Review / AI Code Review (pull_request) Successful in 6m55s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 3m25s
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
2026-10-05 09:16:02 +00:00
xiaoxia 9ffe909dc0 fix(viral-video): 时长滚轮改为弹层式,保持与其他表单项外观一致 (#2199)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Check push changed paths (push) Successful in 18s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m47s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 44s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m4s
CI/CD Pipeline / Build Staging API Image (push) Successful in 33s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 43s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m2s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m34s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m19s
AI Code Review / AI Code Review (pull_request) Successful in 6m44s
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
2026-10-05 17:09:02 +08:00
xiaoxia 6243196408 feat(vision): #2200 V2图片分析快速路径 OCR+lite JSON VLM并行 目标单图<3s/8图<15s (#2200)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Check push changed paths (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (push) Has been cancelled
CI/CD Pipeline / PR Build Web Image (push) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (push) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Staging API Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
2026-10-05 17:08:52 +08:00
CI Bot 3d8f2c2ce2 style: auto-format with black + isort + ruff + prettier [skip ci-format-check]
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 3s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 6s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 7s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 57s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m9s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m10s
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
CI/CD Pipeline / Build Staging API Image (push) Successful in 49s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 37s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m50s
CI/CD Pipeline / Integration Tests (push) Successful in 3m10s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m18s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 3m40s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m24s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m36s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m9s
AI Code Review / AI Code Review (pull_request) Successful in 6m49s
CI/CD Pipeline / Validate - Style (push) Failing after 7m49s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m16s
CI/CD Pipeline / Validate - Security (push) Successful in 8m14s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m10s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m52s
CI/CD Pipeline / Unit Tests (push) Failing after 11m2s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
2026-10-05 08:36:18 +00:00
xiaoxia 3eef497dfe feat(viral-video): 文案视频时长改为15-30秒滚轮picker (#2196)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 3s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 4s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 7s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 58s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m15s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m13s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m19s
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m55s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m29s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m19s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 3m53s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m32s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 5m16s
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Failing after 5m50s
AI Code Review / AI Code Review (pull_request) Has been cancelled
2026-10-05 16:30:20 +08:00
xiaoxia 61c15eb987 fix(viral_video): #2199 _is_vision_result_usable放宽判定+_normalize兼容dict
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 9s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 8s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m8s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m11s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 20s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m52s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 42s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 2m59s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m14s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m21s
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Failing after 10m43s
两个bug修复:
1. _normalize兼容VLM直接返回JSON dict(裸JSON不包裹fence时json.loads返回dict),
   之前isinstance(raw,str)判False走badtype fallback导致name=未识别,usable永远False
2. _is_vision_result_usable放宽判定:有人像描述即视为usable(爆款视频核心是给
   信任链t2i做人物参考),非人像场景才要求name+summary+features;summary长度30→5
竞速循环能正确识别pro返回的人像结果,竞速胜出日志正常
2026-10-05 16:26:34 +08:00
xiaoxia 0012ecad30 fix(viral_video): #2198b _normalize兼容VLM直接返回dict(JSON),竞速判定不再误判失败
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 3s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 24s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m11s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m3s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m11s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 34s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m50s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 36s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
根因:_call() 里 json.loads 成功时返回 dict,但 _normalize 第一行 isinstance(raw,str) 判False
直接走 _vision_fallback 返回 name=未识别,导致 _is_vision_result_usable=False。
外层 fallback 路径再次 _normalize 又因dict问题走badtype,靠outfit回填逻辑拼了结果。
修复:
1. _normalize 先判断 isinstance(raw,dict),直接从dict取字段构造product
2. 字符串解析失败时再尝试 json.loads 递归处理(兼容裸JSON字符串)
3. 竞速判定现在能正确识别pro/dict返回,'竞速胜出=pro'日志正常打印
2026-10-05 16:24:07 +08:00
CI Bot e1994ada0a style: auto-format with black + isort + ruff + prettier [skip ci-format-check]
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 8s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 9s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 9s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 35s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 59s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m5s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m4s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m34s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m23s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m34s
CI/CD Pipeline / Integration Tests (push) Successful in 4m10s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 4m29s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m33s
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Style (push) Failing after 6m0s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m3s
AI Code Review / AI Code Review (pull_request) Successful in 6m57s
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
2026-10-05 08:15:39 +00:00
xiaoxia f9f6c53ef4 chore: trigger CI rebuild for #2198 lite/pro race [skip ci-format-check]
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 3s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 3s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / Check push changed paths (push) Successful in 12s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m20s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m5s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m19s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m39s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m46s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 4m14s
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 50s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m23s
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
2026-10-05 16:09:11 +08:00
xiaoxia 9699a1fcde fix(viral_video): #2198 lite/pro并行竞速,单图最坏75s(原串行100s+)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been cancelled
CI/CD Pipeline / Check push changed paths (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (push) Has been cancelled
CI/CD Pipeline / PR Build Web Image (push) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 38s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 59s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m22s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m4s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 3m5s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m15s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m53s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m55s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 4m7s
CI/CD Pipeline / Validate - Style (pull_request) Failing after 6m5s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m26s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 9m38s
AI Code Review / AI Code Review (pull_request) Successful in 10m17s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 3s
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
问题:实测lite 40s 100%超时→pro串行跑40-65s,3图2并发最坏=40+60+40=140-190s,img#1粉波点裙pro 60s超时直接失败。
改动:
1. _analyze_single_image内部用2线程ThreadPoolExecutor并行发lite(30s)和pro(75s),
   as_completed取第一个usable结果即返回,消除串行等待惩罚
2. _step_image_analysis阶段统一在try外层置client.max_retries=0、finally恢复,
   子线程_call不再嵌套修改client属性避免竞态
3. lite timeout 40→30s(快速路径30s还没出就等pro),pro timeout 60→75s(给10s余量防偶发慢)
4. 单图最坏75s(pro慢到75s才出),典型40-50s,3图2并发≈75s;外层图片并发仍≤2(总VLM并发=4)
5. elapsed日志加label字段(lite/pro)便于区分竞速胜出方
2026-10-05 16:08:00 +08:00
xiaoxia 305e2bd9d5 fix(viral_video): #2194b balance VLM timeout lite40s/pro60s,E2E验证25s太紧导致2/3图误判未识别
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 5s
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 5s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 5s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 29s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m34s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m36s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m17s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m33s
CI/CD Pipeline / Integration Tests (push) Successful in 3m34s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 3m47s
CI/CD Pipeline / Build Staging API Image (push) Successful in 56s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m6s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m0s
CI/CD Pipeline / Validate - Style (push) Failing after 5m47s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 6m57s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m17s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m17s
CI/CD Pipeline / Validate - Security (push) Successful in 9m26s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m41s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 2m58s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m59s
CI/CD Pipeline / Unit Tests (push) Failing after 14m2s
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
E2E实测(b8e27707/85c65d16)发现:lite timeout=25s时2并发下偶发2/3图返回未识别,
因为lite超时后走pro fallback=45s,但pro在2并发下也偶尔超时返回None。
调整为 lite 40s + pro 60s(都禁重试),单图最坏100s,比原240s改善>50%,
同时保证成功率>90%(不会误判未识别)。
2026-10-05 15:34:07 +08:00
CI Bot 30cc58441f style: auto-format with black + isort + ruff + prettier [skip ci-format-check]
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 6s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / Check push changed paths (push) Successful in 52s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 3m57s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m28s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m58s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m37s
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m51s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m52s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Has been cancelled
2026-10-05 07:28:34 +00:00
xiaoxia b3b5dbd459 chore: trigger CI rebuild for #2194/#2195 VLM timeout fixes [skip ci-format-check]
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Check push changed paths (push) Successful in 7s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m0s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m10s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 56s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m9s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m27s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 3m39s
CI/CD Pipeline / Integration Tests (push) Successful in 3m40s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m14s
CI/CD Pipeline / Build Staging API Image (push) Successful in 5m31s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m49s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
2026-10-05 15:22:01 +08:00
xiaoxia 9f5948dd2b fix(viral_video): #2194 图片URL可达性检查 HEAD→GET+Range,避免OSS签名URL 403假阴
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 5s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 30s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m5s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m16s
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
运维发现 OSS 签名 URL 把 HTTP Method 纳入签名,前端/SDK 生成的签名是 GET-only,
HEAD 请求返回 403 SignatureDoesNotMatch 误判 URL 无效(实际 GET 完全正常下载)。
- _normalize_image_url 的 HEAD 5s 检查改为 GET stream=True + Range: bytes=0-1024 只取前1KB
- 避免日志假warning,也不影响后续VLM实际下载(VLM用GET不受影响)
- 连带说明:用户4min卡顿的主因是VLM底层httpx重试叠加(lite30s×2+pro90s×2=240s),
  已在#2194前一commit(fbc1df3)修复为max_retries=0+lite25s+pro45s=单图最坏70s
2026-10-05 15:18:27 +08:00
xiaoxia fbc1df36e0 fix(viral_video): #2194 VLM单图最坏240s→70s,禁用httpx底层重试+收紧timeout
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 11s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 16s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 24s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 35s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 3m26s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m37s
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m18s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m12s
AI Code Review / AI Code Review (pull_request) Successful in 6m54s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 8m3s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 3m4s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 3m42s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 0s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Failing after 5m30s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 47s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 57s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 6m10s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 2s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
P0根因:用户实测图片分析卡4分钟+。代码分析发现:
- _analyze_single_image 底层 DoubaoClient.max_retries=1(共2次请求)
- lite timeout=30s × 2次重试 = 60s
- lite失败后 pro_fallback timeout=90s × 2次重试 = 180s
- 单图最坏 60+180 = 240s,3图2并发最坏 ~240s+,恰好命中用户4分钟描述

修复:
1. _call() 临时将 client.max_retries=0 单次调用,不重复请求
2. lite timeout 30s → 25s(超时立即降级pro)
3. pro fallback timeout 90s → 45s(pro稳定响应<30s)
4. 单图最坏 25+45=70s,3图2并发最坏约70s(含排队)
5. 每张图VLM调用结束打印elapsed日志,方便后续排查
2026-10-05 15:14:42 +08:00
xiaoxia d36cc09be5 feat(ui): 恢复积分系统UI显示(Header徽章+积分中心+预校验) (#2193)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 8s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 28s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m34s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m3s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m56s
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
CI/CD Pipeline / Build Staging API Image (push) Successful in 2m9s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m15s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m11s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m9s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m52s
AI Code Review / AI Code Review (pull_request) Successful in 6m41s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m24s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 2m56s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m42s
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Lint (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
2026-10-05 15:03:48 +08:00
CI Bot fa4dbc6761 style: auto-format with black + isort + ruff + prettier [skip ci-format-check]
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 5s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 6s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 23s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 42s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 57s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 55s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m43s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m20s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 3m33s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 3m35s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 3m52s
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
CI/CD Pipeline / Validate - Style (push) Successful in 4m18s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m41s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m3s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m13s
AI Code Review / AI Code Review (pull_request) Successful in 6m52s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m12s
CI/CD Pipeline / Validate - Security (push) Successful in 7m51s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m42s
CI/CD Pipeline / Unit Tests (push) Successful in 11m20s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 36m49s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
2026-10-05 05:56:41 +00:00
xiaoxia 77133eb9a0 fix(viral_video): #2188 VLM outfit回填服装关键词扩充
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check push changed paths (push) Successful in 17s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 28s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 47s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m51s
CI/CD Pipeline / Build Staging API Image (push) Successful in 33s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m21s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 3m47s
CI/CD Pipeline / Integration Tests (push) Successful in 3m40s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m54s
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Successful in 9m45s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m16s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 4m22s
CI/CD Pipeline / Validate - Style (pull_request) Failing after 4m25s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 47s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m50s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m23s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 2s
- 原 cloth_kws 漏了'上衣/打底衫/罩衫/雪纺衫/西服/套装/网纱/短袖/长袖/无袖'等常见词,
  导致'白色V领上衣''黑色透视网纱短袖上衣'等未命中,回退到通用'日常服装'
- 扩充到40+关键词,覆盖衬衫/T恤/毛衣/外套/裙装/裤装/制服/通用上装词
- 提取窗口 ci-8/ci+4 → ci-12/ci+8,向前多抓颜色/材质形容词,向后多抓款式词
- 重复词(马甲/背心)清理
2026-10-05 13:47:26 +08:00
CI Bot 35207ae040 style: auto-format with black + isort + ruff + prettier [skip ci-format-check]
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 31s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 56s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 15s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 3m22s
CI/CD Pipeline / Integration Tests (push) Successful in 3m16s
CI/CD Pipeline / Validate - Style (push) Successful in 4m37s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m31s
CI/CD Pipeline / Validate - Security (push) Successful in 7m24s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m50s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 6m21s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m19s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m26s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m4s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 3m4s
AI Code Review / AI Code Review (pull_request) Successful in 7m42s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m36s
CI/CD Pipeline / Unit Tests (push) Successful in 12m28s
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m7s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m50s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 30s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m23s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m36s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 5m58s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 6m9s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 6m58s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 10m15s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 1s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
2026-10-05 04:26:27 +00:00
xiaoxia 5af16f1aea feat(viral_video): #2188 voice_source='my_voice'/'clone' 克隆音色支持
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 5s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 5s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 59s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 59s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m18s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m46s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m32s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m17s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 3m55s
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
- 新增 _resolve_tts_voice_id(job):voice_source 为 my_voice/clone 时,
  前端传的 voice_id 是 VoiceCloneProfile.id,查 DB 取 profile.voice_id(CosyVoice 真正的克隆音色ID)
- profile 不存在/未就绪/voice_id为空时回退默认 longxiaochun_v3,任务不崩
- preset 或 voice_source 为空时,voice_id 直接当 CosyVoice 音色名透传(与原有行为一致)
- _step_tts 改用 _resolve_tts_voice_id 解析后的 voice_id 调 synthesize
- 不改 DB schema,不加字段;voice_source/voice_id schema 已在之前合入
2026-10-05 12:21:53 +08:00
xiaoxia c232721fff feat(viral-video): 音色选择默认改为"我的音色"克隆音色主路径 (#2189)
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 15s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 15s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 36s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m3s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m8s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 40s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m16s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 29s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m48s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 3m7s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m29s
CI/CD Pipeline / Validate - Style (push) Successful in 3m32s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m12s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m28s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m49s
CI/CD Pipeline / Integration Tests (push) Successful in 5m55s
CI/CD Pipeline / Validate - Security (push) Successful in 6m36s
AI Code Review / AI Code Review (pull_request) Successful in 6m50s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m8s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 4m28s
CI/CD Pipeline / Unit Tests (push) Successful in 14m1s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-10-05 12:01:32 +08:00
xiaoxia fc27d4e81e fix(viral_video): VLM图片分析3个P0 bug (#2188) (#2188)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 4s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Check push changed paths (push) Has been cancelled
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-10-05 12:00:37 +08:00
xiaoxia 3c782f89d1 fix(#2187): outfit提取正则优化,保留颜色形容词 (#2187)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 26s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 58s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m0s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m17s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 33s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m8s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m8s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m15s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m47s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 4m54s
CI/CD Pipeline / Validate - Style (push) Successful in 5m32s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m31s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m49s
AI Code Review / AI Code Review (pull_request) Successful in 6m57s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 2m50s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m52s
CI/CD Pipeline / Validate - Security (push) Successful in 10m56s
CI/CD Pipeline / Unit Tests (push) Successful in 12m0s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Failing after 38m2s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-10-05 02:04:07 +08:00
xiaoxia 2b4f11036f fix(#2186): portrait_prompt智能回填+few-shot示例,服装发型还原增强 (#2186)
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 4s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 18s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 1m2s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m22s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m44s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m5s
CI/CD Pipeline / Validate - Style (push) Successful in 4m12s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m8s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 4m57s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 4m35s
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m52s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m46s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m11s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m1s
CI/CD Pipeline / Validate - Security (push) Successful in 7m47s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 3m19s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m20s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 4m37s
AI Code Review / AI Code Review (pull_request) Successful in 11m31s
CI/CD Pipeline / Unit Tests (push) Successful in 12m38s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-10-05 01:03:15 +08:00
xiaoxia 2881da65cf Merge pull request #2185: require people attrs + worker fallback
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 3s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m1s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m0s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m46s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m13s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 6m43s
2026-10-05 00:24:44 +08:00
xiaoxia 1037e218bb fix(#2185): 人物外貌属性强制描述+兜底,提升Seedream t2i还原度 (#2185)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 27s
CI/CD Pipeline / Build Staging API Image (push) Successful in 52s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 34s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 43s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 3m30s
CI/CD Pipeline / Integration Tests (push) Successful in 3m34s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m23s
CI/CD Pipeline / Validate - Style (push) Successful in 4m13s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m37s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m9s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m45s
CI/CD Pipeline / Validate - Security (push) Successful in 7m34s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 4m1s
CI/CD Pipeline / Unit Tests (push) Successful in 11m12s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-10-05 00:24:42 +08:00
xiaoxia f0514d7487 fix(#2185): 人物外貌属性强制描述+兜底,提升Seedream t2i还原度
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m27s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 2m48s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m6s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m10s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 3m14s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 3m37s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m53s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 4m9s
AI Code Review / AI Code Review (pull_request) Successful in 6m35s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 6m46s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 1s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m17s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 4m14s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 1m3s
VLM对hair/skin_tone/face_shape/outfit四项输出"无法判断"导致Seedream自由发挥,
发型服装还原失败。双层修复:

1. prompts.py image_analysis system prompt强化:
   - 明确has_person=true时hair/skin_tone/face_shape/outfit四项禁止填"无法判断"
   - 提供hair/skin_tone/face_shape/outfit的具体示例值供参照
   - 即使局部遮挡也要基于可见部分合理推断

2. worker _xml_to_product双层保险:
   - VLM仍输出"无法判断"时,用通用兜底值(自然发型/自然肤色/标准脸型/日常服装)
   - 保证portrait_prompt始终包含完整外貌描述(性别/年龄/发型/肤色/脸型/穿着/表情)
   - 确保preheat_trust_chain的人物描述过滤器(len>=10)不会过滤掉结果

预期:人像图VLM输出具体外貌→Seedream t2i还原发型服装脸型→
Seedance reference_image为高还原度AI人像→人物整体相似度>85%(上次脸部80-90%,本次服装发型也应还原)
2026-10-05 00:17:01 +08:00
xiaoxia bf8f62ec5b Merge pull request #2184: fix xml people portrait_prompt trust-chain
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 24s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m1s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m31s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m40s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 4m5s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m0s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m15s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 6m19s
CI/CD Pipeline / CI Gate (pull_request) Successful in 1s
AI Code Review / AI Code Review (pull_request) Successful in 7m16s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m54s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 7m53s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m37s
CI/CD Pipeline / Integration Tests (push) Successful in 9m35s
CI/CD Pipeline / Validate - Style (push) Successful in 10m9s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m30s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 11m21s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m52s
CI/CD Pipeline / Validate - Security (push) Successful in 16m10s
CI/CD Pipeline / Unit Tests (push) Successful in 17m38s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
2026-10-04 23:49:36 +08:00
CI Bot cb911f5eba style: auto-format with black + isort + ruff + prettier [skip ci-format-check]
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1s
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m1s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m56s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m32s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m6s
AI Code Review / AI Code Review (pull_request) Successful in 7m10s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 9m22s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 9m46s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 9m52s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 11m25s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 12m44s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 23m18s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 1s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 34s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 1m32s
2026-10-04 15:23:27 +00:00
xiaoxia f6fa3ea653 fix(#2184): VLM <people>标签解析+扩展外貌属性,修复信任链第4处断链
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 59s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m57s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m25s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m58s
AI Code Review / AI Code Review (pull_request) Successful in 6m59s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 8m52s
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
问题根因:#2177 XML重构后VLM prompt契约改为顶层<people has_person count gender age_range pose expression/>标签,
人物信息不再是<product portrait_prompt=...>属性。worker的_xml_to_product只读product属性,
VLM输出<people has_person="true" ...>被忽略,所有人物判断走默认"无人像",
导致:preheat跳过→现场t2i跳过→真人图直传Seedance→400 portrait_intercept→降级纯t2v(无参考图→人物相似度仅30-40%)

修复:
1. _xml_to_product解析顶层<people>标签,拼装portrait_prompt供信任链使用
2. 扩展VLM <people>标签新增外貌属性:hair/skin_tone/face_shape/outfit(原6属性→10属性)
   提供足够细节(60-100字外貌描述)给Seedream t2i生成还原度高的AI人像
3. 同步更新example为新属性格式
4. 兼容旧schema:product属性仍有portrait_prompt时优先使用
5. 无product标签但<people has_person=true>时也构造结果,不丢人物信息
2026-10-04 23:12:00 +08:00
CI Merge 6a7709ba43 Merge pull request #2183: real trust-chain preheat + LLM timeout fix
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 3s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 21s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 2m36s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m15s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 2m49s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m30s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 4m33s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m1s
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m14s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m37s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 7m4s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 2m0s
CI/CD Pipeline / Integration Tests (push) Successful in 10m27s
CI/CD Pipeline / Validate - Style (push) Successful in 10m55s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 2m50s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m58s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 12m19s
CI/CD Pipeline / Unit Tests (push) Successful in 17m7s
CI/CD Pipeline / Validate - Security (push) Successful in 33m1s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Failing after 35m2s
# Conflicts:
#	apps/worker/worker_app/tasks/viral_video.py
2026-10-04 22:30:49 +08:00
xiaoxia 2c70dd4c29 Merge pull request 'feat(viral_video): #2040 接入Prompt模板系统+删除冗余硬编码prompt' (#2177) from fix/2040-wire-prompt-templates into develop
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 5s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 3s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 10s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 2m14s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m48s
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 20s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m45s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 19s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 13s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m19s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 25s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 1s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
AI Code Review / AI Code Review (pull_request) Successful in 6m44s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 2m3s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m47s
CI/CD Pipeline / Integration Tests (push) Successful in 10m37s
CI/CD Pipeline / Validate - Style (push) Successful in 11m58s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m38s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 4m20s
CI/CD Pipeline / Unit Tests (push) Successful in 18m37s
CI/CD Pipeline / Validate - Security (push) Successful in 26m44s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 32m59s
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
feat(viral_video): #2040 Prompt模板接线+删硬编码(DB读取+XML解析+三档融合+Reviewer) (#2177)
2026-10-04 21:51:50 +08:00
CI Bot 5548e78eee style: auto-format with black + isort + ruff + prettier [skip ci-format-check]
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 54s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m50s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m33s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m0s
AI Code Review / AI Code Review (pull_request) Successful in 7m4s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 9m59s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 12m57s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 13m14s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 11m4s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 19m21s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 26m10s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 1s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
2026-10-04 13:51:16 +00:00
xiaoxia 44bd96b148 fix(#2183): 信任链真·现场t2i+preheat接线+portrait_intercept降级纯t2v+timeout调大
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 8s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 20s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m20s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m44s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 5m35s
AI Code Review / AI Code Review (pull_request) Successful in 10m19s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 9m26s
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
- 信任链3处断链修复:
  1. run_viral_video_analyze VLM完成后立即启动_start_trust_chain_preheat(后台daemon与文案阶段并行)
  2. _step_render 预热不可用时真·同步调用Seedream t2i(而非打假日志直接传原图),120s超时
  3. ai_client.video_generation遇到portrait_intercept 400时自动移除所有参考图降级纯t2v重试一次
- LLM timeout调大(实测pro 1500tok输出需75.8s):
  - _step_script_generation: fast-first/fast-retry 45→90s, pro-fallback 60→120s
  - _step_intent_parsing: 45→60s
  - _step_review: 30→45s
- generate_copy celery时限放宽:soft=360→600s, hard=420→660s(三级重试最坏~405s)
- 三层兜底:后台预热→现场t2i→400纯t2v,保证人像链路必出片
2026-10-04 21:38:31 +08:00
xiaoxia dda67cd10f Merge pull request 'fix(#2181): doubao_fast_model 默认改pro,避免文案阶段走lite超时' (#2182) from fix/fast-model-default-pro into develop
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 5s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 33s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m56s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m32s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m19s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m29s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m53s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m1s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 6m13s
CI/CD Pipeline / CI Gate (pull_request) Successful in 1s
AI Code Review / AI Code Review (pull_request) Successful in 7m17s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 2m0s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 7m54s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m33s
CI/CD Pipeline / Integration Tests (push) Successful in 9m14s
CI/CD Pipeline / Validate - Style (push) Successful in 10m47s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m8s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m51s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 12m36s
CI/CD Pipeline / Unit Tests (push) Successful in 17m26s
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
2026-10-04 21:29:47 +08:00
xiaoxia-saas-bot 233d0272a9 fix(viral_video): #2040 rebase 后清理F841死代码+保留#2180 timeout修复
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 32s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m53s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 4m52s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 5m33s
AI Code Review / AI Code Review (pull_request) Successful in 6m41s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 9m6s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 10m19s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 10m25s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 12m49s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 10m39s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 27m35s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
- 删除 script_generation 中旧prompt遗留的未使用变量(style_hint/ratio/viral_structure_block/persona_hint)
- 冲突解决保留 #2180 全部修复: VLM/LLM timeout 15/25→45, pro 25→60, max_retries 2→1
- black/isort/ruff 全绿;viral 相关71测试全过
2026-10-04 21:15:59 +08:00
Xiaoxia Agent 631dd643c0 fix(viral_video): #2040 修复 style check F401/F821 导入问题
- _step_image_analysis/_step_intent_parsing 的局部导入补 render_system_prompt(F821 未定义名)
- _step_script_generation 的冗余 render_system_prompt 导入删除(F401 未使用)

black/isort/ruff 全绿,viral_video 单测 150/150 通过。
2026-10-04 21:15:59 +08:00
CI Bot 50489b05d6 style: auto-format with black + isort + ruff + prettier [skip ci-format-check] 2026-10-04 21:15:59 +08:00
Xiaoxia Agent 252ea71d50 test: 新增 prompt 模板接线集成测试 + 修复旧测试适配 XML 输出
- 新增 test_viral_video_wiring.py:9 个集成测试覆盖四步接线全流程
  - image_analysis / intent_parsing 走 loader + XML 解析
  - storyboard 三档 fusion_level 注入 system_prompt
  - review 走 Reviewer 且 pass/rewrite 两条路径正确
  - 端到端验证每步都调用 prompt_loader
- 修复 test_script_generation_returns_copy_result:mock 改为返回 XML 字符串
- 修复 test_review_pass_v16:mock Reviewer.review 返回真实 ReviewResult
- viral_video.py 增加 import re,_xml_to_product 的 text_on_package 同时从子标签读取(兜底)
- prompts.py _STORYBOARD_SYSTEM 改为普通字符串 + {fusion_instruction}/{global_constraints}/{negative_rules} 占位符,支持运行时注入

全量 viral_video 单测 150/150 通过,无回归。

Closes #2040
2026-10-04 21:15:59 +08:00
xiaoxia-saas-bot d5f6e9499d feat(viral_video): #2040 接入Prompt模板系统+删除冗余硬编码prompt 2026-10-04 21:15:59 +08:00
32 changed files with 3745 additions and 508 deletions
+2
View File
@@ -0,0 +1,2 @@
Mon Oct 5 04:09:11 PM CST 2026
2198 lite/pro并行竞速 (commit 9699a1f) — CI rebuild trigger Mon Oct 5 08:09:11 AM UTC 2026
+61
View File
@@ -0,0 +1,61 @@
"""功能计费积分字段(爆款/对口型/智能剪辑 DB 化计费)。
给 gpu_lipsync_tasks / generation_tasks / lipsync_jobs 三张表加积分字段:
- credits_prepaid: 提交任务时预扣积分
- credits_cost: 最终结算积分
- credits_transaction_id: 预扣流水 ID
注意:feature_pricing_configs 配置表由 xiaoxia-admin 侧 migration 建立,
本仓库只读,不在此创建。
Revision ID: 096_feature_billing_fields
Revises: 095_viral_video_prompt_templates
Create Date: 2026-10-05
"""
import sqlalchemy as sa
from alembic import op
revision = "096_feature_billing_fields"
down_revision = "095_viral_video_prompt_templates"
branch_labels = None
depends_on = None
_TABLES = ("gpu_lipsync_tasks", "generation_tasks", "lipsync_jobs")
_COLUMNS = (
("credits_prepaid", sa.Float(), "0"),
("credits_cost", sa.Float(), "0"),
("credits_transaction_id", sa.String(36), ""),
)
def _table_exists(conn, name: str) -> bool:
return name in sa.inspect(conn).get_table_names()
def upgrade() -> None:
conn = op.get_bind()
for table in _TABLES:
if not _table_exists(conn, table):
continue
existing = {c["name"] for c in sa.inspect(conn).get_columns(table)}
for col_name, col_type, default in _COLUMNS:
if col_name in existing:
continue
op.add_column(
table,
sa.Column(col_name, col_type, nullable=False, server_default=default),
)
def downgrade() -> None:
conn = op.get_bind()
for table in _TABLES:
if not _table_exists(conn, table):
continue
existing = {c["name"] for c in sa.inspect(conn).get_columns(table)}
for col_name, _col_type, _default in _COLUMNS:
if col_name not in existing:
continue
op.drop_column(table, col_name)
+48 -1
View File
@@ -44,6 +44,7 @@ from packages.application import (
GetGenerationTaskUseCase,
ListGeneratedVideosByTaskUseCase,
)
from packages.domain import feature_pricing_service
from packages.domain.smart_match import smart_select_assets
# #2035:文案关键词 → 素材分类 映射表(用于 smart_match category_match 维度)
@@ -163,7 +164,6 @@ def _infer_expected_categories(script_tags: set[str] | None) -> set[str] | None:
return matched or None
logger = logging.getLogger(__name__)
router = APIRouter()
@@ -700,6 +700,17 @@ def create_generation_task(
logger.info("画中画已下线,strategy_id %s → one_take", effective_strategy_id)
effective_strategy_id = "one_take"
# ── smart_edit 计费预扣(全局 points 开关 + 功能开关均开才扣) ──
# 首期固定价:dynamic_cost=0,price=(0+fixed_cost)×multiplier,price_cap 封顶。
# 预览任务不扣费;按任务条数扣费,任一任务预扣失败(余额不足)整体拒绝。
smart_edit_charge = 0.0
charged_task_count = 0
if not request.is_preview and feature_pricing_service.is_feature_enabled("smart_edit"):
unit_credits, _bd = feature_pricing_service.calculate_price("smart_edit", 0.0)
if unit_credits > 0:
smart_edit_charge = round(unit_credits * count, 2)
charged_task_count = count
# 批量生成(count>1):每个变体必须走与单视频完全相同的独立选片流程(#1743/#1749)。
# - 变体 0:clone 源 plan(不污染源 plan),变体 1..N-1 用 reselect_plan_for_variant
# 完整重跑选片(素材级去重:fresh 优先 → 受控复用 overlap≤20% → 短素材禁复用);
@@ -930,6 +941,42 @@ def create_generation_task(
)
# 变体序号写入 extra_meta(响应/排查时可辨识)
task.extra_meta["variant_index"] = task_index
# smart_edit 逐条预扣(首期固定价,credits_cost=prepaid,不做结算)
task_txn_id = ""
if charged_task_count > 0:
from packages.domain.points_service import PointsService
unit_credits = round(smart_edit_charge / count, 2)
res = PointsService().deduct_points(
user_id=user_id,
amount=unit_credits,
source="smart_edit",
db=db,
description="智能剪辑生成预扣",
ref_id=task.id,
)
if not res.get("success"):
# 余额不足:退还本次请求已扣积分后整体拒绝
already_charged = round(unit_credits * task_index, 2)
if already_charged > 0:
PointsService().refund_points(
user_id=user_id,
amount=already_charged,
source="smart_edit",
db=db,
ref_id=task.id,
description="智能剪辑批量提交失败退回",
)
raise HTTPException(
status_code=402,
detail=(f"积分不足:智能剪辑每条需 {unit_credits:.2f} 积分,当前余额 {res.get('balance', 0)}"),
)
task_txn_id = str(res.get("transaction_id") or "")
task.credits_prepaid = unit_credits
task.credits_cost = unit_credits
task.credits_transaction_id = task_txn_id
generation_task_repository.update(task)
try:
# 兜底关联编辑计划:前端未传 source_edit_plan_id 时,
# 通过 template_id + user_id 在 DB 层直接查找最新的 plan。
@@ -228,6 +228,8 @@ class GpuLipsyncService:
lipsync_job_id: str = "",
user_id: str = "",
project_id: str = "",
credits_prepaid: float = 0.0,
credits_transaction_id: str = "",
) -> GpuLipsyncTaskModel:
task_id = str(uuid.uuid4())
now = datetime.now(UTC)
@@ -240,6 +242,8 @@ class GpuLipsyncService:
audio_url=audio_url,
status="pending",
attempt=0,
credits_prepaid=float(credits_prepaid or 0.0),
credits_transaction_id=str(credits_transaction_id or ""),
created_at=now,
updated_at=now,
)
+157
View File
@@ -38,6 +38,7 @@ from sqlalchemy.orm import Session
from packages.adapters.sqlalchemy_impl.models import LipsyncJobModel
from packages.application.cosyvoice_service import CosyVoiceError
from packages.config import get_api_settings
from packages.domain import feature_pricing_service
from packages.domain.sentence_timings import (
compute_sentence_timings,
probe_audio_duration,
@@ -368,6 +369,8 @@ class LipsyncService:
lipsync_job_id=job.id,
user_id=job.user_id,
project_id=job.project_id,
credits_prepaid=float(getattr(job, "credits_prepaid", 0) or 0),
credits_transaction_id=str(getattr(job, "credits_transaction_id", "") or ""),
)
logger.info(
"[lipsync] 已创建 GPU 任务(异步): job_id=%s gpu_task=%s",
@@ -415,6 +418,121 @@ class LipsyncService:
job.output_duration,
)
# ── lip_sync 计费辅助 ────────────────────────────────────────────────
@staticmethod
def _estimate_duration(
*,
audio_duration: Optional[float] = None,
sentence_timings: Optional[list] = None,
script_text: str = "",
) -> float:
"""预估音频/成片秒数。
优先级:audio_duration(预合成前端已 ffprobe)> timings 末句 end_time >
脚本字数 / 5 字每秒 > 默认 10 秒。
"""
if audio_duration and float(audio_duration) > 0:
return float(audio_duration)
if sentence_timings:
max_end = 0.0
for item in sentence_timings:
if isinstance(item, dict):
end = item.get("end_time") or item.get("end") or 0.0
else:
end = 0.0
try:
max_end = max(max_end, float(end))
except (TypeError, ValueError):
continue
if max_end > 0:
return max_end
text = (script_text or "").strip()
if text:
return max(1.0, len(text) / 5.0)
return 10.0
def _settle_lip_sync(self, job: LipsyncJobModel, actual_duration: float) -> None:
"""按实际时长结算(首期只退不补:final < prepaid 退差额,> 不补)。
幂等:credits_cost 已 > 0 说明结算过,直接跳过。
结算失败不阻塞业务(结果已产出),仅记录日志。
"""
try:
prepaid = float(getattr(job, "credits_prepaid", 0) or 0)
if prepaid <= 0:
return
if float(getattr(job, "credits_cost", 0) or 0) > 0:
return
feature_cfg = feature_pricing_service.get_feature_config("lip_sync")
unit_cost = float(feature_cfg.dynamic_unit_cost) if feature_cfg is not None else 0.0
duration = float(actual_duration or 0.0)
if duration <= 0:
duration = self._estimate_duration(
sentence_timings=job.sentence_timings,
script_text=job.script_text,
)
final_price, _bd = feature_pricing_service.calculate_price("lip_sync", duration * unit_cost)
final_price = round(float(final_price), 2)
job.credits_cost = final_price
if final_price < prepaid - 0.009:
refund = round(prepaid - final_price, 2)
from packages.domain.points_service import PointsService
res = PointsService().refund_points(
user_id=job.user_id,
amount=refund,
source="lip_sync",
db=self.db,
ref_id=str(job.credits_transaction_id or job.id),
description="对口型结算退费",
)
if not res.get("success"):
logger.warning(
"[lip_sync] 结算退费失败 job_id=%s refund=%.2f(不阻塞)",
job.id,
refund,
)
# final > prepaid:首期只退不补,不补扣
self.db.commit()
except Exception: # noqa: BLE001
logger.exception("[lip_sync] 结算异常 job_id=%s(不阻塞结果)", job.id)
try:
self.db.rollback()
except Exception: # noqa: BLE001
pass
def _refund_lip_sync(self, job: LipsyncJobModel) -> None:
"""任务失败/取消时全额退还预扣积分(credits_cost 已结算则退实际未消耗部分)。"""
try:
prepaid = float(getattr(job, "credits_prepaid", 0) or 0)
if prepaid <= 0:
return
txn_id = str(getattr(job, "credits_transaction_id", "") or "")
cost = float(getattr(job, "credits_cost", 0) or 0)
refund = round(prepaid - cost, 2) if cost > 0 else round(prepaid, 2)
if refund <= 0:
return
from packages.domain.points_service import PointsService
res = PointsService().refund_points(
user_id=job.user_id,
amount=refund,
source="lip_sync",
db=self.db,
ref_id=txn_id or job.id,
description="对口型失败/取消退款",
)
if res.get("success"):
job.credits_cost = prepaid # 标记已全额退回,防重复退
self.db.commit()
except Exception: # noqa: BLE001
logger.exception("[lip_sync] 退款异常 job_id=%s", job.id)
try:
self.db.rollback()
except Exception: # noqa: BLE001
pass
# ── 创建任务 ──────────────────────────────────────────────────────────
def create_job(
@@ -466,6 +584,35 @@ class LipsyncService:
if not isinstance(sentence_timings, list) or len(sentence_timings) == 0:
raise MediaKitError("预合成模式 sentence_timings 不能为空", code="InvalidInput")
# 0.5 lip_sync 计费预扣(全局 points 开关 + 功能开关均开才扣)
prepaid_credits = 0.0
prepaid_txn_id = ""
if feature_pricing_service.is_feature_enabled("lip_sync"):
est_duration = self._estimate_duration(
audio_duration=audio_duration,
sentence_timings=sentence_timings,
script_text=script_text,
)
feature_cfg = feature_pricing_service.get_feature_config("lip_sync")
unit_cost = float(feature_cfg.dynamic_unit_cost) if feature_cfg is not None else 0.0
dynamic_cost = est_duration * unit_cost
prepaid_credits, _bd = feature_pricing_service.calculate_price("lip_sync", dynamic_cost)
if prepaid_credits > 0:
from packages.domain.points_service import PointsService
res = PointsService().deduct_points(
user_id=user_id,
amount=prepaid_credits,
source="lip_sync",
db=self.db,
description="对口型生成预扣",
)
if not res.get("success"):
raise ValueError(
f"积分不足:本次对口型需 {prepaid_credits:.2f} 积分,当前余额 {res.get('balance', 0)}"
)
prepaid_txn_id = str(res.get("transaction_id") or "")
# 1. 创建数据库记录
job_id = str(uuid.uuid4())
job = LipsyncJobModel(
@@ -482,6 +629,8 @@ class LipsyncService:
emotion=emotion or "",
# 音频直传(含预合成)直接进入 pending(后续同步改为 submitted);TTS 模式进入 tts_processing
status="tts_processing" if is_tts_mode else "pending",
credits_prepaid=prepaid_credits,
credits_transaction_id=prepaid_txn_id,
)
self.db.add(job)
self.db.flush()
@@ -677,6 +826,8 @@ class LipsyncService:
job.completed_at = _now
job.updated_at = _now
self.db.commit()
# lip_sync 超时全额退款
self._refund_lip_sync(job)
return job
# 未提交的任务不轮询
@@ -702,6 +853,8 @@ class LipsyncService:
job.completed_at = datetime.now(UTC)
job.updated_at = datetime.now(UTC)
self.db.commit()
# lip_sync 结算(只退不补)
self._settle_lip_sync(job, float(job.output_duration or 0.0))
# 异步转存自家 OSS
try:
from app.tasks.lipsync_tts import persist_output_video_task
@@ -719,6 +872,8 @@ class LipsyncService:
job.error_message = error.get("message", "任务执行失败")
job.error_code = error.get("code", "TaskFailed")
job.completed_at = datetime.now(UTC)
# lip_sync 失败全额退款(先退款再统一 commit)
self._refund_lip_sync(job)
else:
# 中间状态(running/processing/queued 等)同步到 DB,避免前端永远卡在 submitted
if isinstance(mk_status, str) and mk_status:
@@ -812,6 +967,8 @@ class LipsyncService:
job.status = "cancelled"
job.updated_at = datetime.now(UTC)
self.db.commit()
# lip_sync 取消全额退款
self._refund_lip_sync(job)
self.db.refresh(job)
return job
+29
View File
@@ -104,6 +104,7 @@ def lipsync_gpu_process_async(self, job_id: str, user_id: str, gpu_task_id: str)
job.updated_at = datetime.now(UTC)
db.commit()
logger.info("[lipsync_gpu_async] GPU 任务已被用户取消: job_id=%s", job_id)
_refund_lip_sync(db, job)
return
if final_task.status != "done":
@@ -141,6 +142,7 @@ def lipsync_gpu_process_async(self, job_id: str, user_id: str, gpu_task_id: str)
job_id,
job.output_duration,
)
_settle_lip_sync(db, job, final_task)
except Exception as exc:
logger.exception("[lipsync_gpu_async] 异常: job_id=%s err=%s", job_id, exc)
try:
@@ -157,6 +159,33 @@ def lipsync_gpu_process_async(self, job_id: str, user_id: str, gpu_task_id: str)
db.close()
def _settle_lip_sync(db: Session, job: LipsyncJobModel, gpu_task) -> None:
"""GPU 成功后结算:同步 credits_cost 到 gpu 任务并按实际时长多退少不补。"""
try:
from app.services.lipsync_service import LipsyncService
# GPU 任务表先同步结算结果(标记用)
LipsyncService._settle_lip_sync(job, float(getattr(gpu_task, "result_duration", 0) or 0.0))
gpu_task.credits_cost = float(job.credits_cost or 0.0)
db.commit()
except Exception: # noqa: BLE001
logger.exception("[lipsync_gpu_async] lip_sync 结算异常 job_id=%s(不阻塞)", job.id)
try:
db.rollback()
except Exception: # noqa: BLE001
pass
def _refund_lip_sync(db: Session, job: LipsyncJobModel) -> None:
"""GPU 取消/失败路径全额退款。"""
try:
from app.services.lipsync_service import LipsyncService
LipsyncService(db)._refund_lip_sync(job)
except Exception: # noqa: BLE001
logger.exception("[lipsync_gpu_async] lip_sync 退款异常 job_id=%s", job.id)
def _fallback_to_mediakit(db: Session, job: LipsyncJobModel) -> None:
"""GPU 失败时回退到 MediaKit 云端渲染。"""
try:
+4 -4
View File
@@ -176,7 +176,7 @@ export interface ViralVideoJob {
fusion_level?: FusionLevel
voice_id?: string
voice_mode?: "global" | "per_video"
voice_source?: "preset" | "library" | "clone" | "upload"
voice_source?: "preset" | "library" | "clone" | "upload" | "my_voice"
bgm_preference?: string
intent_result?: IntentResult
intent_text?: string
@@ -212,7 +212,7 @@ export interface GenerateViralVideoRequest {
user_copy_text?: string
fusion_level?: FusionLevel
voice_id?: string
voice_source?: "preset" | "library" | "clone" | "upload"
voice_source?: "preset" | "library" | "clone" | "upload" | "my_voice"
bgm_preference?: string
industry?: string
target_customer?: string
@@ -244,7 +244,7 @@ export interface AnalyzeImagesRequest {
/** TTS 音色 ID(STEP1 已选音色时传) */
voice_id?: string
/** 音色来源:preset | library | clone | upload */
voice_source?: "preset" | "library" | "clone" | "upload"
voice_source?: "preset" | "library" | "clone" | "upload" | "my_voice"
/** Seedance 视频比例:9:16 | 16:9 | 1:1 */
video_ratio?: string
/** Seedance 模型 ID(空则使用服务端默认) */
@@ -273,7 +273,7 @@ export interface GenerateCopyRequest {
/** TTS 音色 ID(优先级高于 persona_id) */
voice_id?: string
/** 音色来源:preset | library | clone | upload */
voice_source?: "preset" | "library" | "clone" | "upload"
voice_source?: "preset" | "library" | "clone" | "upload" | "my_voice"
/** Seedance 视频比例(9:16/16:9/1:1 等) */
video_ratio?: string
/** Seedance 模型 ID(空则使用服务端默认) */
+2
View File
@@ -18,6 +18,8 @@ export interface VoiceClone {
language: string
gender: string
error_message: string | null
/** CosyVoice 实际使用的音色 ID(status=ready 时由后端填充,用于 TTS 调用) */
voice_id?: string | null
created_at: string
updated_at: string
}
+1
View File
@@ -18,6 +18,7 @@ export const toVoiceClone = (profile: VoiceCloneProfile): VoiceClone => ({
language: profile.language || "",
gender: profile.gender || "",
error_message: profile.error_message || null,
voice_id: profile.voice_id,
created_at: profile.created_at,
updated_at: profile.updated_at,
})
@@ -0,0 +1,182 @@
/* DurationWheelPicker —— 弹层式滚轮选择器(样式与表单一致) */
/* 触发按钮:外观复用 .vv-select 风格 */
.dw-trigger {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 36px;
padding: 0 12px;
background: #fff;
border: 1px solid #e0e0e8;
border-radius: 8px;
font-size: 13px;
color: #1f2937;
cursor: pointer;
box-sizing: border-box;
transition: all 0.15s;
user-select: none;
}
.dw-trigger:hover {
border-color: #c0c0d0;
}
.dw-trigger-open,
.dw-trigger:focus-within {
border-color: #7c3aed !important;
box-shadow: 0 0 0 2px rgba(124, 58, 237, 0.12);
}
.dw-trigger-disabled {
opacity: 0.5;
pointer-events: none;
cursor: not-allowed;
}
.dw-trigger-val {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.dw-trigger-placeholder {
color: #9ca3af;
}
.dw-trigger-arrow {
font-size: 10px;
color: #9ca3af;
margin-left: 8px;
transition: transform 0.2s;
}
.dw-trigger-arrow-up {
transform: rotate(180deg);
}
/* 弹层容器 */
.dw-popup {
padding: 8px;
min-width: 140px;
}
/* 滚轮 */
.dw-picker {
position: relative;
width: 100%;
overflow: hidden;
border-radius: 8px;
background: #fafafe;
border: 1px solid #e5e7eb;
}
.dw-picker-list {
margin: 0;
padding: 0;
list-style: none;
height: 100%;
overflow-y: scroll;
scroll-snap-type: y mandatory;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
}
.dw-picker-list::-webkit-scrollbar {
display: none;
}
.dw-picker-item {
display: flex;
align-items: baseline;
justify-content: center;
gap: 3px;
scroll-snap-align: center;
cursor: pointer;
font-size: 15px;
color: #9ca3af;
font-weight: 400;
transition:
color 0.15s,
transform 0.15s,
font-weight 0.15s;
}
.dw-picker-item-val {
font-variant-numeric: tabular-nums;
}
.dw-picker-item-unit {
font-size: 13px;
color: inherit;
}
.dw-picker-item-active {
color: #7c3aed;
font-weight: 600;
}
.dw-picker-item-active .dw-picker-item-val {
font-size: 18px;
}
.dw-picker-item-active .dw-picker-item-unit {
font-size: 14px;
}
/* 中心选中条 */
.dw-picker-mask {
position: absolute;
left: 6px;
right: 6px;
pointer-events: none;
background: #f5f0ff;
border-radius: 6px;
z-index: 1;
}
.dw-picker-mask::before,
.dw-picker-mask::after {
content: "";
position: absolute;
left: 0;
right: 0;
height: 1px;
background: #d8c4ff;
}
.dw-picker-mask::before {
top: 0;
}
.dw-picker-mask::after {
bottom: 0;
}
/* 上下渐变 */
.dw-picker-fade {
position: absolute;
left: 0;
right: 0;
height: 40%;
pointer-events: none;
z-index: 2;
}
.dw-picker-fade-top {
top: 0;
background: linear-gradient(to bottom, #fafafe 25%, rgba(250, 250, 254, 0));
}
.dw-picker-fade-bottom {
bottom: 0;
background: linear-gradient(to top, #fafafe 25%, rgba(250, 250, 254, 0));
}
/* 弹层按钮区 */
.dw-popup-actions {
display: flex;
gap: 8px;
justify-content: flex-end;
margin-top: 8px;
}
.dw-popup-actions .ant-btn {
border-radius: 6px;
}
.dw-popup-actions .ant-btn-primary {
background: #7c3aed;
}
.dw-popup-actions .ant-btn-primary:hover {
background: #6d28d9 !important;
}
/* 覆盖 antd Popover 默认内边距 */
.dw-popover .ant-popover-inner {
padding: 0 !important;
overflow: hidden;
}
.dw-popover .ant-popover-arrow {
display: none;
}
@@ -0,0 +1,180 @@
/**
* DurationWheelPicker —— 竖屏滚轮式时长选择器(弹层版)
*
* 设计:
* - 外观是和其他表单 Select 一致的输入框(白色底+1px灰边+紫色focus ring)
* - 点击输入框弹出 Popover,内部是滚轮 picker(原生 scroll-snap,零依赖)
* - 滚轮样式:白底容器,选中行 #7c3aed 紫字加粗+浅紫背景条
* - 支持触摸/鼠标滚轮/点击;松手吸附;底部"确认/取消"按钮
* - 默认范围 15–30 秒,步长 1 秒
*/
import React, { useEffect, useMemo, useRef, useState, useCallback } from "react"
import { Popover, Button } from "antd"
import { DownOutlined } from "@ant-design/icons"
import "./DurationWheelPicker.css"
export interface DurationWheelPickerProps {
value?: number
min?: number
max?: number
step?: number
unit?: string
onChange?: (value: number) => void
placeholder?: string
disabled?: boolean
/** 弹层宽度,默认 160px */
popupWidth?: number
/** 弹层内滚轮高度,默认 180px */
wheelHeight?: number
}
const ITEM_HEIGHT = 36
const DurationWheelPicker: React.FC<DurationWheelPickerProps> = ({
value = 20,
min = 15,
max = 30,
step = 1,
unit = "秒",
onChange,
placeholder = "请选择时长",
disabled = false,
popupWidth = 160,
wheelHeight = 180,
}) => {
const options = useMemo(() => {
const arr: number[] = []
for (let v = min; v <= max; v += step) arr.push(v)
return arr
}, [min, max, step])
const [open, setOpen] = useState(false)
// 弹层内暂存值,点确认才提交
const [draft, setDraft] = useState<number>(value)
const listRef = useRef<HTMLUListElement>(null)
const scrollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
useEffect(() => {
if (open) {
setDraft(value)
// 下一帧滚到当前值
requestAnimationFrame(() => scrollToValue(value, false))
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [open])
const scrollToValue = useCallback(
(v: number, smooth = true) => {
const list = listRef.current
if (!list) return
const idx = options.indexOf(v)
if (idx < 0) return
list.scrollTo({ top: idx * ITEM_HEIGHT, behavior: smooth ? "smooth" : "auto" })
},
[options],
)
const handleScroll = () => {
if (scrollTimerRef.current) clearTimeout(scrollTimerRef.current)
scrollTimerRef.current = setTimeout(() => {
const list = listRef.current
if (!list) return
const idx = Math.round(list.scrollTop / ITEM_HEIGHT)
const clamped = Math.max(0, Math.min(options.length - 1, idx))
const targetTop = clamped * ITEM_HEIGHT
if (Math.abs(list.scrollTop - targetTop) > 1) {
list.scrollTo({ top: targetTop, behavior: "smooth" })
}
setDraft(options[clamped])
}, 100)
}
const handleConfirm = () => {
onChange?.(draft)
setOpen(false)
}
const handleCancel = () => {
setOpen(false)
}
const handleItemClick = (v: number) => {
setDraft(v)
scrollToValue(v, true)
}
const maskTop = wheelHeight / 2 - ITEM_HEIGHT / 2
const wheel = (
<div className="dw-popup">
<div
className="dw-picker"
style={{ height: wheelHeight, width: popupWidth - 24 /* padding */ }}
>
<div className="dw-picker-mask" style={{ top: maskTop, height: ITEM_HEIGHT }} aria-hidden />
<div className="dw-picker-fade dw-picker-fade-top" aria-hidden />
<div className="dw-picker-fade dw-picker-fade-bottom" aria-hidden />
<ul
ref={listRef}
className="dw-picker-list"
onScroll={handleScroll}
style={{
paddingTop: wheelHeight / 2 - ITEM_HEIGHT / 2,
paddingBottom: wheelHeight / 2 - ITEM_HEIGHT / 2,
}}
>
{options.map((v) => {
const isActive = v === draft
return (
<li
key={v}
className={`dw-picker-item${isActive ? " dw-picker-item-active" : ""}`}
style={{ height: ITEM_HEIGHT, lineHeight: `${ITEM_HEIGHT}px` }}
onClick={() => handleItemClick(v)}
aria-selected={isActive}
role="option"
>
<span className="dw-picker-item-val">{v}</span>
<span className="dw-picker-item-unit">{unit}</span>
</li>
)
})}
</ul>
</div>
<div className="dw-popup-actions">
<Button size="small" onClick={handleCancel}>
取消
</Button>
<Button size="small" type="primary" onClick={handleConfirm}>
确认
</Button>
</div>
</div>
)
return (
<Popover
open={!disabled && open}
onOpenChange={(v) => setOpen(v)}
content={wheel}
trigger="click"
placement="bottomLeft"
overlayClassName="dw-popover"
overlayStyle={{ padding: 0 }}
overlayInnerStyle={{ padding: 0, borderRadius: 10 }}
destroyTooltipOnHide
>
<div
className={`dw-trigger${disabled ? " dw-trigger-disabled" : ""}${open ? " dw-trigger-open" : ""}`}
style={{ height: 36 }}
>
<span className={`dw-trigger-val${value != null ? "" : " dw-trigger-placeholder"}`}>
{value != null ? `${value}${unit}` : placeholder}
</span>
<DownOutlined className={`dw-trigger-arrow${open ? " dw-trigger-arrow-up" : ""}`} />
</div>
</Popover>
)
}
export default DurationWheelPicker
+1 -1
View File
@@ -10,4 +10,4 @@
* 功能流程不做积分预校验,直接走生成。
* - true:展示完整积分系统 UI。
*/
export const ENABLE_CREDIT_SYSTEM = false
export const ENABLE_CREDIT_SYSTEM = true
@@ -1834,3 +1834,117 @@
color: #7c3aed;
font-weight: 500;
}
/* ── v1.6 我的音色(默认主路径) ── */
.vv-voice-section {
margin-top: 4px;
border: 1px solid #e5e7eb;
border-radius: 8px;
background: #fff;
padding: 10px;
}
.vv-voice-section-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
}
.vv-voice-section-title {
font-size: 13px;
font-weight: 600;
color: #1f2937;
display: inline-flex;
align-items: center;
gap: 6px;
}
.vv-voice-section-title .anticon {
color: #7c3aed;
}
.vv-link-btn-sm {
font-size: 12px;
padding: 2px 6px;
display: inline-flex;
align-items: center;
gap: 4px;
}
.vv-my-voice-list {
display: flex;
flex-direction: column;
gap: 4px;
max-height: 220px;
overflow-y: auto;
}
.vv-my-voice-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px;
border-radius: 6px;
cursor: pointer;
transition: background 0.15s;
}
.vv-my-voice-item:hover {
background: #f5f0ff;
}
.vv-my-voice-item.selected {
background: #f5f0ff;
}
.vv-my-voice-item.selected .vv-voice-radio {
border-color: #7c3aed;
background: #7c3aed;
box-shadow: inset 0 0 0 2px #fff;
}
.vv-voice-empty {
padding: 16px 12px;
text-align: center;
color: #9ca3af;
font-size: 12px;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.vv-voice-empty-ic {
font-size: 28px;
color: #d1d5db;
}
.vv-voice-empty-text {
font-size: 12px;
}
.vv-voice-alt-row {
display: flex;
gap: 8px;
margin-top: 8px;
}
.vv-voice-alt-btn {
flex: 1;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 8px 10px;
background: #fafafe;
border: 1px solid #e5e7eb;
border-radius: 6px;
color: #6b7280;
font-size: 12px;
cursor: pointer;
transition: all 0.15s;
}
.vv-voice-alt-btn:hover {
border-color: #7c3aed;
color: #7c3aed;
background: #f5f0ff;
}
.vv-voice-alt-btn.selected {
background: #f5f0ff;
border-color: #7c3aed;
color: #7c3aed;
}
.vv-voice-panel-actions {
display: flex;
gap: 12px;
margin-bottom: 6px;
padding-bottom: 6px;
border-bottom: 1px dashed #e5e7eb;
}
+184 -42
View File
@@ -23,10 +23,13 @@ import {
CheckCircleFilled,
EditOutlined,
HistoryOutlined,
UserOutlined,
} from "@ant-design/icons"
import { Select, Input, message } from "antd"
import { uploadAssetDirect, getAssetLibraries, getAssetsByKind, type AssetItem } from "@/api/assets"
import { fetchPresetVoices } from "@/api/voices"
import { getVoiceClones, getVoiceClonePreview } from "@/api/voice-clone"
import type { VoiceClone } from "@/api/voice-clone"
import {
FUSION_LEVELS,
STYLE_STRENGTHS,
@@ -94,13 +97,15 @@ type RefVideo = {
} | null
type RefAudio = {
source: "preset" | "library" | "upload" | "clone"
source: "preset" | "library" | "upload" | "clone" | "my_voice"
id?: string
name: string
url?: string
/** 克隆音色的 CosyVoice voice_id(source=my_voice 时使用) */
ttsVoiceId?: string
} | null
type VoicePanel = "preset" | "upload" | "library" | "record" | "douyin" | null
type VoicePanel = "my_voices" | "preset" | "upload" | "library" | "record" | "douyin" | null
type TabTask = {
id: string
@@ -213,12 +218,12 @@ const PURPOSES = [
"悬念短剧",
"情绪短片",
]
const DURATIONS = [15, 20, 30, 45, 60]
const RATIOS = [
{ v: "9:16", label: "9:16 竖屏(抖音/视频号)" },
{ v: "16:9", label: "16:9 横屏(B站/YouTube)" },
{ v: "1:1", label: "1:1 方形(小红书)" },
]
const DURATIONS = Array.from({ length: 16 }, (_, i) => 15 + i)
/** 兜底模型列表(接口未返回时使用,字段与 ViralVideoModel 对齐;后端返回后自动覆盖) */
const FALLBACK_VIDEO_MODELS: ViralVideoModel[] = [
{
@@ -432,7 +437,7 @@ const emptyTask = (id: string, title: string): TabTask => ({
language: "中文(普通话)",
viralStructure: STRUCTURES[0],
marketingPurpose: "",
duration: 15,
duration: 20,
persona: "",
videoRatio: "9:16",
videoModel: "seedance-2.5",
@@ -485,6 +490,9 @@ const ViralVideoPage: React.FC = () => {
{ id: string; name: string; url: string; desc?: string }[]
>([])
const [presetVoices, setPresetVoices] = useState<PresetVoice[]>([])
/** 我的克隆音色(GET /voice-clones?status=ready) */
const [myVoices, setMyVoices] = useState<VoiceClone[]>([])
const [myVoicesLoading, setMyVoicesLoading] = useState(false)
const [voicePickerOpen, setVoicePickerOpen] = useState(false)
const [videoModels, setVideoModels] = useState<ViralVideoModel[]>(FALLBACK_VIDEO_MODELS)
const [assetPicker, setAssetPicker] = useState<{
@@ -514,8 +522,18 @@ const ViralVideoPage: React.FC = () => {
[activeId],
)
/* ── 加载音色 ── */
/* ── 加载音色(我的克隆音色 + 上传的配音素材 + 预设音色) ── */
const reloadMyVoices = useCallback(() => {
setMyVoicesLoading(true)
getVoiceClones({ status: "ready", limit: 50 })
.then((list) => {
setMyVoices(list.filter((v) => v.status === "ready"))
})
.catch(() => setMyVoices([]))
.finally(() => setMyVoicesLoading(false))
}, [])
useEffect(() => {
reloadMyVoices()
getAssetsByKind("voice", { limit: 50 })
.then((list) =>
setVoiceAssets(
@@ -523,7 +541,7 @@ const ViralVideoPage: React.FC = () => {
id: a.id,
name: a.name,
url: a.file_url || "",
desc: a.duration ? `${Math.round(a.duration)}s` : "我的音色",
desc: a.duration ? `${Math.round(a.duration)}s` : "配音文件",
})),
),
)
@@ -544,7 +562,7 @@ const ViralVideoPage: React.FC = () => {
// 接口失败兜底:弹窗内 MOCK_VOICES 会生效(voice_id 与后端 CosyVoice 一致)
setPresetVoices([])
})
}, [])
}, [reloadMyVoices])
/* ── 加载视频模型列表 ── */
useEffect(() => {
@@ -914,21 +932,36 @@ const ViralVideoPage: React.FC = () => {
[setTask, uploadFile],
)
const onCloneSuccess = (voice: { id?: string; name?: string }) => {
const onCloneSuccess = (
voice: VoiceClone | { id?: string; name?: string; voice_id?: string | null },
) => {
setCloneModalOpen(false)
// 克隆成功后刷新我的音色列表
reloadMyVoices()
const vid = "voice_id" in voice ? voice.voice_id : undefined
if (voice?.id) {
setTask({
refAudio: { source: "clone", id: voice.id, name: voice.name || "我录制的音色" },
refAudio: {
source: "my_voice",
id: voice.id,
name: voice.name || "我录制的音色",
ttsVoiceId: vid || undefined,
},
voicePanel: null,
})
getAssetsByKind("voice", { limit: 50 })
.then((list) =>
setVoiceAssets(
list.map((a) => ({ id: a.id, name: a.name, url: a.file_url || "", desc: "我的音色" })),
list.map((a) => ({
id: a.id,
name: a.name,
url: a.file_url || "",
desc: a.duration ? `${Math.round(a.duration)}s` : "配音文件",
})),
),
)
.catch(() => {})
message.success("录音已完成,已自动选中")
message.success("音色克隆完成,已自动选中")
}
}
@@ -1014,7 +1047,12 @@ const ViralVideoPage: React.FC = () => {
: undefined,
fusion_level: task.fusionLevel,
style_strength: task.refVideo?.ossUrl ? task.styleStrength : undefined,
voice_id: task.refAudio?.source === "preset" ? task.refAudio.id : undefined,
voice_id:
task.refAudio?.source === "preset"
? task.refAudio.id
: task.refAudio?.source === "my_voice"
? task.refAudio.ttsVoiceId || task.refAudio.id
: undefined,
voice_source: task.refAudio?.source || undefined,
video_ratio: task.videoRatio,
video_model: task.videoModel,
@@ -1058,7 +1096,12 @@ const ViralVideoPage: React.FC = () => {
style_strength: task.refVideo?.ossUrl ? task.styleStrength : undefined,
user_copy_text: task.storyboard?.voiceover_script || task.userCopy || undefined,
fusion_level: task.fusionLevel,
voice_id: task.refAudio?.id || undefined,
voice_id:
task.refAudio?.source === "preset"
? task.refAudio.id
: task.refAudio?.source === "my_voice"
? task.refAudio.ttsVoiceId || task.refAudio.id
: undefined,
voice_source: task.refAudio?.source,
industry: task.industry || undefined,
target_customer: task.targetCustomer || undefined,
@@ -2033,43 +2076,119 @@ const ViralVideoPage: React.FC = () => {
)}
</div>
{/* 参考音频 2x2 */}
{/* 配音选择(默认"我的音色") */}
<div className="vv-subblock">
<div className="vv-subblock-head">
<span className="vv-subblock-title">参考音频</span>
<span className="vv-subblock-title">AI 配音</span>
<span className="vv-opt-tag">选填</span>
<span className="vv-subblock-hint">最大 10MB · 最长 30 秒</span>
<span className="vv-subblock-hint">
默认使用我的克隆音色,也可选择内置音色或上传配音
</span>
</div>
<div className="vv-audio-grid">
{/* 我的音色(主路径) */}
<div className="vv-voice-section">
<div className="vv-voice-section-head">
<span className="vv-voice-section-title">
<UserOutlined /> 我的音色
</span>
<button
className="vv-link-btn vv-link-btn-sm"
onClick={() => setCloneModalOpen(true)}
>
<PlusOutlined /> 录制新音色
</button>
</div>
{myVoicesLoading ? (
<div className="vv-muted vv-voice-empty">加载中…</div>
) : myVoices.length === 0 ? (
<div className="vv-voice-empty">
<AudioMutedOutlined className="vv-voice-empty-ic" />
<div className="vv-voice-empty-text">还没有克隆音色</div>
<button
className="vv-btn vv-btn-primary vv-btn-sm"
onClick={() => setCloneModalOpen(true)}
>
去录制一个
</button>
</div>
) : (
<div className="vv-my-voice-list">
{myVoices.map((v) => {
const selected =
task.refAudio?.source === "my_voice" && task.refAudio.id === v.id
const playing = task.playingVoiceId === `my-${v.id}`
return (
<div
key={v.id}
className={`vv-my-voice-item ${selected ? "selected" : ""}`}
onClick={() =>
setTask({
refAudio: {
source: "my_voice",
id: v.id,
name: v.name,
ttsVoiceId: v.voice_id || undefined,
},
voicePanel: null,
})
}
>
<div className="vv-voice-radio" />
<div className="vv-voice-info">
<div className="vv-voice-name">{v.name}</div>
<div className="vv-voice-desc">
AI 克隆声音
{v.gender
? ` · ${v.gender === "male" ? "男" : v.gender === "female" ? "女" : ""}`
: ""}
</div>
</div>
<button
className={`vv-voice-play ${playing ? "playing" : ""}`}
onClick={(e) => {
e.stopPropagation()
// 克隆音色试听:优先 sample_url,否则调用 preview 接口
if (v.sample_url) {
toggleVoice({ id: `my-${v.id}`, url: v.sample_url })
} else {
message.info("正在获取试听音频…")
getVoiceClonePreview(v.id)
.then((r) => {
if (r.audio_url)
toggleVoice({ id: `my-${v.id}`, url: r.audio_url })
})
.catch(() => message.error("试听获取失败"))
}
}}
>
{playing ? <PauseCircleOutlined /> : <PlayCircleOutlined />}
</button>
</div>
)
})}
</div>
)}
</div>
{/* 次要选项:内置音色 / 上传配音 */}
<div className="vv-voice-alt-row">
<button
className={`vv-audio-cell ${task.refAudio?.source === "preset" ? "selected" : ""}`}
className={`vv-voice-alt-btn ${task.refAudio?.source === "preset" ? "selected" : ""}`}
onClick={() => setVoicePickerOpen(true)}
>
<FileTextOutlined className="vv-audio-ic" />
<span>选择内置音色</span>
<FileTextOutlined /> 内置音色
</button>
<button
className={`vv-audio-cell ${task.voicePanel === "upload" ? "active" : ""} ${task.refAudio?.source === "upload" ? "selected" : ""}`}
onClick={() => voiceInputRef.current?.click()}
className={`vv-voice-alt-btn ${task.refAudio?.source === "upload" || task.refAudio?.source === "library" ? "selected" : ""}`}
onClick={() =>
setTask({ voicePanel: task.voicePanel === "library" ? null : "library" })
}
>
<UploadOutlined className="vv-audio-ic" />
<span>本地上传</span>
</button>
<button
className={`vv-audio-cell ${task.voicePanel === "library" ? "active" : ""} ${task.refAudio?.source === "library" ? "selected" : ""}`}
onClick={() => setAssetPicker({ open: true, kind: "voice", multiple: false })}
>
<FolderOpenOutlined className="vv-audio-ic" />
<span>从素材库选择</span>
</button>
<button
className={`vv-audio-cell ${task.voicePanel === "record" ? "active" : ""} ${task.refAudio?.source === "clone" ? "selected" : ""}`}
onClick={() => setCloneModalOpen(true)}
>
<AudioMutedOutlined className="vv-audio-ic" />
<span>直接录音</span>
<FolderOpenOutlined /> 上传配音
</button>
</div>
<input
ref={voiceInputRef}
type="file"
@@ -2083,7 +2202,14 @@ const ViralVideoPage: React.FC = () => {
{task.refAudio && (
<div className="vv-selected-audio">
<SoundOutlined style={{ color: "#7c3aed", marginRight: 6 }} />
<span style={{ flex: 1 }}>已选:{task.refAudio.name}</span>
<span style={{ flex: 1 }}>
已选:
{task.refAudio.source === "my_voice"
? `我的音色 · ${task.refAudio.name}`
: task.refAudio.source === "preset"
? `内置 · ${task.refAudio.name}`
: task.refAudio.name}
</span>
<button className="vv-link-btn" onClick={() => setTask({ refAudio: null })}>
移除
</button>
@@ -2091,16 +2217,32 @@ const ViralVideoPage: React.FC = () => {
)}
{task.voicePanel === "library" && (
<div className="vv-voice-panel">
<div className="vv-voice-panel-actions">
<button
className="vv-link-btn vv-link-btn-sm"
onClick={() => voiceInputRef.current?.click()}
>
<UploadOutlined /> 本地上传音频文件
</button>
<button
className="vv-link-btn vv-link-btn-sm"
onClick={() =>
setAssetPicker({ open: true, kind: "voice", multiple: false })
}
>
<FolderOpenOutlined /> 从素材库选择
</button>
</div>
{voiceAssets.length === 0 ? (
<div className="vv-muted" style={{ padding: 12, textAlign: "center" }}>
暂无已上传的音频
暂无已上传的配音文件
</div>
) : (
<div className="vv-voice-list">
{voiceAssets.map((v) => (
<div
key={v.id}
className={`vv-voice-item ${task.refAudio?.id === v.id && task.refAudio.source === "library" ? "selected" : ""}`}
className={`vv-voice-item ${task.refAudio?.id === v.id && (task.refAudio.source === "library" || task.refAudio.source === "upload") ? "selected" : ""}`}
onClick={() =>
pickVoiceAsset({
id: v.id,
@@ -2289,7 +2431,7 @@ const ViralVideoPage: React.FC = () => {
options={PURPOSES.map((i) => ({ value: i, label: i }))}
/>
</div>
<div className="vv-form-row" style={{ gridColumn: "1 / -1" }}>
<div className="vv-form-row">
<label className="vv-label">文案视频时长</label>
<Select
className="vv-select"
@@ -387,6 +387,41 @@ BATCH_RENDER_SIMILARITY_LIMIT = 0.20
"""批次内成片查重相似度阈值:超过则重选独立 plan 重渲一次(20%)。"""
def _refund_smart_edit_prepaid(task_id: str) -> None:
"""智能剪辑任务最终失败时退还预扣积分(幂等)。"""
session = SessionLocal()
try:
from packages.adapters.sqlalchemy_impl.generation_task_repository import (
SQLAlchemyGenerationTaskRepository,
)
from packages.domain.points_service import PointsService
repo = SQLAlchemyGenerationTaskRepository(session)
task = repo.get(task_id)
if not task:
return
prepaid = float(getattr(task, "credits_prepaid", 0) or 0)
if prepaid <= 0:
return
txn_id = getattr(task, "credits_transaction_id", "") or ""
res = PointsService().refund_points(
user_id=task.user_id,
amount=prepaid,
source="smart_edit",
db=session,
ref_id=task.id,
related_transaction_id=txn_id or None,
description="智能剪辑任务失败退回",
)
task.credits_cost = 0.0
task.credits_prepaid = 0.0
repo.update(task)
if not res.get("success"):
logger.warning("[task_id=%s] 失败退积分未成功: %s", task_id, res)
finally:
session.close()
def should_rerender_for_batch_dedup(*, batch_id: str, render_attempt: int, batch_similarity) -> bool:
"""批次内查重后判定是否需要重选 plan 重渲。
@@ -1167,6 +1202,10 @@ def generate_video(self, task_id: str) -> dict:
"mark_failed",
error_message="source_edit_plan_id is required. Please create a preview task first.",
)
try:
_refund_smart_edit_prepaid(task_id)
except Exception:
logger.warning("[task_id=%s] 失败退积分异常", task_id, exc_info=True)
return {
"status": "failed",
"task_id": task_id,
@@ -1205,6 +1244,7 @@ def generate_video(self, task_id: str) -> dict:
)
# ── 自动重试逻辑 ──────────────────────────────────────────────────
will_retry = False
try:
from packages.adapters.sqlalchemy_impl.generation_task_repository import (
SQLAlchemyGenerationTaskRepository,
@@ -1217,6 +1257,7 @@ def generate_video(self, task_id: str) -> dict:
if _task and _task.auto_retry_enabled and _task.auto_retry_max > 0:
current_retry = _task.retry_count or 0
if current_retry < _task.auto_retry_max:
will_retry = True
logger.info(
"[task_id=%s] 触发自动重试: 当前重试次数=%d, 最大重试次数=%d",
task_id,
@@ -1250,6 +1291,13 @@ def generate_video(self, task_id: str) -> dict:
exc_info=True,
)
# 最终失败(不再重试):退还 smart_edit 预扣积分
if not will_retry:
try:
_refund_smart_edit_prepaid(task_id)
except Exception:
logger.warning("[task_id=%s] 失败退积分异常", task_id, exc_info=True)
return {
"status": "failed",
"task_id": task_id,
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
"""V2 图片分析:火山OCR专用API + doubao-lite强约束JSON并行,单次pro VLM兜底。"""
from .fast_path import analyze_image_v2, analyze_images_v2 # noqa: F401
@@ -0,0 +1,307 @@
# -*- coding: utf-8 -*-
"""把 fast_json VLM 输出 + OCR 文本组装为与旧 _normalize() 完全一致的 dict。
目标:下游(信任链t2i/intent_parsing/script_generation)零改动。
必出字段:name, brand, category, appearance, packaging, text_on_package,
key_features, scene, mood, portrait_prompt, summary, _source
"""
from __future__ import annotations
from typing import Any
# ---------- portrait_prompt 模板 ----------
# 目标:60-100 字的人物穿搭描述,用于 Seedream 纯文生图。要求具体、风格化、视觉细节丰富。
# 旧 VLM 输出格式参考:"一位25岁左右的亚洲女性,身穿白色V领短袖T恤,黑色高腰阔腿裤,
# 搭配银色项链,长发披肩,表情自信,街拍风格,阳光明媚的城市街头"
def _join_parts(*parts: str | None) -> str:
return "".join(p for p in parts if p)
_AGE_PREFIX = {
"青年": "年轻",
"中年": "中年",
"老年": "老年",
}
# gender 后缀
_GENDER_WORD = {"男": "男性", "女": "女性"}
def _person_subject(fj: dict[str, Any]) -> str:
"""人物主语:年轻女性 / 中年男性 / 少女 / 小男孩 / 人物 等。"""
gender = fj.get("gender") or ""
age = fj.get("age_range") or ""
gw = _GENDER_WORD.get(gender, "")
if age == "儿童":
if gender == "女":
return "小女孩"
if gender == "男":
return "小男孩"
return "儿童"
if age == "青少年":
if gender == "女":
return "少女"
if gender == "男":
return "少年"
return "青少年"
prefix = _AGE_PREFIX.get(age, "")
if gw:
return f"{prefix}{gw}" if prefix else gw
return f"{prefix}人物" if prefix else "人物"
def _build_wear_sentence(fj: dict[str, Any]) -> str:
"""穿搭段:上装+下装/连衣裙,带颜色+材质+图案。"""
upper = fj.get("upper_wear") or ""
upper_color = fj.get("upper_color") or ""
lower = fj.get("lower_wear") or ""
lower_color = fj.get("lower_color") or ""
dress_color = fj.get("dress_color") or ""
material = fj.get("material") or ""
pattern = fj.get("pattern") or ""
is_dress = ("连衣裙" in upper) or ("裙" in upper and not lower)
if is_dress:
c = dress_color or upper_color
wear = f"{c}{upper}" if c else upper
if material and material not in wear:
wear = f"{material}{wear}"
if pattern and pattern not in wear and pattern != "纯色":
wear += f",{pattern}图案"
return f"身穿{wear}"
parts: list[str] = []
if upper:
up = f"{upper_color}{upper}" if upper_color else upper
if material and material not in up:
up = f"{material}{up}"
if pattern and pattern != "纯色" and pattern not in up:
up += f"({pattern})"
parts.append(f"上身{up}" if up else "")
if lower:
lo = f"{lower_color}{lower}" if lower_color else lower
parts.append(f"下身{lo}" if lo else "")
return ",".join(p for p in parts if p)
def _build_portrait_prompt(fj: dict[str, Any]) -> str:
"""组装最终 portrait_prompt(目标 60-100 字,用于 Seedream 纯文生图)。"""
if not fj.get("has_person"):
# 非人像:用商品+场景+mood 拼一段
name = fj.get("product_name") or "商品"
brand = fj.get("brand") or ""
colors = fj.get("colors") or []
style = fj.get("style") or ""
scene = fj.get("scene") or ""
mood = fj.get("mood") or ""
pieces = []
if brand:
pieces.append(brand)
pieces.append(name)
if colors:
pieces.append("、".join(colors[:3]) + "配色")
if style:
pieces.append(style + "风格")
if mood:
pieces.append(mood + "氛围")
if scene and scene not in ("通用",):
pieces.append(scene + "场景")
pieces.append("产品特写")
prompt = ",".join(p for p in pieces if p)
return prompt if len(prompt) >= 10 else "产品展示图,特写镜头"
subject = _person_subject(fj)
wear = _build_wear_sentence(fj)
accessories = fj.get("accessories") or []
if isinstance(accessories, str):
accessories = [accessories]
acc_str = ""
if accessories:
acc_str = ",佩戴" + "、".join(str(a) for a in accessories if a)
hairstyle = fj.get("hairstyle") or ""
expression = fj.get("expression") or ""
pose = fj.get("pose") or ""
style = fj.get("style") or ""
scene = fj.get("scene") or ""
mood = fj.get("mood") or ""
detail_parts: list[str] = []
if hairstyle:
detail_parts.append(hairstyle)
if expression and expression not in ("自然", "平静"):
detail_parts.append(f"神情{expression}")
if pose and pose not in ("站立",):
detail_parts.append(pose)
style_parts: list[str] = []
if style:
style_parts.append(style)
if mood:
style_parts.append(mood)
if scene and scene not in ("通用",):
style_parts.append(scene)
pieces = [f"一位{subject}"]
if wear:
pieces.append(wear)
if acc_str:
pieces.append(acc_str.lstrip(","))
if detail_parts:
pieces.append(",".join(detail_parts))
if style_parts:
# 风格词之间不用逗号,用空格紧凑
pieces.append("".join(style_parts) + "风格")
else:
pieces.append("人像写真")
full = ",".join(p for p in pieces if p)
# 过短补充镜头词
if len(full) < 40:
full += ",自然光线下人像特写,画面清晰"
# 过长截断
if len(full) > 120:
full = full[:120].rstrip(",") + "。"
return full
# ---------- 商品字段 ----------
def _infer_name(fj: dict[str, Any], ocr_texts: list[str]) -> str:
pname = fj.get("product_name")
if pname and pname != "未识别":
return str(pname)
# 人物图 → name 用穿搭主件
if fj.get("has_person"):
up = fj.get("upper_wear") or ""
if "连衣裙" in up:
return up
return up or "人物穿搭"
if ocr_texts:
# 商品名可能是 OCR 最长的一行(品牌/产品名)
return max(ocr_texts, key=len)
return "未识别"
def _infer_brand(fj: dict[str, Any], ocr_texts: list[str]) -> str:
brand = fj.get("brand")
if brand:
return str(brand)
# OCR 里短的、纯字母/汉字短串可能是 brand
for t in ocr_texts:
if 1 < len(t) <= 12:
return t
return "无法判断"
def _infer_category(fj: dict[str, Any]) -> str:
cat = fj.get("category")
if cat:
return str(cat)
if fj.get("has_person"):
return "服饰"
return "非产品图"
def _build_appearance(fj: dict[str, Any]) -> str:
"""外观描述:颜色+款式+材质+图案 拼成一段。"""
parts: list[str] = []
for key, _label in [
("upper_color", "主色"),
("upper_wear", "款式"),
("material", "材质"),
("pattern", "图案"),
]:
v = fj.get(key)
if v and v not in ("无法判断", "未知", "纯色"):
parts.append(str(v))
if not parts:
if fj.get("has_person"):
return "人像穿搭整体造型"
return "无法判断"
return "、".join(parts)
def _build_key_features(fj: dict[str, Any], ocr_texts: list[str]) -> list[str]:
feats: list[str] = []
for key in (
"upper_wear",
"lower_wear",
"upper_color",
"lower_color",
"dress_color",
"material",
"pattern",
"style",
"accessories",
):
v = fj.get(key)
if not v:
continue
if isinstance(v, list):
feats.extend(str(x) for x in v if x)
elif isinstance(v, str) and v not in ("无法判断", "未知", "纯色"):
feats.append(v)
if ocr_texts:
feats.append(f"画面文字: {'/'.join(ocr_texts[:3])}")
# 去重
out: list[str] = []
seen: set[str] = set()
for f in feats:
f = f.strip()
if f and f not in seen and len(f) <= 30:
seen.add(f)
out.append(f)
return out[:6] if out else ["无法判断"]
def assemble_result(
idx: int,
fast_json: dict[str, Any] | None,
ocr_texts: list[str],
) -> dict[str, Any]:
"""把 fast_json 结果 + OCR 文本组装成下游兼容的 product dict。"""
fj = fast_json or {}
ocr_texts = ocr_texts or []
portrait_prompt = _build_portrait_prompt(fj)
name = _infer_name(fj, ocr_texts)
brand = _infer_brand(fj, ocr_texts)
category = _infer_category(fj)
appearance = _build_appearance(fj)
key_features = _build_key_features(fj, ocr_texts)
scene = fj.get("scene") or "通用"
mood = fj.get("mood") or ""
packaging = "无法判断" # 包装细节专用API无,保留占位
text_on_package = ocr_texts[:8]
summary = _build_summary(fj, name, brand, category)
return {
"name": name,
"brand": brand,
"category": category,
"appearance": appearance,
"packaging": packaging,
"text_on_package": text_on_package,
"key_features": key_features,
"scene": scene,
"mood": mood,
"portrait_prompt": portrait_prompt,
"summary": summary,
"_source": "v2_fast_json",
}
def _build_summary(fj: dict, name: str, brand: str, category: str) -> str:
if fj.get("has_person"):
up = fj.get("upper_wear") or "穿搭"
style = fj.get("style") or ""
base = f"{style}{up}" if style and style not in up else up
return base
if brand != "无法判断" and name != brand:
return f"{brand} {name}"
return name
@@ -0,0 +1,144 @@
# -*- coding: utf-8 -*-
"""V2 图片分析主路径:每图并行 OCR(火山MediaKit,未配置时自动跳过)+ qwen3.8-flash JSON VLM,
失败时单次 qwen3.7-plus 兜底。
架构(灵应10-05确认):
- 唯一后端:阿里云百炼 DashScope,qwen3.8-flash 做快速路径、qwen3.7-plus 做兜底
- 主力:单图2路并行(OCR + fast VLM),外层N图全并发(workers=8)
- 兜底:单次 pro VLM 调用,无竞速/重试/复杂超时
- 输出 dict 格式与旧版完全一致,下游零改动
"""
from __future__ import annotations
import logging
import os
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import Any
from . import assembler, ocr_volc, vlm_fallback, vlm_fast_json
logger = logging.getLogger(__name__)
# 超时(可通过环境变量覆盖)
_IMG_WORKERS = int(os.environ.get("VISION_V2_IMG_WORKERS", "8"))
_FAST_TIMEOUT = float(os.environ.get("VISION_V2_FAST_TIMEOUT", "8"))
_FAST_JSON_TIMEOUT = float(os.environ.get("VISION_V2_FAST_JSON_TIMEOUT", "8"))
_OCR_TIMEOUT = float(os.environ.get("VISION_V2_OCR_TIMEOUT", "6"))
_PRO_TIMEOUT = float(os.environ.get("VISION_V2_PRO_TIMEOUT", "20"))
_FALLBACK_RESULT = {
"name": "未识别",
"brand": "无法判断",
"category": "非产品图",
"appearance": "无法判断",
"packaging": "无法判断",
"text_on_package": [],
"key_features": ["无法判断"],
"scene": "通用",
"mood": "",
"portrait_prompt": "无法判断",
"summary": "未识别",
}
def _is_usable(r: dict[str, Any]) -> bool:
pp = (r.get("portrait_prompt") or "").strip()
if pp and pp not in ("无人像", "无法判断", "未识别"):
return True
name = (r.get("name") or "").strip()
if name and name not in ("未识别", "无法判断", "未知"):
return True
return False
def analyze_image_v2(idx: int, img_url: str) -> dict[str, Any]:
t0 = time.time()
fj_result: dict[str, Any] | None = None
ocr_result: list[str] = []
with ThreadPoolExecutor(max_workers=2) as pool:
f_fj = pool.submit(vlm_fast_json.call_fast_json, img_url, timeout=_FAST_JSON_TIMEOUT)
f_ocr = pool.submit(ocr_volc.call_ocr, img_url, timeout=_OCR_TIMEOUT)
try:
for fut in as_completed([f_fj, f_ocr], timeout=_FAST_TIMEOUT):
try:
res = fut.result(timeout=1)
except Exception as e:
logger.warning("[vision.v2] 图片 #%d 子任务异常: %s", idx, e)
continue
if fut is f_fj and isinstance(res, dict):
fj_result = res
elif fut is f_ocr and isinstance(res, list):
ocr_result = res
except TimeoutError:
for f in (f_fj, f_ocr):
if not f.done():
f.cancel()
logger.warning("[vision.v2] 图片 #%d fast路径超时(%.0fs),走pro兜底", idx, _FAST_TIMEOUT)
fast_elapsed = time.time() - t0
if fj_result:
assembled = assembler.assemble_result(idx, fj_result, ocr_result)
if _is_usable(assembled):
assembled["_fast_elapsed"] = round(fast_elapsed, 2)
logger.info(
"[vision.v2] 图片 #%d fast命中 elapsed=%.2fs pp=%s",
idx,
fast_elapsed,
(assembled.get("portrait_prompt") or "")[:40],
)
return assembled
pro_t0 = time.time()
pro_result = vlm_fallback.call_pro_vlm(img_url, idx, timeout=_PRO_TIMEOUT)
if pro_result and _is_usable(pro_result):
pro_result["_fallback_used"] = True
pro_result["_fast_elapsed"] = round(fast_elapsed, 2)
pro_result["_pro_elapsed"] = round(time.time() - pro_t0, 2)
if ocr_result and not pro_result.get("text_on_package"):
pro_result["text_on_package"] = ocr_result[:8]
logger.info("[vision.v2] 图片 #%d pro兜底命中 total=%.2fs", idx, time.time() - t0)
return pro_result
logger.warning("[vision.v2] 图片 #%d 全路径失败 elapsed=%.2fs", idx, time.time() - t0)
out = dict(_FALLBACK_RESULT)
out["_source"] = "v2_all_failed"
out["text_on_package"] = ocr_result[:8]
out["_fast_elapsed"] = round(fast_elapsed, 2)
return out
def analyze_images_v2(img_urls: list[str]) -> list[dict[str, Any]]:
if not img_urls:
return []
workers = min(_IMG_WORKERS, len(img_urls), 16)
results: list[dict[str, Any] | None] = [None] * len(img_urls)
logger.info(
"[vision.v2] 开始图片分析 n=%d workers=%d fast_timeout=%.0fs pro_timeout=%.0fs",
len(img_urls),
workers,
_FAST_TIMEOUT,
_PRO_TIMEOUT,
)
t0 = time.time()
with ThreadPoolExecutor(max_workers=workers) as pool:
future_to_idx = {pool.submit(analyze_image_v2, idx, url): idx for idx, url in enumerate(img_urls)}
for fut in as_completed(future_to_idx):
idx = future_to_idx[fut]
try:
results[idx] = fut.result()
except Exception as e:
logger.warning("[vision.v2] 图片 #%d future异常: %s", idx, e, exc_info=True)
r = dict(_FALLBACK_RESULT)
r["_source"] = "v2_future_exception"
results[idx] = r
elapsed = time.time() - t0
succ = sum(1 for r in results if r and _is_usable(r))
fb = sum(1 for r in results if r and r.get("_fallback_used"))
logger.info("[vision.v2] 完成 n=%d usable=%d pro_fallback=%d elapsed=%.2fs", len(img_urls), succ, fb, elapsed)
return [r for r in results if r is not None]
@@ -0,0 +1,109 @@
# -*- coding: utf-8 -*-
"""火山引擎 AI MediaKit OCR(同步)调用封装。
接口:POST {mediakit_base_url}/tools-sync/ocr
鉴权:Bearer {mediakit_api_key}
请求体:{"image_url": "<公网可访问URL>"} (部分版本也支持 image_base64)
响应:{"code":0,"data":{"texts":[{"text":"...","bbox":[x,y,w,h],...},...],...}}
目标:识别商品包装/Logo/水印上的文字,作为 fast_json VLM 的补充。
返回值:识别到的文本字符串列表(失败返回 [])。
"""
from __future__ import annotations
import logging
import time
from typing import Any
logger = logging.getLogger(__name__)
DEFAULT_TIMEOUT = 8 # OCR 秒级返回,8s 绰绰有余
def call_ocr(img_url: str, *, timeout: int = DEFAULT_TIMEOUT) -> list[str]:
"""调用 MediaKit 同步 OCR,返回去重后的纯文本列表。
不做重试(外层降级逻辑负责)。失败/未配置返回空列表,不抛异常。
"""
t0 = time.time()
try:
import httpx
from packages.shared.mediakit_client import get_mediakit_client
client = get_mediakit_client()
if not client.is_available:
logger.info("[vision.v2] mediakit 未配置,跳过 OCR")
return []
url = f"{client.base_url}/tools-sync/ocr"
headers = {
"Authorization": f"Bearer {client.api_key}",
"Content-Type": "application/json",
}
payload: dict[str, Any] = {"image_url": img_url}
# 部分文档版本用 image_base64,但公网 URL 场景下 image_url 最简
resp = httpx.post(url, headers=headers, json=payload, timeout=timeout)
elapsed = time.time() - t0
if resp.status_code != 200:
logger.warning(
"[vision.v2] OCR HTTP %d elapsed=%.1fs body=%s",
resp.status_code,
elapsed,
resp.text[:200],
)
return []
data = resp.json()
# 兼容几种可能的响应结构
code = data.get("code", data.get("status", 0))
if code not in (0, "OK", "success", 200):
logger.warning("[vision.v2] OCR 业务错误 code=%s elapsed=%.1fs resp=%s", code, elapsed, str(data)[:200])
return []
texts = _extract_texts(data)
# 去重 + 过滤空
seen: set[str] = set()
out: list[str] = []
for t in texts:
t = (t or "").strip()
if t and t not in seen and len(t) <= 100: # 过滤过长的误识别
seen.add(t)
out.append(t)
logger.info("[vision.v2] OCR 完成 elapsed=%.1fs n=%d texts=%s", elapsed, len(out), out[:5])
return out
except Exception as e:
elapsed = time.time() - t0
logger.warning("[vision.v2] OCR 异常 elapsed=%.1fs err=%s", elapsed, e, exc_info=True)
return []
def _extract_texts(data: dict) -> list[str]:
"""从 OCR 响应中抽取文本,兼容多种结构。"""
out: list[str] = []
# 常见结构1: data.texts = [{"text": "..."}, ...]
d = data.get("data") or data
if isinstance(d, dict):
for key in ("texts", "lines", "words", "items", "result"):
items = d.get(key)
if isinstance(items, list):
for it in items:
if isinstance(it, dict):
txt = it.get("text") or it.get("content") or it.get("word")
if txt:
out.append(str(txt))
elif isinstance(it, str):
out.append(it)
break
# 结构2: data.text = "..."
if not out:
t = d.get("text")
if isinstance(t, str):
out.append(t)
# 结构3: data.ocr_text / data.content
if not out:
for key in ("ocr_text", "content", "raw_text"):
v = d.get(key)
if isinstance(v, str) and v.strip():
out.append(v)
break
return out
@@ -0,0 +1,174 @@
# -*- coding: utf-8 -*-
"""V2 pro 兜底:qwen3.7-plus(阿里云百炼/DashScope)单次调用。
fast_json 结果不可用时单次调用,无竞速、无重试、无复杂超时逻辑。
直接 httpx 发精简 JSON-only prompt(比旧版 prompt_loader XML 模板短很多,降低延迟)。
"""
from __future__ import annotations
import json
import logging
import os
import time
from typing import Any
logger = logging.getLogger(__name__)
_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"
_PRO_MODEL = "qwen3.7-plus"
_DEFAULT_TIMEOUT = 20
_DEFAULT_MAX_TOKENS = 800
_PRO_SYSTEM = (
"你是图片分析助手。仔细观察图片,严格按JSON schema返回一个对象,不要任何解释、"
"不要markdown、不要代码块、不要前后缀文字。字段值不确定时填null或空数组。\n"
"{\n"
' "has_person": true/false,\n'
' "gender": "男"/"女"/null,\n'
' "age_range": "儿童"/"青少年"/"青年"/"中年"/"老年"/null,\n'
' "outfit": "人物穿搭描述,60字以内(例:白色T恤+牛仔裤)",\n'
' "hair": "发型",\n'
' "pose": "姿态",\n'
' "expression": "表情",\n'
' "scene": "场景",\n'
' "mood": "氛围",\n'
' "has_product": true/false,\n'
' "category": "服饰/鞋包/美妆/数码/食品/家居/配饰/母婴/非产品图",\n'
' "product_name": "产品名称,非产品图填null",\n'
' "brand": "品牌或文字标识,无则null",\n'
' "key_features": ["特征数组"]\n'
"}"
)
_PRO_USER = "分析这张图片,返回符合schema的JSON。"
def _strip_code_fence(s: str) -> str:
s = s.strip()
if s.startswith("```"):
lines = s.split("\n")
if lines and lines[0].startswith("```"):
lines = lines[1:]
if lines and lines[-1].strip().startswith("```"):
lines = lines[:-1]
s = "\n".join(lines).strip()
return s
def _assemble_pp(obj: dict[str, Any]) -> str:
if not obj.get("has_person", False):
return "无人像"
parts: list[str] = []
gender = obj.get("gender")
age = obj.get("age_range")
if gender:
parts.append(gender + ("性" if not gender.endswith("性") else ""))
if age:
parts.append(age)
parts.append("人物")
hair = obj.get("hair")
if hair:
parts.append(hair)
outfit = obj.get("outfit")
if outfit:
parts.append(f"身着{outfit}")
pose = obj.get("pose")
if pose:
parts.append(f"姿态{pose}")
expr = obj.get("expression")
if expr:
parts.append(f"表情{expr}")
return ",".join(parts) if parts else "无人像"
def call_pro_vlm(
img_url: str,
idx: int,
*,
timeout: int = _DEFAULT_TIMEOUT,
) -> dict[str, Any] | None:
"""单次调用 qwen3.7-plus,解析后返回 product dict;失败返回 None。"""
t0 = time.time()
import httpx
api_key = os.environ.get("DASHSCOPE_API_KEY")
if not api_key:
logger.warning("[vision.v2] DASHSCOPE_API_KEY 未配置,跳过 pro 兜底")
return None
url = f"{_BASE_URL}/chat/completions"
payload: dict[str, Any] = {
"model": _PRO_MODEL,
"messages": [
{"role": "system", "content": _PRO_SYSTEM},
{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": img_url}},
{"type": "text", "text": _PRO_USER},
],
},
],
"temperature": 0.3,
"max_tokens": _DEFAULT_MAX_TOKENS,
"stream": False,
"enable_thinking": False,
}
try:
r = httpx.post(
url,
headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
json=payload,
timeout=timeout,
)
elapsed = time.time() - t0
if r.status_code != 200:
logger.warning("[vision.v2] pro HTTP %d elapsed=%.1fs body=%s", r.status_code, elapsed, r.text[:200])
return None
data = r.json()
raw = (data.get("choices") or [{}])[0].get("message", {}).get("content")
if not raw:
logger.warning("[vision.v2] pro 返回空 elapsed=%.1fs", elapsed)
return None
usage = data.get("usage") or {}
logger.info(
"[vision.v2] pro 完成 idx=%d model=%s elapsed=%.1fs in=%d out=%d",
idx,
_PRO_MODEL,
elapsed,
usage.get("prompt_tokens", 0),
usage.get("completion_tokens", 0),
)
text = _strip_code_fence(raw)
lpos, r_pos = text.find("{"), text.rfind("}")
if lpos < 0 or r_pos <= lpos:
logger.warning("[vision.v2] pro 无JSON elapsed=%.1fs head=%s", elapsed, raw[:200])
return None
obj = json.loads(text[lpos : r_pos + 1])
if not isinstance(obj, dict):
return None
scene = obj.get("scene") or "通用"
mood = obj.get("mood") or ""
pp = _assemble_pp(obj)
has_person = obj.get("has_person", False)
has_product = obj.get("has_product", False)
name = obj.get("product_name") or "未识别"
brand = obj.get("brand") or "无法判断"
category = obj.get("category") or ("非产品图" if has_person and not has_product else "无法判断")
return {
"name": name,
"brand": brand,
"category": category,
"appearance": obj.get("outfit") or "无法判断",
"packaging": "无法判断",
"text_on_package": [],
"key_features": obj.get("key_features") or ["无法判断"],
"scene": scene,
"mood": mood,
"portrait_prompt": pp,
"summary": f"{brand} {name}" if name != "未识别" else "未识别",
"_source": "vlm_pro",
}
except Exception as e:
logger.warning("[vision.v2] pro 异常 idx=%d elapsed=%.1fs err=%s", idx, time.time() - t0, e, exc_info=True)
return None
@@ -0,0 +1,177 @@
# -*- coding: utf-8 -*-
"""V2 快速路径:qwen3.8-flash(阿里云百炼/DashScope)强约束 JSON-only 调用。
目标:替代"人体属性/商品检测/图像标签"三个火山不存在的专用云端 API。
设计要点:
- 直接用 httpx 发最小 payload 到 DashScope OpenAI 兼容 endpoint,不走 ai_client 包装
- enable_thinking=false 关闭推理链(reasoning 是延迟主因)
- system prompt 极致精简,只给字段 schema 和强约束(禁止自然语言、禁止 markdown)
- max_tokens=350、temperature=0.1(稳定输出 JSON)
- timeout=8s(失败由外层走 pro 兜底)
- API Key 从环境变量 DASHSCOPE_API_KEY 读取
"""
from __future__ import annotations
import json
import logging
import os
import time
from typing import Any
logger = logging.getLogger(__name__)
# DashScope OpenAI 兼容 endpoint
_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"
_FAST_MODEL = "qwen3.8-flash"
_DEFAULT_TIMEOUT = 8
_DEFAULT_MAX_TOKENS = 350
# 极简 system prompt:只给字段定义 + 硬性输出要求
_FAST_SYSTEM = (
"你是图片结构化识别器。严格按下方 JSON schema 返回一个对象,不要任何解释、"
"不要markdown、不要代码块、不要前后缀文字。字段值不确定时填 null 或空数组。\n"
"{\n"
' "has_person": true/false,\n'
' "gender": "男"/"女"/null,\n'
' "age_range": "儿童"/"青少年"/"青年"/"中年"/"老年"/null,\n'
' "upper_wear": "上装款式,如T恤/衬衫/卫衣/毛衣/西装/夹克/连衣裙/吊带/背心/外套等",\n'
' "upper_color": "上装主色",\n'
' "lower_wear": "下装款式;穿连衣裙时填null",\n'
' "lower_color": "下装主色",\n'
' "dress_color": "连衣裙主色(穿连衣裙时填)",\n'
' "accessories": ["眼镜"/"帽子"/"项链"/"耳环"/"背包"/"手表"等数组],\n'
' "hairstyle": "发型,如短发/长发/马尾/卷发/丸子头/光头等",\n'
' "expression": "表情,如微笑/严肃/酷/开心等",\n'
' "pose": "姿势,如站立/坐姿/侧身/行走等",\n'
' "scene": "场景,如室内/街拍/户外/办公室/家居/海边/雪景/森林等",\n'
' "style": "风格,如休闲/商务/运动/复古/潮流/甜美/酷飒/优雅/街头/法式等",\n'
' "has_product": true/false,\n'
' "category": "产品类目:服饰/鞋包/美妆/数码/食品/家居/配饰/母婴/非产品图",\n'
' "product_name": "产品名称,非产品图填null",\n'
' "brand": "品牌或文字标识,无则null",\n'
' "material": "材质,如棉质/牛仔/皮革/真丝/针织/涤纶等",\n'
' "pattern": "图案,如纯色/条纹/波点/格子/印花/碎花/Logo等",\n'
' "colors": ["主色数组"],\n'
' "mood": "整体氛围/情绪,如清新/活力/高级/温暖/冷峻/甜美/复古等"\n'
"}"
)
_FAST_USER = "识别这张图片的人物穿搭与主体信息,只返回JSON对象。"
def _api_key() -> str | None:
return os.environ.get("DASHSCOPE_API_KEY")
def _strip_code_fence(s: str) -> str:
s = s.strip()
if s.startswith("```"):
lines = s.split("\n")
if lines and lines[0].startswith("```"):
lines = lines[1:]
if lines and lines[-1].strip().startswith("```"):
lines = lines[:-1]
s = "\n".join(lines).strip()
return s
def call_fast_json(
img_url: str,
*,
timeout: int = _DEFAULT_TIMEOUT,
max_tokens: int = _DEFAULT_MAX_TOKENS,
) -> dict[str, Any] | None:
"""调用 qwen3.8-flash 返回结构化 dict;失败/非 JSON 返回 None。"""
t0 = time.time()
import httpx
api_key = _api_key()
if not api_key:
logger.warning("[vision.v2] DASHSCOPE_API_KEY 未配置,跳过 fast_json")
return None
url = f"{_BASE_URL}/chat/completions"
payload: dict[str, Any] = {
"model": _FAST_MODEL,
"messages": [
{"role": "system", "content": _FAST_SYSTEM},
{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": img_url}},
{"type": "text", "text": _FAST_USER},
],
},
],
"temperature": 0.1,
"max_tokens": max_tokens,
"stream": False,
"enable_thinking": False,
}
try:
resp = httpx.post(
url,
headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
json=payload,
timeout=timeout,
)
elapsed = time.time() - t0
if resp.status_code == 400 and "enable_thinking" in resp.text[:300].lower():
# 极少数 endpoint 版本不识别 enable_thinking,重试一次不带
logger.warning("[vision.v2] fast_json HTTP 400 thinking 参数不兼容,重试 elapsed=%.1fs", elapsed)
payload.pop("enable_thinking", None)
resp = httpx.post(
url,
headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
json=payload,
timeout=timeout,
)
elapsed = time.time() - t0
if resp.status_code != 200:
logger.warning(
"[vision.v2] fast_json HTTP %d elapsed=%.1fs body=%s", resp.status_code, elapsed, resp.text[:200]
)
return None
data = resp.json()
raw = (data.get("choices") or [{}])[0].get("message", {}).get("content")
if not raw:
logger.warning("[vision.v2] fast_json 返回空 elapsed=%.1fs", elapsed)
return None
usage = data.get("usage") or {}
reasoning_tokens = usage.get("reasoning_tokens", 0)
ctd = usage.get("completion_tokens_details") or {}
if not reasoning_tokens:
reasoning_tokens = ctd.get("reasoning_tokens", 0)
logger.info(
"[vision.v2] fast_json 完成 model=%s elapsed=%.1fs in=%d out=%d reasoning=%d",
_FAST_MODEL,
elapsed,
usage.get("prompt_tokens", 0),
usage.get("completion_tokens", 0),
reasoning_tokens,
)
text = _strip_code_fence(raw)
lpos, r = text.find("{"), text.rfind("}")
if lpos >= 0 and r > lpos:
text = text[lpos : r + 1]
try:
obj = json.loads(text)
except json.JSONDecodeError:
logger.warning("[vision.v2] fast_json JSON 解析失败 elapsed=%.1fs head=%s", elapsed, raw[:200])
return None
if not isinstance(obj, dict):
logger.warning("[vision.v2] fast_json 非 dict: %s", type(obj))
return None
logger.info(
"[vision.v2] fast_json 完成 elapsed=%.1fs has_person=%s has_product=%s category=%s",
elapsed,
obj.get("has_person"),
obj.get("has_product"),
obj.get("category"),
)
return obj
except Exception as e:
elapsed = time.time() - t0
logger.warning("[vision.v2] fast_json 异常 elapsed=%.1fs err=%s", elapsed, e, exc_info=True)
return None
@@ -335,6 +335,10 @@ class GenerationTaskModel(Base):
bgm_config = Column(JSON, nullable=False, default=dict)
extra_meta = Column("metadata", JSON, nullable=False, default=dict)
logs = Column(Text, nullable=False, default="[]", server_default="[]")
# 功能计费(smart_edit):预扣积分 / 最终积分 / 预扣流水 ID
credits_prepaid = Column(Float, nullable=False, default=0.0, server_default="0")
credits_cost = Column(Float, nullable=False, default=0.0, server_default="0")
credits_transaction_id = Column(String(36), nullable=False, default="", server_default="")
created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(UTC))
updated_at = Column(
DateTime,
@@ -727,6 +731,11 @@ class LipsyncJobModel(Base):
# 精确句子时间戳(TTS 合成后由 silencedetect 计算,用于 B-roll 精确定位)
sentence_timings = Column(JSON, nullable=True) # list[{index,text,start_time,end_time}]
# 功能计费(lip_sync):预扣积分 / 最终积分 / 预扣流水 ID
credits_prepaid = Column(Float, nullable=False, default=0.0, server_default="0")
credits_cost = Column(Float, nullable=False, default=0.0, server_default="0")
credits_transaction_id = Column(String(36), nullable=False, default="", server_default="")
# 时间戳
submitted_at = Column(DateTime, nullable=True)
completed_at = Column(DateTime, nullable=True)
@@ -905,6 +914,11 @@ class GpuLipsyncTaskModel(Base):
# 心跳:worker 最近一次 poll/result 的时间,用于判定 worker 失联
last_heartbeat_at = Column(DateTime, nullable=True)
# 功能计费(lip_sync):预扣积分 / 最终积分 / 预扣流水 ID
credits_prepaid = Column(Float, nullable=False, default=0.0, server_default="0")
credits_cost = Column(Float, nullable=False, default=0.0, server_default="0")
credits_transaction_id = Column(String(36), nullable=False, default="", server_default="")
class GpuWorkerModel(Base):
"""GPU Worker 注册表 — 反向轮询模式下用于心跳与监控."""
+57 -12
View File
@@ -50,14 +50,25 @@ _IMAGE_ANALYSIS_SYSTEM = f"""你是电商商品视觉分析师,负责从商品
请严格按下面的标签格式输出,标签名一个都不能改,不要输出任何解释,不要用代码块:
<products> 下面每个产品用一个 <product> 标签,属性 name 是产品名、features 是外观特征、position 是 main 或 secondary、image_index 是第几张图(从0开始)。
<colors> 下面每个主要颜色用一个 <color> 标签,属性 hex 是色值、name 是颜色名、coverage 是占比小数。
<people> 用一个标签,属性 has_person、count、gender、age_range、pose、expression 分别描述人物情况。
<people> 用一个标签,属性 has_person、count、gender、age_range、hair(发型发色)、skin_tone(肤色)、face_shape(脸型)、outfit(穿着)、pose(姿态)、expression(表情)分别描述人物外貌。有人物时属性尽量具体(如hair="黑色长直发"、outfit="白色衬衫"),无人像时除has_person=false外其他填"无法判断"。
<mood> 标签写画面整体情绪氛围。
<visible_text> 下面每处可见文字用一个 <text_item> 标签,属性 text 是文字内容、position 是位置。
<scene> 标签写场景描述。
<quality> 用一个标签,属性 resolution、lighting、composition、blur 描述画质。
<key_selling_points> 下面每个卖点用一个 <point> 标签。
看不到或无法判断的内容,属性值填“无法判断”,布尔值填 false,不要留空标签。"""
【人物属性硬性要求(has_person=true时必须遵守)】
hair/skin_tone/face_shape/outfit四项绝对禁止填“无法判断”,必须基于图片可见特征给出具体中文描述:
- hair:必须描述发型+发色,如“黑色齐肩直发”“棕色微卷中长发”“深棕色短发”
- skin_tone:必须描述肤色,如“暖调自然肤色”“白皙肤色”“小麦色”
- face_shape:必须描述脸型,如“鹅蛋脸”“圆脸”“瓜子脸”“方脸”
- outfit:必须描述可见穿着,如“米色翻领衬衫”“白色T恤”“黑色连衣裙”
即使局部被遮挡也要根据可见部分合理推断;确实看不清时按最接近的直观印象描述。
其他非人物属性看不到或无法判断时填“无法判断”,布尔值填false,不要留空标签。
【有人物场景输出参考(女性手持商品示例,必须写全10个属性,禁止省略)】
<people has_person="true" count="1" gender="女" age_range="青年" hair="黑色齐肩直发" skin_tone="暖调自然肤色" face_shape="鹅蛋脸" outfit="米色翻领衬衫" pose="正面半身,手持商品" expression="面带微笑"/>"""
_IMAGE_ANALYSIS_USER = """请分析以下商品图片,共 {image_count} 张。
所属行业:{industry}
@@ -73,7 +84,7 @@ _IMAGE_ANALYSIS_EXAMPLE = """<products>
<color hex="#D32F2F" name="红色" coverage="0.4"/>
<color hex="#FFFFFF" name="白色" coverage="0.5"/>
</colors>
<people has_person="false" count="0" gender="无法判断" age_range="无法判断" pose="无法判断" expression="无法判断"/>
<people has_person="false" count="0" gender="无法判断" age_range="无法判断" hair="无法判断" skin_tone="无法判断" face_shape="无法判断" outfit="无法判断" pose="无法判断" expression="无法判断"/>
<mood>干净、实用</mood>
<visible_text>
<text_item text="多功能油污净" position="瓶身正面"/>
@@ -132,7 +143,10 @@ _FUSION_SYSTEM = """你负责为短视频生成营销文案。请按思维链分
<hook> 开头3秒钩子,5到15字。
<body_points> 每个要点用一个 <point> 标签,属性 elaboration 是展开说明、image_index 是对应第几张图(从0开始),标签内容写要点。
<cta> 口语化的行动号召。
<script_segments> 每段配音用一个 <segment> 标签,属性 duration_sec 是秒数、image_index 是对应图片,标签内容写配音文案。
<script_segments> 每段配音用一个 <segment> 标签,属性 duration_sec 是秒数、image_index 是对应图片,标签内容写配音文案(纯口播文本,不加旁白标注、不加镜头标注、不加"主播:"之类前缀)。
<voiceover_script> 把所有 segment 的配音文案按顺序自然拼接成一段完整的纯口播文本(无标记、无括号、无前缀),长度要适配 {duration} 秒,约 {approx_chars} 字。
<overview_theme> 视频主题(一句话概括)。
<scene_and_lighting> 整体场景描述+光线设定(100-200字,要具体:在哪拍、什么光线、什么色调、什么氛围)。
<word_count> 配音总字数,只写数字。
<estimated_duration> 预计时长秒数,只写数字。
@@ -161,25 +175,38 @@ _FUSION_EXAMPLE = """<title>厨房重油污,别再用洗洁精硬擦了</title
<segment duration_sec="6" image_index="0">后来换了这个大公鸡头油污净,喷上等几分钟,一擦就干净</segment>
<segment duration_sec="4" image_index="0">39块钱625ml,厨房重油污的可以试一瓶</segment>
</script_segments>
<voiceover_script>这油污我真的忍很久了,用洗洁精擦半天都没用。后来换了这个大公鸡头油污净,喷上等几分钟,一擦就干净。39块钱625ml,厨房重油污的可以试一瓶。</voiceover_script>
<overview_theme>厨房油污清洁好物分享</overview_theme>
<scene_and_lighting>简洁明亮的厨房台面场景,自然光从窗户洒入,色调温暖柔和,突出产品白色瓶身与去油污对比效果。</scene_and_lighting>
<word_count>58</word_count>
<estimated_duration>13</estimated_duration>"""
# ── 模板4:编导级分镜(LLM)────────────────────────────────────────────
_STORYBOARD_SYSTEM = f"""你是短视频编导,负责把文案拆成可拍摄的分镜。
_STORYBOARD_SYSTEM = """你是短视频编导,负责把文案拆成可拍摄的分镜,为 Seedance 2.5 视频模型写编导分镜脚本。脚本将整体作为 prompt 一次性传给视频模型,必须让模型在连贯镜头流中清楚每段时间拍什么、画面如何、人物说什么。
工作方式:
1. 按文案的 script_segments 顺序分配镜头。
2. 每个镜头确定画面、运镜、时长、配音和字幕。
2. 每个镜头确定景别/角度/运镜、画面场景与对白、人物动作细节、音效/BGM、转场。
3. 检查所有镜头时长加起来接近目标时长,误差不超过2秒。
4. image_index 必须在已上传图片范围内,第一张主图必须用在第一个镜头。
{GLOBAL_CONSTRAINTS}
{fusion_instruction}
{global_constraints}
{negative_rules}
请严格按下面的标签格式输出,不要解释,不要用代码块:
<clips> 下面每个镜头用一个 <clip> 标签,属性 image_index 是图片序号(从0开始)、transition 取 fade、cut、zoom_in、slide_left、dissolve、wipe 之一、zoom 取 in、out 或 null、duration_sec 是该镜头秒数、bgm_note 是该段BGM情绪。每个 <clip> 里面包含:
<voice_text> 该镜头配音文本;
<subtitle_text> 字幕文本,可与配音一致或更精简;
<ken_burns> 用一个空标签,属性 start、end 写“x,y”坐标、ease 写缓动方式;不需要运镜时坐标相同。"""
<clips> 下面每个镜头用一个 <clip> 标签,属性 image_index 是图片序号(从0开始)、transition 取 fade/cut/zoom_in/slide_left/dissolve/wipe 之一、zoom 取 in/out/null、duration_sec 是该镜头秒数、bgm_note 是该段BGM情绪。每个 <clip> 里面包含:
<voice_text> 该镜头配音文本(纯口播文本,不加旁白标注);
<subtitle_text> 字幕文本,可与配音一致或更精简;
<shot_type_angle_movement> 景别+角度+运镜(例:近景俯拍45度,缓慢推镜;中景平视,固定镜头;特写平视,快速拉镜);
<scene_and_dialogue> 画面场景描述 + 人物口播台词(对白要自然口语化,像朋友聊天,不要硬广推销腔);
<action_details> 人物动作、表情、物品操作细节(手怎么动、表情变化、产品怎么展示);
<audio_bgm> 环境音+BGM提示(例:轻快流行BGM,环境嘈杂咖啡店背景音);
<transition> 硬切/淡入淡出/叠化(最后一镜写『结束』即可);
<reference_image_index> 参考图片索引(0-based,对应第几张产品图,无则空);
<ken_burns> 用一个空标签,属性 start、end 写"x,y"坐标、ease 写缓动方式;不需要运镜时坐标相同。"""
_STORYBOARD_USER = """目标时长:{duration}秒
上传图片数量:{image_count}张(第1张是主图/封面)
@@ -194,17 +221,35 @@ _STORYBOARD_EXAMPLE = """<clips>
<clip image_index="0" transition="cut" zoom="null" duration_sec="3" bgm_note="日常、轻微烦躁">
<voice_text>这油污我真的忍很久了</voice_text>
<subtitle_text>这油污忍很久了</subtitle_text>
<shot_type_angle_movement>近景俯拍45度,缓慢推镜</shot_type_angle_movement>
<scene_and_dialogue>厨房台面,主妇皱眉看着灶台油污。对白:这油污我真的忍很久了</scene_and_dialogue>
<action_details>右手拿着脏抹布,无奈摇头</action_details>
<audio_bgm>轻快日常BGM,带一点烦躁感</audio_bgm>
<transition>硬切</transition>
<reference_image_index>0</reference_image_index>
<ken_burns start="0,0" end="0,0" ease="linear"/>
</clip>
<clip image_index="0" transition="zoom_in" zoom="in" duration_sec="6" bgm_note="轻快、出现转机">
<voice_text>后来换了大公鸡头油污净,喷上等几分钟,一擦就干净</voice_text>
<subtitle_text>喷上等几分钟,一擦就干净</subtitle_text>
<shot_type_angle_movement>特写平视,固定镜头</shot_type_angle_movement>
<scene_and_dialogue>手部特写,喷油污净在油污处。对白:后来换了这个大公鸡头油污净,喷上等几分钟,一擦就干净</scene_and_dialogue>
<action_details>左手拿产品瓶身,右手按压喷头,等待片刻后用抹布轻擦</action_details>
<audio_bgm>轻快转折BGM,带清爽感</audio_bgm>
<transition>淡入淡出</transition>
<reference_image_index>0</reference_image_index>
<ken_burns start="20,20" end="80,80" ease="ease-in-out"/>
</clip>
<clip image_index="0" transition="fade" zoom="null" duration_sec="4" bgm_note="温暖、推荐">
<voice_text>39块钱625ml,厨房重油污的可以试一瓶</voice_text>
<subtitle_text>39元625ml,可以试一瓶</subtitle_text>
<ken_burns start="0,0" end="0,0" ease="linear"/>
<shot_type_angle_movement>中景平视,缓慢拉镜</shot_type_angle_movement>
<scene_and_dialogue>产品正面展示,明亮背景。对白:39块钱625ml,厨房重油污的可以试一瓶</scene_and_dialogue>
<action_details>产品置于画面中央,轻微转动展示瓶身</action_details>
<audio_bgm>温暖收尾BGM</audio_bgm>
<transition>结束</transition>
<reference_image_index>0</reference_image_index>
<ken_burns start="50,50" end="20,20" ease="ease-in-out"/>
</clip>
</clips>"""
+1 -1
View File
@@ -103,7 +103,7 @@ class SharedSettings(BaseSettings):
doubao_vision_lite_model: str = (
"doubao-seed-2-1-lite-260915" # 快速视觉(Seed 2.1 Lite 原生多模态;原 vision-lite-250315 不可用)
)
doubao_vision_use_lite: bool = False # #2181: lite视觉模型100%超时,默认关闭走pro(25-38s稳定返回)
doubao_vision_use_lite: bool = True # #2188: lite恢复稳定,爆款视频默认lite-first提速(20-30s)
doubao_embedding_model: str = "doubao-embedding-vision-251215" # 多模态向量化(原 large-text-240915 已 Retiring)
doubao_video_model: str = "doubao-seedance-2-5-260628"
doubao_video_timeout: int = 600 # 视频生成轮询总超时(秒)
+376
View File
@@ -0,0 +1,376 @@
"""功能计费配置服务:从 feature_pricing_configs 读配置,300 秒 TTL 内存缓存。
配置表由 xiaoxia-admin 侧维护(同库 PostgreSQL),本服务只读。
DB 不可用 / 表不存在 / 无数据时自动回落到内置兜底配置,保证业务不崩。
计费公式:最终积分 = (动态成本 + 固定成本) × 利润系数,price_cap 封顶。
启用条件:全局 points_enabled 总开关 AND 功能 is_enabled 同时为 true。
"""
from __future__ import annotations
import json
import logging
import threading
import time
from dataclasses import dataclass, field
from typing import Optional
import sqlalchemy as sa
from packages.adapters.sqlalchemy_impl import session as _session_mod
logger = logging.getLogger(__name__)
CACHE_TTL_SECONDS = 300.0
# ── 爆款视频兜底模型单价(与旧硬编码表/现状一致;DB 不可用时使用) ───────
# 结构:models[model_key][resolution]["true"/"false"] = 单价
# token 模式:元/百万输出 tokens;per_second 模式:元/秒
# 注意:仅 seedance-2.5 配置 true(图生视频)单价;其余模型只有 false,
# 精确 key 缺失时由 points_rules 回落到 seedance-2.5/false(与旧现状一致)。
_FALLBACK_VIRAL_MODEL_PRICING: dict = {
"seedance-2.5": {
"480p": {"false": 70.0, "true": 42.0},
"720p": {"false": 70.0, "true": 42.0},
"1080p": {"false": 77.0, "true": 46.0},
},
"seedance-2.0": {
"480p": {"false": 46.0},
"720p": {"false": 46.0},
"1080p": {"false": 51.0},
"4k": {"false": 80.0},
},
"seedance-2.0-fast": {
"480p": {"false": 28.0},
"720p": {"false": 28.0},
},
"seedance-2.0-mini": {
"480p": {"false": 9.2},
"720p": {"false": 9.2},
},
"wan-3.0": {
"480p": {"false": 0.3},
"720p": {"false": 0.6},
"1080p": {"false": 1.2},
},
}
@dataclass
class FeatureConfig:
"""功能计费配置快照。"""
feature_key: str
name: str = ""
emoji: str = ""
is_enabled: bool = False
fixed_cost: float = 0.0
profit_multiplier: float = 1.0
dynamic_unit_cost: float = 0.0
billing_mode: str = "model_based"
price_cap: float = 0.0
model_pricing: dict = field(default_factory=dict)
description: str = ""
# ── 进程内缓存:(loaded_monotonic, {feature_key: FeatureConfig}) ──────────
_lock = threading.Lock()
_cache: Optional[tuple[float, dict[str, FeatureConfig]]] = None
def _fallback_configs() -> dict[str, FeatureConfig]:
"""内置兜底配置:爆款启用(与现状一致),其余两个关闭。"""
return {
"viral_video": FeatureConfig(
feature_key="viral_video",
name="爆款视频",
emoji="🎬",
is_enabled=True,
fixed_cost=0.15,
profit_multiplier=1.3,
dynamic_unit_cost=0.0,
billing_mode="model_based",
price_cap=0.0,
model_pricing=json.loads(json.dumps(_FALLBACK_VIRAL_MODEL_PRICING)),
description="爆款视频动态定价(兜底配置)",
),
"lip_sync": FeatureConfig(
feature_key="lip_sync",
name="对口型",
emoji="🎙️",
is_enabled=False,
fixed_cost=0.0,
profit_multiplier=1.0,
dynamic_unit_cost=0.0,
billing_mode="per_second",
price_cap=0.0,
description="对口型计费(兜底配置,默认关闭)",
),
"smart_edit": FeatureConfig(
feature_key="smart_edit",
name="智能剪辑",
emoji="✂️",
is_enabled=False,
fixed_cost=0.0,
profit_multiplier=1.0,
dynamic_unit_cost=0.0,
billing_mode="model_based",
price_cap=0.0,
description="智能剪辑固定价计费(兜底配置,默认关闭)",
),
}
_lazy_session = None
def _get_session():
"""优先用全局 SessionLocal(worker);否则按应用配置懒建同步引擎(api)。"""
global _lazy_session
if _session_mod.SessionLocal is not None:
return _session_mod.SessionLocal()
if _lazy_session is not None:
return _lazy_session()
try:
from packages.config import get_shared_settings
url = str(get_shared_settings().database_url)
except Exception: # noqa: BLE001
return None
if not url:
return None
url = url.replace("postgresql+asyncpg://", "postgresql+psycopg://")
if url.startswith("postgresql://"):
url = url.replace("postgresql://", "postgresql+psycopg://")
engine = sa.create_engine(url, pool_pre_ping=True, pool_size=2, max_overflow=2)
from sqlalchemy.orm import sessionmaker
_lazy_session = sessionmaker(bind=engine)
return _lazy_session()
def _parse_model_pricing(raw) -> dict:
"""解析 model_pricing_json(Text JSON),空/失败 → {}。"""
if raw is None:
return {}
if isinstance(raw, dict):
return raw
text = str(raw).strip()
if not text:
return {}
try:
data = json.loads(text)
except (ValueError, TypeError):
logger.warning("model_pricing_json 解析失败,按空配置处理: %r", text[:200])
return {}
return data if isinstance(data, dict) else {}
def _to_float(value, default: float = 0.0) -> float:
try:
if value is None:
return default
return float(value)
except (TypeError, ValueError):
return default
def _load_all() -> dict[str, FeatureConfig]:
"""SELECT * FROM feature_pricing_configs,返回 {feature_key: FeatureConfig}。
表不存在 / DB 异常由调用方捕获并回落兜底配置。
"""
session = None
try:
session = _get_session()
if session is None:
raise RuntimeError("no db session available")
sql = sa.text("""
SELECT feature_key, name, emoji, is_enabled, fixed_cost,
profit_multiplier, dynamic_unit_cost, billing_mode,
price_cap, model_pricing_json, description
FROM feature_pricing_configs
""")
rows = session.execute(sql).mappings().all()
configs: dict[str, FeatureConfig] = {}
for row in rows:
key = str(row["feature_key"] or "").strip()
if not key:
continue
configs[key] = FeatureConfig(
feature_key=key,
name=str(row["name"] or key),
emoji=str(row["emoji"] or ""),
is_enabled=bool(row["is_enabled"]),
fixed_cost=_to_float(row["fixed_cost"]),
profit_multiplier=_to_float(row["profit_multiplier"], 1.0),
dynamic_unit_cost=_to_float(row["dynamic_unit_cost"]),
billing_mode=str(row["billing_mode"] or "model_based"),
price_cap=_to_float(row["price_cap"]),
model_pricing=_parse_model_pricing(row["model_pricing_json"]),
description=str(row["description"] or ""),
)
return configs
finally:
if session is not None:
try:
session.close()
except Exception: # noqa: BLE001
pass
def _get_cache() -> dict[str, FeatureConfig]:
"""TTL 内返回缓存,否则重新 load;DB 异常/表不存在时返回内置兜底配置。"""
global _cache
now = time.monotonic()
with _lock:
if _cache is not None and now - _cache[0] < CACHE_TTL_SECONDS:
return _cache[1]
try:
loaded = _load_all()
except Exception: # noqa: BLE001 - 表不存在/DB 不可用时静默回落
logger.info("feature_pricing_configs 读取失败,使用内置兜底配置", exc_info=True)
return _fallback_configs()
# DB 可用但表为空:同样回落兜底(保证爆款现状不被改变)
if not loaded:
fallback = _fallback_configs()
with _lock:
_cache = (now, fallback)
return fallback
# 以兜底为底(DB 未配置的 feature_key 仍有兜底),DB 行覆盖
merged = _fallback_configs()
merged.update(loaded)
with _lock:
_cache = (now, merged)
return merged
def get_feature_config(feature_key: str) -> Optional[FeatureConfig]:
"""获取指定功能配置,未知 key 返回 None。"""
key = str(feature_key or "").strip()
if not key:
return None
return _get_cache().get(key)
def _global_points_enabled() -> bool:
"""全局积分总开关(兼容 api / worker 运行时),取不到时默认关闭。"""
try:
from packages.shared import get_shared_settings
return bool(get_shared_settings().points_enabled)
except Exception: # noqa: BLE001
pass
try:
from app.config import settings
return bool(getattr(settings, "points_enabled", False))
except Exception: # noqa: BLE001
return False
def is_feature_enabled(feature_key: str) -> bool:
"""功能是否启用并扣费:全局 points_enabled AND 功能 is_enabled。"""
cfg = get_feature_config(feature_key)
if cfg is None:
return False
return bool(cfg.is_enabled) and _global_points_enabled()
def calculate_price(feature_key: str, dynamic_cost: float = 0.0) -> tuple[float, dict]:
"""按公式计算最终积分并返回明细。
price = (dynamic_cost + fixed_cost) × profit_multiplier
price_cap > 0 时封顶(取 min)。
功能未启用 → (0.0, breakdown{is_enabled: False, charged: False})。
"""
cfg = get_feature_config(feature_key)
dynamic = max(0.0, _to_float(dynamic_cost))
if cfg is None or not cfg.is_enabled:
return 0.0, {
"feature_key": feature_key,
"is_enabled": False,
"charged": False,
"dynamic_cost": dynamic,
"fixed_cost": 0.0,
"profit_multiplier": 1.0,
"price_cap": 0.0,
"final_price": 0.0,
}
fixed = max(0.0, cfg.fixed_cost)
multiplier = cfg.profit_multiplier if cfg.profit_multiplier > 0 else 1.0
raw_price = (dynamic + fixed) * multiplier
cap = cfg.price_cap if cfg.price_cap and cfg.price_cap > 0 else 0.0
final_price = min(raw_price, cap) if cap else raw_price
final_price = round(float(final_price), 2)
breakdown = {
"feature_key": cfg.feature_key,
"is_enabled": True,
"charged": True,
"dynamic_cost": round(dynamic, 4),
"fixed_cost": float(fixed),
"profit_multiplier": float(multiplier),
"price_cap": float(cap),
"raw_price": round(float(raw_price), 4),
"final_price": final_price,
}
return final_price, breakdown
def lookup_model_price(
model_pricing: dict,
model_key: str,
resolution: str,
has_video_input: bool,
) -> Optional[float]:
"""从 model_pricing dict 取模型单价,兼容两种常见 JSON 结构。
1. 嵌套:{model: {resolution: {"true"/"false": price}}}
(内层 bool key 也兼容直接 bool / 省略)
2. 扁平:{"model|resolution|true_or_false": price}
(分隔符支持 | / : / , / 空格;bool 段可省略)
取不到返回 None。
"""
if not isinstance(model_pricing, dict):
return None
model = str(model_key or "").strip()
res = str(resolution or "").strip()
flag = "true" if has_video_input else "false"
# 1. 嵌套
model_node = model_pricing.get(model)
if isinstance(model_node, dict):
res_node = model_node.get(res)
if isinstance(res_node, dict):
# 精确 bool key 命中才返回;不做“只有一个值就取”的模糊匹配
# (否则缺失 true 时会错误地取到 false 价,破坏旧版回落规则)
if flag in res_node:
return _to_float(res_node[flag]) if res_node[flag] is not None else None
if has_video_input in res_node:
val = res_node[has_video_input]
return _to_float(val) if val is not None else None
elif isinstance(res_node, (int, float)):
return float(res_node)
# 2. 扁平
for sep in ("|", ":", ",", " "):
for key in (
f"{model}{sep}{res}{sep}{flag}",
f"{model}{sep}{res}",
):
if key in model_pricing:
value = model_pricing[key]
return _to_float(value) if value is not None else None
return None
def refresh_feature_configs() -> None:
"""清空缓存(下次读取重新 load DB;测试/admin 改配置后可手动调)。"""
global _cache
with _lock:
_cache = None
+77 -14
View File
@@ -2,17 +2,21 @@
v1.6.1: 按产品决策,智能混剪/AI数字人/AI配音/抖音解析/改写/标题/封面 全部免费,
仅保留声音克隆合成(voice_clone_synth)的扣点逻辑;声音克隆训练保持免费。
爆款视频(viral_video)走动态定价,见本文件 VIRAL_VIDEO_MODEL_PRICES + calculate_viral_video_credits。
爆款视频(viral_video)走动态定价,计费参数 DB 化(feature_pricing_configs,
见 feature_pricing_service),calculate_viral_video_credits 从配置读取单价/
固定成本/利润系数/封顶,DB 不可用时回落兜底配置。
"""
from __future__ import annotations
import math
# ============ 爆款视频动态定价 (#2151) ============
# key = (model_id, resolution, has_video_input),单位:
# - billing_mode=token: 元/百万tokens(输出)
# - billing_mode=per_second: 元/秒(视频时长)
from packages.domain import feature_pricing_service
# ============ 爆款视频动态定价 ============
# 单价/固定成本/利润系数已 DB 化(feature_pricing_configs,feature_key=viral_video),
# 由 feature_pricing_service 读取(300s 缓存),DB 不可用时回落内置兜底配置。
# 以下三个常量仅为向后兼容保留(旧引用方/兜底场景),值取自兜底配置。
VIRAL_VIDEO_MODEL_PRICES: dict[tuple[str, str, bool], float] = {
("seedance-2.5", "480p", False): 70.0,
("seedance-2.5", "720p", False): 70.0,
@@ -33,9 +37,9 @@ VIRAL_VIDEO_MODEL_PRICES: dict[tuple[str, str, bool], float] = {
("wan-3.0", "1080p", False): 1.2,
}
# 固定成本(元):VLM 分析 + LLM 文案 + TTS + OSS + 服务器
# 固定成本(元):VLM 分析 + LLM 文案 + TTS + OSS + 服务器(兜底默认值)
VIRAL_VIDEO_FIXED_COST = 0.15
# 利润系数
# 利润系数(兜底默认值)
VIRAL_VIDEO_PROFIT_MULTIPLIER = 1.3
# Seedance 输出帧率
VIRAL_VIDEO_FPS = 24
@@ -222,17 +226,22 @@ def calculate_viral_video_credits_with_breakdown(
) -> tuple[float, dict]:
"""计算爆款视频所需积分(1 积分 = 1 元),并返回计费公式明细。
单价/固定成本/利润系数/封顶从 feature_pricing_configs(viral_video)读取;
DB 不可用时回落与现状一致的内置兜底配置。
公式:
tokens = duration * width * height * fps / 1024
video_cost = tokens / 1_000_000 * model_token_price
total = round((video_cost + fixed_cost) * profit_multiplier, 2)
price_cap > 0 时封顶取 min
若传入 actual_tokens 则用它替代计算值。
Returns:
(credits, breakdown) 二元组:
- credits: 四舍五入保留两位小数的最终积分
- breakdown: dict,包含 tokens / video_cost / fixed_cost / profit_multiplier /
model_price / width / height / fps 字段,便于前端展示计费明细。
model_price / width / height / fps / feature_enabled / charged / price_cap
字段,便于前端展示计费明细。功能关闭时 credits=0、charged=False。
"""
w = max(1, int(width or 1))
h = max(1, int(height or 1))
@@ -242,11 +251,36 @@ def calculate_viral_video_credits_with_breakdown(
cfg = get_viral_video_model_config(prefix)
res_key = _infer_resolution_key(w, h)
billing = cfg.get("billing_mode", "token")
key = (prefix, res_key, bool(has_video_input))
price = VIRAL_VIDEO_MODEL_PRICES.get(key)
dur = max(1, int(duration_seconds or 15))
# ── 从 DB 配置(兜底内置)取计费参数 ──
feature_cfg = feature_pricing_service.get_feature_config("viral_video")
# 注意:此处 feature_enabled 只表示“功能自身开关”,不并入全局 points_enabled
# 总开关(保持与旧版计费函数行为一致:价格照常计算)。全局总开关由业务层
# (route/worker)通过 feature_pricing_service.is_feature_enabled 统一把关。
feature_enabled = bool(feature_cfg.is_enabled) if feature_cfg is not None else True
model_pricing = feature_cfg.model_pricing if feature_cfg is not None else {}
fixed_cost = float(feature_cfg.fixed_cost) if feature_cfg is not None else float(VIRAL_VIDEO_FIXED_COST)
multiplier = (
float(feature_cfg.profit_multiplier)
if feature_cfg is not None and feature_cfg.profit_multiplier > 0
else float(VIRAL_VIDEO_PROFIT_MULTIPLIER)
)
price_cap = float(feature_cfg.price_cap) if feature_cfg is not None else 0.0
# 单价:优先配置 dict;复刻旧版回落规则——精确 key 取不到时,回落
# seedance-2.5 同分辨率 False 单价;最终兜底 70.0。
price = feature_pricing_service.lookup_model_price(model_pricing, prefix, res_key, bool(has_video_input))
if price is None:
# 配置表未命中:先尝试配置里的 seedance-2.5/False
if prefix != "seedance-2.5" or bool(has_video_input):
price = feature_pricing_service.lookup_model_price(model_pricing, "seedance-2.5", res_key, False)
if price is None:
key = (prefix, res_key, bool(has_video_input))
price = VIRAL_VIDEO_MODEL_PRICES.get(key)
if price is None:
price = VIRAL_VIDEO_MODEL_PRICES.get(("seedance-2.5", res_key, False), 70.0)
dur = max(1, int(duration_seconds or 15))
if billing == "per_second":
tokens = 0.0
video_cost = dur * float(price)
@@ -259,13 +293,40 @@ def calculate_viral_video_credits_with_breakdown(
video_cost = tokens / 1_000_000.0 * float(price)
billing_unit = "token"
total = (video_cost + VIRAL_VIDEO_FIXED_COST) * VIRAL_VIDEO_PROFIT_MULTIPLIER
if not feature_enabled:
# 功能关闭(is_enabled=false 或全局 points 关闭):不扣费,明细照旧返回
credits = 0.0
raw_total = (video_cost + fixed_cost) * multiplier
breakdown = {
"tokens": float(tokens),
"video_cost": float(video_cost),
"fixed_cost": float(fixed_cost),
"profit_multiplier": float(multiplier),
"price_cap": float(price_cap or 0.0),
"model_price": float(price),
"model_key": prefix,
"billing_mode": billing,
"billing_unit": billing_unit,
"width": int(w),
"height": int(h),
"fps": int(effective_fps),
"duration": dur,
"feature_enabled": False,
"charged": False,
"raw_price": round(float(raw_total), 4),
}
return credits, breakdown
total = (video_cost + fixed_cost) * multiplier
if price_cap and price_cap > 0:
total = min(total, price_cap)
credits = round(float(total), 2)
breakdown = {
"tokens": float(tokens),
"video_cost": float(video_cost),
"fixed_cost": float(VIRAL_VIDEO_FIXED_COST),
"profit_multiplier": float(VIRAL_VIDEO_PROFIT_MULTIPLIER),
"fixed_cost": float(fixed_cost),
"profit_multiplier": float(multiplier),
"price_cap": float(price_cap or 0.0),
"model_price": float(price),
"model_key": prefix,
"billing_mode": billing,
@@ -274,6 +335,8 @@ def calculate_viral_video_credits_with_breakdown(
"height": int(h),
"fps": int(effective_fps),
"duration": dur,
"feature_enabled": True,
"charged": True,
}
return credits, breakdown
+21 -1
View File
@@ -585,7 +585,7 @@ class DoubaoClient:
# #2172/#2174: 信任链——使用预热好的 Seedream t2i 文生图(纯模型生成人像,是方舟信任产物,
# 不会触发肖像审核)。预热在 VLM 分析后由 daemon 线程后台完成,结果通过 pre_trusted_images 传入。
# - 预热结果有效 → 替换原参考图,走 omni_ref 模式
# - 预热结果不可用 → 直接用原图(若被400肖像拦截,#2166自动降级纯t2v),避免现场跑t2i阻塞渲染
# - 预热结果不可用 → 直接用原图(上层 _step_render 已现场同步跑 Seedream t2i 兜底;若再被400拦截,下方自动降级纯t2v)
# 信任链只作用于 doubao provider;DashScope(Wan) 保持原行为。
trust_chain_applied = False
if provider == "doubao" and getattr(self, "trust_chain_enabled", True) and pre_trusted_images:
@@ -763,6 +763,26 @@ class DoubaoClient:
# 保留第二次的错误信息
sc, body = sc2, body2
# #2183: portrait_intercept / 真人肖像审核拦截 → 去掉所有参考图(含image_url首帧),纯 t2v 重试一次
# 信任链预热或现场 t2i 都失败时的最后兜底,保证能出片
if not task_id and sc == 400:
_err_code_for_400, _ = _classify_video_error(sc, body, last_err)
if _err_code_for_400 == "portrait_intercept" and (image_url or ref_imgs):
logger.warning(
"Seedance 创建因 portrait_intercept 失败,降级纯 t2v(移除所有参考图)重试: img=%d ref=%d",
1 if image_url else 0,
len(ref_imgs),
)
_t2v_payload = dict(create_payload)
_t2v_payload["content"] = [{"type": "text", "text": prompt.strip()}]
_t2v_payload["ratio"] = ratio or "9:16"
task_id, last_err, sc3, body3 = _do_create(_t2v_payload)
if task_id:
sc, body = sc3, body3
logger.info("[trust-chain] portrait_intercept 降级纯 t2v 成功 task_id=%s", task_id)
else:
sc, body = sc3, body3
if not task_id:
err_code, user_msg = _classify_video_error(sc, body, last_err)
self.last_video_error = {
+221
View File
@@ -0,0 +1,221 @@
"""功能计费改造测试:爆款读配置、对口型/智能剪辑预扣逻辑。
策略:
- 爆款:通过修改缓存中的 FeatureConfig(multiplier/model_pricing)验证价格随配置变化
- lip_sync / smart_edit:直接测 LipsyncService 的预扣/结算/退款辅助方法,
PointsService 用 mock,避免依赖真实积分账户。
"""
from __future__ import annotations
from unittest.mock import MagicMock, patch
import pytest
from packages.domain import feature_pricing_service as fps
from packages.domain.feature_pricing_service import FeatureConfig, refresh_feature_configs
@pytest.fixture(autouse=True)
def _reset_cache():
refresh_feature_configs()
yield
refresh_feature_configs()
def _seed_cache(configs: dict) -> None:
import time
fps._cache = (time.monotonic(), configs)
class TestViralVideoReadsConfig:
def test_multiplier_change_changes_price(self):
"""配置里 multiplier 改大后,爆款价格随之变大(证明不再读死常量)。"""
from packages.domain.points_rules import calculate_viral_video_credits
# 基线兜底
base = calculate_viral_video_credits(15, 1280, 720)
assert base == 29.68
fallback = fps._fallback_configs()
vv = fallback["viral_video"]
vv.profit_multiplier = 2.0
_seed_cache(fallback)
changed = calculate_viral_video_credits(15, 1280, 720)
assert changed > base
# 精确校验:video_cost 相同,仅系数从 1.3 → 2.0
_, bd = __import__(
"packages.domain.points_rules", fromlist=["calculate_viral_video_credits_with_breakdown"]
).calculate_viral_video_credits_with_breakdown(15, 1280, 720)
assert bd["profit_multiplier"] == 2.0
def test_model_price_from_config(self):
"""model_pricing 改单价后,token 成本按新单价计算。"""
from packages.domain.points_rules import calculate_viral_video_credits_with_breakdown
fallback = fps._fallback_configs()
vv = fallback["viral_video"]
# seedance-2.5/720p/false 从 70 改成 100
vv.model_pricing["seedance-2.5"]["720p"]["false"] = 100.0
_seed_cache(fallback)
_, bd = calculate_viral_video_credits_with_breakdown(15, 1280, 720)
assert bd["model_price"] == 100.0
def test_price_cap_from_config(self):
from packages.domain.points_rules import calculate_viral_video_credits_with_breakdown
fallback = fps._fallback_configs()
vv = fallback["viral_video"]
vv.price_cap = 5.0
_seed_cache(fallback)
credits, bd = calculate_viral_video_credits_with_breakdown(15, 1280, 720)
assert credits == 5.0
assert bd["price_cap"] == 5.0
def test_disabled_feature_returns_zero_credits(self):
"""功能 is_enabled=false 时计费函数返回 0(纯计费层语义)。"""
from packages.domain.points_rules import calculate_viral_video_credits_with_breakdown
fallback = fps._fallback_configs()
fallback["viral_video"].is_enabled = False
_seed_cache(fallback)
credits, bd = calculate_viral_video_credits_with_breakdown(15, 1280, 720)
assert credits == 0.0
assert bd["feature_enabled"] is False
assert bd["charged"] is False
class TestLipSyncPricing:
def _make_service(self):
from app.services.lipsync_service import LipsyncService
svc = LipsyncService.__new__(LipsyncService)
svc.db = MagicMock()
return svc
def _lip_cfg(self, **kw):
base = dict(
feature_key="lip_sync",
name="对口型",
is_enabled=True,
fixed_cost=0.1,
profit_multiplier=1.0,
dynamic_unit_cost=0.05,
billing_mode="per_second",
price_cap=0.0,
model_pricing={},
description="",
)
base.update(kw)
return FeatureConfig(**base)
def test_estimate_duration_from_script(self):
svc = self._make_service()
# 10 个字 / 5 = 2 秒,下限 1
assert svc._estimate_duration(script_text="一二三四五六七八九十") == 2.0
# 无任何信息 → 默认 10 秒
assert svc._estimate_duration() == 10.0
def test_calculate_lipsync_price_per_second(self):
_seed_cache({"lip_sync": self._lip_cfg()})
price, bd = fps.calculate_price("lip_sync", dynamic_cost=20.0 * 0.05)
# dynamic 1.0 + fixed 0.1 = 1.1
assert price == 1.1
assert bd["charged"] is True
def test_settle_refunds_overcharge(self):
"""实际时长短 → 只退不补,退还差额。"""
svc = self._make_service()
_seed_cache({"lip_sync": self._lip_cfg()})
job = MagicMock()
job.credits_prepaid = 2.0
job.credits_cost = 0.0 # 未结算
job.user_id = "u1"
job.credits_transaction_id = "txn-old"
with patch("packages.domain.points_service.PointsService") as MockPS:
inst = MockPS.return_value
inst.refund_points.return_value = {"success": True}
svc._settle_lip_sync(job, actual_duration=10.0)
# final: (10*0.05 + 0.1)*1.0 = 0.6;退 2.0-0.6=1.4
assert round(job.credits_cost, 2) == 0.6
inst.refund_points.assert_called_once()
kwargs = inst.refund_points.call_args.kwargs
assert kwargs["amount"] == 1.4
def test_settle_no_refund_when_longer(self):
"""首期只退不补:实际更贵不补扣。"""
svc = self._make_service()
_seed_cache({"lip_sync": self._lip_cfg()})
job = MagicMock()
job.credits_prepaid = 0.5
job.credits_cost = 0.0
with patch("packages.domain.points_service.PointsService") as MockPS:
inst = MockPS.return_value
svc._settle_lip_sync(job, actual_duration=60.0)
assert round(job.credits_cost, 2) > 0.5
inst.refund_points.assert_not_called()
def test_refund_on_failure_full(self):
svc = self._make_service()
job = MagicMock()
job.credits_prepaid = 3.0
job.credits_cost = 0.0
job.user_id = "u1"
job.credits_transaction_id = "t1"
with patch("packages.domain.points_service.PointsService") as MockPS:
inst = MockPS.return_value
inst.refund_points.return_value = {"success": True}
svc._refund_lip_sync(job)
kwargs = inst.refund_points.call_args.kwargs
assert kwargs["amount"] == 3.0
class TestSmartEditFixedPrice:
def test_fixed_price_formula(self):
"""首期固定价:dynamic=0,price=fixed*multiplier,cap 封顶。"""
cfg = FeatureConfig(
feature_key="smart_edit",
name="智能剪辑",
is_enabled=True,
fixed_cost=2.0,
profit_multiplier=1.5,
billing_mode="model_based",
price_cap=0.0,
)
_seed_cache({"smart_edit": cfg})
price, bd = fps.calculate_price("smart_edit", dynamic_cost=0.0)
# (0+2)*1.5 = 3.0
assert price == 3.0
assert bd["dynamic_cost"] == 0.0
def test_fixed_price_with_cap(self):
cfg = FeatureConfig(
feature_key="smart_edit",
is_enabled=True,
fixed_cost=10.0,
profit_multiplier=2.0,
price_cap=8.0,
)
_seed_cache({"smart_edit": cfg})
price, _ = fps.calculate_price("smart_edit", dynamic_cost=0.0)
assert price == 8.0
def test_disabled_smart_edit_free(self):
cfg = FeatureConfig(feature_key="smart_edit", is_enabled=False, fixed_cost=2.0)
_seed_cache({"smart_edit": cfg})
price, bd = fps.calculate_price("smart_edit", dynamic_cost=0.0)
assert price == 0.0
assert bd["charged"] is False
+235
View File
@@ -0,0 +1,235 @@
"""feature_pricing_service 单元测试。
覆盖:
- 300s TTL 内存缓存(命中不重复 load / 过期重新 load / refresh 强制刷新)
- calculate_price 公式 (dynamic+fixed)*multiplier、price_cap 封顶、round
- disabled / 未知 key 返回 0
- DB 异常 / 空表 → 内置兜底配置(爆款启用且价格与现状一致)
- lookup_model_price 嵌套/扁平结构与旧版回落语义
"""
from __future__ import annotations
import time
import pytest
from packages.domain import feature_pricing_service as fps
from packages.domain.feature_pricing_service import (
CACHE_TTL_SECONDS,
FeatureConfig,
calculate_price,
get_feature_config,
is_feature_enabled,
lookup_model_price,
refresh_feature_configs,
)
@pytest.fixture(autouse=True)
def _reset_cache():
"""每个用例前后清空模块缓存,避免相互污染。"""
refresh_feature_configs()
yield
refresh_feature_configs()
def _cfg(key="x", **kw) -> FeatureConfig:
base = dict(
feature_key=key,
name=key,
is_enabled=True,
fixed_cost=0.2,
profit_multiplier=2.0,
dynamic_unit_cost=0.0,
billing_mode="per_second",
price_cap=0.0,
model_pricing={},
description="",
)
base.update(kw)
return FeatureConfig(**base)
class TestCacheTTL:
def test_cache_hit_avoids_reload(self, monkeypatch):
"""TTL 内第二次读取不再调 _load_all。"""
calls = {"n": 0}
def fake_load():
calls["n"] += 1
return {"x": _cfg()}
monkeypatch.setattr(fps, "_load_all", fake_load)
get_feature_config("x")
get_feature_config("x")
get_feature_config("x")
assert calls["n"] == 1
def test_expired_cache_reloads(self, monkeypatch):
"""超过 TTL 后重新 load。"""
calls = {"n": 0}
def fake_load():
calls["n"] += 1
return {"x": _cfg()}
monkeypatch.setattr(fps, "_load_all", fake_load)
get_feature_config("x")
assert calls["n"] == 1
# 把缓存时间戳回拨到 TTL 之前
ts, data = fps._cache
fps._cache = (ts - CACHE_TTL_SECONDS - 1, data)
get_feature_config("x")
assert calls["n"] == 2
def test_refresh_forces_reload(self, monkeypatch):
calls = {"n": 0}
def fake_load():
calls["n"] += 1
return {"x": _cfg()}
monkeypatch.setattr(fps, "_load_all", fake_load)
get_feature_config("x")
refresh_feature_configs()
get_feature_config("x")
assert calls["n"] == 2
def test_ttl_constant_is_300(self):
assert CACHE_TTL_SECONDS == 300.0
class TestCalculatePrice:
def test_basic_formula(self, monkeypatch):
# (dynamic 1.0 + fixed 0.2) * 2.0 = 2.4
monkeypatch.setattr(fps, "_load_all", lambda: {"x": _cfg(dynamic_unit_cost=1.0)})
price, bd = calculate_price("x", dynamic_cost=1.0)
assert price == 2.4
assert bd["dynamic_cost"] == 1.0
assert bd["fixed_cost"] == 0.2
assert bd["profit_multiplier"] == 2.0
assert bd["final_price"] == 2.4
assert bd["charged"] is True
def test_price_cap_clamps(self, monkeypatch):
# raw = (1+0.2)*2 = 2.4,cap=1.0 → 1.0
monkeypatch.setattr(fps, "_load_all", lambda: {"x": _cfg(price_cap=1.0)})
price, bd = calculate_price("x", dynamic_cost=1.0)
assert price == 1.0
assert bd["price_cap"] == 1.0
def test_no_cap_keeps_raw(self, monkeypatch):
# cap=0 视为不封顶
monkeypatch.setattr(fps, "_load_all", lambda: {"x": _cfg(price_cap=0.0)})
price, _ = calculate_price("x", dynamic_cost=1.0)
assert price == 2.4
def test_rounded_two_decimals(self, monkeypatch):
monkeypatch.setattr(
fps,
"_load_all",
lambda: {"x": _cfg(fixed_cost=0.1, profit_multiplier=1.0)},
)
price, _ = calculate_price("x", dynamic_cost=1.0 / 3.0)
# 0.3333... + 0.1 = 0.4333 → 0.43
assert price == 0.43
def test_negative_dynamic_treated_as_zero(self, monkeypatch):
monkeypatch.setattr(fps, "_load_all", lambda: {"x": _cfg()})
price, _ = calculate_price("x", dynamic_cost=-5.0)
# (0 + 0.2) * 2 = 0.4
assert price == 0.4
def test_disabled_returns_zero(self, monkeypatch):
monkeypatch.setattr(fps, "_load_all", lambda: {"x": _cfg(is_enabled=False)})
price, bd = calculate_price("x", dynamic_cost=1.0)
assert price == 0.0
assert bd["is_enabled"] is False
assert bd["charged"] is False
def test_unknown_key_returns_zero(self, monkeypatch):
monkeypatch.setattr(fps, "_load_all", lambda: {"x": _cfg()})
price, bd = calculate_price("nope", dynamic_cost=1.0)
assert price == 0.0
assert bd["charged"] is False
class TestDBFailureFallback:
def test_load_exception_uses_fallback(self, monkeypatch):
def boom():
raise RuntimeError("table does not exist")
monkeypatch.setattr(fps, "_load_all", boom)
cfg = get_feature_config("viral_video")
assert cfg is not None
assert cfg.is_enabled is True
assert cfg.fixed_cost == 0.15
assert cfg.profit_multiplier == 1.3
def test_empty_table_uses_fallback(self, monkeypatch):
monkeypatch.setattr(fps, "_load_all", lambda: {})
assert get_feature_config("viral_video").is_enabled is True
assert get_feature_config("lip_sync").is_enabled is False
assert get_feature_config("smart_edit").is_enabled is False
def test_fallback_viral_price_matches_current(self, monkeypatch):
"""兜底爆款价格与旧硬编码现状一致:seedance-2.5/720p/false=70。"""
monkeypatch.setattr(fps, "_load_all", lambda: {})
from packages.domain.points_rules import calculate_viral_video_credits
# 默认全局开关关闭,但纯计费函数价格照常算
assert calculate_viral_video_credits(15, 1280, 720) == 29.68
def test_db_row_overrides_fallback(self, monkeypatch):
monkeypatch.setattr(
fps,
"_load_all",
lambda: {"viral_video": _cfg("viral_video", fixed_cost=0.5, profit_multiplier=2.0, price_cap=50.0)},
)
cfg = get_feature_config("viral_video")
assert cfg.fixed_cost == 0.5
assert cfg.profit_multiplier == 2.0
assert cfg.price_cap == 50.0
class TestIsFeatureEnabled:
def test_disabled_feature(self, monkeypatch):
monkeypatch.setattr(fps, "_load_all", lambda: {"x": _cfg(is_enabled=False)})
assert is_feature_enabled("x") is False
def test_global_switch_off_blocks_enabled_feature(self, monkeypatch):
monkeypatch.setattr(fps, "_load_all", lambda: {"x": _cfg(is_enabled=True)})
monkeypatch.setattr(fps, "_global_points_enabled", lambda: False)
assert is_feature_enabled("x") is False
def test_both_switches_on(self, monkeypatch):
monkeypatch.setattr(fps, "_load_all", lambda: {"x": _cfg(is_enabled=True)})
monkeypatch.setattr(fps, "_global_points_enabled", lambda: True)
assert is_feature_enabled("x") is True
class TestLookupModelPrice:
NESTED = {
"seedance-2.5": {
"720p": {"false": 70.0, "true": 42.0},
},
"wan-3.0": {"480p": {"false": 0.3}},
}
def test_nested_exact_hit(self):
assert lookup_model_price(self.NESTED, "seedance-2.5", "720p", False) == 70.0
assert lookup_model_price(self.NESTED, "seedance-2.5", "720p", True) == 42.0
def test_missing_bool_key_returns_none(self):
# wan-3.0/480p 只有 false,请求 true → None(由调用方回落)
assert lookup_model_price(self.NESTED, "wan-3.0", "480p", True) is None
def test_unknown_model_returns_none(self):
assert lookup_model_price(self.NESTED, "nope", "720p", False) is None
def test_flat_structure(self):
flat = {"m|720p|false": 12.5}
assert lookup_model_price(flat, "m", "720p", False) == 12.5
assert lookup_model_price(flat, "m", "720p", True) is None
+28 -30
View File
@@ -403,33 +403,30 @@ class TestViralVideoPipeline:
"""v1.6: _step_script_generation 返回 dict 形式的 CopyResult,含 voiceover_script + shots。"""
from apps.worker.worker_app.tasks.viral_video import _step_script_generation
mock_llm.return_value = {
"overview": {"theme": "口红推荐", "total_duration": 15, "aspect_ratio": "9:16"},
"scene_and_lighting": "明亮化妆台,柔和自然光",
"shots": [
{
"time_range": "0-5秒",
"shot_type_angle_movement": "近景平视,缓慢推镜",
"scene_and_dialogue": "女主微笑展示口红:大家好,今天分享一款口红",
"action_details": "手持口红特写",
"audio_bgm": "轻快流行BGM",
"transition": "硬切",
"reference_image_index": 0,
},
{
"time_range": "5-15秒",
"shot_type_angle_movement": "特写,固定镜头",
"scene_and_dialogue": "涂抹口红:颜色特别好看很显白",
"action_details": "嘴唇涂抹特写",
"audio_bgm": "轻快BGM继续",
"transition": "结束",
"reference_image_index": 1,
},
],
"hard_constraints": ["无字幕无水印"],
"negative_prompts": ["字幕", "水印"],
"voiceover_script": "大家好,今天分享一款口红,颜色特别好看很显白。",
}
mock_llm.return_value = """<clips>
<clip image_index="0" transition="cut" zoom="null" duration_sec="5" bgm_note="轻快流行BGM">
<voice_text>大家好,今天分享一款口红</voice_text>
<subtitle_text>大家好,今天分享一款口红</subtitle_text>
<shot_type_angle_movement>近景平视,缓慢推镜</shot_type_angle_movement>
<scene_and_dialogue>女主微笑展示口红:大家好,今天分享一款口红</scene_and_dialogue>
<action_details>手持口红特写</action_details>
<audio_bgm>轻快流行BGM</audio_bgm>
<transition>硬切</transition>
<reference_image_index>0</reference_image_index>
<ken_burns start="0,0" end="0,0" ease="linear"/>
</clip>
<clip image_index="0" transition="fade" zoom="null" duration_sec="10" bgm_note="轻快BGM">
<voice_text>颜色特别好看很显白</voice_text>
<subtitle_text>颜色特别好看很显白</subtitle_text>
<shot_type_angle_movement>特写,固定镜头</shot_type_angle_movement>
<scene_and_dialogue>涂抹口红:颜色特别好看很显白</scene_and_dialogue>
<action_details>嘴唇涂抹特写</action_details>
<audio_bgm>轻快BGM继续</audio_bgm>
<transition>结束</transition>
<reference_image_index>1</reference_image_index>
<ken_burns start="0,0" end="0,0" ease="linear"/>
</clip>
</clips>"""
result = _step_script_generation(
mock_job, {"intent": "推广口红", "key_messages": [], "tone": "亲切"}, {"products": []}
)
@@ -452,12 +449,13 @@ class TestViralVideoPipeline:
assert result["voiceover_script"]
assert len(result["shots"]) >= 1
@patch("packages.shared.ai_service.call_llm")
def test_review_pass_v16(self, mock_llm, mock_job):
@patch("packages.application.viral_video.reviewer.Reviewer.review")
def test_review_pass_v16(self, mock_review, mock_job):
"""v1.6 _step_review 接收 copy_result dict。"""
from apps.worker.worker_app.tasks.viral_video import _step_review
from packages.application.viral_video.reviewer import ReviewIssue, ReviewResult
mock_llm.return_value = {"passed": True, "score": 90, "details": {}}
mock_review.return_value = ReviewResult(passed=True, score=90, issues=[], rewrite_suggestions=[])
cr = {"voiceover_script": "大家好", "shots": []}
result = _step_review(mock_job, cr)
assert result["passed"] is True
+335
View File
@@ -0,0 +1,335 @@
"""#2040 接线集成测试:验证运行中的 viral_video 任务使用 prompt_loader 从 DB 读取模板。
mock LLM/Vision 调用,验证:
1. image_analysis 走 loader 模板 + XML 解析
2. intent_parsing 走 loader 模板 + XML 解析
3. script_generation 走 storyboard 模板 + XML 解析,输出兼容 Seedance 的 copy_result
4. review 走 Reviewer(review 模板)带自动重写
5. 三档融合(ai_full / ai_polish / user_primary)注入不同 FUSION_INSTRUCTIONS
"""
from __future__ import annotations
import sys
from pathlib import Path as _Path
_WORKER_ROOT = _Path(__file__).resolve().parents[2] / "apps" / "worker"
if str(_WORKER_ROOT) not in sys.path:
sys.path.insert(0, str(_WORKER_ROOT))
from unittest.mock import MagicMock, patch
import pytest
from packages.domain.viral_video import ViralVideoJob
@pytest.fixture
def job():
j = ViralVideoJob(
user_id="u1",
images=["https://img/1.jpg", "https://img/2.jpg"],
industry="美妆",
duration=15,
user_copy_text="这款口红真的太绝了,显白又持久,姐妹们冲!",
fusion_level="ai_polish",
)
return j
# ── Mock LLM/Vision 返回的 XML 文本 ─────────────────────────────────
IMAGE_XML = """
<analysis>
<scene>室内桌面拍摄,柔和自然光</scene>
<mood>清新温暖</mood>
<product name="lipstick" brand="品牌X" category="唇部彩妆"
appearance="管状红色膏体" packaging="黑色金属管"
features="显白,持久,滋润" portrait_prompt="无人像"
summary="品牌X红色口红">
<text_on_package>品牌X,211</text_on_package>
</product>
</analysis>
""".strip()
INTENT_XML = """
<intent>
<intent_summary>推广显白持久口红</intent_summary>
<core_messages>
<message must_keep="true">显白</message>
<message must_keep="true">持久</message>
</core_messages>
<personal_brands>
<brand text="品牌X" category="brand"/>
</personal_brands>
<emotion_tone>亲切自然</emotion_tone>
<suggested_title>显白持久口红推荐</suggested_title>
</intent>
""".strip()
STORYBOARD_XML = """
<clips>
<clip image_index="0" transition="cut" zoom="null" duration_sec="5" bgm_note="轻快BGM">
<voice_text>这款口红真的太绝了</voice_text>
<subtitle_text>显白又持久</subtitle_text>
<shot_type_angle_movement>近景俯拍45度,缓慢推镜</shot_type_angle_movement>
<scene_and_dialogue>厨房台面,主妇展示口红。对白:这款口红真的太绝了</scene_and_dialogue>
<action_details>右手持口红展示膏体</action_details>
<audio_bgm>轻快BGM</audio_bgm>
<transition>硬切</transition>
<reference_image_index>0</reference_image_index>
<ken_burns start="0,0" end="0,0" ease="linear"/>
</clip>
</clips>
""".strip()
@pytest.fixture(autouse=True)
def invalidate_loader_cache():
from packages.application.viral_video import prompt_loader as pl
pl.invalidate()
yield
pl.invalidate()
# ── 1) 图片分析走模板 ───────────────────────────────────────────────
class TestImageAnalysisWiring:
def test_step_image_analysis_uses_v2_batch_path(self, job):
"""#2200/#2207 后图片分析走 V2 批处理(OCR+lite JSON 并行),
_step_image_analysis 归一化 URL 后调用 analyze_images_v2。"""
from apps.worker.worker_app.tasks import viral_video as vv
fake_product = {
"name": "lipstick",
"brand": "品牌X",
"category": "唇部彩妆",
"key_features": ["显白", "持久"],
"text_on_package": ["品牌X", "211"],
"_source": "v2",
}
with patch.object(vv, "_normalize_image_url", side_effect=lambda raw, idx: raw):
with patch(
"worker_app.tasks.vision.analyze_images_v2",
return_value=[fake_product, fake_product],
create=True,
) as mock_v2:
result = vv._step_image_analysis(job)
mock_v2.assert_called_once()
# 传入的是归一化后的图片 URL 列表
assert mock_v2.call_args.args[0] == job.images
products = result["products"]
assert len(products) == 2
assert products[0]["name"] == "lipstick"
assert products[0]["brand"] == "品牌X"
assert "显白" in products[0]["key_features"]
assert products[0]["text_on_package"] == ["品牌X", "211"]
def test_step_image_analysis_empty_images(self, job):
from apps.worker.worker_app.tasks import viral_video as vv
job.images = []
result = vv._step_image_analysis(job)
assert result == {"products": []}
# ── 2) 意图解析走模板 ───────────────────────────────────────────────
class TestIntentParsingWiring:
def test_uses_loader_and_parses_xml(self, job):
from apps.worker.worker_app.tasks import viral_video as vv
img_result = {"products": [{"name": "lipstick", "brand": "品牌X", "key_features": ["显白", "持久"]}]}
with patch("packages.shared.ai_service.call_llm", return_value=INTENT_XML) as mock_llm:
result = vv._step_intent_parsing(job, img_result)
mock_llm.assert_called_once()
assert result["intent"] == "推广显白持久口红"
assert "显白" in result["key_messages"]
assert result["suggested_title"] == "显白持久口红推荐"
# ── 3) 脚本生成:storyboard 模板 + XML 解析 + fusion_level 注入 ────
class TestScriptGenerationWiring:
@pytest.mark.parametrize("level", ["ai_full", "ai_polish", "user_primary"])
def test_fusion_level_injected(self, job, level):
"""三档融合水平被注入到 storyboard 模板的 system_prompt"""
from apps.worker.worker_app.tasks import viral_video as vv
from packages.application.viral_video.prompts import FUSION_INSTRUCTIONS
job.fusion_level = level
intent = {"intent": "推广", "key_messages": ["显白"], "tone": "亲切"}
captured_system = {}
def fake_call_llm(messages, **kw):
captured_system["final"] = messages[0]["content"]
return STORYBOARD_XML
with patch("packages.shared.ai_service.call_llm", side_effect=fake_call_llm):
result = vv._step_script_generation(job, intent, {})
# fusion_level 对应的指令文本被注入到 system prompt 中
assert FUSION_INSTRUCTIONS[level] in captured_system["final"], f"fusion_level {level} 指令未注入 system_prompt"
# 输出保持 Seedance 兼容结构
assert "overview" in result
assert "shots" in result
assert len(result["shots"]) >= 1
assert result["shots"][0]["shot_type_angle_movement"]
assert result["voiceover_script"]
def test_fallback_when_xml_and_json_unparseable(self, job):
"""XML 解析失败且无法解析为 JSON 时,回退到兜底脚本"""
from apps.worker.worker_app.tasks import viral_video as vv
job.fusion_level = "ai_polish"
intent = {"intent": "推广", "key_messages": [], "tone": "亲切"}
with patch("packages.shared.ai_service.call_llm", return_value="not xml not json"):
result = vv._step_script_generation(job, intent, {})
assert isinstance(result, dict)
assert "voiceover_script" in result
assert "shots" in result
# ── 4) Review 使用 Reviewer + 自动重写 ─────────────────────────────
class TestReviewWiring:
def test_pass_path(self, job):
from apps.worker.worker_app.tasks import viral_video as vv
from packages.application.viral_video.reviewer import Reviewer, ReviewResult
copy_result = {
"title": "口红推荐",
"overview": {"theme": "口红推荐"},
"voiceover_script": "这款口红显白又持久",
"shots": [{"scene_and_dialogue": "展示口红"}],
}
job.intent_result = {"key_messages": ["显白", "持久"], "intent": "推广"}
pass_result = ReviewResult(passed=True, score=90, issues=[], rewrite_suggestions=[])
with patch.object(Reviewer, "review", return_value=pass_result):
out = vv._step_review(job, copy_result)
assert out["passed"] is True
def test_rewrite_path(self, job):
"""审核不通过时触发自动重写,并更新 job.copy_result"""
from apps.worker.worker_app.tasks import viral_video as vv
from packages.application.viral_video.reviewer import Reviewer, ReviewResult
from packages.application.viral_video.schemas import FusionResult, ReviewIssue, ScriptSegment
copy_result = {
"title": "原标题",
"overview": {"theme": "原标题"},
"voiceover_script": "这款口红绝了",
"shots": [{"scene_and_dialogue": "展示"}],
}
job.intent_result = {"key_messages": ["显白"], "intent": "推广"}
fail_result = ReviewResult(
passed=False,
score=50,
issues=[ReviewIssue(dimension="违规词", severity="high", location="开头", text="绝了")],
rewrite_suggestions=["去掉夸大词"],
)
rewritten = FusionResult(
title="新标题",
hook="修改后钩子",
script_segments=[ScriptSegment(text="修改后口播正文")],
cta="行动号召",
word_count=10,
estimated_duration=10,
)
pass_after = ReviewResult(passed=True, score=88, issues=[], rewrite_suggestions=[])
with (
patch.object(Reviewer, "review", side_effect=[fail_result, pass_after]),
patch.object(Reviewer, "rewrite", return_value=rewritten),
):
out = vv._step_review(job, copy_result)
assert out["passed"] is True
assert "rewritten_copy" in out
assert job.generated_copy_text == "修改后口播正文"
# ── 5) 端到端:每个 step 调用 loader 对应 prompt_type ──────────────
class TestEndToEndLoaderUsed:
def test_each_step_calls_loader(self, job):
from apps.worker.worker_app.tasks import viral_video as vv
from packages.application.viral_video import prompt_loader as pl
called_types = []
real_get = pl.get_template
def spy_get(prompt_type, **kwargs):
called_types.append(prompt_type)
return real_get(prompt_type, **kwargs)
v2_product = {
"name": "lipstick",
"brand": "品牌X",
"key_features": ["显白", "持久"],
}
with (
patch.object(pl, "get_template", side_effect=spy_get),
patch.object(vv, "_normalize_image_url", side_effect=lambda raw, idx: raw),
patch(
"worker_app.tasks.vision.analyze_images_v2",
return_value=[v2_product],
create=True,
),
patch("packages.shared.ai_service.call_llm", return_value=INTENT_XML),
):
# 1) image(V2 路径,不再经过 prompt_loader)
img_step = vv._step_image_analysis(job)
img_res = img_step["products"][0]
# 2) intent(走 loader image_analysis? 否——intent_parsing 模板)
intent_res = vv._step_intent_parsing(job, {"products": [img_res]})
# V2 图片分析不再调用 loader;意图解析调用 intent_parsing 模板
assert "image_analysis" not in called_types
assert "intent_parsing" in called_types
# script 和 review 单独验证(需要不同的 LLM 返回)
called_types_2 = []
def spy_get_2(prompt_type, **kwargs):
called_types_2.append(prompt_type)
return real_get(prompt_type, **kwargs)
with (
patch.object(pl, "get_template", side_effect=spy_get_2),
patch("packages.shared.ai_service.call_llm", return_value=STORYBOARD_XML),
):
copy_res = vv._step_script_generation(job, intent_res, {"products": [img_res]})
assert "storyboard" in called_types_2
called_types_3 = []
def spy_get_3(prompt_type, **kwargs):
called_types_3.append(prompt_type)
return real_get(prompt_type, **kwargs)
from packages.application.viral_video.reviewer import Reviewer, ReviewResult
pass_result = ReviewResult(passed=True, score=90, issues=[], rewrite_suggestions=[])
job.intent_result = intent_res
job.copy_result = copy_res
with (
patch.object(pl, "get_template", side_effect=spy_get_3),
patch.object(Reviewer, "review", return_value=pass_result) as mock_review,
):
review_res = vv._step_review(job, copy_res)
# review 步骤内部直接调用 Reviewer.review,该方法被 mock,因此 get_template 不会被调用;
# 此处验证 Reviewer.review 被调用即可说明 review 步骤走通了。
assert mock_review.called, "_step_review 未调用 Reviewer.review"
assert isinstance(review_res, dict) and "passed" in review_res