use serde::{Deserialize, Deserializer, Serialize, de::Error as _};
use validator::Validate;
#[derive(Debug, Clone, Serialize, Validate)]
pub struct KnowledgeResponse<T> {
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<T>,
#[serde(skip_serializing_if = "Option::is_none")]
pub code: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timestamp: Option<u64>,
}
#[derive(Deserialize)]
struct KnowledgeResponseWire<T> {
data: Option<T>,
code: Option<i64>,
message: Option<String>,
timestamp: Option<u64>,
}
impl<'de, T> Deserialize<'de> for KnowledgeResponse<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let wire = KnowledgeResponseWire::deserialize(deserializer)?;
if wire.data.is_none()
&& wire.code.is_none()
&& wire.message.is_none()
&& wire.timestamp.is_none()
{
return Err(D::Error::custom(
"knowledge response contained no documented non-null fields",
));
}
Ok(Self {
data: wire.data,
code: wire.code,
message: wire.message,
timestamp: wire.timestamp,
})
}
}
#[derive(Debug, Clone, Serialize, Validate)]
pub struct KnowledgeOperationResponse {
#[serde(skip_serializing_if = "Option::is_none")]
pub code: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timestamp: Option<u64>,
}
#[derive(Deserialize)]
struct KnowledgeOperationResponseWire {
code: Option<i64>,
message: Option<String>,
timestamp: Option<u64>,
}
impl<'de> Deserialize<'de> for KnowledgeOperationResponse {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let wire = KnowledgeOperationResponseWire::deserialize(deserializer)?;
if wire.code.is_none() && wire.message.is_none() && wire.timestamp.is_none() {
return Err(D::Error::custom(
"knowledge operation response contained no documented non-null fields",
));
}
Ok(Self {
code: wire.code,
message: wire.message,
timestamp: wire.timestamp,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct KnowledgeItem {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub embedding_id: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub contextual: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub background: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub document_size: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub length: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub word_num: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct KnowledgeListData {
#[serde(skip_serializing_if = "Option::is_none")]
pub list: Option<Vec<KnowledgeItem>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total: Option<u64>,
}
pub type KnowledgeListResponse = KnowledgeResponse<KnowledgeListData>;
pub type KnowledgeGetResponse = KnowledgeResponse<KnowledgeItem>;
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct KnowledgeUsageCounts {
#[serde(skip_serializing_if = "Option::is_none")]
pub word_num: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub length: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct KnowledgeCapacityData {
#[serde(skip_serializing_if = "Option::is_none")]
pub used: Option<KnowledgeUsageCounts>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total: Option<KnowledgeUsageCounts>,
}
pub type KnowledgeCapacityResponse = KnowledgeResponse<KnowledgeCapacityData>;
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct DocumentFailInfo {
#[serde(skip_serializing_if = "Option::is_none")]
pub embedding_code: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub embedding_msg: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct DocumentItem {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub knowledge_type: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_separator: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sentence_size: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub length: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub word_num: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub embedding_stat: Option<i64>,
#[serde(rename = "failInfo", skip_serializing_if = "Option::is_none")]
pub fail_info: Option<DocumentFailInfo>,
}
pub type DocumentGetResponse = KnowledgeResponse<DocumentItem>;
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct DocumentListData {
#[serde(skip_serializing_if = "Option::is_none")]
pub list: Option<Vec<DocumentItem>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total: Option<u64>,
}
pub type DocumentListResponse = KnowledgeResponse<DocumentListData>;
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct DocumentUrlUploadSuccessInfo {
#[serde(rename = "documentId", skip_serializing_if = "Option::is_none")]
pub document_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct DocumentUrlUploadFailedInfo {
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(rename = "failReason", skip_serializing_if = "Option::is_none")]
pub fail_reason: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct DocumentUrlUploadData {
#[serde(rename = "successInfos", skip_serializing_if = "Option::is_none")]
pub success_infos: Option<Vec<DocumentUrlUploadSuccessInfo>>,
#[serde(rename = "failedInfos", skip_serializing_if = "Option::is_none")]
pub failed_infos: Option<Vec<DocumentUrlUploadFailedInfo>>,
}
pub type DocumentUrlUploadResponse = KnowledgeResponse<DocumentUrlUploadData>;
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct DocumentUploadSuccessInfo {
#[serde(rename = "documentId", skip_serializing_if = "Option::is_none")]
pub document_id: Option<String>,
#[serde(rename = "fileName", skip_serializing_if = "Option::is_none")]
pub file_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct DocumentUploadFailedInfo {
#[serde(rename = "fileName", skip_serializing_if = "Option::is_none")]
pub file_name: Option<String>,
#[serde(rename = "failReason", skip_serializing_if = "Option::is_none")]
pub fail_reason: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct DocumentUploadData {
#[serde(rename = "successInfos", skip_serializing_if = "Option::is_none")]
pub success_infos: Option<Vec<DocumentUploadSuccessInfo>>,
#[serde(rename = "failedInfos", skip_serializing_if = "Option::is_none")]
pub failed_infos: Option<Vec<DocumentUploadFailedInfo>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct DocumentImageItem {
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cos_url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct DocumentImageListData {
#[serde(skip_serializing_if = "Option::is_none")]
pub images: Option<Vec<DocumentImageItem>>,
}
pub type DocumentImageListResponse = KnowledgeResponse<DocumentImageListData>;
pub type DocumentUploadResponse = KnowledgeResponse<DocumentUploadData>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn success_envelopes_follow_optional_schema_and_reject_empty_success() {
assert!(
serde_json::from_value::<KnowledgeResponse<serde_json::Value>>(
serde_json::json!({"code": 200})
)
.is_ok()
);
assert!(
serde_json::from_value::<KnowledgeResponse<serde_json::Value>>(
serde_json::json!({"data": {}})
)
.is_ok()
);
assert!(
serde_json::from_value::<KnowledgeResponse<serde_json::Value>>(serde_json::json!({}))
.is_err()
);
assert!(
serde_json::from_value::<KnowledgeResponse<serde_json::Value>>(
serde_json::json!({"data": null, "code": null})
)
.is_err()
);
assert!(
serde_json::from_value::<KnowledgeOperationResponse>(serde_json::json!({
"unknown": "value"
}))
.is_err()
);
assert!(
serde_json::from_value::<KnowledgeOperationResponse>(serde_json::json!({
"message": "ok"
}))
.is_ok()
);
}
}