diff --git a/scripts/asrx_processor.py b/scripts/asrx_processor.py index c46f9ae..b1d62ac 100755 --- a/scripts/asrx_processor.py +++ b/scripts/asrx_processor.py @@ -110,6 +110,39 @@ def _shared_audio_setup(video_path): return tmp_dir, video_path +def _convert_asr_segments_to_asrx(asr_segments, output_path): + """Convert ASR segments to ASRX format with frame information""" + fps = 30.0 + base_name = os.path.basename(output_path) + uuid_part = base_name.split(".")[0] + probe_path = os.path.join(os.path.dirname(output_path), + f"{uuid_part}.probe.json") + if os.path.exists(probe_path): + try: + with open(probe_path) as pf: + probe_data = json.load(pf) + if "fps" in probe_data: + fps = float(probe_data["fps"]) + except Exception: + pass + + segments = [] + for s in asr_segments: + start_time = s.get("start", s.get("start_time", 0)) + end_time = s.get("end", s.get("end_time", 0)) + start_frame = int(start_time * fps) + end_frame = int(end_time * fps) + segments.append({ + "start_time": start_time, + "end_time": end_time, + "start_frame": start_frame, + "end_frame": end_frame, + "text": s.get("text", ""), + "speaker_id": "SPEAKER_0", + }) + return segments + + def _convert_result(result, output_path): """Stage 3: 將 SelfASRXFixed result 轉為 Rust-expected format""" fps = 30.0 @@ -231,11 +264,12 @@ def process_asrx(video_path: str, output_path: str, uuid: str = "", # Fallback to ASR segments if ASRX fails but ASR has content if asr_segments: print(f"[ASRX] Resume error, falling back to {len(asr_segments)} ASR segments", file=sys.stderr) + segments = _convert_asr_segments_to_asrx(asr_segments, output_path) output_result = { "status": "has_transcript", "language": None, - "segments": [{"start_time": s["start"], "end_time": s["end"], "text": s["text"], "speaker_id": "SPEAKER_0"} for s in asr_segments], - "segment_count": len(asr_segments), + "segments": segments, + "segment_count": len(segments), "fallback_from_asr": True, } else: diff --git a/src/worker/job_worker.rs b/src/worker/job_worker.rs index c37f8b5..ff3de7f 100644 --- a/src/worker/job_worker.rs +++ b/src/worker/job_worker.rs @@ -1201,6 +1201,17 @@ impl JobWorker { if std::path::Path::new(&traced_path).exists() { if let Ok(content) = std::fs::read_to_string(&traced_path) { if let Ok(traced_data) = serde_json::from_str::(&content) { + // Check if status is no_faces (valid completion with no faces) + if let Some(status) = traced_data.get("status").and_then(|s| s.as_str()) { + if status == "no_faces" { + tracing::info!( + "[Ingestion] No faces detected for {} - trace_done=true", + uuid + ); + return true; + } + } + if let Some(traces) = traced_data.get("traces") { // traces can be an object (dictionary) or array let trace_count = if traces.is_object() {