feat: quick search knowledge entities

This commit is contained in:
Per Stark
2025-10-16 20:08:01 +02:00
parent 199186e5a3
commit 7332347f1a
4 changed files with 232 additions and 68 deletions

View File

@@ -6,9 +6,11 @@ use axum::{
};
use common::storage::types::{
conversation::Conversation,
knowledge_entity::{KnowledgeEntity, KnowledgeEntitySearchResult},
text_content::{TextContent, TextContentSearchResult},
user::User,
};
use futures::future::try_join;
use serde::{de, Deserialize, Deserializer, Serialize};
use crate::{
@@ -43,9 +45,19 @@ pub async fn search_result_handler(
Query(params): Query<SearchParams>,
RequireUser(user): RequireUser,
) -> Result<impl IntoResponse, HtmlError> {
#[derive(Serialize)]
struct SearchResultForTemplate {
result_type: String,
score: f32,
#[serde(skip_serializing_if = "Option::is_none")]
text_content: Option<TextContentSearchResult>,
#[serde(skip_serializing_if = "Option::is_none")]
knowledge_entity: Option<KnowledgeEntitySearchResult>,
}
#[derive(Serialize)]
pub struct AnswerData {
search_result: Vec<TextContentSearchResult>,
search_result: Vec<SearchResultForTemplate>,
query_param: String,
user: User,
conversation_archive: Vec<Conversation>,
@@ -56,17 +68,45 @@ pub async fn search_result_handler(
if let Some(actual_query) = params.query {
let trimmed_query = actual_query.trim();
if trimmed_query.is_empty() {
(Vec::new(), String::new())
(Vec::<SearchResultForTemplate>::new(), String::new())
} else {
match TextContent::search(&state.db, trimmed_query, &user.id, 5).await {
Ok(results) => (results, trimmed_query.to_string()),
Err(e) => {
return Err(HtmlError::from(e));
}
const TOTAL_LIMIT: usize = 10;
let (text_results, entity_results) = try_join(
TextContent::search(&state.db, trimmed_query, &user.id, TOTAL_LIMIT),
KnowledgeEntity::search(&state.db, trimmed_query, &user.id, TOTAL_LIMIT),
)
.await?;
let mut combined_results: Vec<SearchResultForTemplate> =
Vec::with_capacity(text_results.len() + entity_results.len());
for text_result in text_results {
let score = text_result.score;
combined_results.push(SearchResultForTemplate {
result_type: "text_content".to_string(),
score,
text_content: Some(text_result),
knowledge_entity: None,
});
}
for entity_result in entity_results {
let score = entity_result.score;
combined_results.push(SearchResultForTemplate {
result_type: "knowledge_entity".to_string(),
score,
text_content: None,
knowledge_entity: Some(entity_result),
});
}
combined_results.sort_by(|a, b| b.score.total_cmp(&a.score));
combined_results.truncate(TOTAL_LIMIT);
(combined_results, trimmed_query.to_string())
}
} else {
(Vec::new(), String::new())
(Vec::<SearchResultForTemplate>::new(), String::new())
};
Ok(TemplateResponse::new_template(