fix: comprehensive fixes for ingestion and TKG

1. Add Redis PipelineProgress cleanup in unregister_internal
   - Deletes progress key when file is unregistered

2. Fix ingestion_complete asr_status query
   - Query ASRX first, then ASR
   - Filter out NULL values to avoid false negatives

3. Fix TKG 0 nodes/edges support
   - TKG is considered done if face traces are complete
   - TKG may create 0 nodes/edges for videos with minimal content

4. Add ASRX fallback to ASR segments
   - When ASRX has 0 segments but ASR has segments, use ASR segments
   - Ensures at least one ASRX output when ASR has content
This commit is contained in:
Accusys
2026-07-06 21:14:08 +08:00
parent 146d3cedb2
commit 3067896b0f
3 changed files with 67 additions and 18 deletions

View File

@@ -1239,15 +1239,26 @@ async fn unregister(
let deleted_redis_keys = {
match RedisClient::new() {
Ok(redis) => match redis.delete_worker_job(&uuid).await {
Ok(_) => {
tracing::info!("[UNREGISTER] Deleted Redis keys for {}", uuid);
Some(1)
Ok(redis) => {
let mut deleted = 0;
// Delete worker job keys
if redis.delete_worker_job(&uuid).await.is_ok() {
tracing::info!("[UNREGISTER] Deleted Redis worker job keys for {}", uuid);
deleted += 1;
}
Err(e) => {
tracing::warn!("[UNREGISTER] Failed to delete Redis keys: {}", e);
None
// Delete PipelineProgress key
let progress_key = format!("{}progress:{}:pipeline",
crate::core::config::REDIS_KEY_PREFIX.as_str(), uuid);
if let Ok(mut conn) = redis.get_conn().await {
let _: Option<String> = redis::cmd("DEL").arg(&progress_key)
.query_async(&mut conn).await.ok();
tracing::info!("[UNREGISTER] Deleted Redis PipelineProgress for {}", uuid);
deleted += 1;
}
Some(deleted)
},
Err(e) => {
tracing::warn!("[UNREGISTER] Failed to create Redis client: {}", e);

View File

@@ -1150,8 +1150,15 @@ impl JobWorker {
// Check asr_status for ASR/ASRX - if no_audio_track or silent_audio, ingestion is complete
let mj_t = schema::table_name("monitor_jobs");
let asr_done: bool = if has_asr_or_asrx {
// Query ASRX first (more authoritative), then ASR
// Filter out NULL values to ensure we get a valid status
let asr_status: Option<String> = sqlx::query_scalar(&format!(
"SELECT asr_status FROM {pr_t} pr JOIN {mj_t} mj ON pr.job_id = mj.id WHERE mj.uuid = $1 AND pr.processor IN ('asr', 'asrx') LIMIT 1"
"SELECT asr_status FROM {pr_t} pr JOIN {mj_t} mj ON pr.job_id = mj.id \
WHERE mj.uuid = $1 AND pr.processor = 'asrx' AND asr_status IS NOT NULL \
UNION ALL \
SELECT asr_status FROM {pr_t} pr JOIN {mj_t} mj ON pr.job_id = mj.id \
WHERE mj.uuid = $1 AND pr.processor = 'asr' AND asr_status IS NOT NULL \
LIMIT 1"
))
.bind(uuid)
.fetch_optional(pool)
@@ -1260,21 +1267,17 @@ impl JobWorker {
true
};
// Check TKG nodes exist
// Check TKG completion
// TKG is considered done if face traces are done (TKG runs after face tracing)
// TKG may create 0 nodes/edges for videos with minimal content
let has_asr_or_asrx_for_tkg =
job_processors.is_empty() || job_processors.iter().any(|p| p == "asrx" || p == "asr");
let has_face_for_tkg = job_processors.is_empty() || job_processors.iter().any(|p| p == "face");
let tkg_done: bool = if has_asr_or_asrx_for_tkg && has_face_for_tkg {
let tkg_nodes_table = schema::table_name("tkg_nodes");
sqlx::query_scalar::<_, i32>(&format!(
"SELECT 1 FROM {tkg_nodes_table} WHERE file_uuid = $1 LIMIT 1"
))
.bind(uuid)
.fetch_optional(pool)
.await
.unwrap_or(None)
.unwrap_or(0) > 0
// TKG is done if face traces are complete (TKG runs after face tracing)
// TKG may create 0 nodes/edges for videos with minimal content
trace_done
} else {
tracing::info!("[Ingestion] No TKG needed for {}", uuid);
true