gproxy_protocol/adapt/generate/resources/
responses.rs1use super::*;
2use crate::wire::{DeclaredFields, openai::responses as r};
3
4impl<R: ResourceAccess> GenerationResources<'_, R> {
5 pub async fn responses(
6 &self,
7 input: r::GenerateContentRequestBody,
8 ) -> Result<r::GenerateContentRequestBody, TransformError> {
9 let mut input = input.into_declared();
10 let mut budget = self.budget(crate::Dialect::OpenAi);
11 if let Some(r::Input::Items(items)) = &mut input.input {
12 for item in items {
13 match item {
14 r::InputItem::Message(message) => {
15 for part in &mut message.content {
16 budget.input_part(part).await?;
17 }
18 }
19 r::InputItem::Easy(message) => {
20 if let r::MessageContent::Parts(parts) = &mut message.content {
21 for part in parts {
22 budget.input_part(part).await?;
23 }
24 }
25 }
26 r::InputItem::FunctionCallOutput(output) => {
27 if let r::FunctionOutput::Content(parts) = &mut output.output {
28 for part in parts {
29 budget.function_part(part).await?;
30 }
31 }
32 }
33 r::InputItem::CustomToolCallOutput(output) => {
34 if let r::CustomOutput::Content(parts) = &mut output.output {
35 for part in parts {
36 budget.input_part(part).await?;
37 }
38 }
39 }
40 _ => {}
41 }
42 }
43 }
44 Ok(input)
45 }
46}
47
48impl<R: ResourceAccess> Budget<'_, '_, R> {
49 async fn input_part(&mut self, part: &mut r::InputContent) -> Result<(), TransformError> {
50 match part {
51 r::InputContent::Image(image) => {
52 let id = image.file_id.as_ref().and_then(|v| v.as_ref());
53 let url = image.image_url.as_ref().and_then(|v| v.as_ref());
54 if id.is_some() && url.is_some() {
55 return Err(TransformError::shape(
56 "input_image",
57 "ambiguous native ID and URL",
58 ));
59 }
60 let reference = if let Some(id) = id {
61 ResourceReference::Id(id.clone())
62 } else if let Some(url) = url {
63 if url.starts_with("data:") {
64 return Ok(());
65 }
66 ResourceReference::Url(url.clone())
67 } else {
68 return Ok(());
69 };
70 let Some(media) = self.read(reference, true).await? else {
71 return Ok(());
72 };
73 image.image_url = Some(Some(media.data_uri()));
74 image.file_id = None;
75 }
76 r::InputContent::File(file) => {
77 let id = file.file_id.as_ref().and_then(|v| v.as_ref());
78 let url = file.file_url.as_ref();
79 if usize::from(id.is_some())
80 + usize::from(url.is_some())
81 + usize::from(file.file_data.is_some())
82 > 1
83 {
84 return Err(TransformError::shape(
85 "input_file",
86 "ambiguous file representations",
87 ));
88 }
89 let reference = if let Some(id) = id {
90 ResourceReference::Id(id.clone())
91 } else if let Some(url) = url {
92 ResourceReference::Url(url.clone())
93 } else {
94 return Ok(());
95 };
96 let Some(media) = self.read(reference, false).await? else {
97 return Ok(());
98 };
99 file.file_data = Some(media.data_uri());
100 file.file_id = None;
101 file.file_url = None;
102 if file.filename.is_none() {
103 file.filename = media.filename;
104 }
105 }
106 r::InputContent::Text(_) => {}
107 }
108 Ok(())
109 }
110}
111
112impl<R: ResourceAccess> Budget<'_, '_, R> {
113 async fn function_part(
114 &mut self,
115 part: &mut r::FunctionOutputContent,
116 ) -> Result<(), TransformError> {
117 match part {
118 r::FunctionOutputContent::Image(image) => {
119 let id = image.file_id.as_ref().and_then(|v| v.as_ref());
120 let url = image.image_url.as_ref().and_then(|v| v.as_ref());
121 if id.is_some() && url.is_some() {
122 return Err(TransformError::shape(
123 "function_output.image",
124 "ambiguous native ID and URL",
125 ));
126 }
127 let reference = if let Some(id) = id {
128 ResourceReference::Id(id.clone())
129 } else if let Some(url) = url {
130 if url.starts_with("data:") {
131 return Ok(());
132 }
133 ResourceReference::Url(url.clone())
134 } else {
135 return Ok(());
136 };
137 let Some(media) = self.read(reference, true).await? else {
138 return Ok(());
139 };
140 image.image_url = Some(Some(media.data_uri()));
141 image.file_id = None;
142 }
143 r::FunctionOutputContent::File(file) => {
144 let id = file.file_id.as_ref().and_then(|v| v.as_ref());
145 let url = file.file_url.as_ref().and_then(|v| v.as_ref());
146 let data = file.file_data.as_ref().and_then(|v| v.as_ref());
147 if usize::from(id.is_some())
148 + usize::from(url.is_some())
149 + usize::from(data.is_some())
150 > 1
151 {
152 return Err(TransformError::shape(
153 "function_output.file",
154 "ambiguous file representations",
155 ));
156 }
157 let reference = if let Some(id) = id {
158 ResourceReference::Id(id.clone())
159 } else if let Some(url) = url {
160 ResourceReference::Url(url.clone())
161 } else {
162 return Ok(());
163 };
164 let Some(media) = self.read(reference, false).await? else {
165 return Ok(());
166 };
167 file.file_data = Some(Some(media.data_uri()));
168 file.file_id = None;
169 file.file_url = None;
170 if file.filename.as_ref().is_none_or(|v| v.is_none()) {
171 file.filename = media.filename.map(Some);
172 }
173 }
174 r::FunctionOutputContent::Text(_) => {}
175 }
176 Ok(())
177 }
178}