Compare commits

...

23 Commits

Author SHA1 Message Date
xiaoxia 2ce31a4438 Merge pull request 'fix(viral-video) v1.6.1: P0 渲染卡死根因修复 + P1 VLM 快速降级' (#2148) from fix/2148-p0-render-hang-p1-vlm-fast-fail 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 1s
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 / Frontend Lint (push) 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 / 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 / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (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 / Check push changed paths (push) Successful in 19s
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 / 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 / Build Staging API Image (push) Successful in 49s
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 / PR Build Worker Image (pull_request) Successful in 1m23s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 48s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m10s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m10s
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
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 / Frontend Unit Tests (push) Successful in 3m31s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 4m35s
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m34s
CI/CD Pipeline / Integration Tests (push) Successful in 5m1s
CI/CD Pipeline / Validate - Style (push) Successful in 6m31s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m54s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 7m5s
AI Code Review / AI Code Review (pull_request) Successful in 7m3s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m26s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m44s
CI/CD Pipeline / Unit Tests (push) Successful in 13m21s
CI/CD Pipeline / Validate - Security (push) Successful in 19m54s
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
2026-10-02 17:01:25 +08:00
CI Bot 9a4206e65c 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 / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 3s
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 / 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 43s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m14s
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 1m21s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m6s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 5m41s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 6m22s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 6m36s
AI Code Review / AI Code Review (pull_request) Successful in 6m50s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 13m4s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 10m51s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 15m30s
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) Successful in 1s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 33s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 1m15s
2026-10-02 08:42:16 +00:00
xiaoxia 70aeb5e642 fix(viral-video): P0 渲染卡死 + P1 VLM lite 快速降级(v1.6.1)
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 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 / 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 3m3s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m2s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 3m40s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m52s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 5m31s
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 / Integration Tests (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m27s
AI Code Review / AI Code Review (pull_request) Has been cancelled
P0 根因修复(v9 渲染卡死 20+ min):
1. Seedance 2.5 content 数组协议错误:之前把参考音频/视频放在顶层 reference_audios/reference_videos(非官方字段),
   且首帧图不带 role 导致服务端识别为 first_frame 模式(该模式强制 ratio=adaptive),传入 ratio=9:16 导致任务
   静默排队/失败轮询到 900s 超时。
2. 修复:所有参考(图/音/视)放进 content 数组并带正确 role(reference_image/reference_audio/reference_video);
   首张图根据是否有额外参考自动选择 first_frame vs reference_image 模式。
3. ratio 智能选择:纯首帧无参考→adaptive;omni_reference→按用户 ratio(默认 9:16);
   若创建任务因 ratio 返回 HTTP 400,自动回退 adaptive 重试一次。
4. 轮询 total_timeout 从 900s 收紧到 480s(8min),下载超时 120s;
   celery 任务加 soft_time_limit(render 660s/analyze 240s/generate_copy 180s/pipeline 900s)防挂死。
5. 轮询每 5 次打一次 info 日志,失败时完整打印 error.code/message。
6. _hb_stop 提前声明避免 finally UnboundLocalError。

P1 VLM lite 快速降级:
- lite timeout 从 45s 收紧到 15s,pro 降级固定 25s,总耗时 ≤40s(之前 45+60≈100s)。
- 日志:创建任务时打印 mode(first_frame/omni_ref)、ratio、参考数量。
2026-10-02 16:34:56 +08:00
xiaoxia d707b64876 tune(viral-video): VLM lite timeout 25s→45s (#2147)
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 2s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) 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 / 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 / Check push changed paths (push) Successful in 18s
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 / Build Production API 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 Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 54s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m1s
CI/CD Pipeline / Build Staging API Image (push) 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 / PR Build Worker Image (pull_request) Successful in 1m14s
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 / Build Staging Web Image (push) Successful in 31s
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 34s
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 2m8s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m18s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m15s
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 / ACR Image Cleanup (push) Successful in 1m48s
CI/CD Pipeline / Validate - Style (push) Successful in 5m8s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m21s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 2m53s
AI Code Review / AI Code Review (pull_request) Successful in 7m10s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 4m12s
CI/CD Pipeline / Integration Tests (push) Successful in 8m50s
CI/CD Pipeline / Validate - Security (push) Successful in 11m3s
CI/CD Pipeline / Unit Tests (push) Successful in 12m8s
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-02 15:09:23 +08:00
xiaoxia fe4464df2e Merge pull request 'fix(viral-video): P1 VLM模型ID/僵尸任务心跳/文案兜底; P2 ratio/OSS一致性' (#2146) from fix/2141-p1-vlm-timeout-heartbeat-copy 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 1s
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 / 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 / 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 19s
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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m0s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m20s
CI/CD Pipeline / Integration Tests (push) Successful in 4m20s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (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 / Validate - Python (mypy + alembic) (push) Successful in 5m2s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 5m12s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 5m17s
CI/CD Pipeline / Build Staging API Image (push) Successful in 5m0s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m26s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 5m35s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m29s
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
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
AI Code Review / AI Code Review (pull_request) Successful in 7m15s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m24s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m31s
CI/CD Pipeline / Validate - Style (push) Successful in 8m54s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m43s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 2m47s
CI/CD Pipeline / Validate - Security (push) Successful in 10m52s
CI/CD Pipeline / Unit Tests (push) Successful in 12m28s
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
CI/CD Pipeline / Staging E2E Tests (push) Failing after 25m13s
fix(viral-video): P1 VLM/heartbeat/copy fallback/P2 ratio/OSS (#2146)
2026-10-02 14:36:21 +08:00
CI Bot 0c0fe4619d 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 / Check if frontend-only change (pull_request) Successful in 1s
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 38s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 50s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m5s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m45s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 6m48s
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 (pull_request) Successful in 2m58s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 3m52s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 3m57s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 10m41s
AI Code Review / AI Code Review (pull_request) Successful in 15m53s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 10m20s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 10m40s
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 / Canary Release to Production (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 / Production Browser E2E (pull_request) Has been skipped
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 33s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 5m59s
2026-10-02 06:12:07 +00:00
xiaoxia ad686dcd8b fix(viral-video): P1 VLM模型ID/僵尸任务心跳/文案兜底/P2 ratio映射/OSS一致性
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 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 19s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) 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 / 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 3m24s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m9s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 4m44s
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Style (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 - Security (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
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
P1-1: VLM lite/pro模型ID修正(250915→250315/250328),根因是旧ID不存在导致lite必然超时降级pro
- packages/config/base.py: doubao_vision_model/pro/lite 改为火山方舟官方正确ID
- packages/shared/ai_client.py docstring同步更新
- apps/worker/worker_app/tasks/viral_video.py 硬编码字符串同步
- .env.example 同步新ID

P1-2: worker心跳+僵尸任务超时回收
- packages/domain/viral_video.py: 新增heartbeat_at字段+touch_heartbeat()方法
- packages/adapters/sqlalchemy_impl/models.py: ViralVideoJobModel加heartbeat_at列(index=True)
- packages/adapters/sqlalchemy_impl/viral_video_repository.py: to_entity/save/update映射heartbeat_at
- alembic/versions/092_viral_video_heartbeat.py: 幂等迁移,加列+index+给已有running任务初始化
- apps/worker/worker_app/tasks/viral_video.py:
  - 新增_start_heartbeat_thread后台线程,每25s独立session更新heartbeat_at
  - 新增_recover_stale_jobs(): running>10min且心跳>2min未更新→自动标记failed
  - pipeline/analyze/generate_copy/render四个celery任务接入心跳启停+启动时回收僵尸
- apps/api/app/api/routes/viral_video.py: retry接口放宽,允许对超时僵尸任务重试

P1-3: 文案生成质量与兜底修复
- 兜底脚本'很近'→'最近'(之前commit已改)
- _step_script_generation 三级重试: fast(0.8/2500tok)→fast(0.6/3200tok)→pro(0.7/3500tok)
- 新增fallback判定:口播<20字/含兜底特征串/镜头数<1才视为降级,避免正常短脚本误判
- prompt关键要求新增'输出前自检:口播禁止错别字和语病'
- 关键路径打info日志(模型/label/口播长度/镜头数/是否兜底),便于后续排查

P2-1: Seedance图生视频ratio不生效导致9:16出1:1
- 根因: 旧逻辑Bug #2110在image_url存在时不传ratio,模型默认adaptive→首帧方图商品图输出1:1
- 官方文档确认图生视频支持ratio参数,模型会自动居中裁剪首帧
- packages/shared/ai_client.py+ai_service.py: 删除image_url判空,始终传ratio
- 同步更新docstring注释

P2-2: OSS成片eventual consistency导致completed后NoSuchKey
- apps/worker/worker_app/tasks/viral_video.py: 新增_wait_oss_ready(url,timeout=10s)
- mark_completed前循环HEAD公网URL,等200+content-length>0或10s超时

测试: viral-video相关97个单测全部通过,仅更新test_passes_reference_params_to_client以反映新ratio透传行为
2026-10-02 14:05:48 +08:00
xiaoxia 347cc82ffa style(viral-video): 分镜文案区域紧凑化,一屏展示更多镜头 (#2145)
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 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 3s
CI/CD Pipeline / Check push changed paths (push) Successful in 35s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m32s
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 API Image (pull_request) Successful in 31s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 31s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 58s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m45s
CI/CD Pipeline / Integration Tests (push) Successful in 4m22s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 4m41s
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 / Build Production API 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 Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (push) Successful in 5m37s
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 / Build Staging Web Image (push) Successful in 1m46s
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
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
AI Code Review / AI Code Review (pull_request) Successful in 6m52s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 7m1s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m32s
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
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m23s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m12s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 3m34s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m37s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m53s
CI/CD Pipeline / Validate - Security (push) Successful in 11m20s
CI/CD Pipeline / Unit Tests (push) Successful in 13m21s
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-02 13:57:34 +08:00
xiaoxia d3ee11d27a fix(viral-video): 素材库选择弹窗选中态视觉增强 (#2144)
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 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 push changed paths (push) Successful in 51s
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 / 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 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 1m8s
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 50s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m2s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m18s
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 / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 4m8s
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 / Build Production 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 / Validate - Style (push) Successful in 5m16s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m6s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 4m42s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 52s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m4s
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 2m31s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m59s
CI/CD Pipeline / CI Gate (pull_request) Successful in 1s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m12s
AI Code Review / AI Code Review (pull_request) Successful in 6m30s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m58s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 2m53s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 4m43s
CI/CD Pipeline / Validate - Security (push) Successful in 12m11s
CI/CD Pipeline / Unit Tests (push) Successful in 11m36s
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
2026-10-02 13:42:56 +08:00
xiaoxia 16ef616907 fix(viral-video): 分析结果标签从「商品:」改为「图片N:」按上传顺序编号 (#2143)
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 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 42s
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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m4s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 2m41s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m26s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m53s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m7s
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 2m41s
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 / Build Staging Worker Image (push) Successful in 1m28s
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 / PR Build Web Image (pull_request) Successful in 3m12s
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m27s
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
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 6m59s
CI/CD Pipeline / Validate - Style (push) Successful in 8m1s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 7m45s
AI Code Review / AI Code Review (pull_request) Successful in 6m53s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m41s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 2m51s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 3m17s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m32s
CI/CD Pipeline / Validate - Security (push) Successful in 13m53s
CI/CD Pipeline / Unit Tests (push) Successful in 14m9s
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-02 13:27:37 +08:00
xiaoxia ea51b372af fix(viral-video): 营销目的20项完整列表 + 修复图片大小显示0B (#2142)
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 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Check push changed paths (push) Successful in 20s
CI/CD Pipeline / Check push changed paths (pull_request) 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 / 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 41s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 44s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m49s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m7s
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 - Python (mypy + alembic) (push) Successful in 4m44s
CI/CD Pipeline / Integration Tests (push) Successful in 3m50s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (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 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 / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m37s
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 1m24s
CI/CD Pipeline / Validate - Style (push) Successful in 6m14s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m27s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 3m35s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m17s
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
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
AI Code Review / AI Code Review (pull_request) Successful in 6m29s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m8s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m55s
CI/CD Pipeline / Validate - Security (push) Successful in 10m52s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m23s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 4m41s
CI/CD Pipeline / Unit Tests (push) Successful in 12m46s
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
2026-10-02 13:11:09 +08:00
xiaoxia 9c807444da fix(viral-video): 分析/生成期间不再锁定页面其他控件(P0) (#2141)
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 3s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 5s
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 / Check push changed paths (push) Successful in 27s
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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m5s
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 2m0s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m1s
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 / Validate - Python (mypy + alembic) (push) Successful in 4m41s
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 / 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 / Validate - Style (push) Successful in 5m36s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m42s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m35s
CI/CD Pipeline / Integration Tests (push) Successful in 4m39s
AI Code Review / AI Code Review (pull_request) Successful in 6m58s
CI/CD Pipeline / Unit Tests (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 / 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
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
2026-10-02 13:03:31 +08:00
xiaoxia b31205e965 fix(viral-video): VLM lite失败自动降级pro + 10种IP人设注入prompt (#2139) (#2140)
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 3s
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 - 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 / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 23s
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 / 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 / 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 1m19s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m17s
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 / Build Staging API Image (push) Successful in 1m17s
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m1s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 31s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m46s
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
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m17s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 3m35s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m23s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 3m58s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 4m42s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m41s
CI/CD Pipeline / CI Gate (pull_request) Successful in 27s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m49s
CI/CD Pipeline / Validate - Style (push) Successful in 6m4s
AI Code Review / AI Code Review (pull_request) Successful in 6m53s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m19s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m43s
CI/CD Pipeline / Validate - Security (push) Successful in 8m19s
CI/CD Pipeline / Unit Tests (push) Successful in 11m16s
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 / 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-02 12:32:02 +08:00
xiaoxia b4b53c9e5d fix(viral-video): AI润色模式下user_copy_text未传给后端 (#2139)
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 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 7s
CI/CD Pipeline / Check push changed paths (push) Successful in 31s
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
PR Automation / Auto Approve on CI Green (pull_request) Successful in 1m4s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 54s
CI/CD Pipeline / Build Staging API Image (push) Successful in 1m3s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m5s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 46s
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 46s
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m58s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 3m38s
CI/CD Pipeline / Integration Tests (push) Successful in 4m25s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 4m41s
CI/CD Pipeline / Validate - Style (push) Successful in 5m24s
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) (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
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 / Frontend Unit Tests (push) Successful in 6m9s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m48s
AI Code Review / AI Code Review (pull_request) Successful in 9m33s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m3s
CI/CD Pipeline / Validate - Security (push) Successful in 9m44s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m18s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 4m32s
CI/CD Pipeline / Deploy Production (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 / 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 / Unit Tests (push) Has been cancelled
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-10-02 12:18:35 +08:00
xiaoxia cf0a08f503 fix(viral-video): 补 current_stage 列迁移,修复 staging 500 (#2137) (#2138)
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 / 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 45s
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 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) Successful in 32s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 43s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m40s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 58s
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
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m22s
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 40s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 42s
CI/CD Pipeline / CI Gate (pull_request) Successful in 4s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 3m55s
CI/CD Pipeline / Integration Tests (push) Successful in 3m39s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (push) Successful in 4m47s
AI Code Review / AI Code Review (pull_request) Successful in 7m7s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m3s
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 5m8s
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 (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 / Deploy Staging (Watchtower auto-deploy) (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 / Unit Tests (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-02 12:08:28 +08:00
xiaoxia 3ede4dca1f Merge pull request 'fix(viral-video): #2134 generate-copy 提速到 30-40s + 细粒度 phase/phase_message' (#2136) from fix/2134-generate-copy-speed-phase into develop
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 2s
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 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 / 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 - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (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 Unit Tests (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 17s
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 1m24s
CI/CD Pipeline / Build Staging API Image (push) Successful in 49s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m23s
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 37s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 2m9s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m24s
CI/CD Pipeline / CI Gate (pull_request) Successful in 4s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 54s
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 3m14s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m35s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m16s
CI/CD Pipeline / Integration Tests (push) Successful in 4m23s
CI/CD Pipeline / Validate - Style (push) Successful in 5m29s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m38s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m4s
AI Code Review / AI Code Review (pull_request) Successful in 7m4s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m41s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 4m20s
CI/CD Pipeline / Unit Tests (push) Successful in 11m52s
CI/CD Pipeline / Validate - Security (push) Successful in 13m8s
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-02 11:41:45 +08:00
xiaoxia 133a6c5914 fix(viral-video): 推翻暗色主题改回浅色紫色主题 + 6项UI调整 (#2137)
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 / Check push changed paths (push) Successful in 36s
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 (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 / Integration Tests (push) Successful in 4m56s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m14s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m15s
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 (push) Successful in 1m50s
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 Web Image (push) Successful in 53s
CI/CD Pipeline / Validate - Style (push) Successful in 5m54s
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
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 / 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 / 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 / PR Build API Image (pull_request) Successful in 54s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 51s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m9s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m33s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 51s
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m28s
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 / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m12s
AI Code Review / AI Code Review (pull_request) Successful in 8m30s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m8s
CI/CD Pipeline / Validate - Security (push) Successful in 10m42s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m3s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 4m1s
CI/CD Pipeline / Unit Tests (push) Successful in 12m55s
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
2026-10-02 11:08:47 +08:00
CI Bot 1e8ba91bba style: auto-format with black + isort + ruff + prettier [skip ci-format-check]
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m3s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m50s
AI Code Review / AI Code Review (pull_request) Successful in 6m28s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 11m7s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 34s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 4m31s
2026-10-02 03:06:01 +00:00
xiaoxia 2a739dee17 fix(viral-video): #2134 generate-copy 提速 + 细粒度 phase/phase_message
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 / 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 / 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 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 51s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m7s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m27s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m0s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m9s
CI/CD Pipeline / Validate - Style (pull_request) Failing after 4m41s
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 5m0s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 10m11s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 18m38s
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 Production API 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
问题7(generate-copy 提速,目标 30-40s):
- 新增 doubao_fast_model 配置(默认 doubao-1-5-pro-32k-250115),结构化输出任务(意图解析/编导脚本/合规审核)改用快模型,不再使用慢推理模型 doubao-seed-1-6
- call_llm 扩展支持 model/max_tokens/system_prompt 参数;chat_completion 同步支持 model 覆盖
- 编导脚本 temperature 0.8 + max_tokens 2500(从 4096 收紧);意图解析 max_tokens 800;审核 max_tokens 500
- _SCRIPT_GENERATION_PROMPT 精简冗余描述(前导说明和关键要求章节从 ~70 行压到 ~30 行),减少输入/输出 token
- 合规审核异步后置:阶段2 generate-copy 只做关键字黑名单快速检查(不调用 LLM),LLM 深度审核移到阶段3 confirm-copy TTS 之前执行,不再阻塞前端展示脚本
- 新增 _quick_compliance_blacklist_check 处理常见广告法绝对化用语

问题8(细粒度 phase + phase_message):
- ViralVideoJob 新增 phase_message 字段(中文提示文案,前端轮询直接展示)
- SQLAlchemy ViralVideoJobModel 新增 current_stage/phase_message 列(current_stage 原已有但未持久化更新)
- repo 层 _to_domain/save/update 同步处理新字段
- alembic 090 迁移:幂等 ADD COLUMN phase_message VARCHAR(500)
- 新增 _set_stage 辅助:统一设置 current_stage + phase_message + Redis 推送 + DB 持久化
- 所有 celery task(analyze/generate-copy/render/one-click/resume)在关键节点调用 _set_stage 持久化阶段信息
- 阶段文案:analyzing_images→正在分析商品特征 / parsing_intent→正在解析文案意图 / generating_script→正在编排分镜脚本 / reviewing→合规审核中 / tts→正在合成AI配音 / rendering→正在生成视频 / uploading→正在上传视频
- ViralVideoJobResponse schema + _to_response 增加 current_stage/phase_message,前端轮询 GET /{job_id} 直接拿到

配套:
- .env.example + render_env.sh SHARED_SECRETS 补 DOUBAO_FAST_MODEL
- tests _FakeSettings/_make_job 同步新增字段
- _run_render_pipeline 兜底补生成分支不再同步调用 _step_review(由出片前统一审核处理)
2026-10-02 11:01:01 +08:00
xiaoxia 6b75eb5f67 feat(viral-video): VLM提速(lite+并行) + 商品描述增强(6维度+summary) + 爆款结构19选注入 (#2133)
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 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 8s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 13s
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 13s
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 / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (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 / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m13s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m15s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (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 / 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 / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 59s
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 / Build Staging Worker Image (push) Successful in 42s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m58s
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m26s
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 2m54s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m23s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m32s
CI/CD Pipeline / Validate - Style (push) Successful in 3m42s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m39s
CI/CD Pipeline / Validate - Security (push) Successful in 4m45s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m7s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m55s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m34s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m12s
AI Code Review / AI Code Review (pull_request) Successful in 7m7s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m38s
CI/CD Pipeline / Unit Tests (push) Successful in 10m29s
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-02 10:35:21 +08:00
xiaoxia dbb4e57810 feat(viral-video): v1.6 暗色主题 + 分镜脚本线性文档风格 + STEP3改版 (#2135)
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 3s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
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 / 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
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m0s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 2m39s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m24s
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 / 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 / Build Staging API Image (push) Successful in 1m24s
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 / Integration Tests (push) Successful in 3m9s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m36s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
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 - 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 / 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 / Frontend Unit Tests (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 / CI Gate (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
AI Code Review / AI Code Review (pull_request) Has been cancelled
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-10-02 10:31:36 +08:00
xiaoxia ecb049a57e fix(viral-video): v1.6 UI/交互5项修复 (select双框/锁页/步骤解锁/结构19项/分析结果多行) (#2134)
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 1s
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 3s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Successful in 22s
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 2m16s
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 / Integration Tests (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 / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 56s
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 1m3s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 2m47s
CI/CD Pipeline / Integration Tests (push) Successful in 2m33s
CI/CD Pipeline / Validate - Style (push) Successful in 4m15s
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 API Image (push) Successful in 1m50s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m49s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m48s
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 / CI Gate (pull_request) Successful in 3s
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 6m47s
CI/CD Pipeline / Validate - Security (push) Successful in 5m18s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 7m15s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m39s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m10s
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 / Deploy Staging (Watchtower auto-deploy) (push) Successful in 2m58s
CI/CD Pipeline / Unit Tests (push) Failing after 10m54s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m43s
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 / Staging API Integration Tests (push) Successful in 3m58s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Failing after 4m41s
fix(viral-video): v1.6 UI/交互5项修复

- 问题1 Select单边框:统一由.ant-select-selector承担视觉
- 问题2 分析图片只锁按钮自身
- 问题3 STEP1未完成时控件可操作,仅执行按钮disabled
- 问题6 爆款结构补齐19项
- 问题5 图片分析结果多行全字段展示
- CSS重复规则清理+canEditStep3未使用变量清理
2026-10-02 09:57:38 +08:00
xiaoxia 58d6852a71 fix(viral-video): STEP2 generate-copy 补齐 voice_id/voice_source/video_ratio/video_model (#2132)
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 1s
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 2s
CI/CD Pipeline / Check push changed paths (push) Successful in 12s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m51s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m22s
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
AI Code Review / AI Code Review (pull_request) Successful in 6m59s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 25s
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 Unit Tests (push) Successful in 2m54s
CI/CD Pipeline / Build Staging API Image (push) Successful in 38s
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 / 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 Web Image (pull_request) Successful in 2m57s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 56s
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 Worker Image (pull_request) Successful in 3m54s
CI/CD Pipeline / CI Gate (pull_request) Successful in 2s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m14s
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 3m14s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m11s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m38s
CI/CD Pipeline / Validate - Style (push) Successful in 18m23s
CI/CD Pipeline / Integration Tests (push) Successful in 17m56s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 23m59s
CI/CD Pipeline / Unit Tests (push) Failing after 24m21s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 23m14s
CI/CD Pipeline / Validate - Security (push) Successful in 39m14s
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
三步链路中 STEP2 handleGenerateCopy 之前漏传这四个字段,导致用户选的音色/画幅/模型在文案生成阶段没写回 job;
STEP3 worker TTS 拿不到 voice_id,总是走默认 longxiaochun_v3 兜底,用户选音失效。
2026-10-01 23:30:08 +08:00
20 changed files with 2564 additions and 1866 deletions
+5
View File
@@ -212,9 +212,14 @@ COSYVOICE_CLONE_MODEL=voice-enrollment
DOUBAO_API_KEY=your-doubao-api-key
DOUBAO_MODEL=doubao-seed-1-6-250615
DOUBAO_FAST_MODEL=doubao-1-5-pro-32k-250115
DOUBAO_BASE_URL=https://ark.cn-beijing.volces.com/api/v3
DOUBAO_TIMEOUT=30
DOUBAO_MAX_RETRIES=2
# 视觉模型:pro 精度高,lite 速度快(viral-video 商品识别默认用 lite 提速)
DOUBAO_VISION_MODEL=doubao-1-5-vision-pro-250328
DOUBAO_VISION_LITE_MODEL=doubao-1-5-vision-lite-250315
DOUBAO_VISION_USE_LITE=true
# ==================== 积分/会员系统 (#1895) ====================
# 积分系统总开关:默认 false(暂停积分系统)。
@@ -0,0 +1,35 @@
"""viral video add phase_message column (#2134)
Revision ID: 090_viral_video_phase_msg
Revises: 089_viral_video_cols
Create Date: 2026-10-02
#2134 阶段细粒度提示:viral_video 表新增 phase_message 列(中文阶段提示文案)。
current_stage 列已在之前版本存在,本迁移只补 phase_message。
幂等 ADD COLUMN IF NOT EXISTS。
"""
import sqlalchemy as sa
from alembic import op
revision = "090_viral_video_phase_msg"
down_revision = "089_viral_video_cols"
branch_labels = None
depends_on = None
def upgrade() -> None:
# SQLite/PostgreSQL 兼容的幂等添加列
conn = op.get_bind()
inspector = sa.inspect(conn)
cols = {c["name"] for c in inspector.get_columns("viral_video_jobs")}
if "phase_message" not in cols:
op.add_column(
"viral_video_jobs",
sa.Column("phase_message", sa.String(length=500), nullable=False, server_default=""),
)
def downgrade() -> None:
op.drop_column("viral_video_jobs", "phase_message")
+49
View File
@@ -0,0 +1,49 @@
"""viral video add current_stage column (#2137 follow-up)
Revision ID: 091_viral_video_stage
Revises: 090_viral_video_phase_msg
Create Date: 2026-10-02
#2137 follow-up fix: 090 migration missed current_stage column on viral_video_jobs,
causing UndefinedColumn errors and 500s on all authenticated viral-video endpoints.
Idempotently add current_stage and double-check phase_message.
"""
import sqlalchemy as sa
from alembic import op
revision = "091_viral_video_stage"
down_revision = "090_viral_video_phase_msg"
branch_labels = None
depends_on = None
def upgrade() -> None:
conn = op.get_bind()
inspector = sa.inspect(conn)
cols = {c["name"] for c in inspector.get_columns("viral_video_jobs")}
if "current_stage" not in cols:
op.add_column(
"viral_video_jobs",
sa.Column(
"current_stage",
sa.String(length=200),
nullable=False,
server_default="",
),
)
if "phase_message" not in cols:
op.add_column(
"viral_video_jobs",
sa.Column(
"phase_message",
sa.String(length=500),
nullable=False,
server_default="",
),
)
def downgrade() -> None:
op.drop_column("viral_video_jobs", "current_stage")
@@ -0,0 +1,42 @@
"""viral_video_jobs 增加 heartbeat_at 列(worker 心跳,用于僵尸任务超时回收)
Revision ID: 092_viral_video_heartbeat
Revises: 091_viral_video_stage
Create Date: 2026-10-02
"""
import sqlalchemy as sa
from alembic import op
revision = "092_viral_video_heartbeat"
down_revision = "091_viral_video_stage"
branch_labels = None
depends_on = None
def upgrade() -> None:
conn = op.get_bind()
inspector = sa.inspect(conn)
cols = {c["name"] for c in inspector.get_columns("viral_video_jobs")}
if "heartbeat_at" not in cols:
op.add_column("viral_video_jobs", sa.Column("heartbeat_at", sa.DateTime(), nullable=True))
op.execute(
"UPDATE viral_video_jobs SET heartbeat_at = updated_at " "WHERE status = 'running' AND heartbeat_at IS NULL"
)
try:
op.create_index("ix_viral_video_jobs_heartbeat_at", "viral_video_jobs", ["heartbeat_at"])
except Exception:
pass
def downgrade() -> None:
conn = op.get_bind()
inspector = sa.inspect(conn)
cols = {c["name"] for c in inspector.get_columns("viral_video_jobs")}
if "heartbeat_at" in cols:
try:
op.drop_index("ix_viral_video_jobs_heartbeat_at", table_name="viral_video_jobs")
except Exception:
pass
op.drop_column("viral_video_jobs", "heartbeat_at")
+21 -5
View File
@@ -128,6 +128,8 @@ def _to_response(job) -> ViralVideoJobResponse:
style_guide=job.style_guide,
style_template_id=job.style_template_id,
status=job.status,
current_stage=getattr(job, "current_stage", "") or "",
phase_message=getattr(job, "phase_message", "") or "",
image_analysis=getattr(job, "image_analysis", None),
storyboard=getattr(job, "storyboard", None),
generated_copy_text=getattr(job, "generated_copy_text", "") or "",
@@ -398,28 +400,42 @@ def retry_viral_video_job(
authenticated_user: AuthenticatedUser = Depends(get_current_user),
session: Session = Depends(get_db_session),
) -> ViralVideoJobResponse:
"""重试失败的爆款视频任务。"""
"""重试失败的爆款视频任务(也支持对僵尸/超时 running 任务强制重置后重试)。"""
from datetime import datetime, timezone
repo = _get_job_repo(session)
job = repo.get(job_id)
if job is None:
raise HTTPException(status_code=404, detail="任务不存在")
if job.user_id != authenticated_user.user.id:
raise HTTPException(status_code=403, detail="无权操作此任务")
if job.status != ViralVideoStatus.FAILED:
raise HTTPException(status_code=409, detail="只有失败的任务可以重试")
# 判定是否为僵尸 running 任务:running 超过 10 分钟且心跳停止超过 2 分钟
now = datetime.now(timezone.utc)
is_stale_running = False
if job.status == ViralVideoStatus.RUNNING and job.started_at is not None:
hb = getattr(job, "heartbeat_at", None) or job.updated_at
if (now - job.started_at).total_seconds() > 10 * 60 and hb is not None and (now - hb).total_seconds() > 2 * 60:
is_stale_running = True
if job.status != ViralVideoStatus.FAILED and not is_stale_running:
raise HTTPException(status_code=409, detail="只有失败或超时的任务可以重试")
# 重置状态
job.retry_count += 1
job.status = ViralVideoStatus.PENDING
job.error_msg = ""
job.error_msg = "" if not is_stale_running else "任务执行超时,已重置重试"
job.started_at = None
job.completed_at = None
job.current_stage = ""
job.phase_message = ""
job.heartbeat_at = None
repo.update(job)
# 重新入队
try:
celery_app.send_task("worker.run_viral_video_pipeline", args=[job.id])
logger.info("[爆款视频] 重试入队: job_id=%s retry_count=%d", job.id, job.retry_count)
logger.info("[爆款视频] 重试入队: job_id=%s retry_count=%d stale=%s", job.id, job.retry_count, is_stale_running)
except Exception as e:
logger.error("[爆款视频] 重试入队失败: %s", e, exc_info=True)
job.mark_failed(f"重试入队失败: {e}")
+4
View File
@@ -201,6 +201,10 @@ class ViralVideoJobResponse(BaseModel):
style_guide: dict | None = None
style_template_id: str = ""
status: str
current_stage: str = (
"" # 细粒度阶段 snake_case(analyzing_images/parsing_intent/generating_script/reviewing/tts_synthesizing/rendering_video/uploading)
)
phase_message: str = "" # 中文阶段提示文案(前端轮询/SSE 直接展示)
image_analysis: dict | None = None
# v1.6 编导脚本(推荐前端使用)
copy_result: dict | None = None
File diff suppressed because it is too large Load Diff
+379 -249
View File
@@ -9,8 +9,6 @@ import {
CaretRightOutlined,
VideoCameraOutlined,
SoundOutlined,
BulbOutlined,
ThunderboltOutlined,
ReloadOutlined,
WarningFilled,
SearchOutlined,
@@ -23,6 +21,7 @@ import {
LoadingOutlined,
CheckCircleFilled,
EditOutlined,
HistoryOutlined,
} from "@ant-design/icons"
import { Select, Input, message } from "antd"
import { uploadAssetDirect, getAssetLibraries, getAssetsByKind, type AssetItem } from "@/api/assets"
@@ -72,7 +71,7 @@ type UploadedImage = {
localId: string
url: string
name: string
size: number
size: number | undefined
uploading: boolean
pct: number
ossUrl?: string
@@ -122,6 +121,8 @@ type TabTask = {
// STEP3 设置
videoRatio: string
videoModel: string
quality: string
upscale: string
// UI 状态
uiStep: UIStep
imageAnalysis: ImageAnalysisResult | null
@@ -150,14 +151,61 @@ const TARGET_CUSTOMERS = [
"都市蓝领",
"都市银发",
]
const PERSONAS = ["亲切邻家姐姐", "专业顾问", "搞笑段子手", "真实测评博主", "闺蜜种草", "行业专家"]
const PERSONAS = [
"通用个人IP",
"老板型IP",
"专家型IP",
"顾问型IP",
"创始人IP",
"创业者IP",
"从业者经验派",
"避坑顾问型",
"知识科普型",
"测评种草型",
]
const STRUCTURES = [
"痛点开场→卖点→促单",
"反差对比→证据→促单",
"故事讲述→共鸣→促单",
"专家背书→数据→促单",
"反差破局+亮明观点+还原现状",
"痛点场景植入+给出通关秘籍",
"反常识开场+扎心现状+制造焦虑",
"核心难题+化解焦虑+描绘愿景",
"痛点前置+前后对比+给出期许",
"悬念拉满+揭露危害+明确目的",
"情绪共鸣+勾起好奇+拔高价值",
"颠覆认知+现状拆解+赋予价值",
"结果先行+消除顾虑+保留悬念",
"真实困境+认知反转+传授秘籍",
"反差事实+案例佐证+戳破真相",
"预埋悬念+标杆案例+引出核心",
"危机渲染+放大痛点+输出干货",
"逆袭开场+成功诀窍+低价引流",
"反常识观点+分析危害+描述现状",
"正反对比+解析原因+简易方法",
"真实场景+内心刻画+共情引导+展望未来",
"连续否定+代入感受+打破认知+精准戳痛",
"揭秘行业+类比施压+放大焦虑+精准锁客",
]
const PURPOSES = [
"获客引流",
"账号涨粉",
"活动通知",
"口播带货",
"促销转化",
"场景种草",
"痛点解决",
"功能演示",
"门店发现",
"到店实录",
"招牌体验",
"同城团购",
"品牌主张",
"品牌故事",
"生活方式",
"创意概念",
"对话短剧",
"反转短剧",
"悬念短剧",
"情绪短片",
]
const PURPOSES = ["品牌种草", "新品上市", "促销转化", "活动引流"]
const DURATIONS = [15, 20, 30, 45, 60]
const RATIOS = [
{ v: "9:16", label: "9:16 竖屏(抖音/视频号)" },
@@ -168,6 +216,18 @@ const MODELS = [
{ v: "seedance-2.5", label: "Seedance 2.5(推荐)" },
{ v: "seedance-2.0", label: "Seedance 2.0" },
]
const QUALITY_OPTIONS = [
{ v: "480p", label: "480p(快速)" },
{ v: "720p", label: "720p(清晰)" },
{ v: "1080p", label: "1080p(高清)" },
]
const UPSCALE_OPTIONS = [
{ v: "default", label: "默认" },
{ v: "sd", label: "普清" },
{ v: "hd", label: "高清" },
{ v: "uhd", label: "超清" },
{ v: "omnipotent", label: "全能" },
]
const VOICE_TIPS =
"支持 MP3/WAV/M4A/AAC/OGG 格式,最大 10MB,时长 ≤30 秒。建议清晰人声、无背景音乐、环境安静;录音请保持距麦克风 15-20cm,音量适中。"
@@ -306,7 +366,8 @@ const MOCK_STORYBOARD: Storyboard = {
"还在为餐桌选不到好桌子发愁?这张北美黑胡桃木餐桌,一家人坐下来吃饭刚刚好。全实木、无贴皮,纹理好看又耐刮。点小黄车,给家里添一张好桌子。",
}
const fmtSize = (bytes: number) => {
const fmtSize = (bytes: number | undefined) => {
if (!bytes || bytes <= 0) return "--"
if (bytes < 1024) return `${bytes}B`
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`
return `${(bytes / 1024 / 1024).toFixed(1)}MB`
@@ -327,11 +388,13 @@ const emptyTask = (id: string, title: string): TabTask => ({
targetCustomer: "",
language: "中文(普通话)",
viralStructure: STRUCTURES[0],
marketingPurpose: PURPOSES[0],
marketingPurpose: "",
duration: 15,
persona: "",
videoRatio: "9:16",
videoModel: "seedance-2.5",
quality: "480p",
upscale: "default",
uiStep: "step1_upload",
imageAnalysis: null,
storyboard: null,
@@ -343,6 +406,32 @@ const emptyTask = (id: string, title: string): TabTask => ({
})
/* ─────────── 主页面 ─────────── */
function getCopyStageText(stage: string | undefined): string {
switch (stage) {
case "image_analysis":
case "video_analysis":
case "analyzing_images":
return "🔍 正在分析商品特征..."
case "intent_parsing":
case "generating_outline":
case "planning":
return "📋 正在构思脚本框架..."
case "script_generation":
case "generating_storyboard":
case "writing_shots":
return "🎬 正在生成分镜脚本..."
case "review":
case "generating_copy":
case "writing_copy":
return "✍️ 正在撰写口播文案..."
case "finalizing":
return "✨ 正在优化细节..."
default:
return "🎬 AI 正在创作视频分镜脚本..."
}
}
const ViralVideoPage: React.FC = () => {
const [tasks, setTasks] = useState<TabTask[]>(() => [emptyTask("t1", "生成 1")])
const [activeId, setActiveId] = useState<string>("t1")
@@ -493,8 +582,6 @@ const ViralVideoPage: React.FC = () => {
)
/* ── 图片 ── */
const canEditAssets = task.uiStep === "step1_upload" || task.uiStep === "failed"
const appendImagesFromFiles = useCallback(
async (files: FileList | File[]) => {
const remaining = 9 - task.images.length
@@ -530,7 +617,15 @@ const ViralVideoPage: React.FC = () => {
setTask((t) => ({
...t,
images: t.images.map((im) =>
im.localId === item.localId ? { ...im, uploading: false, pct: 100, ossUrl: url } : im,
im.localId === item.localId
? {
...im,
uploading: false,
pct: 100,
ossUrl: url,
size: item.file!.size || im.size,
}
: im,
),
}))
} catch {
@@ -551,7 +646,7 @@ const ViralVideoPage: React.FC = () => {
localId: `lib_${a.id}_${Math.random().toString(36).slice(2, 6)}`,
url: a.thumbnail_url || a.file_url || "",
name: a.name || "未命名",
size: a.file_size || 0,
size: a.file_size || undefined,
uploading: false,
pct: 100,
ossUrl: a.file_url || undefined,
@@ -788,7 +883,9 @@ const ViralVideoPage: React.FC = () => {
duration: task.duration,
persona_id: task.persona || undefined,
user_copy_text:
task.fusionLevel === "user_primary" && task.userCopy ? task.userCopy : undefined,
(task.fusionLevel === "user_primary" || task.fusionLevel === "ai_polish") && task.userCopy
? task.userCopy
: undefined,
fusion_level: task.fusionLevel,
style_strength: task.refVideo?.ossUrl ? task.styleStrength : undefined,
voice_id: task.refAudio?.source === "preset" ? task.refAudio.id : undefined,
@@ -895,10 +992,6 @@ const ViralVideoPage: React.FC = () => {
const outputUrl = task.job?.output_url || task.job?.result_video_url
const errMsg = task.videoError || task.job?.error_message || task.job?.error_msg
const canEditStep2 =
task.uiStep !== "step2_generating" &&
task.uiStep !== "step3_generating" &&
task.uiStep !== "step3_done"
const step2Enabled =
task.uiStep === "step1_done" ||
task.uiStep === "step2_generating" ||
@@ -943,24 +1036,61 @@ const ViralVideoPage: React.FC = () => {
</div>
{products.map((p, i) => (
<div key={i} className="vv-recog-item">
{p.name && (
<div className="vv-recog-line">
<span className="vv-recog-k">图片{i + 1}:</span>
<span>
{p.name || "未识别"}
{p.spec && <span className="vv-recog-meta">({p.spec})</span>}
{p.brand && <span className="vv-recog-meta"> · {p.brand}</span>}
{p.category && <span className="vv-recog-meta"> · {p.category}</span>}
</span>
</div>
{featureText(p.key_features ?? p.features) && (
<div className="vv-recog-line">
<span className="vv-recog-k">商品:</span>
<span>{p.name}</span>
{p.spec && <span style={{ color: "#6b7280" }}>({p.spec})</span>}
{p.brand && <span style={{ color: "#6b7280" }}> · {p.brand}</span>}
<span className="vv-recog-k">核心特征:</span>
<span className="vv-recog-v">{featureText(p.key_features ?? p.features)}</span>
</div>
)}
{featureText(p.features) && (
{p.colors && p.colors.length > 0 && (
<div className="vv-recog-line">
<span className="vv-recog-k">视觉特征:</span>
<span>{featureText(p.features)}</span>
<span className="vv-recog-k">主色调:</span>
<span className="vv-recog-v">{p.colors.join(" / ")}</span>
</div>
)}
{p.label_text && (
{p.material_or_texture && (
<div className="vv-recog-line">
<span className="vv-recog-k">品牌/标签文字:</span>
<span>{p.label_text}</span>
<span className="vv-recog-k">材质/纹理:</span>
<span className="vv-recog-v">{p.material_or_texture}</span>
</div>
)}
{p.visual_style && (
<div className="vv-recog-line">
<span className="vv-recog-k">视觉风格:</span>
<span className="vv-recog-v">{p.visual_style}</span>
</div>
)}
{p.scene && (
<div className="vv-recog-line">
<span className="vv-recog-k">场景:</span>
<span className="vv-recog-v">{p.scene}</span>
</div>
)}
{p.target_audience_hint && (
<div className="vv-recog-line">
<span className="vv-recog-k">目标人群:</span>
<span className="vv-recog-v">{p.target_audience_hint}</span>
</div>
)}
{(p.text_on_image || p.label_text) && (
<div className="vv-recog-line">
<span className="vv-recog-k">包装文字:</span>
<span className="vv-recog-v">{p.text_on_image || p.label_text}</span>
</div>
)}
{p.selling_points && (
<div className="vv-recog-line">
<span className="vv-recog-k">卖点:</span>
<span className="vv-recog-v">{p.selling_points}</span>
</div>
)}
</div>
@@ -1009,8 +1139,11 @@ const ViralVideoPage: React.FC = () => {
if (task.uiStep === "step2_generating") {
return (
<div className="vv-copy-box vv-copy-loading">
<LoadingOutlined style={{ color: "#7c3aed", fontSize: 18, marginRight: 8 }} />
<span>AI 正在创作视频分镜脚本…</span>
<span className="vv-spinner" />
<span className="vv-copy-loading-text">
{task.job?.progress_message || getCopyStageText(task.job?.progress_stage)}
</span>
<span className="vv-copy-loading-hint">预计 10-30 秒,请稍候</span>
</div>
)
}
@@ -1049,160 +1182,160 @@ const ViralVideoPage: React.FC = () => {
) {
return null
}
const locked = task.uiStep === "step3_generating" || task.uiStep === "step3_done"
const locked = false
const isMockPreview = sb === MOCK_STORYBOARD
return (
<div className="vv-copy-box vv-storyboard">
<div className="vv-copy-head">
<EditOutlined style={{ color: "#7c3aed" }} />
<span className="vv-copy-title">AI 分镜脚本</span>
{isMockPreview && (
<span className="vv-copy-tag vv-copy-tag-preview">
示例预览 · 等后端输出新结构后自动替换
</span>
)}
</div>
{/* 1. 总览卡片 */}
<div className="vv-sb-overview">
<div className="vv-sb-ov-field">
<label>主题</label>
<div className="vv-sb-doc">
{/* 视频总览 */}
<h4 className="vv-sb-h">视频总览</h4>
<div className="vv-sb-kv">
<span className="vv-sb-k">整体主题:</span>
<input
className="vv-input vv-sb-input"
className="vv-sb-inline vv-sb-inline-input"
value={sb.overview.theme}
disabled={locked}
onChange={(e) => updateOverview({ theme: e.target.value })}
/>
</div>
<div className="vv-sb-ov-field">
<label>总时长</label>
<div className="vv-sb-kv">
<span className="vv-sb-k">总时长:</span>
<input
className="vv-input vv-sb-input"
className="vv-sb-inline vv-sb-inline-input"
value={sb.overview.total_duration}
disabled={locked}
onChange={(e) => updateOverview({ total_duration: e.target.value })}
/>
</div>
<div className="vv-sb-ov-field">
<label>画幅</label>
<div className="vv-sb-kv">
<span className="vv-sb-k">画幅:</span>
<Select
className="vv-select vv-select-purple vv-sb-input"
style={{ width: "100%" }}
className="vv-select vv-sb-inline-select"
style={{ width: 200 }}
value={sb.overview.aspect_ratio}
disabled={locked}
onChange={(v) => updateOverview({ aspect_ratio: v })}
options={RATIOS.map((r) => ({ value: r.v, label: r.label }))}
options={RATIOS.map((r) => ({ value: r.v, label: r.v }))}
variant="borderless"
/>
</div>
</div>
{/* 2. 场景与光线 */}
<div className="vv-sb-section">
<div className="vv-sb-section-title">
<BulbOutlined style={{ color: "#7c3aed" }} /> 场景与光线
</div>
{/* 场景与光线 */}
<h4 className="vv-sb-h">场景与光线</h4>
<textarea
className="vv-textarea"
className="vv-textarea vv-sb-doc-ta"
value={sb.scene_and_lighting}
disabled={locked}
onChange={(e) => updateStoryboard({ scene_and_lighting: e.target.value })}
placeholder="描述整体场景氛围、光线方向与色温…"
/>
</div>
{/* 3. 逐镜头卡片 */}
<div className="vv-sb-section">
<div className="vv-sb-section-title">
<VideoCameraOutlined style={{ color: "#7c3aed" }} /> 逐镜头拆解({sb.shots.length} 镜)
</div>
<div className="vv-sb-shots">
{/* 逐镜头 */}
<h4 className="vv-sb-h">逐秒镜头拆解</h4>
<div className="vv-sb-doc-shots">
{sb.shots.map((sh, idx) => {
const refImg =
typeof sh.reference_image_index === "number"
? task.images[sh.reference_image_index]
: undefined
return (
<div key={idx} className="vv-sb-shot">
<div className="vv-sb-shot-head">
<span className="vv-sb-shot-num">镜头 {idx + 1}</span>
<div key={idx} className="vv-sb-doc-shot">
<div className="vv-sb-doc-shot-head">
<input
className="vv-sb-time"
className="vv-sb-time-doc"
value={sh.time_range}
disabled={locked}
onChange={(e) => updateShot(idx, { time_range: e.target.value })}
placeholder="0-3秒"
/>
</div>
<div className="vv-sb-shot-grid">
<div className="vv-sb-cell">
<label>景别 / 运镜</label>
<textarea
className="vv-textarea vv-sb-cell-ta"
value={sh.shot_type_angle_movement}
disabled={locked}
onChange={(e) =>
updateShot(idx, { shot_type_angle_movement: e.target.value })
}
/>
</div>
<div className="vv-sb-cell vv-sb-cell-wide">
<label>场景与对白</label>
<textarea
className="vv-textarea vv-sb-cell-ta"
value={sh.scene_and_dialogue}
disabled={locked}
onChange={(e) => updateShot(idx, { scene_and_dialogue: e.target.value })}
/>
</div>
<div className="vv-sb-cell">
<label>动作细节</label>
<textarea
className="vv-textarea vv-sb-cell-ta"
value={sh.action_details}
disabled={locked}
onChange={(e) => updateShot(idx, { action_details: e.target.value })}
/>
</div>
<div className="vv-sb-cell">
<label>音效 / BGM</label>
<textarea
className="vv-textarea vv-sb-cell-ta"
value={sh.audio_bgm}
disabled={locked}
onChange={(e) => updateShot(idx, { audio_bgm: e.target.value })}
/>
</div>
<div className="vv-sb-cell">
<label>转场</label>
<textarea
className="vv-textarea vv-sb-cell-ta"
value={sh.transition}
disabled={locked}
onChange={(e) => updateShot(idx, { transition: e.target.value })}
/>
</div>
<div className="vv-sb-cell vv-sb-ref">
<label>参考图</label>
<div className="vv-sb-ref-box">
{refImg?.url ? (
<img src={refImg.url} alt={`ref-${idx}`} className="vv-sb-ref-img" />
) : (
<span className="vv-sb-ref-empty">未指定</span>
<div className="vv-sb-kv">
<span className="vv-sb-k">景别/角度与运镜:</span>
<textarea
className="vv-textarea vv-sb-doc-ta vv-sb-doc-ta-sm"
value={sh.shot_type_angle_movement}
disabled={locked}
onChange={(e) =>
updateShot(idx, { shot_type_angle_movement: e.target.value })
}
/>
</div>
<div className="vv-sb-kv">
<span className="vv-sb-k">场景与对白:</span>
<textarea
className="vv-textarea vv-sb-doc-ta"
value={sh.scene_and_dialogue}
disabled={locked}
onChange={(e) => updateShot(idx, { scene_and_dialogue: e.target.value })}
/>
</div>
<div className="vv-sb-kv">
<span className="vv-sb-k">动作与真人细节:</span>
<textarea
className="vv-textarea vv-sb-doc-ta vv-sb-doc-ta-sm"
value={sh.action_details}
disabled={locked}
onChange={(e) => updateShot(idx, { action_details: e.target.value })}
/>
</div>
<div className="vv-sb-kv">
<span className="vv-sb-k">音效/BGM:</span>
<textarea
className="vv-textarea vv-sb-doc-ta vv-sb-doc-ta-sm"
value={sh.audio_bgm}
disabled={locked}
onChange={(e) => updateShot(idx, { audio_bgm: e.target.value })}
/>
</div>
<div className="vv-sb-kv">
<span className="vv-sb-k">转场:</span>
<textarea
className="vv-textarea vv-sb-doc-ta vv-sb-doc-ta-sm"
value={sh.transition}
disabled={locked}
onChange={(e) => updateShot(idx, { transition: e.target.value })}
/>
</div>
<div className="vv-sb-kv vv-sb-kv-ref">
<span className="vv-sb-k">参考图片:</span>
{refImg?.url ? (
<span className="vv-sb-ref-badge">
<img src={refImg.url} alt={`ref-${idx}`} className="vv-sb-ref-thumb" />
{!locked && (
<button
className="vv-sb-ref-x"
onClick={() => updateShot(idx, { reference_image_index: undefined })}
aria-label="移除参考图"
>
×
</button>
)}
</div>
</div>
</span>
) : !locked && task.images.length > 0 ? (
<span className="vv-sb-ref-pick">
{task.images.map((im, i) => (
<button
key={im.localId}
className="vv-sb-ref-opt"
onClick={() => updateShot(idx, { reference_image_index: i })}
title={`@图片${i + 1}`}
>
<img src={im.url} alt={`img${i}`} />
</button>
))}
</span>
) : (
<span className="vv-sb-muted">未指定</span>
)}
</div>
</div>
)
})}
</div>
</div>
{/* 4. 硬性约束 */}
<div className="vv-sb-section">
<div className="vv-sb-section-title">
<ThunderboltOutlined style={{ color: "#7c3aed" }} /> 硬性约束
</div>
{/* 硬性约束 */}
<h4 className="vv-sb-h">硬性约束</h4>
<div className="vv-sb-taglist">
{sb.hard_constraints.map((c, i) => (
<span key={i} className="vv-sb-tag vv-sb-tag-hard">
@@ -1229,13 +1362,9 @@ const ViralVideoPage: React.FC = () => {
</button>
)}
</div>
</div>
{/* 5. 负面提示词 */}
<div className="vv-sb-section">
<div className="vv-sb-section-title">
<CloseOutlined style={{ color: "#ef4444" }} /> 负面提示词
</div>
{/* 负面提示词 */}
<h4 className="vv-sb-h">负面提示词</h4>
<div className="vv-sb-taglist">
{sb.negative_prompts.map((c, i) => (
<span key={i} className="vv-sb-tag vv-sb-tag-neg">
@@ -1262,20 +1391,18 @@ const ViralVideoPage: React.FC = () => {
</button>
)}
</div>
</div>
{/* 6. 完整口播稿(折叠) */}
<div className="vv-sb-section">
<button className="vv-sb-collapse" onClick={() => setVoOpen(!voOpen)}>
<span>
{/* 完整口播稿(可折叠) */}
<h4 className="vv-sb-h">
<button className="vv-sb-doc-collapse" onClick={() => setVoOpen(!voOpen)} type="button">
<SoundOutlined style={{ color: "#7c3aed", marginRight: 6 }} />
完整口播稿(TTS 合成使用)
</span>
<span className={`vv-sb-caret ${voOpen ? "open" : ""}`}>▾</span>
</button>
<span className={`vv-sb-caret ${voOpen ? "open" : ""}`}>▾</span>
</button>
</h4>
{voOpen && (
<textarea
className="vv-textarea vv-sb-vo"
className="vv-textarea vv-sb-doc-ta vv-sb-vo"
value={sb.voiceover_script}
disabled={locked}
onChange={(e) => updateStoryboard({ voiceover_script: e.target.value })}
@@ -1284,16 +1411,18 @@ const ViralVideoPage: React.FC = () => {
)}
</div>
{/* 7. 重新生成按钮(ghost) */}
{task.uiStep === "step2_copy_ready" && (
<button
className="vv-btn vv-btn-ghost vv-btn-block"
onClick={handleGenerateCopy}
style={{ marginTop: 12 }}
>
<ReloadOutlined /> 重新生成文案
</button>
)}
<div className="vv-sb-actions">
{isMockPreview && (
<span className="vv-copy-tag vv-copy-tag-preview">
示例预览 · 后端新结构就绪后自动替换
</span>
)}
{task.uiStep === "step2_copy_ready" && (
<button className="vv-btn vv-btn-ghost" onClick={handleGenerateCopy}>
<ReloadOutlined /> 重新生成文案
</button>
)}
</div>
</div>
)
}
@@ -1341,17 +1470,12 @@ const ViralVideoPage: React.FC = () => {
<div className="vv-section-body" style={{ paddingTop: 4 }}>
{/* 图片按钮 */}
<div className="vv-action-row">
<button
className="vv-action-btn"
onClick={() => imgInputRef.current?.click()}
disabled={!canEditAssets}
>
<button className="vv-action-btn" onClick={() => imgInputRef.current?.click()}>
<UploadOutlined /> 本地上传
</button>
<button
className="vv-action-btn"
onClick={() => setAssetPicker({ open: true, kind: "image", multiple: true })}
disabled={!canEditAssets}
>
<FolderOpenOutlined /> 从素材库选择图片
</button>
@@ -1373,7 +1497,7 @@ const ViralVideoPage: React.FC = () => {
已选 <strong style={{ color: "#111827" }}>{task.images.length}</strong>/9
</span>
{task.images.length > 0 && (
<button className="vv-link-btn" onClick={clearImages} disabled={!canEditAssets}>
<button className="vv-link-btn" onClick={clearImages}>
清空图片
</button>
)}
@@ -1406,7 +1530,7 @@ const ViralVideoPage: React.FC = () => {
<button
className="vv-icon-btn"
onClick={() => moveImg(i, -1)}
disabled={i === 0 || im.uploading || !canEditAssets}
disabled={i === 0 || im.uploading}
title="上移"
>
<ArrowUpOutlined />
@@ -1414,7 +1538,7 @@ const ViralVideoPage: React.FC = () => {
<button
className="vv-icon-btn"
onClick={() => moveImg(i, 1)}
disabled={i === task.images.length - 1 || im.uploading || !canEditAssets}
disabled={i === task.images.length - 1 || im.uploading}
title="下移"
>
<ArrowDownOutlined />
@@ -1422,7 +1546,7 @@ const ViralVideoPage: React.FC = () => {
<button
className="vv-icon-btn vv-icon-btn-danger"
onClick={() => removeImg(im.localId)}
disabled={im.uploading || !canEditAssets}
disabled={!!im.uploading}
title="删除"
>
<CloseOutlined />
@@ -1441,11 +1565,7 @@ const ViralVideoPage: React.FC = () => {
<span className="vv-subblock-hint">最大 200MB · 最长 120 秒</span>
</div>
<div className="vv-action-row">
<button
className="vv-action-btn"
onClick={() => videoInputRef.current?.click()}
disabled={!canEditAssets}
>
<button className="vv-action-btn" onClick={() => videoInputRef.current?.click()}>
<UploadOutlined /> 本地上传视频
</button>
<button
@@ -1453,7 +1573,6 @@ const ViralVideoPage: React.FC = () => {
onClick={() =>
setTask({ voicePanel: task.voicePanel === "douyin" ? null : "douyin" })
}
disabled={!canEditAssets}
>
<LinkOutlined /> 抖音链接识别
</button>
@@ -1504,11 +1623,7 @@ const ViralVideoPage: React.FC = () => {
</div>
)}
</div>
<button
className="vv-link-btn"
onClick={removeRefVideo}
disabled={!canEditAssets}
>
<button className="vv-link-btn" onClick={removeRefVideo}>
删除重传
</button>
{task.refVideo.ossUrl && (
@@ -1522,7 +1637,6 @@ const ViralVideoPage: React.FC = () => {
key={s.value}
className={`vv-pill ${task.styleStrength === s.value ? "active" : ""}`}
onClick={() => setTask({ styleStrength: s.value })}
disabled={!canEditAssets}
>
{s.label}
</button>
@@ -1545,7 +1659,6 @@ const ViralVideoPage: React.FC = () => {
<button
className={`vv-audio-cell ${task.refAudio?.source === "preset" ? "selected" : ""}`}
onClick={() => setVoicePickerOpen(true)}
disabled={!canEditAssets}
>
<FileTextOutlined className="vv-audio-ic" />
<span>选择内置音色</span>
@@ -1553,7 +1666,6 @@ const ViralVideoPage: React.FC = () => {
<button
className={`vv-audio-cell ${task.voicePanel === "upload" ? "active" : ""} ${task.refAudio?.source === "upload" ? "selected" : ""}`}
onClick={() => voiceInputRef.current?.click()}
disabled={!canEditAssets}
>
<UploadOutlined className="vv-audio-ic" />
<span>本地上传</span>
@@ -1561,7 +1673,6 @@ const ViralVideoPage: React.FC = () => {
<button
className={`vv-audio-cell ${task.voicePanel === "library" ? "active" : ""} ${task.refAudio?.source === "library" ? "selected" : ""}`}
onClick={() => setAssetPicker({ open: true, kind: "voice", multiple: false })}
disabled={!canEditAssets}
>
<FolderOpenOutlined className="vv-audio-ic" />
<span>从素材库选择</span>
@@ -1569,7 +1680,6 @@ const ViralVideoPage: React.FC = () => {
<button
className={`vv-audio-cell ${task.voicePanel === "record" ? "active" : ""} ${task.refAudio?.source === "clone" ? "selected" : ""}`}
onClick={() => setCloneModalOpen(true)}
disabled={!canEditAssets}
>
<AudioMutedOutlined className="vv-audio-ic" />
<span>直接录音</span>
@@ -1589,11 +1699,7 @@ const ViralVideoPage: React.FC = () => {
<div className="vv-selected-audio">
<SoundOutlined style={{ color: "#7c3aed", marginRight: 6 }} />
<span style={{ flex: 1 }}>已选:{task.refAudio.name}</span>
<button
className="vv-link-btn"
onClick={() => setTask({ refAudio: null })}
disabled={!canEditAssets}
>
<button className="vv-link-btn" onClick={() => setTask({ refAudio: null })}>
移除
</button>
</div>
@@ -1689,7 +1795,7 @@ const ViralVideoPage: React.FC = () => {
</div>
{/* ═══════════ 中列 STEP 2 ═══════════ */}
<div className={`vv-col ${step2Enabled ? "" : "vv-col-disabled"}`}>
<div className="vv-col">
<div className="vv-section">
<div className="vv-step-subhead">
<span className={`vv-step-badge ${step2Enabled ? "" : "vv-step-badge-dim"}`}>2</span>
@@ -1705,22 +1811,27 @@ const ViralVideoPage: React.FC = () => {
key={f.value}
className={`vv-fusion-btn ${task.fusionLevel === f.value ? "active" : ""}`}
onClick={() => setTask({ fusionLevel: f.value })}
disabled={!canEditStep2 || !step2Enabled}
>
<strong>{f.label}</strong>
{f.desc}
</button>
))}
</div>
{task.fusionLevel === "user_primary" && (
{(task.fusionLevel === "ai_polish" || task.fusionLevel === "user_primary") && (
<div className="vv-form-row">
<label className="vv-label">写下你的文案/草稿</label>
<label className="vv-label">
{task.fusionLevel === "ai_polish" ? "写下你的文案草稿" : "写下你的文案/草稿"}
</label>
<textarea
key={task.fusionLevel}
className="vv-textarea"
placeholder="请输入你想要的原始文案,AI 将严格保留你的表达"
placeholder={
task.fusionLevel === "ai_polish"
? "请输入你的文案草稿,AI将在此基础上润色优化..."
: "请输入你想要的原始文案,AI将严格保留你的表达..."
}
value={task.userCopy}
onChange={(e) => setTask({ userCopy: e.target.value })}
disabled={!canEditStep2 || !step2Enabled}
/>
</div>
)}
@@ -1736,77 +1847,71 @@ const ViralVideoPage: React.FC = () => {
placeholder="如:家具店、宠物店、装修公司"
value={task.industry}
onChange={(e) => setTask({ industry: e.target.value })}
disabled={!canEditStep2 || !step2Enabled}
/>
</div>
<div className="vv-form-row">
<label className="vv-label">目标客户</label>
<Select
className="vv-select vv-select-purple"
className="vv-select"
style={{ width: "100%" }}
placeholder="请选择目标客户"
value={task.targetCustomer || undefined}
onChange={(v) => setTask({ targetCustomer: v })}
options={TARGET_CUSTOMERS.map((i) => ({ value: i, label: i }))}
allowClear
disabled={!canEditStep2 || !step2Enabled}
/>
</div>
<div className="vv-form-row">
<label className="vv-label">台词语言</label>
<Select
className="vv-select vv-select-purple"
className="vv-select"
style={{ width: "100%" }}
value={task.language}
onChange={(v) => setTask({ language: v })}
options={LANGUAGES.map((i) => ({ value: i, label: i }))}
disabled={!canEditStep2 || !step2Enabled}
/>
</div>
<div className="vv-form-row">
<label className="vv-label">我的人设</label>
<Select
className="vv-select vv-select-purple"
className="vv-select"
style={{ width: "100%" }}
placeholder="请选择人设"
placeholder="请选择人设类型"
optionFilterProp="children"
value={task.persona || undefined}
onChange={(v) => setTask({ persona: v })}
options={PERSONAS.map((i) => ({ value: i, label: i }))}
allowClear
disabled={!canEditStep2 || !step2Enabled}
/>
</div>
<div className="vv-form-row">
<label className="vv-label">爆款结构</label>
<Select
className="vv-select vv-select-purple"
className="vv-select"
style={{ width: "100%" }}
value={task.viralStructure}
onChange={(v) => setTask({ viralStructure: v })}
options={STRUCTURES.map((i) => ({ value: i, label: i }))}
disabled={!canEditStep2 || !step2Enabled}
/>
</div>
<div className="vv-form-row">
<label className="vv-label">营销目的</label>
<Select
className="vv-select vv-select-purple"
className="vv-select"
style={{ width: "100%" }}
value={task.marketingPurpose}
placeholder="请选择营销目的"
value={task.marketingPurpose || undefined}
onChange={(v) => setTask({ marketingPurpose: v })}
options={PURPOSES.map((i) => ({ value: i, label: i }))}
disabled={!canEditStep2 || !step2Enabled}
/>
</div>
<div className="vv-form-row" style={{ gridColumn: "1 / -1" }}>
<label className="vv-label">文案视频时长</label>
<Select
className="vv-select vv-select-purple"
className="vv-select"
style={{ width: "100%" }}
value={task.duration}
onChange={(v) => setTask({ duration: v })}
options={DURATIONS.map((n) => ({ value: n, label: `${n}秒` }))}
disabled={!canEditStep2 || !step2Enabled}
/>
</div>
</div>
@@ -1860,43 +1965,68 @@ const ViralVideoPage: React.FC = () => {
</div>
{/* ═══════════ 右列 STEP 3 ═══════════ */}
<div className={`vv-col ${step3Enabled ? "" : "vv-col-disabled"}`}>
<div className="vv-col">
<div className="vv-section">
<div className="vv-step-subhead">
<span className={`vv-step-badge ${step3Enabled ? "" : "vv-step-badge-dim"}`}>3</span>
<span className="vv-step-subtitle">STEP 3 视频设置并生成视频</span>
<div className="vv-step-subhead vv-step3-head">
<div className="vv-step3-head-left">
<span className={`vv-step-badge ${step3Enabled ? "" : "vv-step-badge-dim"}`}>
3
</span>
<span className="vv-step-subtitle">STEP 3 生成视频</span>
</div>
{step3Enabled && (
<button
className="vv-btn vv-btn-ghost vv-btn-xs vv-history-btn"
onClick={() => message.info("历史作品功能开发中")}
>
<HistoryOutlined /> 历史作品
</button>
)}
{!step3Enabled && <span className="vv-step-lock">请先完成 STEP 2</span>}
</div>
<div className="vv-step3-divider" />
<div className="vv-section-body">
<div className="vv-form-row">
<label className="vv-label">视频比例</label>
<Select
className="vv-select"
style={{ width: "100%" }}
value={task.videoRatio}
onChange={(v) => setTask({ videoRatio: v })}
options={RATIOS.map((r) => ({ value: r.v, label: r.label }))}
disabled={
!step3Enabled ||
task.uiStep === "step3_generating" ||
task.uiStep === "step3_done"
}
/>
</div>
<div className="vv-form-row">
<label className="vv-label">生成模型</label>
<Select
className="vv-select"
style={{ width: "100%" }}
value={task.videoModel}
onChange={(v) => setTask({ videoModel: v })}
options={MODELS.map((m) => ({ value: m.v, label: m.label }))}
disabled={
!step3Enabled ||
task.uiStep === "step3_generating" ||
task.uiStep === "step3_done"
}
/>
<div className="vv-step3-grid">
<div className="vv-form-row">
<label className="vv-label">视频比例</label>
<Select
className="vv-select vv-select-step3"
style={{ width: "100%" }}
value={task.videoRatio}
onChange={(v) => setTask({ videoRatio: v })}
options={RATIOS.map((r) => ({ value: r.v, label: r.v }))}
/>
</div>
<div className="vv-form-row">
<label className="vv-label">视频模型</label>
<Select
className="vv-select vv-select-step3"
style={{ width: "100%" }}
value={task.videoModel}
onChange={(v) => setTask({ videoModel: v })}
options={MODELS.map((m) => ({ value: m.v, label: m.label }))}
/>
</div>
<div className="vv-form-row">
<label className="vv-label">清晰度</label>
<Select
className="vv-select vv-select-step3"
style={{ width: "100%" }}
value={task.quality}
onChange={(v) => setTask({ quality: v })}
options={QUALITY_OPTIONS.map((m) => ({ value: m.v, label: m.label }))}
/>
</div>
<div className="vv-form-row">
<label className="vv-label">成片超分</label>
<Select
className="vv-select vv-select-step3"
style={{ width: "100%" }}
value={task.upscale}
onChange={(v) => setTask({ upscale: v })}
options={UPSCALE_OPTIONS.map((m) => ({ value: m.v, label: m.label }))}
/>
</div>
</div>
</div>
</div>
File diff suppressed because it is too large Load Diff
@@ -950,6 +950,9 @@ class ViralVideoJobModel(Base):
video_model = Column(String(100), nullable=False, default="")
# 结果与状态
status = Column(String(30), nullable=False, default="pending", index=True)
current_stage = Column(String(200), nullable=False, default="") # 细粒度阶段 snake_case
phase_message = Column(String(500), nullable=False, default="") # 阶段中文提示文案
heartbeat_at = Column(DateTime, nullable=True, index=True) # worker 心跳,用于僵尸任务超时回收
intent_result = Column(JSON, nullable=True)
image_analysis = Column(JSON, nullable=True)
storyboard = Column(JSON, nullable=True)
@@ -37,6 +37,9 @@ def _to_domain(model: ViralVideoJobModel) -> ViralVideoJob:
video_ratio=getattr(model, "video_ratio", "9:16") or "9:16",
video_model=getattr(model, "video_model", "") or "",
status=ViralVideoStatus(model.status) if model.status else ViralVideoStatus.PENDING,
current_stage=getattr(model, "current_stage", "") or "",
phase_message=getattr(model, "phase_message", "") or "",
heartbeat_at=getattr(model, "heartbeat_at", None),
intent_result=dict(model.intent_result) if model.intent_result else None,
image_analysis=dict(model.image_analysis) if getattr(model, "image_analysis", None) else None,
storyboard=list(model.storyboard) if getattr(model, "storyboard", None) else None,
@@ -83,6 +86,9 @@ class SQLAlchemyViralVideoJobRepository:
video_ratio=job.video_ratio,
video_model=job.video_model,
status=job.status,
current_stage=job.current_stage or "",
phase_message=job.phase_message or "",
heartbeat_at=job.heartbeat_at,
intent_result=job.intent_result,
image_analysis=job.image_analysis,
storyboard=job.storyboard,
@@ -106,6 +112,9 @@ class SQLAlchemyViralVideoJobRepository:
if model is None:
raise ValueError(f"ViralVideoJob {job.id} not found")
model.status = job.status
model.current_stage = job.current_stage or ""
model.phase_message = job.phase_message or ""
model.heartbeat_at = job.heartbeat_at
model.intent_result = job.intent_result
model.image_analysis = job.image_analysis
model.storyboard = job.storyboard
+5 -2
View File
@@ -90,11 +90,14 @@ class SharedSettings(BaseSettings):
# ── 豆包大模型(火山引擎方舟) ────────────────────────────────────────
doubao_api_key: str = ""
doubao_model: str = "doubao-seed-1-6-250615"
doubao_model: str = "doubao-seed-1-6-250615" # 推理模型(通用兜底)
doubao_fast_model: str = "doubao-1-5-pro-32k-250115" # 快速结构化输出模型(编导脚本/意图解析/审核)
doubao_base_url: str = "https://ark.cn-beijing.volces.com/api/v3"
doubao_timeout: int = 30
doubao_max_retries: int = 2
doubao_vision_model: str = "doubao-1-5-vision-pro-250915"
doubao_vision_model: str = "doubao-1-5-vision-pro-250328" # 高精度视觉(备用)
doubao_vision_lite_model: str = "doubao-1-5-vision-lite-250315" # 快速视觉(商品识别默认,速度优先)
doubao_vision_use_lite: bool = True # viral-video 图片分析默认用 lite 提速
doubao_embedding_model: str = "doubao-embedding-large-text-240915"
doubao_video_model: str = "doubao-seedance-2-5-260628"
doubao_video_timeout: int = 600 # 视频生成轮询总超时(秒)
+15 -2
View File
@@ -117,6 +117,9 @@ class ViralVideoJob:
# 状态
id: str = field(default_factory=lambda: uuid4().hex)
status: ViralVideoStatus = ViralVideoStatus.PENDING
current_stage: str = "" # 细粒度阶段(ViralVideoStage.value,snake_case)
phase_message: str = "" # 阶段中文提示文案,前端轮询直接展示
heartbeat_at: datetime | None = None # worker 心跳时间,用于超时僵尸任务检测
result_video_url: str = ""
credits_cost: int = 0
error_msg: str = ""
@@ -138,9 +141,19 @@ class ViralVideoJob:
):
raise ValueError(f"Cannot transition from {self.status} to running")
self.status = ViralVideoStatus.RUNNING
now = datetime.now(timezone.utc)
if self.started_at is None:
self.started_at = datetime.now(timezone.utc)
self.updated_at = datetime.now(timezone.utc)
self.started_at = now
self.heartbeat_at = now
self.updated_at = now
def touch_heartbeat(self) -> None:
"""更新心跳时间(worker 在长任务中周期性调用,用于超时检测)。"""
now = datetime.now(timezone.utc)
if self.started_at is None:
self.started_at = now
self.heartbeat_at = now
self.updated_at = now
def mark_image_analyzed(self) -> None:
if self.status not in (ViralVideoStatus.PENDING, ViralVideoStatus.RUNNING):
+158 -108
View File
@@ -40,6 +40,8 @@ class DoubaoClient:
self.timeout: int = settings.doubao_timeout
self.max_retries: int = settings.doubao_max_retries
self.vision_model: str = settings.doubao_vision_model
self.vision_lite_model: str = settings.doubao_vision_lite_model
self.fast_model: str = settings.doubao_fast_model
def embed_text(self, text: str, timeout: int | None = None) -> list[float] | None:
"""调用豆包文本 Embedding API,返回浮点向量;失败返回 None。"""
@@ -92,6 +94,7 @@ class DoubaoClient:
messages: list[dict[str, str]],
temperature: float = 0.7,
max_tokens: int = 1024,
model: str | None = None,
) -> Optional[str]:
"""调用 Chat Completion 接口.
@@ -112,7 +115,7 @@ class DoubaoClient:
"Content-Type": "application/json",
}
payload: dict[str, Any] = {
"model": self.model,
"model": model or self.model,
"messages": messages,
"temperature": temperature,
"max_tokens": max_tokens,
@@ -154,11 +157,12 @@ class DoubaoClient:
max_tokens: int = 2048,
temperature: float = 0.3,
timeout: int | None = None,
model: str | None = None,
) -> Optional[str]:
"""调用豆包视觉理解 API(OpenAI 兼容多模态格式).
将 images 附加到最后一条 user message 的 content 中,
使用 vision_model(默认 doubao-1-5-vision-pro-250915)。
使用 vision_model(默认 doubao-1-5-vision-pro-250328)。
Args:
messages: 对话消息列表。最后一条 user message 会被注入图片内容。
@@ -204,7 +208,7 @@ class DoubaoClient:
"Content-Type": "application/json",
}
payload: dict[str, Any] = {
"model": self.vision_model,
"model": model or self.vision_model,
"messages": vision_messages,
"temperature": temperature,
"max_tokens": max_tokens,
@@ -258,26 +262,13 @@ class DoubaoClient:
reference_audios: list[str] | None = None,
reference_videos: list[str] | None = None,
) -> str | None:
"""调用 Seedance 2.5 文生/图生视频(异步任务→轮询→下载),返回本地 MP4 路径;失败返回 None。
"""调用 Seedance 2.5 生视频(异步任务→轮询→下载),返回本地 MP4 路径;失败返回 None。
v1.6: 支持多参考图(产品素材)+ 参考音频(TTS口型驱动)+ 参考视频,单次生成最长 30 秒。
Args:
prompt: 文本提示词(含完整编导脚本:总览+场景光线+逐镜头时间轴+硬约束+负面词)
image_url: 首帧参考图 URL(可选,提供则走图生视频首帧模式,ratio 跟随首帧)
duration: 视频时长 4~30 秒
ratio: 宽高比 16:9/9:16/1:1/4:3/3:4/21:9/adaptive;image_url 存在时自动忽略
resolution: 480p/720p/1080p
generate_audio: 是否让模型原生合成音效/BGM(v1.6 默认 True,配合 reference_audios 做口型驱动)
watermark: 是否加水印
output_dir: 下载目录,默认 /tmp
model: 指定模型 ID;空则用 settings.doubao_video_model
reference_images: 多参考图 URL 列表(产品素材,最多30张;注意 image_url 为首帧单独传)
reference_audios: 参考音频 URL 列表(TTS口播,驱动口型,最多10段)
reference_videos: 参考视频 URL 列表(风格参考)
Returns:
本地 MP4 文件路径,失败返回 None。
【v1.6.1 修复】严格按官方 content 数组协议构造请求:
- 所有参考(图/音/视)必须放进 content 数组并带 role 字段,不能放顶层 reference_audios/reference_videos(非官方字段,会被忽略或导致异常)。
- 首帧图(first_frame 模式)Seedance 2.5 强制 ratio=adaptive;走 omni_reference(参考生视频)模式时才能指定 9:16/1:1 等具体比例。
判定:传了参考音频/视频或 ≥1 张多参考图时,走 omni_reference(首张图 role=reference_image);纯首帧无参考时走 first_frame(ratio 强制 adaptive)。
- 创建任务若因 ratio 报错(HTTP 400),自动回退到 ratio=adaptive 重试一次。
"""
if not self.is_available:
return None
@@ -286,18 +277,48 @@ class DoubaoClient:
settings = get_shared_settings()
poll_interval = getattr(settings, "doubao_video_poll_interval", 10) or 10
total_timeout = getattr(settings, "doubao_video_timeout", 900) or 900
# 收紧总超时:轮询 8min + 下载 2min = 最长 ~10min,防止出现 20min 卡死
total_timeout = getattr(settings, "doubao_video_timeout", 480) or 480
default_video_model = getattr(settings, "doubao_video_model", None) or "doubao-seedance-2-5-260628"
video_model = model or default_video_model
ref_audios = [u for u in (reference_audios or [])[:10] if u and isinstance(u, str)]
ref_videos = [u for u in (reference_videos or [])[:3] if u and isinstance(u, str)]
ref_imgs = [u for u in (reference_images or [])[:9] if u and isinstance(u, str)]
# 判断任务模式:有参考音/视/多图 → omni_reference(支持指定 ratio);纯首帧 → first_frame(ratio=adaptive)
has_extra_refs = bool(ref_audios or ref_videos or ref_imgs)
is_first_frame_mode = bool(image_url) and not has_extra_refs
# 最终 ratio:first_frame 模式强制 adaptive,否则按用户传值(默认 9:16)
final_ratio = "adaptive" if is_first_frame_mode else (ratio or "9:16")
# 构造 content 数组:text + 图 + 音 + 视
content: list[dict[str, Any]] = [{"type": "text", "text": prompt.strip()}]
if image_url:
content.append({"type": "image_url", "image_url": {"url": image_url}})
# v1.6: 多参考图(产品素材)
if reference_images:
for url in reference_images[:30]:
if url and isinstance(url, str):
content.append({"type": "image_url", "image_url": {"url": url}})
if has_extra_refs:
# omni_reference:首张图作为 reference_image,允许指定 ratio
content.append(
{
"type": "image_url",
"image_url": {"url": image_url},
"role": "reference_image",
}
)
else:
# 纯首帧:不带 role,服务端识别为 first_frame(或显式 role=first_frame)
content.append(
{
"type": "image_url",
"image_url": {"url": image_url},
"role": "first_frame",
}
)
for u in ref_imgs:
content.append({"type": "image_url", "image_url": {"url": u}, "role": "reference_image"})
for u in ref_audios:
content.append({"type": "audio_url", "audio_url": {"url": u}, "role": "reference_audio"})
for u in ref_videos:
content.append({"type": "video_url", "video_url": {"url": u}, "role": "reference_video"})
create_payload: dict[str, Any] = {
"model": video_model,
@@ -306,18 +327,8 @@ class DoubaoClient:
"duration": int(duration),
"resolution": resolution,
"watermark": bool(watermark),
"ratio": final_ratio,
}
# v1.6: 参考音频(TTS 驱动口型)
if reference_audios:
create_payload["reference_audios"] = [
{"url": u, "role": "audio_url"} for u in reference_audios[:10] if u and isinstance(u, str)
]
# v1.6: 参考视频(风格参考)
if reference_videos:
create_payload["reference_videos"] = [{"url": u} for u in reference_videos[:5] if u and isinstance(u, str)]
# Bug #2110 / v1.6: ratio=None 时不传(首帧图生视频跟随原图比例)
if ratio and not image_url:
create_payload["ratio"] = ratio
headers = {
"Authorization": f"Bearer {self.api_key}",
@@ -325,78 +336,94 @@ class DoubaoClient:
}
create_url = f"{self.base_url}/contents/generations/tasks"
logger.info(
"Seedance 创建任务请求: url=%s model=%s duration=%ds ratio=%s gen_audio=%s image_url=%s ref_imgs=%d ref_audios=%d ref_videos=%d",
create_url,
"Seedance 创建任务: model=%s dur=%ds ratio=%s mode=%s gen_audio=%s img=%d aud=%d vid=%d",
video_model,
duration,
ratio or "(follow-image)",
final_ratio,
"first_frame" if is_first_frame_mode else "omni_ref",
generate_audio,
bool(image_url),
len(reference_images or []),
len(reference_audios or []),
len(reference_videos or []),
(1 if image_url else 0) + len(ref_imgs),
len(ref_audios),
len(ref_videos),
)
# 1) 创建任务(带重试)
task_id: str | None = None
last_error: Exception | None = None
for attempt in range(self.max_retries + 1):
try:
resp = httpx.post(create_url, headers=headers, json=create_payload, timeout=self.timeout)
# 测试环境下 MagicMock().status_code 是 MagicMock,与 int 比较会抛 TypeError;
# 用显式 int() 转换+类型判断,避免误判。
def _do_create(payload: dict) -> tuple[str | None, Exception | None, int, str]:
"""返回 (task_id, last_err, status_code, body_text)。"""
last_err: Exception | None = None
for attempt in range(self.max_retries + 1):
try:
_status = int(resp.status_code)
except (TypeError, ValueError):
_status = 200
if _status >= 400:
# 把响应体完整打出来(通常含 error.code/message,能直接定位:模型未开通/Key 无权限/模型 ID 错误)
logger.error(
"Seedance 创建任务 HTTP %d: body=%s",
resp.status_code,
(resp.text or "")[:1000],
)
resp.raise_for_status()
data = resp.json()
task_id = data.get("id")
if task_id:
break
last_error = RuntimeError(f"create task returned no id: {str(data)[:200]}")
except Exception as e:
last_error = e
if attempt < self.max_retries:
wait = 0.5 * (2**attempt)
logger.warning(
"Seedance 创建任务失败,%.1fs 后重试 (%d/%d): %s", wait, attempt + 1, self.max_retries + 1, e
)
time.sleep(wait)
resp = httpx.post(create_url, headers=headers, json=payload, timeout=self.timeout)
sc = int(getattr(resp, "status_code", 0) or 0)
body = (getattr(resp, "text", "") or "")[:1500]
if sc >= 400:
logger.error("Seedance 创建任务 HTTP %d: body=%s", sc, body)
try:
resp.raise_for_status()
except Exception as ee:
last_err = ee
if attempt < self.max_retries:
time.sleep(0.5 * (2**attempt))
continue
return None, last_err, sc, body
data = resp.json()
tid = data.get("id")
if tid:
return tid, None, sc, body
last_err = RuntimeError(f"create ok but no id: {str(data)[:300]}")
except Exception as e:
last_err = e
if attempt < self.max_retries:
wait = 0.5 * (2**attempt)
logger.warning(
"Seedance 创建任务失败,%.1fs 后重试 (%d/%d): %s",
wait,
attempt + 1,
self.max_retries + 1,
e,
)
time.sleep(wait)
return None, last_err, 0, ""
# 第一次尝试
task_id, last_err, sc, body = _do_create(create_payload)
# ratio 兜底:HTTP 400 且 body 提到 ratio / adaptive → 回退 adaptive 再试一次
if (
not task_id
and sc == 400
and final_ratio != "adaptive"
and (
"ratio" in (body or "").lower()
or "aspect" in (body or "").lower()
or "adaptive" in (body or "").lower()
)
):
logger.warning("Seedance 创建因 ratio 失败,回退 ratio=adaptive 重试")
create_payload["ratio"] = "adaptive"
task_id, last_err, sc2, body2 = _do_create(create_payload)
if not task_id:
logger.error(
"Seedance 创建任务最终失败: model=%s base_url=%s err=%s 【排查建议】"
"1) 确认方舟控制台已开通 Doubao-Seedance-2.5 模型;"
"2) DOUBAO_API_KEY 对应的账号有该模型调用权限;"
"3) DOUBAO_BASE_URL 必须为 https://ark.cn-beijing.volces.com/api/v3;"
"4) 若控制台用「推理接入点」(endpoint),请把 DOUBAO_VIDEO_MODEL 改为 ep-xxx 接入点 ID。",
"Seedance 创建任务最终失败: model=%s base_url=%s err=%s body=%s 【排查】"
"1) 方舟控制台已开通 doubao-seedance-2-5-260628;2) API Key 有该模型权限;"
"3) DOUBAO_BASE_URL=https://ark.cn-beijing.volces.com/api/v3;4) 参考素材 URL 公网可访问。",
video_model,
self.base_url,
last_error,
last_err,
(body or "")[:500],
)
return None
logger.info(
"Seedance 任务已创建: task_id=%s model=%s duration=%ds gen_audio=%s",
task_id,
video_model,
duration,
generate_audio,
)
logger.info("Seedance 任务已创建: task_id=%s ratio=%s", task_id, create_payload["ratio"])
# 2) 轮询状态
poll_url = f"{create_url}/{task_id}"
deadline = time.time() + total_timeout
video_url: str | None = None
last_status: str = "queued"
poll_count = 0
while time.time() < deadline:
poll_count += 1
try:
resp = httpx.get(poll_url, headers=headers, timeout=self.timeout)
try:
@@ -411,48 +438,71 @@ class DoubaoClient:
content_obj = data.get("content") or {}
video_url = content_obj.get("video_url")
if video_url:
logger.info("Seedance 任务成功: task_id=%s polls=%d", task_id, poll_count)
break
last_error = RuntimeError(f"task succeeded but no video_url: {str(data)[:300]}")
last_err = RuntimeError(f"task succeeded but no video_url: {str(data)[:300]}")
logger.error("Seedance succeeded 但无 video_url: %s", last_err)
break
if status == "failed":
err = data.get("error") or {}
last_error = RuntimeError(f"task failed: {err.get('code','')} {err.get('message','')}")
last_err = RuntimeError(f"task failed: code={err.get('code','')} msg={err.get('message','')}")
logger.error("Seedance 任务失败 task_id=%s: %s", task_id, last_err)
break
if status in ("expired", "cancelled"):
last_error = RuntimeError(f"task {status}")
last_err = RuntimeError(f"task {status}")
logger.error("Seedance 任务 %s: task_id=%s", status, task_id)
break
# queued / running: 继续轮询
# 每 5 次轮询打一次 info 日志,便于观察进度
if poll_count % 5 == 0:
logger.info("Seedance 轮询中: task_id=%s status=%s polls=%d", task_id, status, poll_count)
except httpx.HTTPStatusError as e:
last_error = e
logger.warning(
"Seedance 轮询 HTTP %d: body=%s",
e.response.status_code,
(e.response.text or "")[:500],
)
last_err = e
logger.warning("Seedance 轮询 HTTP %d: %s", e.response.status_code, (e.response.text or "")[:300])
except Exception as e:
last_error = e
last_err = e
logger.debug("Seedance 轮询异常: %s", e)
time.sleep(poll_interval)
if not video_url:
logger.error("Seedance 任务未成功: task_id=%s status=%s err=%s", task_id, last_status, last_error)
logger.error(
"Seedance 任务未成功: task_id=%s last_status=%s polls=%d err=%s (总等待 %.0fs)",
task_id,
last_status,
poll_count,
last_err,
total_timeout,
)
return None
# 3) 下载到本地
# 3) 下载到本地(下载超时收紧到 120s)
try:
out_dir = output_dir or "/tmp"
os.makedirs(out_dir, exist_ok=True)
local_path = f"{out_dir}/seedance_{task_id}_{uuid.uuid4().hex[:8]}.mp4"
with httpx.stream("GET", video_url, timeout=300) as r:
download_timeout = 120.0
logger.info(
"Seedance 开始下载: task_id=%s url=%s timeout=%.0fs", task_id, video_url[:120], download_timeout
)
with httpx.stream("GET", video_url, timeout=download_timeout) as r:
r.raise_for_status()
downloaded = 0
with open(local_path, "wb") as f:
for chunk in r.iter_bytes(chunk_size=1024 * 256):
if chunk:
f.write(chunk)
logger.info("Seedance 视频下载完成: %s (%d bytes)", local_path, os.path.getsize(local_path))
downloaded += len(chunk)
size = os.path.getsize(local_path)
logger.info("Seedance 视频下载完成: %s size=%d bytes", local_path, size)
if size == 0:
logger.error("Seedance 下载文件大小为 0")
try:
os.remove(local_path)
except Exception:
pass
return None
return local_path
except Exception as e:
logger.error("Seedance 视频下载失败: %s", e)
logger.error("Seedance 视频下载失败: %s", e, exc_info=True)
return None
+61 -28
View File
@@ -496,16 +496,32 @@ def run_generate_cover(
# ── 通用 LLM / Vision 调用(#2039 ViralVideoOrchestrator 使用,复用现有豆包客户端)──
def call_llm(prompt: str, temperature: float = 0.7) -> object:
"""调用豆包大模型(文本对话),返回解析后的 JSON(dict/list)或原文字符串;失败返回 None。"""
def call_llm(
prompt: str,
temperature: float = 0.7,
max_tokens: int = 2048,
model: str | None = None,
system_prompt: str | None = None,
) -> object:
"""调用豆包大模型(文本对话),返回解析后的 JSON(dict/list)或原文字符串;失败返回 None。
Args:
prompt: 用户侧提示。
temperature: 采样温度。
max_tokens: 输出上限(结构化任务默认 2048,长文案可按需加大)。
model: 覆盖默认模型(如 fast_model 提速用),None 走配置默认推理模型。
system_prompt: 覆盖默认 system prompt。
"""
client = get_doubao_client()
if not client.is_available:
return None
if system_prompt is None:
system_prompt = "你是专业的短视频内容策划助手。需要结构化输出时请严格使用 JSON。"
messages = [
{"role": "system", "content": "你是专业的短视频内容策划助手。需要结构化输出时请严格使用 JSON。"},
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt},
]
raw = client.chat_completion(messages, temperature=temperature, max_tokens=4096)
raw = client.chat_completion(messages, temperature=temperature, max_tokens=max_tokens, model=model)
if raw is None:
return None
try:
@@ -514,14 +530,26 @@ def call_llm(prompt: str, temperature: float = 0.7) -> object:
return raw
def call_vision(image_url: str, prompt: str) -> object:
def call_vision(
image_url: str,
prompt: str,
*,
model: str | None = None,
max_tokens: int = 1024,
temperature: float = 0.2,
timeout: int = 45,
system_prompt: str | None = None,
) -> object:
"""调用豆包视觉大模型分析图片,返回解析后的 JSON 或原文字符串;失败返回 None。
Bug #2114 (VLM 牛头不对马嘴根因修复):
之前误走 client.chat_completion(用文本模型 doubao-seed-1.6),多模态 content list 被当成
纯文本发给文本模型 → 模型要么看不到图、要么抛 400,静默被 except 吞掉 → 返回 None →
_step_image_analysis fallback 到 {"name":"未识别"} → 后续文案/分镜完全没图的信息。
现改走 vision_completion,走视觉模型 doubao-1-5-vision-pro-250915。
Args:
image_url: 可公网访问的图片 URL(直接传给豆包视觉模型,无需本地下载)。
prompt: 用户侧文本提示。
model: 覆盖默认视觉模型(如 vision_lite_model 提速用),None 走配置默认。
max_tokens: 输出上限,商品识别用 800~1200 足够,避免长输出拖慢首 token。
temperature: 温度。
timeout: 单次请求超时(秒)。
system_prompt: 覆盖默认 system prompt(viral-video 商品分析会传专门的详细 prompt)。
"""
client = get_doubao_client()
if not client.is_available:
@@ -531,28 +559,33 @@ def call_vision(image_url: str, prompt: str) -> object:
logger.warning("[call_vision] 空 image_url,跳过视觉分析")
return None
system_prompt = (
"你是资深电商视觉分析师。请严格基于用户提供的图片观察回答,"
"图片里没有的信息不要凭空想象或编造;看不清或无法判断时明确说"
"「图片中无法判断」,不要猜测。输出必须是严格 JSON,不要附加 Markdown 或解释文字。"
)
if system_prompt is None:
system_prompt = (
"你是资深电商视觉分析师。请严格基于用户提供的图片观察回答,"
"图片里没有的信息不要凭空想象或编造;看不清或无法判断时明确说"
"「无法判断」,不要猜测。输出必须是严格 JSON,不要附加 Markdown 或解释文字。"
)
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt},
]
used_model = model or getattr(client, "vision_model", "?")
logger.info(
"[call_vision] 调用豆包视觉模型 vision_model=%s image_url=%s prompt_len=%d",
getattr(client, "vision_model", "?"),
"[call_vision] 调用豆包视觉模型 model=%s image_url=%s prompt_len=%d max_tokens=%d timeout=%d",
used_model,
image_url[:120],
len(prompt),
max_tokens,
timeout,
)
raw = client.vision_completion(
messages=messages,
images=[image_url],
temperature=0.2,
max_tokens=2048,
timeout=60,
temperature=temperature,
max_tokens=max_tokens,
timeout=timeout,
model=model,
)
if raw is None:
logger.warning("[call_vision] 视觉模型返回 None (image_url=%s)", image_url[:80])
@@ -585,20 +618,20 @@ def call_video_generation(
reference_audios: list[str] | None = None,
reference_videos: list[str] | None = None,
) -> str | None:
"""调用 Seedance 2.5 生成视频(v1.6 单次出片版),返回本地 MP4 路径;失败返回 None。
"""调用 Seedance 2.5 生成视频(v1.6.1 单次出片版),返回本地 MP4 路径;失败返回 None。
v1.6:
- 默认 generate_audio=True,模型原生合成环境音效/BGM;
- reference_audios 传 TTS 音频 URL 数组做口型驱动;
- reference_images 传产品素材 URL 数组做视觉参考;
- 单次最长 30 秒,不分段不拼接;
- image_url 存在时为「首帧图生视频」模式,自动不传 ratio(Bug #2110)。
v1.6.1 关键约束(避免 20min 卡死):
- 参考音频/视频/多图全部放进 content 数组并带 role=reference_audio/reference_video/reference_image;
- 纯首帧无参考时(first_frame 模式),Seedance 2.5 强制 ratio=adaptive;
传了参考音/视/多图时走 omni_reference 模式,ratio 可指定为 9:16(客户端内部自动判断)。
- ratio 默认 9:16(竖屏),客户端会根据是否有参考自动在 first_frame/adaptive 与 omni/9:16 间切换;
若创建任务因 ratio 报错(HTTP 400),客户端会自动回退到 adaptive 再试一次。
"""
client = get_doubao_client()
if not client.is_available:
logger.warning("[ai_service] 豆包客户端未配置,跳过视频生成")
return None
effective_ratio = None if image_url else ratio
effective_ratio = ratio or "9:16"
try:
kwargs: dict = dict(
prompt=prompt,
+1 -1
View File
@@ -57,7 +57,7 @@ if [ "$TARGET_ENV" = "staging" ]; then
fi
# 共用 secrets 直接导出(如果存在)
SHARED_SECRETS="OSS_ACCESS_KEY_ID OSS_ACCESS_KEY_SECRET COSYVOICE_API_KEY DASHSCOPE_API_KEY MEDIAKIT_API_KEY DOUBAO_API_KEY DOUBAO_MODEL DOUBAO_BASE_URL DOUBAO_VISION_MODEL WECHAT_APP_ID WECHAT_APP_SECRET TIKHUB_API_KEY APIZERO_API_KEY GPU_WORKER_TOKEN"
SHARED_SECRETS="OSS_ACCESS_KEY_ID OSS_ACCESS_KEY_SECRET COSYVOICE_API_KEY DASHSCOPE_API_KEY MEDIAKIT_API_KEY DOUBAO_API_KEY DOUBAO_MODEL DOUBAO_FAST_MODEL DOUBAO_BASE_URL DOUBAO_VISION_MODEL DOUBAO_VISION_LITE_MODEL DOUBAO_VISION_USE_LITE WECHAT_APP_ID WECHAT_APP_SECRET TIKHUB_API_KEY APIZERO_API_KEY GPU_WORKER_TOKEN"
for var in $SHARED_SECRETS; do
value="${!var:-}"
# 已经在环境中了,无需额外操作
+3
View File
@@ -14,10 +14,13 @@ from packages.shared.ai_client import DoubaoClient
class _FakeSettings:
doubao_api_key = "test-key"
doubao_model = "test-model"
doubao_fast_model = "test-fast-model"
doubao_base_url = "https://ark.cn-beijing.volces.com/api/v3"
doubao_timeout = 10
doubao_max_retries = 0
doubao_vision_model = "test-vision"
doubao_vision_lite_model = "test-vision-lite"
doubao_vision_use_lite = False
doubao_embedding_model = "test-embedding"
+2 -2
View File
@@ -44,7 +44,7 @@ class TestCheckDatabase:
assert result["type"] == "postgresql"
assert result["message"] == "Database connection successful"
mock_psycopg.connect.assert_called_once_with(
"postgresql+psycopg://test:test@localhost/test", connect_timeout=3
"postgresql://test:test@localhost/test", connect_timeout=3
)
mock_cur.execute.assert_called_once_with("SELECT 1")
mock_conn.close.assert_called_once()
@@ -96,7 +96,7 @@ class TestCheckMigrations:
assert result["status"] == "healthy"
assert result["message"] == "Database migrations applied"
mock_psycopg.connect.assert_called_once_with(
"postgresql+psycopg://test:test@localhost/test", connect_timeout=3
"postgresql://test:test@localhost/test", connect_timeout=3
)
mock_conn.close.assert_called_once()
+2 -2
View File
@@ -253,8 +253,8 @@ class TestCallVideoGenerationV16:
)
assert result == str(out)
kwargs = mock_client.video_generation.call_args.kwargs
# 首帧模式不传 ratio(Bug #2110)
assert "ratio" not in kwargs
# 图生视频也必须传 ratio(避免首帧方图导致默认输出 1:1)
assert kwargs.get("ratio") == "9:16", f"ratio 应透传,got {kwargs.get('ratio')!r}"
assert kwargs["image_url"] == "https://img/x.jpg"
assert kwargs["reference_audios"] == ["https://oss/tts.mp3"]
assert kwargs["reference_images"] == ["https://img/r1.jpg"]
+2
View File
@@ -61,6 +61,8 @@ def _make_job(job_id: str = "job-1", user_id: str = "u1", status: str = "pending
"video_ratio": "9:16",
"video_model": "",
"credits_cost": 0,
"current_stage": "",
"phase_message": "",
"updated_at": None,
"is_terminal": False,
"effective_copy_text": "",