fix: support videos with no audio or no faces
1. trace_done now checks for 'no_faces' status in face_traced.json - Videos with no detected faces now complete correctly - Previously stuck because trace_count=0 returned false 2. ASRX fallback to ASR segments includes start_frame/end_frame - Added _convert_asr_segments_to_asrx helper function - TKG can now process fallback segments correctly This allows processing of: - Videos with no audio track (ASR: no_audio_track) - Videos with no faces (face_traced.json: no_faces)
This commit is contained in:
@@ -110,6 +110,39 @@ def _shared_audio_setup(video_path):
|
|||||||
return tmp_dir, 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):
|
def _convert_result(result, output_path):
|
||||||
"""Stage 3: 將 SelfASRXFixed result 轉為 Rust-expected format"""
|
"""Stage 3: 將 SelfASRXFixed result 轉為 Rust-expected format"""
|
||||||
fps = 30.0
|
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
|
# Fallback to ASR segments if ASRX fails but ASR has content
|
||||||
if asr_segments:
|
if asr_segments:
|
||||||
print(f"[ASRX] Resume error, falling back to {len(asr_segments)} ASR segments", file=sys.stderr)
|
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 = {
|
output_result = {
|
||||||
"status": "has_transcript",
|
"status": "has_transcript",
|
||||||
"language": None,
|
"language": None,
|
||||||
"segments": [{"start_time": s["start"], "end_time": s["end"], "text": s["text"], "speaker_id": "SPEAKER_0"} for s in asr_segments],
|
"segments": segments,
|
||||||
"segment_count": len(asr_segments),
|
"segment_count": len(segments),
|
||||||
"fallback_from_asr": True,
|
"fallback_from_asr": True,
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1201,6 +1201,17 @@ impl JobWorker {
|
|||||||
if std::path::Path::new(&traced_path).exists() {
|
if std::path::Path::new(&traced_path).exists() {
|
||||||
if let Ok(content) = std::fs::read_to_string(&traced_path) {
|
if let Ok(content) = std::fs::read_to_string(&traced_path) {
|
||||||
if let Ok(traced_data) = serde_json::from_str::<serde_json::Value>(&content) {
|
if let Ok(traced_data) = serde_json::from_str::<serde_json::Value>(&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") {
|
if let Some(traces) = traced_data.get("traces") {
|
||||||
// traces can be an object (dictionary) or array
|
// traces can be an object (dictionary) or array
|
||||||
let trace_count = if traces.is_object() {
|
let trace_count = if traces.is_object() {
|
||||||
|
|||||||
Reference in New Issue
Block a user