use serde::{Deserialize, Serialize};
use validator::Validate;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum SearchEngine {
SearchStd,
SearchPro,
SearchProSogou,
SearchProQuark,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum SearchRecencyFilter {
OneDay,
OneWeek,
OneMonth,
OneYear,
NoLimit,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum ContentSize {
Medium,
High,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchIntent {
pub query: String,
pub intent: String,
pub keywords: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchResult {
pub title: String,
pub content: String,
pub link: String,
pub media: String,
pub icon: String,
pub refer: String,
pub publish_date: String,
}
#[derive(Debug, Clone, Serialize, Validate)]
pub struct WebSearchBody {
#[validate(length(max = 70, message = "search_query cannot exceed 70 characters"))]
pub search_query: String,
pub search_engine: SearchEngine,
#[serde(skip_serializing_if = "Option::is_none")]
pub search_intent: Option<bool>,
#[validate(range(min = 1, max = 50, message = "count must be between 1 and 50"))]
#[serde(skip_serializing_if = "Option::is_none")]
pub count: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub search_domain_filter: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub search_recency_filter: Option<SearchRecencyFilter>,
#[serde(skip_serializing_if = "Option::is_none")]
pub content_size: Option<ContentSize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub request_id: Option<String>,
#[validate(length(
min = 6,
max = 128,
message = "user_id must be between 6 and 128 characters"
))]
#[serde(skip_serializing_if = "Option::is_none")]
pub user_id: Option<String>,
}
impl WebSearchBody {
pub fn new(search_query: String, search_engine: SearchEngine) -> Self {
Self {
search_query,
search_engine,
search_intent: None,
count: None,
search_domain_filter: None,
search_recency_filter: None,
content_size: None,
request_id: None,
user_id: None,
}
}
pub fn with_search_intent(mut self, enabled: bool) -> Self {
self.search_intent = Some(enabled);
self
}
pub fn with_count(mut self, count: i32) -> Self {
self.count = Some(count);
self
}
pub fn with_domain_filter(mut self, domain: String) -> Self {
self.search_domain_filter = Some(domain);
self
}
pub fn with_recency_filter(mut self, filter: SearchRecencyFilter) -> Self {
self.search_recency_filter = Some(filter);
self
}
pub fn with_content_size(mut self, size: ContentSize) -> Self {
self.content_size = Some(size);
self
}
pub fn with_request_id(mut self, request_id: String) -> Self {
self.request_id = Some(request_id);
self
}
pub fn with_user_id(mut self, user_id: String) -> Self {
self.user_id = Some(user_id);
self
}
pub fn validate_constraints(&self) -> crate::ZaiResult<()> {
self.validate()
.map_err(|e| crate::client::error::ZaiError::ApiError {
code: 1200,
message: format!("Validation error: {}", e),
})?;
if let Some(count) = self.count
&& matches!(self.search_engine, SearchEngine::SearchProSogou)
{
match count {
10 | 20 | 30 | 40 | 50 => {},
_ => {
return Err(crate::client::error::ZaiError::ApiError {
code: 1200,
message: "search_pro_sogou only supports count values: 10, 20, 30, 40, 50"
.to_string(),
});
},
}
}
Ok(())
}
}