use serde::{Deserialize, Serialize};
use crate::prelude::*;
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct SearchRequest {
pub query: String,
pub source: DocumentsSource,
#[serde(skip_serializing_if = "Option::is_none")]
pub instructions: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ranking_metric: Option<RankingMetric>,
#[serde(skip_serializing_if = "Option::is_none")]
pub retrieval_mode: Option<RetrievalMode>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct SearchResponse {
pub matches: Vec<SearchMatch>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct SearchMatch {
pub file_id: String,
pub chunk_id: String,
pub chunk_content: String,
pub score: f32,
pub collection_ids: Vec<String>,
#[serde(default)]
pub fields: HashMap<String, String>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct DocumentsSource {
pub collection_ids: Vec<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct SearchParameters {
#[serde(skip_serializing_if = "Option::is_none")]
pub from_date: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_date: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_search_results: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub return_citations: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sources: Option<Vec<SearchSource>>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum SearchSource {
X {
#[serde(skip_serializing_if = "Option::is_none")]
excluded_x_handles: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
included_x_handles: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
x_handles: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
post_favorite_count: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
post_view_count: Option<i32>,
},
Web {
#[serde(skip_serializing_if = "Option::is_none")]
allowed_websites: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
excluded_websites: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
country: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
safe_search: Option<bool>,
},
News {
#[serde(skip_serializing_if = "Option::is_none")]
country: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
excluded_websites: Option<Vec<String>>,
},
Rss {
#[serde(skip_serializing_if = "Option::is_none")]
urls: Option<Vec<String>>,
},
}
impl Default for SearchSource {
fn default() -> Self {
SearchSource::Web {
allowed_websites: None,
excluded_websites: None,
country: None,
safe_search: None,
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum RankingMetric {
#[default]
RankingMetricUnknown,
RankingMetricL2Distance,
RankingMetricCosineSimilarity,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum RetrievalMode {
Hybrid {
#[serde(skip_serializing_if = "Option::is_none")]
reranker: Option<HybridReranker>,
#[serde(skip_serializing_if = "Option::is_none")]
search_multiplier: Option<i32>,
},
Semantic {
#[serde(skip_serializing_if = "Option::is_none")]
reranker: Option<RerankerModel>,
},
Keyword {
#[serde(skip_serializing_if = "Option::is_none")]
reranker: Option<RerankerModel>,
},
}
impl Default for RetrievalMode {
fn default() -> Self {
RetrievalMode::Hybrid {
reranker: None,
search_multiplier: None,
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum HybridReranker {
RerankerModel {
#[serde(skip_serializing_if = "Option::is_none")]
instructions: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
model: Option<String>,
},
Rrf {
#[serde(skip_serializing_if = "Option::is_none")]
embedding_weight: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
text_weight: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
k: Option<i32>,
},
}
impl Default for HybridReranker {
fn default() -> Self {
HybridReranker::Rrf {
embedding_weight: None,
text_weight: None,
k: None,
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct RerankerModel {
#[serde(skip_serializing_if = "Option::is_none")]
pub instructions: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct ReciprocalRankFusion {
#[serde(skip_serializing_if = "Option::is_none")]
pub embedding_weight: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text_weight: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub k: Option<i32>,
}