Skip to main content

gproxy_protocol/transform/openai/create_image_edit/gemini/
request.rs

1use 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}