gproxy_protocol/adapt/video/
direct.rs1use super::*;
2
3pub(super) fn facts(
4 resources: &BTreeMap<String, ResolvedVideoResource>,
5 limits: VideoLimits,
6) -> Result<(), TransformError> {
7 super::resources::bound_value(
8 &resources
9 .iter()
10 .map(|(key, value)| {
11 (
12 key,
13 &value.reference,
14 &value.url,
15 &value.bytes_base64_encoded,
16 &value.mime_type,
17 )
18 })
19 .collect::<Vec<_>>(),
20 limits,
21 )?;
22 Ok(())
23}
24
25pub(super) fn check_template(
26 request: &WireRequest<()>,
27 method: http::Method,
28) -> Result<(), TransformError> {
29 if request.method != method
30 || request
31 .query
32 .as_ref()
33 .is_some_and(|query| !query.is_empty())
34 || !request.path.starts_with('/')
35 || request.path.starts_with("//")
36 || request.path.contains(['?', '#', '\\', '\r', '\n'])
37 {
38 return Err(TransformError::shape(
39 "video.template",
40 "origin-relative method-matched template required",
41 ));
42 }
43 Ok(())
44}
45
46#[allow(clippy::too_many_arguments)]
47pub async fn openai_to_gemini_create<U: Upstream>(
48 upstream: &U,
49 target: &U::Target,
50 template: WireRequest<()>,
51 input: o::CreateVideoRequestBody,
52 target_model: &str,
53 resources: BTreeMap<String, ResolvedVideoResource>,
54 context: OpenAiVideoResponseContext,
55 limits: VideoLimits,
56) -> Result<JsonInvocation<Converted<o::VideoGenerationResponseBody>>, TransformError> {
57 facts(&context.resources, limits)?;
58 facts(&resources, limits)?;
59 check_template(&template, http::Method::POST)?;
60 let input = input.into_declared();
61 super::resources::bound_value(&input, limits)?;
62 let prepared = video::openai_to_gemini_request(input, target_model, &resources)?;
63 let request = WireRequest {
64 method: template.method,
65 path: template.path,
66 query: template.query,
67 headers: template.headers,
68 body: prepared.value.body,
69 };
70 match invoke_json::<_, _, g::VideoOperation>(upstream, target, request, limits.codec).await? {
71 JsonInvocation::Rejected(response) => Ok(JsonInvocation::Rejected(response)),
72 JsonInvocation::Success(response) => Ok(JsonInvocation::Success(crate::WireResponse {
73 status: response.status,
74 headers: response.headers,
75 body: video::gemini_operation_to_openai_response(response.body, &context)?,
76 })),
77 }
78}
79
80pub async fn openai_to_gemini_query<U: Upstream>(
81 upstream: &U,
82 target: &U::Target,
83 template: WireRequest<()>,
84 context: OpenAiVideoResponseContext,
85 limits: VideoLimits,
86) -> Result<JsonInvocation<Converted<o::VideoGenerationResponseBody>>, TransformError> {
87 facts(&context.resources, limits)?;
88 check_template(&template, http::Method::GET)?;
89 let response =
90 invoke_empty::<_, g::VideoOperation>(upstream, target, template, limits.codec).await?;
91 match response {
92 JsonInvocation::Success(response) => Ok(JsonInvocation::Success(crate::WireResponse {
93 status: response.status,
94 headers: response.headers,
95 body: video::gemini_operation_to_openai_response(response.body, &context)?,
96 })),
97 JsonInvocation::Rejected(response) => Ok(JsonInvocation::Rejected(response)),
98 }
99}
100
101#[allow(clippy::too_many_arguments)]
102pub async fn gemini_to_openai_create<U: Upstream>(
103 upstream: &U,
104 target: &U::Target,
105 template: WireRequest<()>,
106 input: g::PredictLongRunningRequestBody,
107 target_model: &str,
108 resources: BTreeMap<String, ResolvedVideoResource>,
109 context: GeminiOperationContext,
110 limits: VideoLimits,
111) -> Result<JsonInvocation<Converted<g::VideoOperation>>, TransformError> {
112 facts(&resources, limits)?;
113 check_template(&template, http::Method::POST)?;
114 let input = input.into_declared();
115 super::resources::bound_value(&input, limits)?;
116 let prepared = video::gemini_to_openai_request(input, target_model, &resources)?;
117 let request = WireRequest {
118 method: template.method,
119 path: template.path,
120 query: template.query,
121 headers: template.headers,
122 body: prepared.value.body,
123 };
124 match invoke_json::<_, _, o::VideoGenerationResponseBody>(
125 upstream,
126 target,
127 request,
128 limits.codec,
129 )
130 .await?
131 {
132 JsonInvocation::Rejected(response) => Ok(JsonInvocation::Rejected(response)),
133 JsonInvocation::Success(response) => Ok(JsonInvocation::Success(crate::WireResponse {
134 status: response.status,
135 headers: response.headers,
136 body: video::openai_response_to_gemini_operation(response.body, &context)?,
137 })),
138 }
139}
140
141pub async fn gemini_to_openai_query<U: Upstream>(
142 upstream: &U,
143 target: &U::Target,
144 template: WireRequest<()>,
145 context: GeminiOperationContext,
146 limits: VideoLimits,
147) -> Result<JsonInvocation<Converted<g::VideoOperation>>, TransformError> {
148 check_template(&template, http::Method::GET)?;
149 let response =
150 invoke_empty::<_, o::VideoGenerationResponseBody>(upstream, target, template, limits.codec)
151 .await?;
152 match response {
153 JsonInvocation::Success(response) => Ok(JsonInvocation::Success(crate::WireResponse {
154 status: response.status,
155 headers: response.headers,
156 body: video::openai_response_to_gemini_operation(response.body, &context)?,
157 })),
158 JsonInvocation::Rejected(response) => Ok(JsonInvocation::Rejected(response)),
159 }
160}
161
162pub async fn native_create<U: Upstream>(
165 upstream: &U,
166 target: &U::Target,
167 request: WireRequest<o::NativeCreateVideoRequestBody>,
168 limits: VideoLimits,
169) -> Result<JsonInvocation<o::NativeVideo>, TransformError> {
170 if request.method != http::Method::POST
171 || request
172 .query
173 .as_ref()
174 .is_some_and(|query| !query.is_empty())
175 || !request.path.starts_with('/')
176 || request.path.starts_with("//")
177 || request.path.contains(['?', '#', '\\', '\r', '\n'])
178 {
179 return Err(TransformError::shape(
180 "video.template",
181 "origin-relative POST template required",
182 ));
183 }
184 invoke_json(upstream, target, request, limits.codec).await
185}
186
187pub async fn native_retrieve<U: Upstream>(
188 upstream: &U,
189 target: &U::Target,
190 request: WireRequest<()>,
191 limits: VideoLimits,
192) -> Result<JsonInvocation<o::NativeVideo>, TransformError> {
193 check_template(&request, http::Method::GET)?;
194 invoke_empty(upstream, target, request, limits.codec).await
195}