use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NativeRequest {
pub contents: Vec<NativeContent>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub system_instruction: Option<NativeSystemInstruction>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub tools: Vec<NativeToolList>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tool_config: Option<NativeToolConfig>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub generation_config: Option<NativeGenerationConfig>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NativeContent {
pub role: String,
pub parts: Vec<NativePart>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum NativePart {
Text(String),
InlineData(NativeInlineData),
FileData(NativeFileData),
FunctionCall(NativeFunctionCall),
FunctionResponse(NativeFunctionResponse),
}
impl Serialize for NativePart {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeMap;
match self {
NativePart::Text(s) => {
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry("text", s)?;
map.end()
}
NativePart::InlineData(d) => {
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry("inlineData", d)?;
map.end()
}
NativePart::FileData(d) => {
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry("fileData", d)?;
map.end()
}
NativePart::FunctionCall(fc) => {
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry("functionCall", fc)?;
map.end()
}
NativePart::FunctionResponse(fr) => {
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry("functionResponse", fr)?;
map.end()
}
}
}
}
impl<'de> Deserialize<'de> for NativePart {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let map = serde_json::Map::deserialize(deserializer)?;
if let Some(v) = map.get("text") {
let s = v
.as_str()
.ok_or_else(|| serde::de::Error::custom("text must be a string"))?;
return Ok(NativePart::Text(s.to_string()));
}
if let Some(v) = map.get("inlineData") {
let d: NativeInlineData =
serde_json::from_value(v.clone()).map_err(serde::de::Error::custom)?;
return Ok(NativePart::InlineData(d));
}
if let Some(v) = map.get("fileData") {
let d: NativeFileData =
serde_json::from_value(v.clone()).map_err(serde::de::Error::custom)?;
return Ok(NativePart::FileData(d));
}
if let Some(v) = map.get("functionCall") {
let fc: NativeFunctionCall =
serde_json::from_value(v.clone()).map_err(serde::de::Error::custom)?;
return Ok(NativePart::FunctionCall(fc));
}
if let Some(v) = map.get("functionResponse") {
let fr: NativeFunctionResponse =
serde_json::from_value(v.clone()).map_err(serde::de::Error::custom)?;
return Ok(NativePart::FunctionResponse(fr));
}
Err(serde::de::Error::custom(
"NativePart: unrecognized part type in object",
))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NativeInlineData {
pub mime_type: String,
pub data: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NativeFileData {
pub mime_type: String,
pub file_uri: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NativeFunctionCall {
pub name: String,
pub args: Value,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NativeFunctionResponse {
pub name: String,
pub response: Value,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NativeSystemInstruction {
pub parts: Vec<NativePart>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NativeToolList {
pub function_declarations: Vec<NativeFunctionDeclaration>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NativeFunctionDeclaration {
pub name: String,
pub description: String,
pub parameters: Value,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NativeToolConfig {
pub function_calling_config: NativeFunctionCallingConfig,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NativeFunctionCallingConfig {
pub mode: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub allowed_function_names: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NativeGenerationConfig {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max_output_tokens: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub temperature: Option<f32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub top_p: Option<f32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub top_k: Option<u32>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub stop_sequences: Vec<String>,
}