1crate::ix!();
3
4#[derive(Builder,Getters,Clone,Debug,Serialize,Deserialize)]
5#[builder(setter(into))]
6#[getset(get="pub")]
7pub struct BatchResponseRecord {
8 id: BatchRequestId,
9 custom_id: CustomRequestId,
10 response: BatchResponseContent,
11
12 #[builder(default)]
13 error: Option<serde_json::Value>, }
15
16impl BatchResponseRecord {
17
18 pub fn mock_with_code_and_default_body(custom_id: &str, code: u16) -> Self {
19 let body = if code == 200 {
21 json!({
22 "id": "success-id",
23 "object": "chat.completion",
24 "created": 0,
25 "model": "test-model",
26 "choices": [],
27 "usage": {
28 "prompt_tokens": 0,
29 "completion_tokens": 0,
30 "total_tokens": 0
31 }
32 })
33 } else {
34 json!({
35 "error": {
36 "message": format!("Error for {custom_id}"),
37 "type": "test_error",
38 "param": null,
39 "code": null
40 }
41 })
42 };
43
44 BatchResponseRecord::mock_with_code_and_body(custom_id,code,&body)
45 }
46
47 pub fn mock_with_code_and_body(custom_id: &str, code: u16, body: &serde_json::Value) -> Self {
48 BatchResponseRecord {
49 id: BatchRequestId::new(format!("batch_req_{custom_id}")),
50 custom_id: CustomRequestId::new(custom_id),
51 response: BatchResponseContent::mock_with_code_and_body(custom_id,code,body),
52 error: None,
53 }
54 }
55
56 pub fn mock(custom_id: &str) -> Self {
57 BatchResponseRecord {
58 id: BatchRequestId::new(format!("batch_req_{}", custom_id)),
59 custom_id: CustomRequestId::new(custom_id),
60 response: BatchResponseContent::mock(custom_id),
61 error: None,
62 }
63 }
64
65 pub fn mock_with_code(custom_id: &str, code: u16) -> Self {
71
72 if code == 200 {
74 let body = json!({
75 "id": "success-id",
76 "object": "chat.completion",
77 "created": 0,
78 "model": "test-model",
79 "choices": [],
80 "usage": {
81 "prompt_tokens": 0,
82 "completion_tokens": 0,
83 "total_tokens": 0
84 }
85 });
86 return BatchResponseRecord {
87 id: BatchRequestId::new(format!("batch_req_{}", custom_id)),
88 custom_id: CustomRequestId::new(custom_id),
89 response: BatchResponseContent::mock_with_code_and_body(custom_id,code,&body),
90 error: None,
91 };
92 }
93
94 let body = json!({
96 "error": {
97 "message": format!("Error for {}", custom_id),
98 "type": "test_error",
99 "param": null,
100 "code": null
101 }
102 });
103 BatchResponseRecord {
104 id: BatchRequestId::new(format!("batch_req_{}", custom_id)),
105 custom_id: CustomRequestId::new(custom_id),
106 response: BatchResponseContent::mock_with_code_and_body(custom_id,code,&body),
107 error: None,
108 }
109 }
110}
111
112#[cfg(test)]
113mod batch_response_record_tests {
114 use super::*;
115
116 #[traced_test]
117 fn test_full_batch_deserialization() {
118 info!("Starting test: test_full_batch_deserialization");
119
120 let json = r#"
121 {
122 "id": "batch_req_673d5e5fc66481908be3f82f25681838",
123 "custom_id": "request-0",
124 "response": {
125 "status_code": 200,
126 "request_id": "7b003085175d218b0ceb2b79d7f60bca",
127 "body": {
128 "id": "chatcmpl-AVW7Z2Dd49g7Zq5eVExww6dlKA8T9",
129 "object": "chat.completion",
130 "created": 1732075005,
131 "model": "gpt-4o-2024-08-06",
132 "choices": [{
133 "index": 0,
134 "message": {
135 "role": "assistant",
136 "content": "Response content here.",
137 "refusal": null
138 },
139 "logprobs": null,
140 "finish_reason": "stop"
141 }],
142 "usage": {
143 "prompt_tokens": 1528,
144 "completion_tokens": 2891,
145 "total_tokens": 4419
146 }
147 }
148 },
149 "error": null
150 }
151 "#;
152
153 let batch_response: BatchResponseRecord = serde_json::from_str(json).unwrap();
154 pretty_assert_eq!(
155 batch_response.id,
156 BatchRequestId::new("batch_req_673d5e5fc66481908be3f82f25681838")
157 );
158 pretty_assert_eq!(
159 batch_response.custom_id,
160 CustomRequestId::new("request-0")
161 );
162 assert!(batch_response.error.is_none());
163
164 let response = batch_response.response;
165 pretty_assert_eq!(*response.status_code(), 200);
166 pretty_assert_eq!(response.request_id(), "7b003085175d218b0ceb2b79d7f60bca");
167
168 let body = response.body();
169
170 pretty_assert_eq!(
172 body.id(),
173 Some(&"chatcmpl-AVW7Z2Dd49g7Zq5eVExww6dlKA8T9".to_string())
174 );
175 pretty_assert_eq!(
176 body.object(),
177 Some(&"chat.completion".to_string())
178 );
179 pretty_assert_eq!(
180 body.model(),
181 Some(&"gpt-4o-2024-08-06".to_string())
182 );
183
184 let choices = body.choices();
185 assert!(choices.is_some());
186 let choices = choices.unwrap();
187 pretty_assert_eq!(choices.len(), 1);
188
189 let choice = &choices[0];
190 pretty_assert_eq!(*choice.index(), 0);
191 pretty_assert_eq!(choice.finish_reason(), &FinishReason::Stop);
192 pretty_assert_eq!(choice.message().role(), &MessageRole::Assistant);
193 pretty_assert_eq!(choice.message().content(), "Response content here.");
194
195 info!("Finished test: test_full_batch_deserialization");
196 }
197}