auto-save 2026-05-14 04:21 (~6)

This commit is contained in:
2026-05-14 04:21:26 +08:00
parent b52642ba77
commit ec96e81c02
6 changed files with 93 additions and 23 deletions

View File

@@ -607,6 +607,7 @@ async def pipeline_analyze(
frame_count: int = KEYFRAME_COUNT,
target: FrameExtractTarget = "balanced",
mode: FrameExtractMode = "replace",
quality: FrameExtractQuality = "accurate",
) -> None:
"""阶段 2拆音轨 + 抽关键帧。ASR/翻译是独立文案轨,不阻塞视觉素材流。"""
job = JOBS[job_id]
@@ -629,11 +630,11 @@ async def pipeline_analyze(
n = max(1, min(int(frame_count), 20))
target_label = FRAME_TARGET_LABELS.get(target, FRAME_TARGET_LABELS["balanced"])
quality_label = FRAME_QUALITY_LABELS.get(quality, FRAME_QUALITY_LABELS["accurate"])
duration = max(float(job.duration or 1.0), 0.1)
scan_fps = min(2.0, max(0.02, 180.0 / duration))
estimated_scan_count = max(1, int(duration * scan_fps))
scan_fps, scan_width, metric_width, estimated_scan_count = _scan_profile(duration, quality)
update(job, message=f"低清扫描候选 · {target_label} · 约 {estimated_scan_count} 帧…", progress=45)
update(job, message=f"本地{quality_label}扫描 · {target_label} · 约 {estimated_scan_count} 帧…", progress=45)
frames_dir = d / "frames"
replacing = mode == "replace"
existing_frames = list(job.frames) if not replacing else []
@@ -648,7 +649,7 @@ async def pipeline_analyze(
# 1) 低分辨率、低帧率扫描。扫描图只用于候选评分,最终不直接作为关键帧。
run([
"ffmpeg", "-y", "-i", str(mp4),
"-vf", f"fps={scan_fps:.4f},scale=360:-2",
"-vf", f"fps={scan_fps:.4f},scale={scan_width}:-2",
"-q:v", "4",
str(scan_dir / "s_%05d.jpg"),
])
@@ -660,7 +661,7 @@ async def pipeline_analyze(
candidates: list[dict] = []
for i, p in enumerate(scan_paths):
t = min(i / scan_fps, max(duration - 0.05, 0.0))
item = _frame_metrics(p, i, t)
item = _frame_metrics(p, i, t, metric_width)
if item:
candidates.append(item)
if not candidates:
@@ -668,7 +669,7 @@ async def pipeline_analyze(
# 2) 目标化筛选pHash 去重 + 清晰度 / 中心细节 / 转场变化 / 动作强度 + 时序分桶。
selection_count = n if replacing else min(len(candidates), max(n * 4, n + len(existing_frames) + 2))
update(job, message=f"{target_label}筛选 {n} / {len(candidates)} 张…", progress=60)
update(job, message=f"{quality_label}筛选 · {target_label} · {n} / {len(candidates)} 张…", progress=60)
chosen = _select_keyframes(candidates, selection_count, target)
# 3) 只对最终选中的时间点,从原视频抽高质量关键帧。
@@ -708,7 +709,7 @@ async def pipeline_analyze(
status="frames_extracted",
frames=merged_frames,
progress=70,
message=f"已按「{target_label}{action_label} {len(renamed)} 张关键帧 · 共 {len(merged_frames)}",
message=f"已按「{quality_label} · {target_label}{action_label} {len(renamed)} 张关键帧 · 共 {len(merged_frames)}",
)
except Exception as e:
@@ -1083,13 +1084,14 @@ async def trigger_analyze(
frames: int = KEYFRAME_COUNT,
target: FrameExtractTarget = "balanced",
mode: FrameExtractMode = "replace",
quality: FrameExtractQuality = "accurate",
) -> Job:
job = JOBS.get(job_id)
if not job:
raise HTTPException(404, "job not found")
if job.status not in {"downloaded", "frames_extracted", "transcribed", "failed"}:
raise HTTPException(409, f"status must be downloaded/failed, got {job.status}")
bg.add_task(pipeline_analyze, job_id, frames, target, mode)
bg.add_task(pipeline_analyze, job_id, frames, target, mode, quality)
return job