style: auto-format with black + isort + prettier [skip ci-format-check]
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 0s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 21s
CI/CD Pipeline / Integration Tests (pull_request) Failing after 40s
CI/CD Pipeline / Validate - Style (pull_request) Failing after 1m21s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m26s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 59s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m14s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 2m50s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m13s
AI Code Review / AI Code Review (pull_request) Successful in 6m26s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 7m16s
CI/CD Pipeline / CI Gate (pull_request) Failing after 5s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m46s
CI/CD Pipeline / Canary Release to Production (pull_request) Failing after 141h23m49s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 141h23m49s
CI/CD Pipeline / Build Production Worker Image (pull_request) Failing after 141h23m56s
CI/CD Pipeline / Build Production Web Image (pull_request) Failing after 141h23m56s
CI/CD Pipeline / Build Production API Image (pull_request) Failing after 141h23m57s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 141h30m48s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 141h30m48s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 141h30m52s
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Failing after 141h30m57s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 141h30m58s
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Failing after 141h30m57s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 141h30m58s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 141h31m17s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 141h31m18s
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 141h31m18s
CI/CD Pipeline / Check push changed paths (pull_request) Failing after 141h31m21s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 142h5m38s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Failing after 142h5m47s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 142h6m7s

This commit is contained in:
CI Bot
2026-09-10 09:52:31 +00:00
parent 25f1e43036
commit b62b1bcfcc
4 changed files with 30 additions and 28 deletions
+13 -7
View File
@@ -25,14 +25,14 @@ from app.services.mediakit_client import (
MediaKitError,
get_mediakit_client,
)
# Celery 异步任务:TTS 合成 + MediaKit 提交(#lipsync-speed-optimization)
from app.tasks.lipsync_tts import tts_synthesize_and_submit
from sqlalchemy.orm import Session
from packages.adapters.sqlalchemy_impl.models import LipsyncJobModel
from packages.application.cosyvoice_service import CosyVoiceError, normalize_emotion
from packages.shared.storage import get_shared_storage_service
# Celery 异步任务:TTS 合成 + MediaKit 提交(#lipsync-speed-optimization)
from app.tasks.lipsync_tts import tts_synthesize_and_submit
from packages.shared.url_security import ALLOWED_AUDIO_MIME_TYPES, safe_download_bytes
logger = logging.getLogger(__name__)
@@ -201,10 +201,16 @@ class LipsyncService:
if is_tts_mode:
# 2a. TTS 模式:dispatch Celery 异步任务处理 TTS 合成 + MediaKit 提交
try:
tts_synthesize_and_submit.apply_async(args=(
job_id, user_id, voice_id, script_text, speed,
normalize_emotion(emotion),
))
tts_synthesize_and_submit.apply_async(
args=(
job_id,
user_id,
voice_id,
script_text,
speed,
normalize_emotion(emotion),
)
)
except Exception:
logger.warning(
"Celery 任务提交失败,TTS 任务已创建但未触发执行: %s",
+12 -10
View File
@@ -11,8 +11,8 @@
7. 异常时标记 job 为 failed
"""
import logging
import io
import logging
import uuid
from datetime import datetime, timezone
@@ -40,21 +40,25 @@ def tts_synthesize_and_submit(
在 Celery worker 中运行,不阻塞 HTTP 请求。
"""
from app.services.mediakit_client import MediaKitError, get_mediakit_client
from sqlalchemy.orm import Session as DBSession
from app.services.mediakit_client import MediaKitError, get_mediakit_client
from packages.adapters.sqlalchemy_impl.database import SessionLocal
from packages.adapters.sqlalchemy_impl.models import LipsyncJobModel
from packages.application.cosyvoice_service import CosyVoiceError, CosyVoiceService
from packages.shared.storage import get_shared_storage_service
from packages.shared.downloader import safe_download_bytes
from packages.shared.storage import get_shared_storage_service
db: DBSession = SessionLocal()
try:
job = db.query(LipsyncJobModel).filter(
LipsyncJobModel.id == job_id,
LipsyncJobModel.user_id == user_id,
).first()
job = (
db.query(LipsyncJobModel)
.filter(
LipsyncJobModel.id == job_id,
LipsyncJobModel.user_id == user_id,
)
.first()
)
if job is None:
logger.error("[lipsync_tts] Job not found: job_id=%s", job_id)
@@ -111,9 +115,7 @@ def tts_synthesize_and_submit(
)
storage = get_shared_storage_service()
storage_key = f"lipsync-tts/{user_id}/{job_id}.mp3"
permanent_url = storage.upload_file(
io.BytesIO(audio_data), storage_key, content_type="audio/mpeg"
)
permanent_url = storage.upload_file(io.BytesIO(audio_data), storage_key, content_type="audio/mpeg")
logger.info("[lipsync_tts] TTS 音频已转存 OSS: job_id=%s key=%s", job_id, storage_key)
job.audio_url = permanent_url
except Exception as exc:
@@ -132,9 +132,7 @@ def _lipsync_service_with_mocks():
def test_create_job_tts_direct_mode_synthesizes_audio():
svc, client, cosy = _lipsync_service_with_mocks()
with patch(
"app.services.lipsync_service.tts_synthesize_and_submit"
) as mock_task:
with patch("app.services.lipsync_service.tts_synthesize_and_submit") as mock_task:
mock_task.apply_async.return_value = MagicMock(id="celery-task-123")
job = svc.create_job(
@@ -177,9 +175,7 @@ def test_create_job_tts_failure_raises():
TTS 合成失败由 Celery 任务内部处理并更新 job 状态。"""
svc, client, cosy = _lipsync_service_with_mocks()
with patch(
"app.services.lipsync_service.tts_synthesize_and_submit"
) as mock_task:
with patch("app.services.lipsync_service.tts_synthesize_and_submit") as mock_task:
mock_task.apply_async.return_value = MagicMock(id="celery-task-456")
job = svc.create_job(
@@ -35,9 +35,7 @@ class TestFFmpegPresetOptimization:
final_label=None,
output_path="/tmp/output.mp4",
)
assert "-preset veryfast" in cmd, (
f"期望 -preset veryfast,实际命令: {cmd}"
)
assert "-preset veryfast" in cmd, f"期望 -preset veryfast,实际命令: {cmd}"
def test_preset_veryfast_with_filter(self):
"""带滤镜场景下也必须使用 veryfast."""
@@ -142,8 +140,8 @@ class TestCreateJobAsyncTTS:
call_kwargs = mock_task.apply_async.call_args
args = call_kwargs.kwargs.get("args") or call_kwargs[1].get("args", call_kwargs[0][0] if call_kwargs[0] else ())
assert args[1] == "user-1" # user_id
assert args[2] == "v-1" # voice_id
assert args[3] == "测试文本" # script_text
assert args[2] == "v-1" # voice_id
assert args[3] == "测试文本" # script_text
def test_tts_mode_celery_dispatch_failure_still_creates_job(self):
"""Celery dispatch 失败时,job 记录已创建,状态保持 tts_processing."""