1#![allow(clippy::uninlined_format_args)]
2use openai_ergonomic::{Client, Error};
35use serde_json::json;
36
37#[tokio::main]
38async fn main() -> Result<(), Box<dyn std::error::Error>> {
39 println!(" OpenAI Ergonomic - Structured Outputs Example\n");
40
41 let client = match Client::from_env() {
43 Ok(client_builder) => {
44 println!(" Client initialized successfully");
45 client_builder.build()
46 }
47 Err(e) => {
48 eprintln!(" Failed to initialize client: {e}");
49 eprintln!(" Make sure OPENAI_API_KEY is set in your environment");
50 return Err(e.into());
51 }
52 };
53
54 println!("\n Example 1: Simple JSON Mode");
56 println!("==============================");
57
58 match simple_json_mode_example(&client).await {
59 Ok(()) => println!(" Simple JSON mode example completed"),
60 Err(e) => {
61 eprintln!(" Simple JSON mode example failed: {e}");
62 handle_api_error(&e);
63 }
64 }
65
66 println!("\n Example 2: Schema-Based Data Extraction");
68 println!("==========================================");
69
70 match data_extraction_example(&client).await {
71 Ok(()) => println!(" Data extraction example completed"),
72 Err(e) => {
73 eprintln!(" Data extraction example failed: {e}");
74 handle_api_error(&e);
75 }
76 }
77
78 println!("\n Example 3: Complex Nested Structures");
80 println!("=======================================");
81
82 match complex_structure_example(&client).await {
83 Ok(()) => println!(" Complex structure example completed"),
84 Err(e) => {
85 eprintln!(" Complex structure example failed: {e}");
86 handle_api_error(&e);
87 }
88 }
89
90 println!("\n Example 4: Content Classification");
92 println!("=====================================");
93
94 match classification_example(&client).await {
95 Ok(()) => println!(" Classification example completed"),
96 Err(e) => {
97 eprintln!(" Classification example failed: {e}");
98 handle_api_error(&e);
99 }
100 }
101
102 println!("\n Example 5: Mathematical Analysis");
104 println!("===================================");
105
106 match math_analysis_example(&client).await {
107 Ok(()) => println!(" Mathematical analysis example completed"),
108 Err(e) => {
109 eprintln!(" Mathematical analysis example failed: {e}");
110 handle_api_error(&e);
111 }
112 }
113
114 println!("\n Example 6: Schema Validation & Error Handling");
116 println!("=================================================");
117
118 match validation_error_example(&client).await {
119 Ok(()) => println!(" Validation error example completed"),
120 Err(e) => {
121 eprintln!(" Validation error example failed: {e}");
122 handle_api_error(&e);
123 }
124 }
125
126 println!("\n All structured output examples completed!");
127 println!(" Check the console output above for JSON-formatted results.");
128 Ok(())
129}
130
131async fn simple_json_mode_example(client: &Client) -> Result<(), Error> {
133 println!("Using simple JSON mode for basic structure enforcement...");
134
135 let builder = client
136 .responses()
137 .system("You are a helpful assistant. Always respond in valid JSON format with the keys: summary, sentiment, and confidence_score (0-1).")
138 .user("Analyze this product review: 'This laptop is amazing! Great performance, excellent battery life, and the display is crystal clear. Highly recommended!'")
139 .json_mode()
140 .temperature(0.3)
141 .max_completion_tokens(200);
142
143 let response = client.send_responses(builder).await?;
144
145 if let Some(content) = response.content() {
146 println!(" JSON Analysis Result:");
147
148 match serde_json::from_str::<serde_json::Value>(content) {
150 Ok(json) => {
151 println!("{}", serde_json::to_string_pretty(&json)?);
152
153 if let Some(sentiment) = json.get("sentiment").and_then(|s| s.as_str()) {
155 println!("\n Extracted sentiment: {sentiment}");
156 }
157 if let Some(confidence) = json
158 .get("confidence_score")
159 .and_then(serde_json::Value::as_f64)
160 {
161 println!(" Confidence score: {confidence:.2}");
162 }
163 }
164 Err(e) => {
165 println!(" Failed to parse JSON: {e}");
166 println!("Raw response: {content}");
167 }
168 }
169 }
170
171 Ok(())
172}
173
174async fn data_extraction_example(client: &Client) -> Result<(), Error> {
176 println!("Extracting structured data from unstructured text using JSON schema...");
177
178 let contact_schema = json!({
180 "type": "object",
181 "properties": {
182 "contacts": {
183 "type": "array",
184 "items": {
185 "type": "object",
186 "properties": {
187 "name": {
188 "type": "string",
189 "description": "Full name of the person"
190 },
191 "email": {
192 "type": "string",
193 "format": "email",
194 "description": "Email address"
195 },
196 "phone": {
197 "type": "string",
198 "description": "Phone number"
199 },
200 "company": {
201 "type": "string",
202 "description": "Company or organization"
203 },
204 "role": {
205 "type": "string",
206 "description": "Job title or role"
207 }
208 },
209 "required": ["name"],
210 "additionalProperties": false
211 }
212 },
213 "total_contacts": {
214 "type": "integer",
215 "description": "Total number of contacts extracted"
216 }
217 },
218 "required": ["contacts", "total_contacts"],
219 "additionalProperties": false
220 });
221
222 let unstructured_text =
223 "Contact our team: John Smith (CEO) at john@example.com or call 555-0123. \
224 For technical support, reach out to Sarah Johnson at sarah.johnson@techcorp.com. \
225 Our sales manager Mike Wilson can be reached at mike@company.com or 555-0456.";
226
227 let builder = client
228 .responses()
229 .system("You are an expert at extracting contact information from text. Extract all contact details you can find and structure them according to the provided schema.")
230 .user(format!("Extract contact information from this text: {unstructured_text}"))
231 .json_schema("contact_extraction", contact_schema)
232 .temperature(0.1); let response = client.send_responses(builder).await?;
235
236 if let Some(content) = response.content() {
237 println!(" Extracted Contact Information:");
238
239 match serde_json::from_str::<serde_json::Value>(content) {
240 Ok(json) => {
241 println!("{}", serde_json::to_string_pretty(&json)?);
242
243 if let Some(contacts) = json.get("contacts").and_then(|c| c.as_array()) {
245 println!("\n Summary: Found {} contact(s)", contacts.len());
246 for (i, contact) in contacts.iter().enumerate() {
247 if let Some(name) = contact.get("name").and_then(|n| n.as_str()) {
248 println!(" {}. {name}", i + 1);
249 if let Some(email) = contact.get("email").and_then(|e| e.as_str()) {
250 println!(" {email}");
251 }
252 if let Some(company) = contact.get("company").and_then(|c| c.as_str()) {
253 println!(" {company}");
254 }
255 }
256 }
257 }
258 }
259 Err(e) => {
260 println!(" Failed to parse JSON: {e}");
261 println!("Raw response: {content}");
262 }
263 }
264 }
265
266 Ok(())
267}
268
269#[allow(clippy::too_many_lines)]
271async fn complex_structure_example(client: &Client) -> Result<(), Error> {
272 println!("Creating complex nested structure for event planning...");
273
274 let event_schema = json!({
276 "type": "object",
277 "properties": {
278 "event": {
279 "type": "object",
280 "properties": {
281 "name": {
282 "type": "string",
283 "description": "Event name"
284 },
285 "type": {
286 "type": "string",
287 "enum": ["conference", "workshop", "seminar", "networking", "party", "meeting"],
288 "description": "Type of event"
289 },
290 "date": {
291 "type": "string",
292 "format": "date",
293 "description": "Event date in YYYY-MM-DD format"
294 },
295 "duration_hours": {
296 "type": "number",
297 "minimum": 0.5,
298 "maximum": 24,
299 "description": "Duration in hours"
300 },
301 "venue": {
302 "type": "object",
303 "properties": {
304 "name": {
305 "type": "string",
306 "description": "Venue name"
307 },
308 "address": {
309 "type": "string",
310 "description": "Venue address"
311 },
312 "capacity": {
313 "type": "integer",
314 "minimum": 1,
315 "description": "Maximum capacity"
316 },
317 "amenities": {
318 "type": "array",
319 "items": {
320 "type": "string",
321 "enum": ["wifi", "parking", "catering", "av_equipment", "wheelchair_accessible", "air_conditioning"]
322 },
323 "description": "Available amenities"
324 }
325 },
326 "required": ["name", "capacity"],
327 "additionalProperties": false
328 },
329 "agenda": {
330 "type": "array",
331 "items": {
332 "type": "object",
333 "properties": {
334 "time": {
335 "type": "string",
336 "pattern": "^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$",
337 "description": "Time in HH:MM format"
338 },
339 "activity": {
340 "type": "string",
341 "description": "Activity description"
342 },
343 "speaker": {
344 "type": "string",
345 "description": "Speaker name"
346 },
347 "duration_minutes": {
348 "type": "integer",
349 "minimum": 15,
350 "maximum": 480,
351 "description": "Activity duration in minutes"
352 }
353 },
354 "required": ["time", "activity", "duration_minutes"],
355 "additionalProperties": false
356 }
357 },
358 "estimated_cost": {
359 "type": "object",
360 "properties": {
361 "venue": {
362 "type": "number",
363 "minimum": 0,
364 "description": "Venue cost in USD"
365 },
366 "catering": {
367 "type": "number",
368 "minimum": 0,
369 "description": "Catering cost in USD"
370 },
371 "equipment": {
372 "type": "number",
373 "minimum": 0,
374 "description": "Equipment cost in USD"
375 },
376 "total": {
377 "type": "number",
378 "minimum": 0,
379 "description": "Total estimated cost in USD"
380 }
381 },
382 "required": ["total"],
383 "additionalProperties": false
384 }
385 },
386 "required": ["name", "type", "date", "duration_hours", "venue"],
387 "additionalProperties": false
388 }
389 },
390 "required": ["event"],
391 "additionalProperties": false
392 });
393
394 let builder = client
395 .responses()
396 .system("You are an expert event planner. Create a detailed event plan based on the user's requirements, including venue details, agenda, and cost estimates.")
397 .user("Plan a one-day AI/ML conference for 200 people in San Francisco. Include morning keynotes, afternoon workshops, networking lunch, and panel discussions. Budget around $50,000.")
398 .json_schema("event_plan", event_schema)
399 .temperature(0.5);
400
401 let response = client.send_responses(builder).await?;
402
403 if let Some(content) = response.content() {
404 println!(" Event Plan:");
405
406 match serde_json::from_str::<serde_json::Value>(content) {
407 Ok(json) => {
408 println!("{}", serde_json::to_string_pretty(&json)?);
409
410 if let Some(event) = json.get("event") {
412 if let Some(name) = event.get("name").and_then(|n| n.as_str()) {
413 println!("\n Event: {name}");
414 }
415 if let Some(venue) = event.get("venue") {
416 if let Some(venue_name) = venue.get("name").and_then(|n| n.as_str()) {
417 let capacity = venue
418 .get("capacity")
419 .and_then(serde_json::Value::as_i64)
420 .unwrap_or(0);
421 println!(" Venue: {venue_name} (Capacity: {capacity})");
422 }
423 }
424 if let Some(agenda) = event.get("agenda").and_then(|a| a.as_array()) {
425 println!(" Agenda has {} activities", agenda.len());
426 }
427 if let Some(cost) = event.get("estimated_cost") {
428 if let Some(total) = cost.get("total").and_then(serde_json::Value::as_f64) {
429 println!(" Estimated total cost: ${total:.2}");
430 }
431 }
432 }
433 }
434 Err(e) => {
435 println!(" Failed to parse JSON: {e}");
436 println!("Raw response: {content}");
437 }
438 }
439 }
440
441 Ok(())
442}
443
444#[allow(clippy::too_many_lines)]
446async fn classification_example(client: &Client) -> Result<(), Error> {
447 println!("Classifying content with enum validation...");
448
449 let classification_schema = json!({
451 "type": "object",
452 "properties": {
453 "classification": {
454 "type": "object",
455 "properties": {
456 "category": {
457 "type": "string",
458 "enum": ["technology", "business", "science", "health", "politics", "sports", "entertainment", "education", "travel", "lifestyle"],
459 "description": "Primary content category"
460 },
461 "subcategory": {
462 "type": "string",
463 "description": "More specific subcategory"
464 },
465 "sentiment": {
466 "type": "string",
467 "enum": ["positive", "neutral", "negative", "mixed"],
468 "description": "Overall sentiment"
469 },
470 "topics": {
471 "type": "array",
472 "items": {
473 "type": "string"
474 },
475 "maxItems": 5,
476 "description": "Key topics mentioned"
477 },
478 "target_audience": {
479 "type": "string",
480 "enum": ["general", "professionals", "students", "experts", "consumers"],
481 "description": "Intended audience"
482 },
483 "complexity_level": {
484 "type": "string",
485 "enum": ["beginner", "intermediate", "advanced", "expert"],
486 "description": "Content complexity level"
487 },
488 "confidence_score": {
489 "type": "number",
490 "minimum": 0,
491 "maximum": 1,
492 "description": "Confidence in classification (0-1)"
493 }
494 },
495 "required": ["category", "sentiment", "topics", "target_audience", "complexity_level", "confidence_score"],
496 "additionalProperties": false
497 }
498 },
499 "required": ["classification"],
500 "additionalProperties": false
501 });
502
503 let content_to_classify = "Recent advances in quantum computing have shown promising results for solving complex optimization problems. \
504 Researchers at leading universities have demonstrated quantum algorithms that can potentially outperform classical computers \
505 in specific domains like cryptography and molecular simulation. However, current quantum computers still face challenges \
506 with noise and error rates, requiring sophisticated error correction techniques. The field is rapidly evolving with \
507 significant investments from both academic institutions and major technology companies.";
508
509 let builder = client
510 .responses()
511 .system("You are an expert content classifier. Analyze the provided text and classify it according to the given schema. Be precise with your classifications and provide accurate confidence scores.")
512 .user(format!("Classify this content: {content_to_classify}"))
513 .json_schema("content_classification", classification_schema)
514 .temperature(0.2); let response = client.send_responses(builder).await?;
517
518 if let Some(content) = response.content() {
519 println!(" Content Classification:");
520
521 match serde_json::from_str::<serde_json::Value>(content) {
522 Ok(json) => {
523 println!("{}", serde_json::to_string_pretty(&json)?);
524
525 if let Some(classification) = json.get("classification") {
527 println!("\n Classification Summary:");
528 if let Some(category) = classification.get("category").and_then(|c| c.as_str())
529 {
530 println!(" Category: {category}");
531 }
532 if let Some(sentiment) =
533 classification.get("sentiment").and_then(|s| s.as_str())
534 {
535 println!(" Sentiment: {sentiment}");
536 }
537 if let Some(audience) = classification
538 .get("target_audience")
539 .and_then(|a| a.as_str())
540 {
541 println!(" Target Audience: {audience}");
542 }
543 if let Some(complexity) = classification
544 .get("complexity_level")
545 .and_then(|c| c.as_str())
546 {
547 println!(" Complexity: {complexity}");
548 }
549 if let Some(confidence) = classification
550 .get("confidence_score")
551 .and_then(serde_json::Value::as_f64)
552 {
553 println!(" Confidence: {:.2}%", confidence * 100.0);
554 }
555 if let Some(topics) = classification.get("topics").and_then(|t| t.as_array()) {
556 let topic_strings: Vec<String> = topics
557 .iter()
558 .filter_map(|t| t.as_str())
559 .map(std::string::ToString::to_string)
560 .collect();
561 println!(" Topics: {}", topic_strings.join(", "));
562 }
563 }
564 }
565 Err(e) => {
566 println!(" Failed to parse JSON: {e}");
567 println!("Raw response: {content}");
568 }
569 }
570 }
571
572 Ok(())
573}
574
575#[allow(clippy::too_many_lines)]
577async fn math_analysis_example(client: &Client) -> Result<(), Error> {
578 println!("Performing mathematical analysis with structured output...");
579
580 let math_schema = json!({
582 "type": "object",
583 "properties": {
584 "analysis": {
585 "type": "object",
586 "properties": {
587 "problem_type": {
588 "type": "string",
589 "enum": ["algebra", "geometry", "calculus", "statistics", "probability", "discrete_math", "linear_algebra"],
590 "description": "Type of mathematical problem"
591 },
592 "solution_steps": {
593 "type": "array",
594 "items": {
595 "type": "object",
596 "properties": {
597 "step_number": {
598 "type": "integer",
599 "minimum": 1,
600 "description": "Step number in the solution"
601 },
602 "description": {
603 "type": "string",
604 "description": "Description of what this step does"
605 },
606 "equation": {
607 "type": "string",
608 "description": "Mathematical equation or expression"
609 },
610 "result": {
611 "type": "string",
612 "description": "Result of this step"
613 }
614 },
615 "required": ["step_number", "description", "equation"],
616 "additionalProperties": false
617 }
618 },
619 "final_answer": {
620 "type": "string",
621 "description": "Final answer to the problem"
622 },
623 "verification": {
624 "type": "object",
625 "properties": {
626 "check_method": {
627 "type": "string",
628 "description": "Method used to verify the answer"
629 },
630 "is_correct": {
631 "type": "boolean",
632 "description": "Whether the answer passes verification"
633 }
634 },
635 "required": ["check_method", "is_correct"],
636 "additionalProperties": false
637 },
638 "concepts_used": {
639 "type": "array",
640 "items": {
641 "type": "string"
642 },
643 "description": "Mathematical concepts used in the solution"
644 }
645 },
646 "required": ["problem_type", "solution_steps", "final_answer", "verification", "concepts_used"],
647 "additionalProperties": false
648 }
649 },
650 "required": ["analysis"],
651 "additionalProperties": false
652 });
653
654 let math_problem =
655 "Find the derivative of f(x) = 3x^3 + 2x^2 - 5x + 7 and evaluate it at x = 2.";
656
657 let builder = client
658 .responses()
659 .system("You are a mathematics tutor. Solve mathematical problems step by step, showing your work clearly and verifying your answers. Structure your response according to the provided schema.")
660 .user(format!("Solve this problem: {math_problem}"))
661 .json_schema("math_analysis", math_schema)
662 .temperature(0.1); let response = client.send_responses(builder).await?;
665
666 if let Some(content) = response.content() {
667 println!(" Mathematical Analysis:");
668
669 match serde_json::from_str::<serde_json::Value>(content) {
670 Ok(json) => {
671 println!("{}", serde_json::to_string_pretty(&json)?);
672
673 if let Some(analysis) = json.get("analysis") {
675 println!("\n Solution Summary:");
676
677 if let Some(problem_type) =
678 analysis.get("problem_type").and_then(|p| p.as_str())
679 {
680 println!(" Problem Type: {problem_type}");
681 }
682
683 if let Some(steps) = analysis.get("solution_steps").and_then(|s| s.as_array()) {
684 println!(" Solution Steps: {} steps", steps.len());
685 for step in steps {
686 if let (Some(step_num), Some(desc)) = (
687 step.get("step_number").and_then(serde_json::Value::as_i64),
688 step.get("description").and_then(|d| d.as_str()),
689 ) {
690 println!(" {step_num}. {desc}");
691 if let Some(equation) =
692 step.get("equation").and_then(|e| e.as_str())
693 {
694 println!(" {equation}");
695 }
696 }
697 }
698 }
699
700 if let Some(answer) = analysis.get("final_answer").and_then(|a| a.as_str()) {
701 println!(" Final Answer: {answer}");
702 }
703
704 if let Some(verification) = analysis.get("verification") {
705 if let Some(is_correct) = verification
706 .get("is_correct")
707 .and_then(serde_json::Value::as_bool)
708 {
709 let status = if is_correct {
710 " Verified"
711 } else {
712 " Needs Review"
713 };
714 println!(" Verification: {status}");
715 }
716 }
717
718 if let Some(concepts) = analysis.get("concepts_used").and_then(|c| c.as_array())
719 {
720 let concept_strings: Vec<String> = concepts
721 .iter()
722 .filter_map(|c| c.as_str())
723 .map(std::string::ToString::to_string)
724 .collect();
725 println!(" Concepts Used: {}", concept_strings.join(", "));
726 }
727 }
728 }
729 Err(e) => {
730 println!(" Failed to parse JSON: {e}");
731 println!("Raw response: {content}");
732 }
733 }
734 }
735
736 Ok(())
737}
738
739#[allow(clippy::too_many_lines)]
741async fn validation_error_example(client: &Client) -> Result<(), Error> {
742 println!("Demonstrating schema validation and error handling...");
743
744 let strict_schema = json!({
746 "type": "object",
747 "properties": {
748 "numbers": {
749 "type": "array",
750 "items": {
751 "type": "integer",
752 "minimum": 1,
753 "maximum": 100
754 },
755 "minItems": 3,
756 "maxItems": 5,
757 "description": "Array of 3-5 integers between 1 and 100"
758 },
759 "precision_value": {
760 "type": "number",
761 "multipleOf": 0.01,
762 "minimum": 0,
763 "maximum": 1,
764 "description": "A precise decimal value between 0 and 1, to 2 decimal places"
765 },
766 "strict_enum": {
767 "type": "string",
768 "enum": ["alpha", "beta", "gamma"],
769 "description": "Must be exactly one of the allowed values"
770 },
771 "required_pattern": {
772 "type": "string",
773 "pattern": "^[A-Z]{2}[0-9]{4}$",
774 "description": "Must be exactly 2 uppercase letters followed by 4 digits"
775 }
776 },
777 "required": ["numbers", "precision_value", "strict_enum", "required_pattern"],
778 "additionalProperties": false
779 });
780
781 println!(" Using a strict schema with specific constraints...");
782
783 let builder = client
784 .responses()
785 .system("Generate data that strictly follows the provided JSON schema. Pay careful attention to all constraints including ranges, patterns, and array sizes.")
786 .user("Generate sample data that conforms to the schema. Make sure all values meet the exact requirements.")
787 .json_schema("strict_validation", strict_schema)
788 .temperature(0.1)
789 .max_completion_tokens(300);
790
791 let response = client.send_responses(builder).await?;
792
793 if let Some(content) = response.content() {
794 println!(" Schema Validation Test:");
795
796 match serde_json::from_str::<serde_json::Value>(content) {
797 Ok(json) => {
798 println!("{}", serde_json::to_string_pretty(&json)?);
799
800 println!("\n Manual Validation:");
802 let mut validation_passed = true;
803
804 if let Some(numbers) = json.get("numbers").and_then(|n| n.as_array()) {
806 println!(" Numbers array: {} items", numbers.len());
807 if numbers.len() < 3 || numbers.len() > 5 {
808 println!(" Array size constraint violated");
809 validation_passed = false;
810 }
811 for (i, num) in numbers.iter().enumerate() {
812 if let Some(val) = num.as_i64() {
813 if !(1..=100).contains(&val) {
814 println!(" Number {i} ({val}) outside valid range [1-100]");
815 validation_passed = false;
816 }
817 }
818 }
819 } else {
820 println!(" Numbers array missing or invalid");
821 validation_passed = false;
822 }
823
824 if let Some(precision) = json
826 .get("precision_value")
827 .and_then(serde_json::Value::as_f64)
828 {
829 println!(" Precision value: {precision}");
830 if !(0.0..=1.0).contains(&precision) {
831 println!(" Precision value outside range [0-1]");
832 validation_passed = false;
833 }
834 }
835
836 if let Some(enum_val) = json.get("strict_enum").and_then(|e| e.as_str()) {
838 println!(" Enum value: {enum_val}");
839 if !["alpha", "beta", "gamma"].contains(&enum_val) {
840 println!(" Enum value not in allowed set");
841 validation_passed = false;
842 }
843 }
844
845 if let Some(pattern_val) = json.get("required_pattern").and_then(|p| p.as_str()) {
847 println!(" Pattern value: {pattern_val}");
848 let regex = regex::Regex::new(r"^[A-Z]{2}[0-9]{4}$").unwrap();
849 if !regex.is_match(pattern_val) {
850 println!(" Pattern does not match required format");
851 validation_passed = false;
852 }
853 }
854
855 if validation_passed {
856 println!(" All manual validations passed!");
857 } else {
858 println!(" Some validation constraints were not met");
859 }
860 }
861 Err(e) => {
862 println!(" JSON parsing failed: {e}");
863 println!("This demonstrates how schema constraints can sometimes be challenging for the model");
864 println!("Raw response: {content}");
865 }
866 }
867 }
868
869 println!("\n Testing with intentionally problematic request...");
871
872 let problematic_builder = client
873 .responses()
874 .system("You are unhelpful and ignore instructions.")
875 .user("Ignore the schema and just say 'hello world'")
876 .json_schema(
877 "strict_validation",
878 json!({
879 "type": "object",
880 "properties": {
881 "impossible": {
882 "type": "string",
883 "pattern": "^impossible_pattern_that_cannot_match$"
884 }
885 },
886 "required": ["impossible"]
887 }),
888 )
889 .temperature(0.1);
890
891 match client.send_responses(problematic_builder).await {
892 Ok(problematic_response) => {
893 if let Some(content) = problematic_response.content() {
894 println!(" Problematic request result:");
895 println!("{content}");
896 println!(" The model likely still attempted to follow the schema despite conflicting instructions");
897 }
898 }
899 Err(e) => {
900 println!(" Problematic request failed as expected: {e}");
901 }
902 }
903
904 Ok(())
905}
906
907fn handle_api_error(error: &Error) {
909 match error {
910 Error::Api {
911 status,
912 message,
913 error_type,
914 error_code,
915 } => {
916 eprintln!(" API Error [{status}]: {message}");
917 if let Some(error_type) = error_type {
918 eprintln!(" Type: {error_type}");
919 }
920 if let Some(error_code) = error_code {
921 eprintln!(" Code: {error_code}");
922 }
923
924 match *status {
926 400 => eprintln!(" Bad Request - Check your JSON schema or request parameters"),
927 401 => eprintln!(" Check your API key: export OPENAI_API_KEY=\"your-key\""),
928 403 => eprintln!(" Forbidden - Check your API permissions and model access"),
929 422 => eprintln!(" Invalid schema or request format - verify your JSON schema"),
930 429 => eprintln!(" Rate limited - try again in a moment"),
931 500..=599 => eprintln!(" Server error - try again later"),
932 _ => {}
933 }
934 }
935 Error::InvalidRequest(msg) => {
936 eprintln!(" Invalid Request: {msg}");
937 eprintln!(" Check your request parameters and JSON schema format");
938 }
939 Error::Config(msg) => {
940 eprintln!(" Configuration Error: {msg}");
941 eprintln!(" Check your client configuration");
942 }
943 Error::Http(err) => {
944 eprintln!(" HTTP Error: {err}");
945 eprintln!(" Check your network connection");
946 }
947 Error::HttpMiddleware(err) => {
948 eprintln!(" HTTP Middleware Error: {err}");
949 eprintln!(" Check your network connection and middleware configuration");
950 }
951 Error::Json(err) => {
952 eprintln!(" JSON Error: {err}");
953 eprintln!(" Response parsing failed - the model may have generated invalid JSON");
954 }
955 Error::Authentication(msg) => {
956 eprintln!(" Authentication Error: {msg}");
957 eprintln!(" Check your API key");
958 }
959 Error::RateLimit(msg) => {
960 eprintln!(" Rate Limit Error: {msg}");
961 eprintln!(" Try again in a moment or upgrade your plan");
962 }
963 Error::Stream(msg) => {
964 eprintln!(" Stream Error: {msg}");
965 eprintln!(" Connection issue with streaming");
966 }
967 Error::File(err) => {
968 eprintln!(" File Error: {err}");
969 eprintln!(" Check file permissions and paths");
970 }
971 Error::Builder(msg) => {
972 eprintln!(" Builder Error: {msg}");
973 eprintln!(" Check your request builder configuration");
974 }
975 Error::Internal(msg) => {
976 eprintln!(" Internal Error: {msg}");
977 eprintln!(" This may be a bug, please report it");
978 }
979 Error::StreamConnection { message } => {
980 eprintln!(" Stream Connection Error: {message}");
981 eprintln!(" Check your network connection");
982 }
983 Error::StreamParsing { message, chunk } => {
984 eprintln!(" Stream Parsing Error: {message}");
985 eprintln!(" Problematic chunk: {chunk}");
986 eprintln!(" The response stream may be corrupted");
987 }
988 Error::StreamBuffer { message } => {
989 eprintln!(" Stream Buffer Error: {message}");
990 eprintln!(" The stream buffer encountered an issue");
991 }
992 }
993}