From a59c9db81d14cf1e32599f8a0fe499faec61e982 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Thu, 13 Aug 2026 12:01:01 +0000 Subject: [PATCH] style: auto-format with black + isort + prettier [skip ci-format-check] --- .../worker/video_processing/render_adapter.py | 14 +++--- .../video_processing/thumbnail_generator.py | 44 +++++++++++------- .../worker_app/tasks/edit_plan_generation.py | 3 +- packages/shared/ai_service.py | 46 ++++++++++++------- tests/unit/test_cover_frame_pre_extract.py | 5 ++ 5 files changed, 73 insertions(+), 39 deletions(-) diff --git a/apps/worker/video_processing/render_adapter.py b/apps/worker/video_processing/render_adapter.py index cb799bcca..8bf624ae8 100755 --- a/apps/worker/video_processing/render_adapter.py +++ b/apps/worker/video_processing/render_adapter.py @@ -74,7 +74,9 @@ class RenderAdapterResult: failed_clip_ids: list[str] = None # 失败的 clip id 列表 error_message: str = "" error_detail: str = "" # 详细错误信息(如 ffmpeg stderr),用于排查 - cover_candidates: list[dict] | None = None # 封面候选帧 [{"image_url": "...", "frame_time": 5.0, "storage_key": "..."}] + cover_candidates: list[dict] | None = ( + None # 封面候选帧 [{"image_url": "...", "frame_time": 5.0, "storage_key": "..."}] + ) def __post_init__(self): if self.rendered_clip_ids is None: @@ -574,18 +576,18 @@ class RenderAdapter: try: from video_processing.thumbnail_generator import extract_and_upload_cover_frames - cover_candidates = extract_and_upload_cover_frames( - str(result.output_path), plan_id, num_frames=3 - ) + cover_candidates = extract_and_upload_cover_frames(str(result.output_path), plan_id, num_frames=3) if cover_candidates: logger.info( "[render-adapter] 封面候选帧生成成功: plan_id=%s count=%d", - plan_id, len(cover_candidates), + plan_id, + len(cover_candidates), ) except Exception as cover_err: logger.warning( "[render-adapter] 封面候选帧生成失败(不影响主流程): plan_id=%s error=%s", - plan_id, cover_err, + plan_id, + cover_err, ) self._report_progress(progress_cb, 100.0, "渲染完成") diff --git a/apps/worker/video_processing/thumbnail_generator.py b/apps/worker/video_processing/thumbnail_generator.py index 2730ab092..0322320e3 100755 --- a/apps/worker/video_processing/thumbnail_generator.py +++ b/apps/worker/video_processing/thumbnail_generator.py @@ -201,21 +201,29 @@ def extract_cover_candidates( seek_str = _format_seek_time(frame_time) scale_filter = f"scale={width}:-1:force_original_aspect_ratio=decrease,format=yuvj420p" cmd = [ - FFMPEG_BIN, "-y", - "-ss", seek_str, - "-i", video_path, - "-vframes", "1", - "-vf", scale_filter, - "-q:v", "2", + FFMPEG_BIN, + "-y", + "-ss", + seek_str, + "-i", + video_path, + "-vframes", + "1", + "-vf", + scale_filter, + "-q:v", + "2", output_path, ] run_ffmpeg(cmd, capture_output=True, timeout=timeout) if Path(output_path).exists() and Path(output_path).stat().st_size > 0: - results.append({ - "local_path": output_path, - "frame_time": round(frame_time, 2), - }) + results.append( + { + "local_path": output_path, + "frame_time": round(frame_time, 2), + } + ) else: Path(output_path).unlink(missing_ok=True) except Exception as e: @@ -256,14 +264,18 @@ def extract_and_upload_cover_frames( url = upload_to_oss(local_path, storage_key) if url: - results.append({ - "image_url": url, - "frame_time": frame_time, - "storage_key": storage_key, - }) + results.append( + { + "image_url": url, + "frame_time": frame_time, + "storage_key": storage_key, + } + ) logger.info( "封面候选帧上传成功: plan_id=%s idx=%d frame_time=%.2f", - plan_id, idx, frame_time, + plan_id, + idx, + frame_time, ) except Exception as e: logger.warning("封面候选帧上传失败: plan_id=%s idx=%d error=%s", plan_id, idx, e) diff --git a/apps/worker/worker_app/tasks/edit_plan_generation.py b/apps/worker/worker_app/tasks/edit_plan_generation.py index 0d740847c..58155e4ab 100644 --- a/apps/worker/worker_app/tasks/edit_plan_generation.py +++ b/apps/worker/worker_app/tasks/edit_plan_generation.py @@ -263,7 +263,8 @@ def _render_with_unified( plan.config = plan_config logger.info( "封面候选帧已写入 plan.config: plan_id=%s count=%d", - plan_id, len(result.cover_candidates), + plan_id, + len(result.cover_candidates), ) return _finalize_render_success( diff --git a/packages/shared/ai_service.py b/packages/shared/ai_service.py index efe7f7c0a..ad63f7886 100755 --- a/packages/shared/ai_service.py +++ b/packages/shared/ai_service.py @@ -379,18 +379,25 @@ def _extract_frames_with_ffmpeg( # 先用 ffprobe 获取视频时长 import subprocess as _subprocess + from packages.shared.ffmpeg_utils import FFPROBE_BIN duration = 30.0 # 默认假设 30 秒 try: probe_result = _subprocess.run( [ - FFPROBE_BIN, "-v", "error", - "-show_entries", "format=duration", - "-of", "default=noprint_wrappers=1:nokey=1", + FFPROBE_BIN, + "-v", + "error", + "-show_entries", + "format=duration", + "-of", + "default=noprint_wrappers=1:nokey=1", video_url, ], - capture_output=True, text=True, timeout=15, + capture_output=True, + text=True, + timeout=15, ) if probe_result.returncode == 0 and probe_result.stdout.strip(): duration = float(probe_result.stdout.strip()) @@ -409,11 +416,16 @@ def _extract_frames_with_ffmpeg( try: seek_str = f"{int(frame_time // 3600):02d}:{int((frame_time % 3600) // 60):02d}:{frame_time % 60:05.2f}" cmd = [ - FFMPEG_BIN, "-y", - "-ss", seek_str, - "-i", video_url, - "-vframes", "1", - "-q:v", "2", + FFMPEG_BIN, + "-y", + "-ss", + seek_str, + "-i", + video_url, + "-vframes", + "1", + "-q:v", + "2", output_path, ] run_ffmpeg(cmd, capture_output=True, timeout=timeout) @@ -475,6 +487,7 @@ def _call_ai_cover_service( # ai_frame / ai_regenerate - 使用 FFmpeg 本地抽帧 if primary_video_url: import re as _re + primary_video_url = _re.sub(r"(?