openai_tools/responses/
request.rs

1use crate::{
2    common::{
3        errors::{OpenAIToolError, Result},
4        message::Message,
5        structured_output::Schema,
6        tool::Tool,
7    },
8    responses::response::Response,
9};
10use derive_new::new;
11use dotenvy::dotenv;
12use request;
13use serde::{ser::SerializeStruct, Serialize};
14use std::env;
15
16#[derive(Debug, Clone, Default, Serialize, new)]
17pub struct Format {
18    pub format: Schema,
19}
20
21#[derive(Debug, Clone, Default, new)]
22pub struct Body {
23    pub model: String,
24    pub instructions: Option<String>,
25    pub plain_text_input: Option<String>,
26    pub messages_input: Option<Vec<Message>>,
27    pub tools: Option<Vec<Tool>>,
28    pub text: Option<Format>,
29}
30
31impl Serialize for Body {
32    fn serialize<S>(&self, serializer: S) -> anyhow::Result<S::Ok, S::Error>
33    where
34        S: serde::Serializer,
35    {
36        let input = if self.plain_text_input.is_some() {
37            self.plain_text_input.clone().unwrap()
38        } else if self.messages_input.is_some() {
39            serde_json::to_string(&self.messages_input).unwrap()
40        } else {
41            return Err(serde::ser::Error::custom("Either plain_text_input or messages_input must be set."));
42        };
43        let mut state = serializer.serialize_struct("ResponsesBody", 4)?;
44        state.serialize_field("model", &self.model)?;
45        state.serialize_field("instructions", &self.instructions)?;
46        state.serialize_field("input", &input)?;
47        if self.tools.is_some() {
48            state.serialize_field("tools", &self.tools)?;
49        }
50        if self.text.is_some() {
51            state.serialize_field("text", &self.text)?;
52        }
53        state.end()
54    }
55}
56
57#[derive(Debug, Clone, Default, Serialize)]
58pub struct Responses {
59    api_key: String,
60    pub request_body: Body,
61}
62
63impl Responses {
64    pub fn new() -> Self {
65        dotenv().ok();
66        let api_key = env::var("OPENAI_API_KEY").expect("OPENAI_API_KEY is not set.");
67        Self { api_key, request_body: Body::default() }
68    }
69
70    pub fn model_id<T: AsRef<str>>(&mut self, model_id: T) -> &mut Self {
71        self.request_body.model = model_id.as_ref().to_string();
72        self
73    }
74
75    pub fn instructions<T: AsRef<str>>(&mut self, instructions: T) -> &mut Self {
76        self.request_body.instructions = Some(instructions.as_ref().to_string());
77        self
78    }
79
80    pub fn plain_text_input<T: AsRef<str>>(&mut self, input: T) -> &mut Self {
81        self.request_body.plain_text_input = Some(input.as_ref().to_string());
82        self
83    }
84
85    pub fn messages(&mut self, messages: Vec<Message>) -> &mut Self {
86        self.request_body.messages_input = Some(messages);
87        self
88    }
89
90    pub fn tools(&mut self, tools: Vec<Tool>) -> &mut Self {
91        self.request_body.tools = Some(tools);
92        self
93    }
94
95    pub fn text(&mut self, text_format: Schema) -> &mut Self {
96        self.request_body.text = Option::from(Format::new(text_format));
97        self
98    }
99
100    pub async fn complete(&self) -> Result<Response> {
101        if self.api_key.is_empty() {
102            return Err(OpenAIToolError::Error("API key is not set.".into()));
103        }
104        if self.request_body.model.is_empty() {
105            return Err(OpenAIToolError::Error("Model ID is not set.".into()));
106        }
107        if self.request_body.messages_input.is_none() && self.request_body.plain_text_input.is_none() {
108            return Err(OpenAIToolError::Error("Messages are not set.".into()));
109        } else if self.request_body.plain_text_input.is_none() && self.request_body.messages_input.is_none() {
110            return Err(OpenAIToolError::Error("Both plain text input and messages are set. Please use one of them.".into()));
111        }
112
113        let body = serde_json::to_string(&self.request_body)?;
114        let url = "https://api.openai.com/v1/responses".to_string();
115
116        let client = request::Client::new();
117        let mut header = request::header::HeaderMap::new();
118        header.insert("Content-Type", request::header::HeaderValue::from_static("application/json"));
119        header.insert("Authorization", request::header::HeaderValue::from_str(&format!("Bearer {}", self.api_key)).unwrap());
120        header.insert("User-Agent", request::header::HeaderValue::from_static("openai-tools-rust/0.1.0"));
121
122        if cfg!(debug_assertions) {
123            // Replace API key with a placeholder for security
124            let body_for_debug = serde_json::to_string_pretty(&self.request_body).unwrap().replace(&self.api_key, "*************");
125            // Log the request body for debugging purposes
126            tracing::info!("Request body: {}", body_for_debug);
127        }
128
129        let response = client.post(url).headers(header).body(body).send().await.map_err(OpenAIToolError::RequestError)?;
130        let content = response.text().await.map_err(OpenAIToolError::RequestError)?;
131
132        if cfg!(debug_assertions) {
133            tracing::info!("Response content: {}", content);
134        }
135
136        serde_json::from_str::<Response>(&content).map_err(OpenAIToolError::SerdeJsonError)
137    }
138}