gproxy_protocol/transform/openai/create_image_edit/gemini/
request.rs1use crate::gemini::count_tokens::types as gt;
2use crate::gemini::generate_content::request::{
3 GeminiGenerateContentRequest, PathParameters, QueryParameters, RequestBody, RequestHeaders,
4};
5use crate::gemini::stream_generate_content::request::{
6 GeminiStreamGenerateContentRequest,
7 PathParameters as GeminiStreamGenerateContentPathParameters,
8 QueryParameters as GeminiStreamGenerateContentQueryParameters,
9 RequestHeaders as GeminiStreamGenerateContentRequestHeaders,
10};
11use crate::gemini::types::HttpMethod as GeminiHttpMethod;
12use crate::openai::create_image_edit::request::{
13 OpenAiCreateImageEditRequest, RequestBody as CreateImageEditRequestBody,
14};
15use crate::transform::gemini::model_get::utils::ensure_models_prefix;
16use crate::transform::openai::create_image::gemini::utils::{
17 gemini_image_config_from_create_image_edit_size, gemini_part_from_openai_edit_input_image,
18};
19use crate::transform::openai::create_image::utils::create_image_edit_model_to_string;
20use crate::transform::utils::TransformError;
21
22fn validate_create_image_edit_request(
23 body: &CreateImageEditRequestBody,
24) -> Result<(), TransformError> {
25 if body.images.is_empty() {
26 return Err(TransformError::not_implemented(
27 "cannot convert OpenAI image edit request without input images to Gemini generateContent request",
28 ));
29 }
30
31 if body.mask.is_some() {
32 return Err(TransformError::not_implemented(
33 "cannot convert OpenAI image edit request with mask to Gemini generateContent request",
34 ));
35 }
36
37 Ok(())
38}
39
40impl TryFrom<OpenAiCreateImageEditRequest> for GeminiGenerateContentRequest {
41 type Error = TransformError;
42
43 fn try_from(value: OpenAiCreateImageEditRequest) -> Result<Self, TransformError> {
44 let headers = RequestHeaders {
45 extra: value.headers.extra,
46 };
47 let body = value.body;
48 validate_create_image_edit_request(&body)?;
49
50 let mut parts = Vec::with_capacity(body.images.len() + 1);
51 for image in body.images {
52 parts.push(gemini_part_from_openai_edit_input_image(image)?);
53 }
54 parts.push(gt::GeminiPart {
55 text: Some(body.prompt),
56 ..gt::GeminiPart::default()
57 });
58
59 let model = ensure_models_prefix(
60 &body
61 .model
62 .as_ref()
63 .map(create_image_edit_model_to_string)
64 .unwrap_or_default(),
65 );
66
67 Ok(GeminiGenerateContentRequest {
68 method: GeminiHttpMethod::Post,
69 path: PathParameters { model },
70 query: QueryParameters::default(),
71 headers,
72 body: RequestBody {
73 contents: vec![gt::GeminiContent {
74 parts,
75 role: Some(gt::GeminiContentRole::User),
76 }],
77 tools: None,
78 tool_config: None,
79 safety_settings: None,
80 system_instruction: None,
81 generation_config: Some(gt::GeminiGenerationConfig {
82 response_modalities: Some(vec![gt::GeminiModality::Image]),
83 candidate_count: body.n,
84 image_config: gemini_image_config_from_create_image_edit_size(body.size),
85 ..gt::GeminiGenerationConfig::default()
86 }),
87 cached_content: None,
88 store: None,
89 },
90 })
91 }
92}
93
94impl TryFrom<&OpenAiCreateImageEditRequest> for GeminiStreamGenerateContentRequest {
95 type Error = TransformError;
96
97 fn try_from(value: &OpenAiCreateImageEditRequest) -> Result<Self, TransformError> {
98 let output = GeminiGenerateContentRequest::try_from(value.clone())?;
99
100 Ok(Self {
101 method: GeminiHttpMethod::Post,
102 path: GeminiStreamGenerateContentPathParameters {
103 model: output.path.model,
104 },
105 query: GeminiStreamGenerateContentQueryParameters::default(),
106 headers: GeminiStreamGenerateContentRequestHeaders {
107 extra: output.headers.extra,
108 },
109 body: output.body,
110 })
111 }
112}
113
114impl TryFrom<OpenAiCreateImageEditRequest> for GeminiStreamGenerateContentRequest {
115 type Error = TransformError;
116
117 fn try_from(value: OpenAiCreateImageEditRequest) -> Result<Self, TransformError> {
118 GeminiStreamGenerateContentRequest::try_from(&value)
119 }
120}