skill_web/api/
search.rs

1//! Search API client
2
3use super::client::ApiClient;
4use super::error::ApiResult;
5use super::types::*;
6
7/// Search API operations
8#[derive(Clone)]
9pub struct SearchApi {
10    client: ApiClient,
11}
12
13impl SearchApi {
14    /// Create a new search API client
15    pub fn new(client: ApiClient) -> Self {
16        Self { client }
17    }
18
19    /// Perform a semantic search
20    pub async fn search(&self, request: &SearchRequest) -> ApiResult<SearchResponse> {
21        self.client.post("/search", request).await
22    }
23
24    /// Simple search with query string
25    pub async fn query(&self, query: &str) -> ApiResult<SearchResponse> {
26        self.search(&SearchRequest {
27            query: query.to_string(),
28            top_k: 10,
29            skill_filter: None,
30            include_examples: false,
31        })
32        .await
33    }
34
35    /// Search with limited results
36    pub async fn query_top_k(&self, query: &str, top_k: usize) -> ApiResult<SearchResponse> {
37        self.search(&SearchRequest {
38            query: query.to_string(),
39            top_k,
40            skill_filter: None,
41            include_examples: false,
42        })
43        .await
44    }
45
46    /// Search within a specific skill
47    pub async fn search_in_skill(&self, query: &str, skill: &str) -> ApiResult<SearchResponse> {
48        self.search(&SearchRequest {
49            query: query.to_string(),
50            top_k: 10,
51            skill_filter: Some(skill.to_string()),
52            include_examples: false,
53        })
54        .await
55    }
56
57    /// Search with AI-generated examples included
58    pub async fn search_with_examples(&self, query: &str) -> ApiResult<SearchResponse> {
59        self.search(&SearchRequest {
60            query: query.to_string(),
61            top_k: 10,
62            skill_filter: None,
63            include_examples: true,
64        })
65        .await
66    }
67
68    /// Get search configuration
69    pub async fn get_config(&self) -> ApiResult<SearchConfigResponse> {
70        self.client.get("/search/config").await
71    }
72
73    /// Update search configuration
74    pub async fn update_config(
75        &self,
76        request: &UpdateSearchConfigRequest,
77    ) -> ApiResult<SearchConfigResponse> {
78        self.client.put("/search/config", request).await
79    }
80
81    /// Enable or disable hybrid search
82    pub async fn set_hybrid_search(&self, enabled: bool) -> ApiResult<SearchConfigResponse> {
83        self.update_config(&UpdateSearchConfigRequest {
84            enable_hybrid: Some(enabled),
85            ..Default::default()
86        })
87        .await
88    }
89
90    /// Enable or disable reranking
91    pub async fn set_reranking(&self, enabled: bool) -> ApiResult<SearchConfigResponse> {
92        self.update_config(&UpdateSearchConfigRequest {
93            enable_reranking: Some(enabled),
94            ..Default::default()
95        })
96        .await
97    }
98
99    /// Change embedding provider
100    pub async fn set_embedding_provider(
101        &self,
102        provider: &str,
103        model: Option<&str>,
104    ) -> ApiResult<SearchConfigResponse> {
105        self.update_config(&UpdateSearchConfigRequest {
106            embedding_provider: Some(provider.to_string()),
107            embedding_model: model.map(String::from),
108            ..Default::default()
109        })
110        .await
111    }
112
113    /// Change vector backend
114    pub async fn set_vector_backend(&self, backend: &str) -> ApiResult<SearchConfigResponse> {
115        self.update_config(&UpdateSearchConfigRequest {
116            vector_backend: Some(backend.to_string()),
117            ..Default::default()
118        })
119        .await
120    }
121
122    /// Test search connection (quick validation)
123    pub async fn test_connection(
124        &self,
125        request: &TestConnectionRequest,
126    ) -> ApiResult<TestConnectionResponse> {
127        self.client.post("/search/test-connection", request).await
128    }
129
130    /// Test full search pipeline (indexing + search)
131    pub async fn test_pipeline(
132        &self,
133        request: &TestPipelineRequest,
134    ) -> ApiResult<TestPipelineResponse> {
135        self.client.post("/search/test-pipeline", request).await
136    }
137
138    /// Index all skills into the search pipeline
139    pub async fn index(&self) -> ApiResult<IndexResponse> {
140        self.client.post("/search/index", &()).await
141    }
142}