pub trait AsCurl
{
fn as_curl( &self ) -> String;
fn as_curl_with_options( &self, options : &CurlOptions ) -> String;
}
use crate::models::{ GenerateContentRequest, EmbedContentRequest, Blob };
pub type InlineData = Blob;
#[ derive( Debug, Clone ) ]
pub struct CurlOptions
{
pub pretty_json : bool,
pub include_api_key_placeholder : bool,
pub multiline_format : bool,
pub api_key : Option< String >,
}
impl CurlOptions
{
#[ inline ]
#[ must_use ]
pub fn new() -> Self
{
Self {
pretty_json : false,
include_api_key_placeholder : true,
multiline_format : false,
api_key : None,
}
}
#[ inline ]
#[ must_use ]
pub fn pretty() -> Self
{
Self {
pretty_json : true,
include_api_key_placeholder : true,
multiline_format : true,
api_key : None,
}
}
#[ inline ]
pub fn with_api_key< S: Into< String > >( api_key : S ) -> Self
{
Self {
pretty_json : false,
include_api_key_placeholder : false,
multiline_format : false,
api_key : Some( api_key.into() ),
}
}
#[ inline ]
#[ must_use ]
pub fn pretty_json( mut self ) -> Self
{
self.pretty_json = true;
self
}
#[ inline ]
#[ must_use ]
pub fn multiline( mut self ) -> Self
{
self.multiline_format = true;
self
}
}
impl Default for CurlOptions
{
#[ inline ]
fn default() -> Self
{
Self::new()
}
}
mod curl_helpers
{
use super::*;
pub fn generate_curl_command(
url : &str,
json_body : &str,
options : &CurlOptions,
) -> String
{
let formatted_json = if options.pretty_json
{
match serde_json::from_str::< serde_json::Value >( json_body )
{
Ok( value ) => serde_json::to_string_pretty( &value )
.unwrap_or_else( |_| json_body.to_string() ),
Err( _ ) => json_body.to_string(),
}
} else {
json_body.to_string()
};
let url_with_key = if let Some( ref api_key ) = options.api_key
{
format!( "{url}?key={api_key}" )
} else if options.include_api_key_placeholder
{
format!( "{url}?key=YOUR_API_KEY_HERE" )
} else {
url.to_string()
};
if options.multiline_format
{
let json_escaped = formatted_json.replace( '"', "\\\"" );
format!(
"curl -X POST \\\n \"{url_with_key}\" \\\n -H \"Content-Type : application/json\" \\\n -d \"{json_escaped}\""
)
} else {
let json_escaped = formatted_json.replace( '\'', "'\"'\"'" );
format!(
"curl -X POST \"{url_with_key}\" -H \"Content-Type : application/json\" -d '{json_escaped}'"
)
}
}
pub fn safe_json_serialize< T: serde::Serialize >( value : &T ) -> String
{
serde_json ::to_string( value ).unwrap_or_else( |err| {
format!( "{{\"error\": \"Failed to serialize request : {err}\"}}" )
})
}
}
impl AsCurl for GenerateContentRequest
{
#[ inline ]
fn as_curl( &self ) -> String
{
self.as_curl_with_options( &CurlOptions::default() )
}
#[ inline ]
fn as_curl_with_options( &self, options : &CurlOptions ) -> String
{
let url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent";
let json_body = curl_helpers::safe_json_serialize( self );
curl_helpers ::generate_curl_command( url, &json_body, options )
}
}
impl AsCurl for EmbedContentRequest
{
#[ inline ]
fn as_curl( &self ) -> String
{
self.as_curl_with_options( &CurlOptions::default() )
}
#[ inline ]
fn as_curl_with_options( &self, options : &CurlOptions ) -> String
{
let url = "https://generativelanguage.googleapis.com/v1beta/models/text-embedding-004:embedContent";
let json_body = curl_helpers::safe_json_serialize( self );
curl_helpers ::generate_curl_command( url, &json_body, options )
}
}
pub mod debug_helpers
{
use super::*;
#[ inline ]
#[ must_use ]
pub fn simple_generate_curl( text : &str, options : Option< &CurlOptions > ) -> String
{
let request = GenerateContentRequest {
contents : vec![ crate::models::Content {
parts : vec![ crate::models::Part {
text : Some( text.to_string() ),
..Default::default()
} ],
role : "user".to_string(),
} ],
..Default::default()
};
match options
{
Some( opts ) => request.as_curl_with_options( opts ),
None => request.as_curl(),
}
}
#[ inline ]
#[ must_use ]
pub fn simple_embed_curl( text : &str, options : Option< &CurlOptions > ) -> String
{
let request = EmbedContentRequest {
content : crate::models::Content {
parts : vec![ crate::models::Part {
text : Some( text.to_string() ),
..Default::default()
} ],
role : "user".to_string(),
},
task_type : None,
title : None,
output_dimensionality : None,
};
match options
{
Some( opts ) => request.as_curl_with_options( opts ),
None => request.as_curl(),
}
}
}