Skip to main content

context69_contracts/
search.rs

1use chrono::{DateTime, Utc};
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use utoipa::ToSchema;
6use uuid::Uuid;
7
8use crate::Visibility;
9
10#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
11pub struct SearchRequest {
12    pub query: String,
13    #[serde(default, skip_serializing_if = "Option::is_none")]
14    pub locale: Option<String>,
15    #[serde(default = "default_limit")]
16    pub limit: usize,
17    #[serde(default)]
18    pub source_key: Option<String>,
19    #[serde(default)]
20    pub group_path: Option<String>,
21    #[serde(default)]
22    pub published_after: Option<DateTime<Utc>>,
23    #[serde(default)]
24    pub published_before: Option<DateTime<Utc>>,
25    #[serde(default)]
26    pub metadata_filters: Vec<crate::MetadataFilter>,
27}
28
29fn default_limit() -> usize {
30    8
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
34#[serde(rename_all = "snake_case")]
35pub enum SearchMode {
36    Vector,
37    Hybrid,
38}
39
40impl SearchMode {
41    pub fn as_str(self) -> &'static str {
42        match self {
43            Self::Vector => "vector",
44            Self::Hybrid => "hybrid",
45        }
46    }
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
50pub struct SearchHit {
51    pub chunk_id: Uuid,
52    pub document_id: i64,
53    pub group_key: String,
54    pub group_path: String,
55    pub visibility: Visibility,
56    pub source_key: String,
57    pub external_id: String,
58    pub title: String,
59    pub summary: Option<String>,
60    pub source_uri: String,
61    pub published_at: Option<DateTime<Utc>>,
62    pub chunk_index: i32,
63    pub chunk_text: String,
64    pub score: f32,
65    #[serde(default, skip_serializing_if = "Option::is_none")]
66    pub vector_score: Option<f32>,
67    #[serde(default, skip_serializing_if = "Option::is_none")]
68    pub keyword_score: Option<f32>,
69    #[serde(default, skip_serializing_if = "Option::is_none")]
70    pub rerank_score: Option<f32>,
71    #[serde(default, skip_serializing_if = "Option::is_none")]
72    pub match_reason: Option<String>,
73    #[serde(default)]
74    #[schema(value_type = Object)]
75    pub metadata_json: Value,
76    #[serde(default, skip_serializing_if = "Option::is_none")]
77    pub library_file_id: Option<Uuid>,
78    #[serde(default, skip_serializing_if = "Option::is_none")]
79    pub library_section_label: Option<String>,
80    #[serde(default, skip_serializing_if = "Option::is_none")]
81    pub library_path: Option<String>,
82    #[serde(default)]
83    pub is_library_file: bool,
84    #[serde(default, skip_serializing_if = "Option::is_none")]
85    pub requested_locale: Option<String>,
86    #[serde(default, skip_serializing_if = "Option::is_none")]
87    pub content_locale: Option<String>,
88    #[serde(default, skip_serializing_if = "Option::is_none")]
89    pub translation_status: Option<crate::TranslationStatus>,
90    #[serde(default)]
91    pub is_fallback: bool,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
95pub struct SearchResponse {
96    pub query: String,
97    pub hits: Vec<SearchHit>,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
101pub struct DocumentResponse {
102    pub document_id: i64,
103    pub group_key: String,
104    pub group_path: String,
105    pub visibility: Visibility,
106    pub source_key: String,
107    pub external_id: String,
108    pub title: String,
109    pub summary: Option<String>,
110    pub source_uri: String,
111    pub published_at: Option<DateTime<Utc>>,
112    pub updated_at: DateTime<Utc>,
113    pub record_hash: String,
114    #[serde(default)]
115    #[schema(value_type = Object)]
116    pub metadata_json: Value,
117    #[serde(default, skip_serializing_if = "Option::is_none")]
118    pub library_file_id: Option<Uuid>,
119    #[serde(default, skip_serializing_if = "Option::is_none")]
120    pub library_section_label: Option<String>,
121    #[serde(default, skip_serializing_if = "Option::is_none")]
122    pub library_path: Option<String>,
123    #[serde(default)]
124    pub is_library_file: bool,
125    pub chunks: Vec<DocumentChunkResponse>,
126    #[serde(default, skip_serializing_if = "Option::is_none")]
127    pub requested_locale: Option<String>,
128    #[serde(default, skip_serializing_if = "Option::is_none")]
129    pub content_locale: Option<String>,
130    #[serde(default, skip_serializing_if = "Option::is_none")]
131    pub translation_status: Option<crate::TranslationStatus>,
132    #[serde(default)]
133    pub is_fallback: bool,
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, JsonSchema)]
137pub struct DocumentChunkResponse {
138    pub chunk_id: Uuid,
139    pub chunk_index: i32,
140    pub text: String,
141}