openai_interface/embeddings/
response.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Deserialize, Serialize, Clone)]
5pub struct CreateEmbeddingResponse {
6 pub data: Vec<Embedding>,
8 pub model: String,
10 pub object: String,
12 pub usage: Usage,
14}
15
16#[derive(Debug, Deserialize, Serialize, Clone)]
18pub struct Embedding {
19 pub embedding: EmbeddingVector,
24 pub index: usize,
26 pub object: String,
28}
29
30#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
33#[serde(untagged)]
34pub enum EmbeddingVector {
35 Floats(Vec<f32>),
36 Base64(String),
37}
38
39#[derive(Debug, Deserialize, Serialize, Clone)]
41pub struct Usage {
42 pub prompt_tokens: usize,
44 pub total_tokens: usize,
46}
47
48crate::impl_from_str!(CreateEmbeddingResponse);
49
50#[cfg(test)]
51mod tests {
52 #[test]
61 fn parse_float_response() {
62 let content = r#"{
63 "data": [
64 {
65 "embedding": [0.033480461686849594,0.00393357127904892,0.008528660982847214,0.03501124680042267,0.053708694875240326,-0.013427173718610081,0.003826963249593973,-0.0037968941032886505,-0.059481941163539886,0.21693414449691772,0.023467724293470383,-0.011972927488386631,0.017680570483207703,0.006883066613227129,0.04200912266969681,-0.04117812216281891],
66 "index": 0,
67 "object": "embedding"
68 }
69 ],
70 "object": "list",
71 "model": "text-embedding-v4",
72 "usage": {"prompt_tokens": 2, "total_tokens": 2},
73 "id": "7010976a-5a36-955a-b837-0eedda118144"
74 }"#;
75
76 let response: super::CreateEmbeddingResponse = content.parse().unwrap();
77 assert_eq!(response.object, "list");
78 assert_eq!(response.data.len(), 1);
79 assert_eq!(response.data[0].index, 0);
80 assert_eq!(response.data[0].object, "embedding");
81 assert_eq!(response.model, "text-embedding-v4");
82 assert_eq!(response.usage.prompt_tokens, 2);
83 assert_eq!(response.usage.total_tokens, 2);
84 let super::EmbeddingVector::Floats(vector) = &response.data[0].embedding else {
85 panic!("expected float embedding vector");
86 };
87 assert_eq!(vector.len(), 16);
88 #[allow(clippy::excessive_precision)]
89 {
90 assert!((vector[0] - 0.033480461686849594).abs() < 1e-6);
91 }
92 }
93
94 #[test]
103 fn parse_base64_response() {
104 let content = r#"{
105 "object": "list",
106 "data": [
107 {
108 "object": "embedding",
109 "index": 0,
110 "embedding": "AACAPwAAAAAAAAAAAAAAAAAAAAA="
111 }
112 ],
113 "model": "text-embedding-3-small",
114 "usage": {"prompt_tokens": 5, "total_tokens": 5}
115 }"#;
116
117 let response: super::CreateEmbeddingResponse = content.parse().unwrap();
118 assert_eq!(
119 response.data[0].embedding,
120 super::EmbeddingVector::Base64("AACAPwAAAAAAAAAAAAAAAAAAAAA=".to_string())
121 );
122 }
123}