Skip to main content

openai_interface/vector_stores/
search.rs

1//! Search a vector store via `POST /vector_stores/{vector_store_id}/search`.
2//!
3//! > ![warn] This module is untested!
4//! > If you encounter any issues, please report them on the repository.
5
6use serde::Serialize;
7use url::Url;
8
9use crate::{
10    errors::OapiError,
11    rest::post::{Post, PostNoStream},
12};
13
14/// A search result of a vector store query.
15#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
16pub struct VectorStoreSearchResult {
17    /// The ID of the file the result came from.
18    #[serde(default)]
19    pub file_id: Option<String>,
20    /// The filename of the file the result came from.
21    #[serde(default)]
22    pub filename: Option<String>,
23    /// The relevance score of the result.
24    #[serde(default)]
25    pub score: Option<f64>,
26    /// The matching text chunks.
27    #[serde(default)]
28    pub text: Option<Vec<String>>,
29    /// The matching text chunks with their individual scores.
30    #[serde(default)]
31    pub attributes: Option<serde_json::Value>,
32}
33
34/// The response of a vector store search.
35#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
36pub struct VectorStoreSearchResponse {
37    /// The object type (`vector_store.search_results.page`).
38    #[serde(default)]
39    pub object: Option<String>,
40    /// The search query.
41    #[serde(default)]
42    pub search_query: Option<Vec<String>>,
43    /// The matching results.
44    #[serde(default)]
45    pub data: Vec<VectorStoreSearchResult>,
46    /// Whether more results exist after this page.
47    #[serde(default)]
48    pub has_more: Option<bool>,
49    /// The pagination token for the next page.
50    #[serde(default)]
51    pub next_page: Option<String>,
52}
53
54crate::impl_from_str!(VectorStoreSearchResponse);
55
56/// Searches a vector store for matching chunks.
57#[derive(Debug, Clone, Serialize)]
58pub struct SearchVectorStoreRequest<'a> {
59    /// The ID of the vector store to search, e.g. `vs_...`.
60    #[serde(skip)]
61    pub vector_store_id: &'a str,
62    /// The search query.
63    pub query: Vec<String>,
64    /// Whether to rewrite the query with the model (REWRITE or
65    /// DISABLED, as raw JSON when a string).
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub rewrite_query: Option<bool>,
68    /// The maximum number of results to return (1-50, default 10).
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub max_num_results: Option<u32>,
71    /// The attribute filters to apply, as raw JSON.
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub filters: Option<serde_json::Value>,
74    /// The ranking options (e.g. the reranker), as raw JSON.
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub ranking_options: Option<serde_json::Value>,
77    /// Additional JSON properties flattened into the request body, for
78    /// fields not covered by the typed struct.
79    #[serde(flatten, default, skip_serializing_if = "Option::is_none")]
80    pub extra_body_map: Option<serde_json::Map<String, serde_json::Value>>,
81}
82
83impl Post for SearchVectorStoreRequest<'_> {
84    fn is_streaming(&self) -> bool {
85        false
86    }
87
88    /// Builds the URL for the request.
89    ///
90    /// `base_url` should be like <https://api.openai.com/v1>
91    fn build_url(&self, base_url: &str) -> Result<String, OapiError> {
92        let mut url = Url::parse(base_url.trim_end_matches('/')).map_err(OapiError::UrlError)?;
93        url.path_segments_mut()
94            .map_err(|_| OapiError::UrlCannotBeBase(base_url.to_string()))?
95            .push("vector_stores")
96            .push(self.vector_store_id)
97            .push("search");
98        Ok(url.to_string())
99    }
100}
101
102impl PostNoStream for SearchVectorStoreRequest<'_> {
103    type Response = VectorStoreSearchResponse;
104}