style: auto-format with black + isort + 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 2s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / 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 42s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 41s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 43s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / 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 / Validate - Style (pull_request) Successful in 1m41s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m53s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m56s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m56s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m59s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 2m57s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 4m8s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 6m27s
AI Code Review / AI Code Review (pull_request) Successful in 6m40s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 10m35s
CI/CD Pipeline / Validate - Security (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 / 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 / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / 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 42s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 41s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 43s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / 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 / Validate - Style (pull_request) Successful in 1m41s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m53s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m56s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m56s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m59s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 2m57s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 4m8s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 6m27s
AI Code Review / AI Code Review (pull_request) Successful in 6m40s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 10m35s
CI/CD Pipeline / Validate - Security (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
This commit is contained in:
@@ -299,9 +299,7 @@ class AiAvatarRenderService:
|
||||
generate_smart_cover,
|
||||
)
|
||||
|
||||
smart_cover_url = generate_smart_cover(
|
||||
output_video_url, job_id=job_id, max_frames=5
|
||||
)
|
||||
smart_cover_url = generate_smart_cover(output_video_url, job_id=job_id, max_frames=5)
|
||||
except Exception:
|
||||
logger.warning("智能封面(MediaKit)失败,回退 FFmpeg 封面 job_id=%s", job_id, exc_info=True)
|
||||
|
||||
|
||||
@@ -9,13 +9,12 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import logging
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from typing import Optional
|
||||
|
||||
import io
|
||||
|
||||
from app.services.mediakit_client import (
|
||||
STATUS_COMPLETED,
|
||||
STATUS_FAILED,
|
||||
@@ -127,9 +126,7 @@ class LipsyncService:
|
||||
)
|
||||
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("对口型 TTS 音频已转存 OSS: job_id=%s key=%s", job_id, storage_key)
|
||||
return permanent_url
|
||||
except Exception as exc:
|
||||
@@ -316,9 +313,7 @@ class LipsyncService:
|
||||
data = resp.content
|
||||
storage = get_shared_storage_service()
|
||||
storage_key = f"lipsync-outputs/{user_id}/{job_id}.mp4"
|
||||
permanent_url = storage.upload_file(
|
||||
io.BytesIO(data), storage_key, content_type="video/mp4"
|
||||
)
|
||||
permanent_url = storage.upload_file(io.BytesIO(data), storage_key, content_type="video/mp4")
|
||||
logger.info("对口型输出视频已转存 OSS: job_id=%s key=%s", job_id, storage_key)
|
||||
return permanent_url or temp_url
|
||||
except Exception as exc:
|
||||
|
||||
@@ -16,6 +16,7 @@ os.environ.setdefault("JWT_SECRET_KEY", "dev-secret-key-for-testing")
|
||||
|
||||
# ── 情绪归一化 ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_normalize_emotion_english_values():
|
||||
from packages.application.cosyvoice_service import normalize_emotion
|
||||
|
||||
@@ -46,6 +47,7 @@ def test_normalize_emotion_invalid_returns_empty():
|
||||
|
||||
# ── CosyVoice payload 携带 emotion + rate ──────────────────────────────
|
||||
|
||||
|
||||
def _make_service_with_captured_client(captured: dict):
|
||||
"""构造 CosyVoiceService,拦截 post 请求体到 captured['json']."""
|
||||
import httpx as _httpx
|
||||
@@ -103,6 +105,7 @@ def test_submit_synthesize_payload_omits_emotion_when_empty():
|
||||
|
||||
# ── 对口型 TTS 直生分支 ─────────────────────────────────────────────────
|
||||
|
||||
|
||||
def _lipsync_service_with_mocks():
|
||||
from app.services.lipsync_service import LipsyncService
|
||||
|
||||
@@ -129,8 +132,10 @@ 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.get_shared_storage_service") as storage_patch, \
|
||||
patch("app.services.lipsync_service.safe_download_bytes") as dl_patch:
|
||||
with (
|
||||
patch("app.services.lipsync_service.get_shared_storage_service") as storage_patch,
|
||||
patch("app.services.lipsync_service.safe_download_bytes") as dl_patch,
|
||||
):
|
||||
storage = MagicMock()
|
||||
storage.upload_file.return_value = "https://oss/tts.mp3"
|
||||
storage_patch.return_value = storage
|
||||
@@ -176,6 +181,7 @@ def test_create_job_direct_audio_mode_skips_tts():
|
||||
|
||||
def test_create_job_tts_failure_raises():
|
||||
from app.services.mediakit_client import MediaKitError
|
||||
|
||||
from packages.application.cosyvoice_service import CosyVoiceError
|
||||
|
||||
svc, client, cosy = _lipsync_service_with_mocks()
|
||||
@@ -195,6 +201,7 @@ def test_create_job_tts_failure_raises():
|
||||
|
||||
# ── refresh 同步中间状态 ────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_refresh_syncs_running_status():
|
||||
from app.services.lipsync_service import LipsyncService
|
||||
|
||||
@@ -215,6 +222,7 @@ def test_refresh_syncs_running_status():
|
||||
|
||||
# ── 智能封面 ────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def test_smart_cover_selects_best_frame_and_persists():
|
||||
from app.services import ai_avatar_cover_service as cov
|
||||
|
||||
@@ -222,10 +230,12 @@ def test_smart_cover_selects_best_frame_and_persists():
|
||||
{"image_url": "https://mk/f0.jpg"},
|
||||
{"image_url": "https://mk/f1.jpg"},
|
||||
]
|
||||
with patch("packages.shared.mediakit_client.get_mediakit_client") as mk_patch, \
|
||||
patch("packages.shared.cover_frame_scorer.score_frames") as score_patch, \
|
||||
patch("httpx.get") as http_get, \
|
||||
patch("packages.shared.storage.get_shared_storage_service") as storage_patch:
|
||||
with (
|
||||
patch("packages.shared.mediakit_client.get_mediakit_client") as mk_patch,
|
||||
patch("packages.shared.cover_frame_scorer.score_frames") as score_patch,
|
||||
patch("httpx.get") as http_get,
|
||||
patch("packages.shared.storage.get_shared_storage_service") as storage_patch,
|
||||
):
|
||||
mk = MagicMock()
|
||||
mk.is_available = True
|
||||
mk.extract_frames.return_value = snapshots
|
||||
@@ -263,8 +273,11 @@ def test_smart_cover_returns_empty_when_mediakit_unavailable():
|
||||
|
||||
# ── 渲染 script_id 可选(手动文案直生场景)──────────────────────────────
|
||||
|
||||
|
||||
def test_render_request_script_id_optional():
|
||||
import sys, os
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "apps", "api"))
|
||||
from app.schemas.ai_avatar_render import CreateAiAvatarRenderRequest
|
||||
|
||||
|
||||
Reference in New Issue
Block a user