Files
momentry_core/new_handlers.txt
Warren b54c2def30 feat: add migrations, test scripts, and utility tools
- Add database migrations (006-028) for face recognition, identity, file_uuid
- Add test scripts for ASR, face, search, processing
- Add portal frontend (Tauri)
- Add config, benchmark, and monitoring utilities
- Add model checkpoints and pretrained model references
2026-04-30 15:11:53 +08:00

111 lines
3.8 KiB
Plaintext

async fn search_bm25(
State(state): State<AppState>,
Json(req): Json<SearchRequest>,
) -> Result<Json<SearchResponse>, StatusCode> {
let limit = req.limit.unwrap_or(10);
let query_hash = generate_query_hash(&req.query, req.uuid.as_deref(), limit);
let cache_key = keys::bm25_search(&query_hash);
let ttl = state.mongo_cache.ttl_search();
let response = state
.mongo_cache
.get_or_fetch(&cache_key, ttl, keys::CATEGORY_SEARCH, || async {
let pg = PostgresDb::init()
.await
.map_err(|e| anyhow::anyhow!("PG init failed: {}", e))?;
let bm25_results = pg
.search_bm25(&req.query, req.uuid.as_deref(), limit)
.await?;
let results: Vec<SearchResult> = bm25_results
.into_iter()
.map(|r| SearchResult {
uuid: r.uuid,
chunk_id: r.chunk_id,
chunk_type: r.chunk_type,
start_time: r.start_time,
end_time: r.end_time,
text: r.text,
score: r.bm25_score,
})
.collect();
Ok::<SearchResponse, anyhow::Error>(SearchResponse {
results,
query: req.query.clone(),
})
})
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(Json(response))
}
async fn n8n_search_bm25(
State(state): State<AppState>,
Json(req): Json<SearchRequest>,
) -> Result<Json<N8nSearchResponse>, StatusCode> {
let limit = req.limit.unwrap_or(10);
let query_hash = generate_query_hash(&req.query, req.uuid.as_deref(), limit);
let cache_key = keys::n8n_bm25_search(&query_hash);
let ttl = state.mongo_cache.ttl_search();
let response = state
.mongo_cache
.get_or_fetch(&cache_key, ttl, keys::CATEGORY_N8N_SEARCH, || async {
let pg = PostgresDb::init()
.await
.map_err(|e| anyhow::anyhow!("PG init failed: {}", e))?;
let bm25_results = pg
.search_bm25(&req.query, req.uuid.as_deref(), limit)
.await?;
let mut hits = Vec::new();
for r in bm25_results {
if let Some(chunk) = pg
.get_chunk_by_chunk_id_and_uuid(&r.chunk_id, &r.uuid)
.await
.ok()
.flatten()
{
let text = r.text; // Use text from BM25 result
let title = extract_title_from_content(&chunk.content);
let file_path = if chunk.uuid.is_empty() {
None
} else {
let video = pg.get_video_by_uuid(&chunk.uuid).await.ok().flatten();
video.map(|v| v.file_path)
};
hits.push(N8nSearchHit {
id: chunk.chunk_id.clone(),
vid: chunk.uuid.clone(),
start: chunk.start_time().seconds(),
end: chunk.end_time().seconds(),
title: if title.is_empty() {
format!("Chunk {}", chunk.chunk_id)
} else {
title
},
text,
score: r.bm25_score,
file_path,
});
}
}
Ok::<N8nSearchResponse, anyhow::Error>(N8nSearchResponse {
query: req.query.clone(),
count: hits.len(),
hits,
})
})
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(Json(response))
}