feat: Phase 1 handover - schema migration, correction mechanism, API fixes
Schema changes: dev.chunks->dev.chunk, remove old_chunk_id/chunk_index Correction: asr-1.json format, generate/apply scripts API: 37/37 endpoints fixed and tested Docs: HANDOVER_V2.0.md for M4
This commit is contained in:
@@ -2286,7 +2286,8 @@ async fn list_jobs(Query(params): Query<JobsQuery>) -> Result<Json<JobListRespon
|
||||
.into_iter()
|
||||
.map(|r| {
|
||||
let status_str: String = r.try_get("status").unwrap_or_default();
|
||||
let status = MonitorJobStatus::from_db_str(&status_str).unwrap_or(MonitorJobStatus::Pending);
|
||||
let status =
|
||||
MonitorJobStatus::from_db_str(&status_str).unwrap_or(MonitorJobStatus::Pending);
|
||||
JobInfoResponse {
|
||||
id: r.try_get("id").unwrap_or(0),
|
||||
uuid: r.try_get("uuid").unwrap_or_default(),
|
||||
@@ -2507,7 +2508,7 @@ pub async fn start_server(host: &str, port: u16) -> anyhow::Result<()> {
|
||||
.route("/api/v1/files/scan", get(scan_files))
|
||||
.route("/api/v1/file/:file_uuid/probe", get(probe_by_uuid))
|
||||
.route("/api/v1/file/:file_uuid/process", post(trigger_processing))
|
||||
.route("/api/v1/file/:file_uuid/chunks", get(list_pre_chunks))
|
||||
|
||||
.route("/api/v1/progress/:uuid", get(get_progress))
|
||||
.route("/api/v1/jobs", get(list_jobs))
|
||||
.route("/api/v1/config/cache", post(cache_toggle))
|
||||
@@ -2585,7 +2586,7 @@ async fn get_ingest_stats(
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<IngestStatsResponse>, StatusCode> {
|
||||
let table_videos = schema::table_name("videos");
|
||||
let table_chunks = schema::table_name("chunks");
|
||||
let table_chunks = schema::table_name("chunk");
|
||||
|
||||
let total_videos: (i64,) = sqlx::query_as(&format!("SELECT COUNT(*) FROM {}", table_videos))
|
||||
.fetch_one(state.db.pool())
|
||||
@@ -3048,15 +3049,15 @@ async fn video_details(
|
||||
Query(query): Query<VideoDetailsQuery>,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<VideoDetailsResponse>, StatusCode> {
|
||||
let table = schema::table_name("chunks");
|
||||
let table = schema::table_name("chunk");
|
||||
|
||||
if let Some(chunk_id) = query.chunk_id {
|
||||
let row: Option<(
|
||||
i32, String, String, i32, String, f64, i64, i64,
|
||||
i32, String, String, String, f64, i64, i64,
|
||||
Option<String>, serde_json::Value, Option<serde_json::Value>,
|
||||
Option<String>, i32, Option<String>, Option<serde_json::Value>, Option<String>,
|
||||
)> = sqlx::query_as(&format!(
|
||||
"SELECT file_id, uuid, chunk_id, chunk_index, chunk_type::text, fps, start_frame, end_frame,
|
||||
"SELECT file_id, uuid, chunk_id, chunk_type::text, fps, start_frame, end_frame,
|
||||
text_content, content, metadata, vector_id, frame_count,
|
||||
parent_chunk_id, visual_stats, summary_text
|
||||
FROM {} WHERE chunk_id = $1 AND uuid = $2",
|
||||
@@ -3081,20 +3082,20 @@ async fn video_details(
|
||||
|
||||
let row = row.ok_or(StatusCode::NOT_FOUND)?;
|
||||
|
||||
let fps = if row.5 > 0.0 { row.5 } else { 24.0 };
|
||||
let start_frame = row.6;
|
||||
let end_frame = row.7;
|
||||
let fps = if row.4 > 0.0 { row.4 } else { 24.0 };
|
||||
let start_frame = row.5;
|
||||
let end_frame = row.6;
|
||||
let duration_frames = end_frame - start_frame;
|
||||
|
||||
let start_time = start_frame as f64 / fps;
|
||||
let end_time = end_frame as f64 / fps;
|
||||
|
||||
let row_metadata = row.10.clone();
|
||||
let row_metadata = row.9.clone();
|
||||
|
||||
let mut summary_text = row.15.clone();
|
||||
let mut summary_text = row.14.clone();
|
||||
let mut metadata = None;
|
||||
|
||||
if let Some(ref pid_str) = row.13 {
|
||||
if let Some(ref pid_str) = row.12 {
|
||||
if !pid_str.is_empty() {
|
||||
if let Ok(pid) = pid_str.parse::<i32>() {
|
||||
let parent_table = schema::table_name("parent_chunks");
|
||||
@@ -3168,7 +3169,7 @@ async fn video_details(
|
||||
uuid: row.1.clone(),
|
||||
details: VideoDetailsResult::Chunk(ChunkDetailResponse {
|
||||
chunk_id: row.2.clone(),
|
||||
chunk_type: row.4.clone(),
|
||||
chunk_type: row.3.clone(),
|
||||
frame_range: FrameRange {
|
||||
start_frame,
|
||||
end_frame,
|
||||
@@ -3179,12 +3180,12 @@ async fn video_details(
|
||||
start: start_time,
|
||||
end: end_time,
|
||||
},
|
||||
text_content: row.8.clone(),
|
||||
content: Some(row.9.clone()),
|
||||
parent_id: row.13.clone(),
|
||||
text_content: row.7.clone(),
|
||||
content: Some(row.8.clone()),
|
||||
parent_id: row.12.clone(),
|
||||
summary_text,
|
||||
metadata,
|
||||
visual_stats: row.14.clone(),
|
||||
visual_stats: row.13.clone(),
|
||||
speaker_ids,
|
||||
person_ids,
|
||||
}),
|
||||
@@ -3194,123 +3195,6 @@ async fn video_details(
|
||||
Err(StatusCode::BAD_REQUEST)
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct PreChunksQuery {
|
||||
processor_type: Option<String>,
|
||||
page: Option<usize>,
|
||||
page_size: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct PreChunksResponse {
|
||||
pre_chunks: Vec<PreChunkItem>,
|
||||
count: i64,
|
||||
page: usize,
|
||||
page_size: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct PreChunkItem {
|
||||
id: i64,
|
||||
processor_type: String,
|
||||
coordinate_type: String,
|
||||
coordinate_index: i64,
|
||||
start_frame: Option<i64>,
|
||||
end_frame: Option<i64>,
|
||||
start_time: Option<f64>,
|
||||
end_time: Option<f64>,
|
||||
fps: Option<f64>,
|
||||
data: serde_json::Value,
|
||||
identity_id: Option<String>,
|
||||
confidence: Option<f64>,
|
||||
created_at: String,
|
||||
}
|
||||
|
||||
async fn list_pre_chunks(
|
||||
Path(uuid): Path<String>,
|
||||
Query(query): Query<PreChunksQuery>,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<PreChunksResponse>, StatusCode> {
|
||||
let table = schema::table_name("pre_chunks");
|
||||
let page = query.page.unwrap_or(1);
|
||||
let page_size = query.page_size.unwrap_or(20);
|
||||
let offset = (page - 1) * page_size;
|
||||
|
||||
let processor_filter = if let Some(pt) = &query.processor_type {
|
||||
format!("AND processor_type = '{}'", pt.to_lowercase())
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
let count_query = format!(
|
||||
"SELECT COUNT(*) FROM {} WHERE file_uuid = $1 {}",
|
||||
table, processor_filter
|
||||
);
|
||||
|
||||
let count: i64 = sqlx::query(&count_query)
|
||||
.bind(&uuid)
|
||||
.fetch_one(state.db.pool())
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.try_get(0)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
let data_query = format!(
|
||||
"SELECT id, processor_type, coordinate_type, coordinate_index,
|
||||
start_frame, end_frame, start_time, end_time, fps,
|
||||
data, created_at
|
||||
FROM {}
|
||||
WHERE file_uuid = $1 {}
|
||||
ORDER BY coordinate_index ASC
|
||||
LIMIT {} OFFSET {}",
|
||||
table, processor_filter, page_size, offset
|
||||
);
|
||||
|
||||
let rows: Vec<(
|
||||
i64,
|
||||
String,
|
||||
String,
|
||||
i64,
|
||||
Option<i64>,
|
||||
Option<i64>,
|
||||
Option<f64>,
|
||||
Option<f64>,
|
||||
Option<f64>,
|
||||
serde_json::Value,
|
||||
chrono::DateTime<chrono::Utc>,
|
||||
)> = sqlx::query_as(&data_query)
|
||||
.bind(&uuid)
|
||||
.fetch_all(state.db.pool())
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
let pre_chunks = rows
|
||||
.iter()
|
||||
.map(|row| PreChunkItem {
|
||||
id: row.0,
|
||||
processor_type: row.1.clone(),
|
||||
coordinate_type: row.2.clone(),
|
||||
coordinate_index: row.3,
|
||||
start_frame: row.4,
|
||||
end_frame: row.5,
|
||||
start_time: row.6,
|
||||
end_time: row.7,
|
||||
fps: row.8,
|
||||
data: row.9.clone(),
|
||||
identity_id: None,
|
||||
confidence: None,
|
||||
created_at: row.10.to_rfc3339(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Json(PreChunksResponse {
|
||||
pre_chunks,
|
||||
count,
|
||||
page,
|
||||
page_size,
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct DeleteVideoResponse {
|
||||
success: bool,
|
||||
@@ -3404,7 +3288,7 @@ async fn delete_video(
|
||||
let videos_table = schema::table_name("videos");
|
||||
let face_table = schema::table_name("face_detections");
|
||||
let processor_table = schema::table_name("processor_results");
|
||||
let chunks_table = schema::table_name("chunks");
|
||||
let chunks_table = schema::table_name("chunk");
|
||||
let parent_chunks_table = schema::table_name("parent_chunks");
|
||||
|
||||
// Check if video exists first
|
||||
|
||||
Reference in New Issue
Block a user