Refactor vector search to utilize Qdrant VectorDB
This commit is contained in:
1 parent
61c0e88ad8
commit
3add6c3d31
4 files changed
+99
-31
No files matched your search
@@ -618,41 +618,54 @@ impl McpTool for SemanticCodeSearchHandler {
|
||||
|
||||
let query_emb = generate_embedding_async(tool_args.query.clone()).await?;
|
||||
|
||||
// For MVP, we search across snippets dynamically. A true background codebase indexer would be a separate subsystem.
|
||||
let mut results = Vec::new();
|
||||
let mut texts_to_embed = Vec::new();
|
||||
let mut metadata = Vec::new();
|
||||
|
||||
let snippets = state.snippets.read_with(|snips| snips.clone());
|
||||
for snippet in snippets {
|
||||
let combined = format!("{} {} {}", snippet.name, snippet.description, snippet.code);
|
||||
texts_to_embed.push(combined);
|
||||
metadata.push((snippet.name, snippet.description));
|
||||
}
|
||||
|
||||
let sticky = state.sticky.read_with(|s| s.clone());
|
||||
for note in sticky {
|
||||
texts_to_embed.push(note.content.clone());
|
||||
metadata.push(("StickyNote".to_string(), note.content.chars().take(200).collect::<String>()));
|
||||
}
|
||||
|
||||
if let Ok(embeddings) = generate_embeddings_async(texts_to_embed).await {
|
||||
for (emb, meta) in embeddings.into_iter().zip(metadata) {
|
||||
let sim = cosine_similarity(&query_emb, &emb);
|
||||
results.push((sim, meta.0, meta.1));
|
||||
// Search using VectorDB if available
|
||||
let mut vdb_search = false;
|
||||
if let Some(vdb) = &*state.vector_db.read().await {
|
||||
vdb_search = true;
|
||||
if let Ok(search_results) = vdb.search(query_emb.clone(), 5).await {
|
||||
for res in search_results {
|
||||
results.push((res.score, res.id, res.text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal));
|
||||
// Fallback to manual loop if VectorDB is not initialized
|
||||
if !vdb_search {
|
||||
let mut texts_to_embed = Vec::new();
|
||||
let mut metadata = Vec::new();
|
||||
|
||||
let snippets = state.snippets.read_with(|snips| snips.clone());
|
||||
for snippet in snippets {
|
||||
let combined = format!("{} {} {}", snippet.name, snippet.description, snippet.code);
|
||||
texts_to_embed.push(combined);
|
||||
metadata.push((snippet.name, snippet.description));
|
||||
}
|
||||
|
||||
let sticky = state.sticky.read_with(|s| s.clone());
|
||||
for note in sticky {
|
||||
texts_to_embed.push(note.content.clone());
|
||||
metadata.push(("StickyNote".to_string(), note.content.chars().take(200).collect::<String>()));
|
||||
}
|
||||
|
||||
if let Ok(embeddings) = generate_embeddings_async(texts_to_embed).await {
|
||||
for (emb, meta) in embeddings.into_iter().zip(metadata) {
|
||||
let sim = cosine_similarity(&query_emb, &emb);
|
||||
results.push((sim, meta.0, meta.1));
|
||||
}
|
||||
}
|
||||
|
||||
results.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal));
|
||||
results.truncate(5);
|
||||
}
|
||||
|
||||
let top_results: Vec<_> = results.into_iter().take(5).collect();
|
||||
|
||||
if top_results.is_empty() {
|
||||
if results.is_empty() {
|
||||
return Ok(format!("No semantic matches found for query: {}", tool_args.query));
|
||||
}
|
||||
|
||||
let mut out = format!("Semantic Search Results for '{}':\n", tool_args.query);
|
||||
for (score, title, desc) in top_results {
|
||||
for (score, title, desc) in results {
|
||||
out.push_str(&format!("- [{:.2}] {}: {}\n", score, title, desc));
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user