llmclient 0.3.2

Rust LLM client - Gemini, OpenAI, Claude, Mistral, DeepSeek, Groq
Documentation
b0VIM 8.2Bb�h���O�	chrisml2~chris/rust/crash/llmclient/src/gemini.rsutf-8
3210#"! Utp
t]u	p�
MBc�r�dGx �
0�
Q%Dvad)t����V=�����vnmJ'�
�
�
W
!
���mkjR-���ZA$�
�
�
�
i
c
b

�	�	�	�	�	�	�	�	~	}	d	9	�����nO%
������sQ+��~xvuK3�����T��ICB����e ����a    }        self.contents.append(&mut Content::systems(system_prompts));    fn add_systems(&mut self, system_prompts: &[String]) {    /// Supply multi-context 'system' content    }        self.contents.append(&mut Content::multi_part_system(system_prompts));    fn add_multi_part_system(&mut self, system_prompts: &[String]) {    /// Supply multi-parts and single 'system' content    }        self.contents.append(&mut Content::system(system_prompt));    fn add_system(&mut self, system_prompt: &str) {    /// Supply simple, 'system' content    }        self.contents.push(Content::many_text(role, texts));    fn add_many_text(&mut self, role: &str, texts: &[String]) {    /// Add single role with multiple strings for parts as single large content    }        self.contents.push(Content::text(role, text));    fn add_text(&mut self, role: &str, text: &str) {    /// Add single role and single part text    }        self.generation_config.temperature = Some(temperature);    fn set_temperature(&mut self, temperature: f32) {    /// Set temperatureimpl LlmCompletion for GeminiCompletion {}    }        }            generation_config: GenerationConfig::new(Some(0.2), None, None, 1, Some(8192), None)            safety_settings: Vec::new(),            tools: None,            system_instruction: None,            contents: Vec::new(),        GeminiCompletion {     fn default() -> Self {    /// Create default Completion objectimpl Default for GeminiCompletion {}    }        }                .collect()                .map(|si| Part::text(si))            parts: part.iter()            role: "object".into(),        SystemInstruction {    pub fn new(part: Vec<String>) -> Self {    }        SystemInstruction { role: "object".to_string(), parts: vec![Part::text(&part)] }    pub fn new_one(part: String) -> Self {impl SystemInstruction {}    pub parts: Vec<Part>,    pub role: String,pub struct SystemInstruction {#[derive(Debug, Serialize, Clone)]}    }        self.tools = tools;    pub fn set_tools(&mut self, tools: Option<Vec<FunctionDeclaration>>) {    }        self.system_instruction = Some(SystemInstruction::new(system));    pub fn set_system_instruction(&mut self, system: Vec<String>) {    }        }            generation_config            safety_settings,            tools: None,            system_instruction: None,            contents,        GeminiCompletion {    pub fn new(contents: Vec<Content>, safety_settings: Vec<SafetySettings>, generation_config: GenerationConfig) -> Self {    /// Create new Completion objectimpl GeminiCompletion {}    pub generation_config: GenerationConfig,    pub safety_settings: Vec<SafetySettings>,    //pub tools: Option<Vec<Function>>,    pub tools: Option<Vec<FunctionDeclaration>>,    #[serde(skip_serializing_if = "Option::is_none")]    pub system_instruction: Option<SystemInstruction>,    #[serde(skip_serializing_if = "Option::is_none")]    pub contents: Vec<Content>,pub struct GeminiCompletion {// Container for all data to be sent#[serde(rename_all = "camelCase")]#[derive(Debug, Serialize, Clone)]// Chat// Input structuresuse crate::functions::*;use crate::common::{LlmType, LlmCompletion};use crate::gpt::GptMessage;use crate::common::*;use base64::Engine;use base64::prelude::BASE64_STANDARD;use stemplate::Template;use serde_derive::{Deserialize, Serialize};use std::process::Command;use reqwest::Client;use reqwest::header::{HeaderMap, HeaderValue};use std::collections::HashMap;adp�D�b\I��M�
�
�
�
h
g

����6���oD�
�
k
g
6


�	�	G	*	)	�����;$ ����{x%
	���kgd�������}    }        println!("{answer:?}");        let answer = call_actual_function(res.ok());        println!("{res:?}");        let res = call_function_llm("gemini", &messages, &[func_def]).await;*/"#;fn apple(color, taste)// taste: The taste of an apple// color: The color of an apple// Find the color of an apple and its taste pass them to this functionr#"        let func_def2 =        let messages = vec!["a fruit that is red with a sweet taste".to_string()];/*        // This does not work in Gemnini yet"#;fn arithmetic(expr)// expr: An arithmetic expression// Recognize and derive the value of an arithmetic expressionr#"        let func_def =        let messages =  vec!["The answer is (60 * 24) * 365.25".to_string()];    async fn test_call_function_common_gemini() {    #[tokio::test]    }        println!("{answer:?}");        let answer = call_actual_function(res.ok());        println!("{res:?}");        let res = GeminiCompletion::call_model_function(&model, "", &messages, 0.2, false, true, functions).await;        let functions = get_function_json("gemini", &[func_def]);"#;fn arithmetic(expr)// expr: An arithmetic expression// Derive the value of the arithmetic expressionr#"        let func_def =        let messages =  vec!["The answer is (60 * 24) * 365.25".to_string()];        let model: String = std::env::var("GEMINI_MODEL").expect("GEMINI_MODEL not found in enviroment variables");    async fn test_call_function_gemini() {    #[tokio::test]    }        println!("{res:?}");        let res = GeminiCompletion::call_model(&model, "", &messages, 0.2, false, true).await;        let messages = vec!["Hello".to_string()];        let model: String = std::env::var("GEMINI_MODEL").expect("GEMINI_MODEL not found in enviroment variables");    async fn test_call_gemini_dialogue_model() {    #[tokio::test]    }        println!("{res:?}");        let res = GeminiCompletion::call(&system, &messages, 0.2, false, true).await;        messages.push("Is a cuttle fish similar?".to_string());        messages.push(res.unwrap().to_string());        println!("{res:?}");        let res = GeminiCompletion::call(&system, &messages, 0.2, false, true).await;            vec!["How many brains does an octopus have, when they have been injured and lost a leg?".to_string()];        let mut messages =         let system = "Use a Scottish accent to answer questions";    async fn test_call_gemini_dialogue() {    #[tokio::test]    }        gemini(messages).await;            vec![Content::text("user", "How many brains does an octopus have, when they have been injured and lost a leg?")];ad�O
��ZS������pTRQ.�
O



���b\ZYL1_�
�
�
�
�	�	�	�	�	�	�	�	z	_	K	E	C	B		������hRPO�vts��
���]�a`B����������//// Pass a pre-assembled completion object }    call_gemini_completion_model(None, gemini_completion).awaitpub async fn call_gemini_completion(gemini_completion: &GeminiCompletion) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {/// Pass a pre-assembled completion object }    call_gemini_completion_model(None, &gemini_completion).await    let gemini_completion = GeminiCompletion::new(contents, safety, config);    // Create chat completion    let contents = add_system_content(system, contents);pub async fn call_gemini_system_all(system: Option<&str>, contents: Vec<Content>, safety: Vec<SafetySettings>, config: GenerationConfig) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {/// Call Large Language Model (i.e. Google Gemini) with all parameters supplied including system context}    call_gemini_system_all(None, contents, safety, config).awaitpub async fn call_gemini_all(contents: Vec<Content>, safety: Vec<SafetySettings>, config: GenerationConfig) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {/// Call Large Language Model (i.e. Google Gemini) with all parameters supplied}    call_gemini_system_all(system, contents, SafetySettings::no_block(), GenerationConfig::new(Some(0.2), None, None, 1, Some(8192), None)).awaitpub async fn call_gemini_system(system: Option<&str>, contents: Vec<Content>) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {/// Call Large Language Model (i.e. Google Gemini) with 'system context' and defaults}    call_gemini_system(None, contents).awaitpub async fn call_gemini(contents: Vec<Content>) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {/// Call Large Language Model (i.e. Google Gemini) with defaults}    pub text: String,pub struct ResponsePart {#[derive(Debug, Serialize, Deserialize, Clone)]}    pub parts: Option<Vec<ResponsePart>>,    pub role: String,pub struct ResponseContent {#[derive(Debug, Serialize, Deserialize, Clone)]}    }        Self::new()    fn default() -> Self {impl Default for Usage {}    }        }            (0, 0, 0)        } else {            (prompt, candidates, total)        if let Some(prompt) = self.prompt_token_count && let Some(candidates) = self.candidates_token_count && let Some(total) = self.total_token_count {    pub fn to_triple(&self) -> (usize, usize, usize) {    }        Usage { prompt_token_count: None, candidates_token_count: None, total_token_count: None, traffic_type: None, thoughts_token_count: None }        //Usage { prompt_token_count: None, candidates_token_count: None, total_token_count: None, traffic_type: None, prompt_tokens_details: None, candidates_tokens_details: None, thoughts_token_count: None }    pub fn new() -> Self {impl Usage {}    }        //write!(f, "{} + {} = {}", self.prompt_token_count, self.candidates_token_count, self.total_token_count)        }            Ok(())        } else {           printlprintln!("###### {} + {} = {}", prompt, candidates, total);        if let Some(prompt) = self.prompt_token_count && let Some(candidates) = self.candidates_token_count && let Some(total) = self.total_token_count {    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {impl std::fmt::Display for Usage {}    pub token_count: usize,    pub modality: String,pub struct TokensDetails {#[serde(rename_all = "camelCase")]#[derive(Debug, Deserialize, Clone)]}    pub thoughts_token_count: Option<usize>,    #[serde(skip_serializing_if = "Option::is_none")]    */    pub candidates_tokens_details: Option<TokensDetails>,    #[serde(skip_serializing_if = "Option::is_none")]    pub prompt_tokens_details: Option<TokensDetails>,adNG����	��
�
�
L
��ycYSQP7����rpo?%
�
`
3
1
0
�	R	���m����W���pnmA�}{zN��/// Pa/// Pass a pre-as/// Pass a pre-assemble/// Pass a pre-assembled completion object }    call_gemi/// Pass a pre-assembled completion object }    call_gemini_completion_model(None, gemini_completion).awaitpub async fn call_gemini_completion(gemini_completion: &GeminiCompletion) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {/// Pass a pre-assembled completion object }    call_gemini_completion_model(None, &gemini_completion).await    let gemini_completion = GeminiCompletion::new(contents, safety, config);    // Create chat completion    let contents = add_system_content(system, contents);pub async fn call_gemini_system_all(system: Option<&str>, contents: Vec<Content>, safety: Vec<SafetySettings>, config: GenerationConfig) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {/// Call Large Language Model (i.e. Google Gemini) with all parameters supplied including system context}    call_gemini_system_all(None, contents, safety, config).awaitpub async fn call_gemini_all(contents: Vec<Content>, safety: Vec<SafetySettings>, config: GenerationConfig) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {/// Call Large Language Model (i.e. Google Gemini) with all parameters supplied}    call_gemini_system_all(system, contents, SafetySettings::no_block(), GenerationConfig::new(Some(0.2), None, None, 1, Some(8192), None)).awaitpub async fn call_gemini_system(system: Option<&str>, contents: Vec<Content>) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {/// Call Large Language Model (i.e. Google Gemini) with 'system context' and defaults}    call_gemini_system(None, contents).awaitpub async fn call_gemini(contents: Vec<Content>) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {/// Call Large Language Model (i.e. Google Gemini) with defaults}    pub text: String,pub struct ResponsePart {#[derive(Debug, Serialize, Deserialize, Clone)]}    pub parts: Option<Vec<ResponsePart>>,    pub role: String,pub struct ResponseContent {#[derive(Debug, Serialize, Deserialize, Clone)]}    }        Self::new()    fn default() -> Self {impl Default for Usage {}    }        }            (0, 0, 0)        } else {            (prompt, candidates, total)        if let Some(prompt) = self.prompt_token_count && let Some(candidates) = self.candidates_token_count && let Some(total) = self.total_token_count {    pub fn to_triple(&self) -> (usize, usize, usize) {    }        Usage { prompt_token_count: None, candidates_token_count: None, total_token_count: None, traffic_type: None, thoughts_token_count: None }        //Usage { prompt_token_count: None, candidates_token_count: None, total_token_count: None, traffic_type: None, prompt_tokens_details: None, candidates_tokens_details: None, thoughts_token_count: None }    pub fn new() -> Self {impl Usage {}    }        //write!(f, "{} + {} = {}", self.prompt_token_count, self.candidates_token_count, self.total_token_count)        }            Ok(())        } else {            write!(f, "{} + {} = {}", prompt, candidates, total)ad�
V a6�zgN
�
�
E
D
,


������;)
��WVBI�
�
`
/

�	y	9	��~@���W�|��m`���k1���{bD2#���5&���`                .map(|c| if c.safety_ratings.is_some() {            .map(|gr| gr.candidates.iter()        let safety_ratings: Vec<String> = res.iter()            .collect::<String>()).collect();            })                if let Some(finish) = &c.finish_reason { finish.clone() } else { "".into() }            .map(|gr| gr.candidates.iter().map(|c| {        let finish_reason: String = res.iter()            .collect::<String>()).collect();            })                }                    "".into()                } else {                    }                        "".into()                    } else {                        parts.iter().map(|p| p.text.trim().to_owned() + " ").collect::<String>()                    if let Some(parts) = &content.parts {                if let Some(content) = &c.content {            .map(|gr| gr.candidates.iter().map(|c| {        let text: String = res.iter()        // Now unpack it        let res: Vec<GeminiResponse> = serde_json::from_str(&res).unwrap();    } else {        Ok(LlmReturn::new(LlmType::GEMINI_TOOLS, function_calls, finish, triple, timing, None, None))        let finish = h.get("finish").unwrap()[0].clone();        let triple = (i.parse::<usize>().unwrap(), o.parse::<usize>().unwrap(), t.parse::<usize>().unwrap());        let (i, o, t) = (h.get("in").unwrap()[0].clone(), h.get("out").unwrap()[0].clone(), h.get("total").unwrap()[0].clone());//println!("{:?}", serde_json::from_str::<Vec<ParseFunction>>(&function_calls).unwrap());        let function_calls = serde_json::to_string(&funcs).unwrap();        let funcs = unpack_functions(h.clone());        let h = get_functions(&f, &found);        let f: serde_json::Value = serde_json::from_str(&res).unwrap();            "candidates:finishReason:${finish}".to_string()];//            "usageMetadata:${usage}".to_string(),            "usageMetadata:totalTokenCount:${total}".to_string(),            "usageMetadata:candidatesTokenCount:${out}".to_string(),            "usageMetadata:promptTokenCount:${in}".to_string(),            "candidates:content:parts:functionCall:name:${func}".to_string(),            "candidates:content:parts:functionCall:args:${args}".to_string(),        let found = vec![    } else if res.contains("\"functionCall\"") {        Ok(LlmReturn::new(LlmType::GEMINI_ERROR, res[0].error.to_string(), res[0].error.to_string(), (0, 0, 0), timing, None, None))        let res: Vec<LlmError> = serde_json::from_str(&res).unwrap();    if res.contains("\eprintln!("{res}");    let timing = start.elapsed().as_secs() as f64 + start.elapsed().subsec_millis() as f64 / 1000.0;        .map_err(|e| -> Box<dyn std::error::Error + Send> { Box::new(e) })?;        .await        .text()        //.json()        .map_err(|e| -> Box<dyn std::error::Error + Send> { Box::new(e) })?    let res = res    //let res: Vec<GeminiResponse> = res        .await;        .send()        .json(gemini_completion)        .post(url)    let res = client    // Extract Response//println!("gemini_completion: {:?}", serde_json::to_string(&gemini_completion));    let client = get_gemini_client().await?;    let url: String = Template::new("${GEMINI_URL}").render(&env);    }        },            env.insert("GEMINI_MODEL", model.into());        Some(model) => {                },                    env.insert("GEMINI_MODEL", gemini_model);        None => if let Ok(gemini_model) = std::env::var("GEMINI_MODEL") {    match model {    let mut env = HashMap::new();    let start = std::time::Instant::now();pub async fn call_gemini_completion_model(model: Option<&str>, gemini_completion: &GeminiCompletion) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {adZ�����Z
���J�
�
�
�
w
J
#
��i�����qpQ1�
�
{
&
�	�	�	�	�	x		�������K(�����10�����^
��������`#�������<��`@:'�M-'�� 
        let messages =    async fn test_call_gemini_logic() {    #[tokio::test]    }        gemini(messages).await;            vec![Content::text("user", "Write a creative poem about the interplay of artificial intelligence and the human spirit and provide citations")];        let messages =    async fn test_call_gemini_poem() {    #[tokio::test]    }        gemini(messages).await;            vec![Content::text("user", "Give citations for the General theory of Relativity.")];        let messages =    async fn test_call_gemini_citation() {    #[tokio::test]    }        gemini(messages).await;            vec![Content::text("user", "What is the meaning of life?")];        let messages =    async fn test_call_gemini_basic() {    #[tokio::test]    }        }            Err(e) => { println!("{e}"); assert!(false) },            Ok(ret) => { println!("{ret}"); assert!(true) },        match call_gemini(content).await {    async fn gemini(content: Vec<Content>) {    use super::*;mod tests {#[cfg(test)]}    get_client(headers).await    );            .map_err(|e| -> Box<dyn std::error::Error + Send> { Box::new(e) })?,        HeaderValue::from_str(&format!("Bearer {}", api_key))        "Authorization",    headers.insert(    // Create api key header    let mut headers: HeaderMap = HeaderMap::new();    // Create headers    let api_key: String = String::from_utf8_lossy(&output.stdout).trim().to_string();        .expect("Failed to execute command");        .output()        .arg("print-access-token")        .arg("auth")    let output = Command::new("gcloud")    // Extract API Key informationasync fn get_gemini_client() -> Result<Client, Box<dyn std::error::Error + Send>> {}    }        contents    } else {        [Content::system(system), contents].concat()    if let Some(system) = system {pub fn add_system_content(system: Option<&str>, contents: Vec<Content>) -> Vec<Content> {/// Add 'system' content to other content}    }                          ))                          if safety_ratings.is_empty() { None } else { Some(safety_ratings) }                          if citations.is_empty() { None } else { Some(citations) },        Ok(LlmReturn::new(LlmType::GEMINI, text, finish_reason, usage, timing,            .fold(String::new(), |s, l| s + l + "\n");            .filter(|l| !l.starts_with("```"))        let text = text.lines()        // Remove any comments                           s.1 += if let Some(n) = m.candidates_token_count { n                                    s.1 += (if let Some(n) = m.candidates_token_count { n } else { 0 }) + (if let Some(n) = m.thoughts_token_count { n } else { 0 });                    s.0 += if let Some(n) = m.prompt_token_count { n } else { 0 };                if let Some(m) = &g.usage_metadata {            .fold((0, 0, 0), |mut s: Triple, g| {        let usage: Triple = res.iter()            .collect::<String>()).collect();            })                }                    "".into()                } else {                        .map(|c| c.to_string()).collect::<String>()                    citation_metadata.citations.iter()                if let Some(citation_metadata) = &c.citation_metadata {            .map(|gr| gr.candidates.iter().map(|c| {        let citations: String = res.iter()            .collect();            .filter(|s| !s.is_empty() && s != "Some([, , , ])") // NOT elegant!                .collect::<String>())                })                    "".into()                } else {                    format!("{:?}", c.safety_ratings)ad�]�{;50�����\>87�
w
o
n
*
����y�
g
a
`

/			���Q&������S���gf/����R=(���^#���ica`����`<" ���    pub fn one(role: &str, part: Part) -> Self {    /// Supply single role and single part textimpl Content {}    pub parts: Vec<Part>,    //pub parts: Option<Vec<Part>>,    //#[serde(skip_serializing_if = "Option::is_none")]    pub role: String,pub struct Content {#[serde(rename_all = "camelCase")]#[derive(Debug, Serialize, Deserialize, Clone)]/// This is the primary structure for loading a call. See implementation.}    }        call_gemini_completion_model(Some(model), &completion).await        };            generation_config: GenerationConfig::new(Some(temperature), None, None, 1, Some(8192), None)            safety_settings: SafetySettings::high_block(),            tools: Some(FunctionDeclaration::functions(function)),            */            },                Some(SystemInstruction { role: "object".to_string(), parts: vec![Part::text(&system)] })            } else {                None            system_instruction: if system.is_empty() {            /*            system_instruction: None,            contents,        let completion = GeminiCompletion {//println!("{:?}", function);            });                contents.push(Content::text(role, c));                let role = if !is_chat || i % 2 == 0 { "user" } else { "model" };            .for_each(|(i, c)| {            .enumerate()        user.iter()        }            contents.push(Content::text("model", "Understood"));            contents.push(Content::text("user", &system));        if !system.is_empty() {        };            }                format!("{fc}. {system}")            } else {                fc.to_string()            if !system.trim().is_empty() {            let fc = "This is a function call, find arguments and return function call";        } else {            system.to_string()        let system = if function.is_none() {        let mut contents = Vec::new();    async fn call_model_function(model: &str, system: &str, user: &[String], temperature: f32, _is_json: bool, is_chat: bool, function: Option<Vec<Function>>) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {    /// Create and call llm with model/function by supplying data and common parameters    }        Self::call_model_function(model, system, user, temperature, _is_json, is_chat, None).await    async fn call_model(model: &str, system: &str, user: &[String], temperature: f32, _is_json: bool, is_chat: bool) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {    /// Create and call llm by supplying data and common parameters    }        Self::call_model(&model, system, user, temperature, _is_json, is_chat).await        let model: String = std::env::var("GEMINI_MODEL").expect("GEMINI_MODEL not found in enviroment variables");    async fn call(system: &str, user: &[String], temperature: f32, _is_json: bool, is_chat: bool) -> Result<LlmReturn, Box<dyn std::error::Error + Send>> {    /// Create and call llm by supplying data and common parameters    //}    //    self.contents = content.iter().map(|c| *(&c as &Content)).collect();    //fn set_content(&mut self, content: Vec<Box<dyn LlmMessage>>) {    // Set content in precreated completion    }        format!("{:?}", self)    fn debug(&self) -> String where Self: std::fmt::Debug {    /// Return String of Object    }        self.contents.truncate(len);    fn truncate_messages(&mut self, len: usize) {    /// Truncate messages        }        self.contents = Content::dialogue(prompts, has_system);    fn dialogue(&mut self, prompts: &[String], has_system: bool) {    /// Supply multi-String content with user and llm alternatingad�p����[1+*
�\VU�

y
x
2

�������n3���p7�
�
�
�
�
�
u
C
�	�	�	�	o				��~}nW7�����qkj&����NM)�����|zyW'����`*�����vQKJ ��~}S��        match std::fs::read_to_string(file) {    pub fn inline_file(mime_type: &str, file: &str) -> Self {    /// Create inline data Part from file    }        Part::InlineData { mime_type: mime_type.into(), data: BASE64_STANDARD.encode(data) }    pub fn inline_data(mime_type: &str, data: &[u8]) -> Self {    /// Create inline data Part from data    }        Part::Text(text.to_string())    pub fn text(text: &str) -> Self {    /// Create text Partimpl Part {}    VideoMetadata { start_offset: Offset, end_offset: Offset }    #[serde(rename_all = "camelCase")]    FileData { mime_type: String, file_url: String },    #[serde(rename_all = "camelCase")]    InlineData { mime_type: String, data: String },    #[serde(rename_all = "camelCase")]    Text(String),pub enum Part {#[serde(rename_all = "camelCase")]#[derive(Debug, Serialize, Deserialize, Clone)]/// Parts to make up the content }    }        format!("{:?}", self)    fn debug(&self) -> String where Self: std::fmt::Debug {    /// Return String of Object    }            .collect()            })                Self::text(role, p)                let role = if i % 2 == 0 { "user" } else { "model" };            .map(|(i, p)| {            .enumerate()        prompts.iter()    fn dialogue(prompts: &[String], _has_system: bool) -> Vec<Self> {    /// Supply multi-String content with user and model alternating    }            .collect()            })                }                    Self::text("model", "Understood")                } else {                    Self::text("user", &system_prompts[i / 2])                if i % 2 == 0 {            .map(|i| {        (0..n)        let n = system_prompts.len() * 2;    fn systems(system_prompts: &[String]) -> Vec<Self> {    /// Supply multi-context 'system' content    }        vec![Self::many_text("user", system_prompts), Self::text("model", "Understood")]    fn multi_part_system(system_prompts: &[String]) -> Vec<Self> {    /// Supply multi-parts and single 'system' content    }        vec![Self::text("user", system_prompt), Self::text("model", "Understood")]    fn system(system_prompt: &str) -> Vec<Self> {    /// Supply simple, 'system' content    }        Self { role: role.into(), parts }            .collect();            .map(|p| Part::text(p))        let parts: Vec<Part> = parts.iter()    fn many_text(role: &str, parts: &[String]) -> Self {    /// Supply single role with multi-string for iparts with single content    }        Self { role: role.into(), parts: vec![Part::text(text)] }    fn text(role: &str, text: &str) -> Self {    /// Supply single role and single text string for Partimpl LlmMessage for Content {}    }        vec![Self::many("user", parts)]            .collect();            .map(|m| Part::text(&m.content))        let parts: Vec<Part> = messages.iter()    pub fn message_to_content(messages: &[GptMessage]) -> Vec<Self> {    }        vec![Self { role: role.into(), parts: vec![Part::file_data(mime_type, file)] }]    pub fn file(role: &str, mime_type: &str, file: &str) -> Vec<Self> {    /// Supply file data for previously supplied file    }        vec![Self { role: role.into(), parts: vec![Part::inline_data(mime_type, content)] }]    pub fn to_inline(role: &str, mime_type: &str, content: &[u8]) -> Vec<Self> {    /// Supply inline file data    }        Self { role: role.into(), parts }    pub fn many(role: &str, parts: Vec<Part>) -> Self {    /// Supply single role and multi-part text    }        Self { role: role.into(), parts: vec![part]  }adcM������k�
t

������eQ9$"!�������T>�
�
�
b

�	y		�s,"���J��S��F�����se�d�g����cb    /// High threshold for blocking calls i.e. block only 'bad' stuff    }        ]                threshold: HarmBlockThreshold::BlockMedAndAbove.to_string() }            SafetySettings { category: HarmCategory::HarmCategoryDangerousContent.to_string(),                threshold: HarmBlockThreshold::BlockMedAndAbove.to_string() },            SafetySettings { category: HarmCategory::HarmCategorySexuallyExplicit.to_string(),                threshold: HarmBlockThreshold::BlockMedAndAbove.to_string() },            SafetySettings { category: HarmCategory::HarmCategoryHateSpeech.to_string(),                threshold: HarmBlockThreshold::BlockMedAndAbove.to_string() },            SafetySettings { category: HarmCategory::HarmCategoryHarassment.to_string(),        vec![    pub fn med_block() -> Vec<Self> {    /// Medium threshold for blocking calls i.e. block moderately 'bad' stuff    }        ]                threshold: HarmBlockThreshold::BlockLowAndAbove.to_string() }            SafetySettings { category: HarmCategory::HarmCategoryDangerousContent.to_string(),                threshold: HarmBlockThreshold::BlockLowAndAbove.to_string() },            SafetySettings { category: HarmCategory::HarmCategorySexuallyExplicit.to_string(),                threshold: HarmBlockThreshold::BlockLowAndAbove.to_string() },            SafetySettings { category: HarmCategory::HarmCategoryHateSpeech.to_string(),                threshold: HarmBlockThreshold::BlockLowAndAbove.to_string() },            SafetySettings { category: HarmCategory::HarmCategoryHarassment.to_string(),        vec![    pub fn low_block() -> Vec<Self> {    /// Low threshold for blocking calls i.e let most stuff through    }        ]                threshold: HarmBlockThreshold::BlockNone.to_string() }            SafetySettings { category: HarmCategory::HarmCategoryDangerousContent.to_string(),                threshold: HarmBlockThreshold::BlockNone.to_string() },            SafetySettings { category: HarmCategory::HarmCategorySexuallyExplicit.to_string(),                threshold: HarmBlockThreshold::BlockNone.to_string() },            SafetySettings { category: HarmCategory::HarmCategoryHateSpeech.to_string(),                threshold: HarmBlockThreshold::BlockNone.to_string() },            SafetySettings { category: HarmCategory::HarmCategoryHarassment.to_string(),        vec![    pub fn no_block() -> Vec<Self> {    /// Don't Block ever i.e let everything through (Google may not like this!)impl SafetySettings {// Safety Settings, simple setting functions}    pub threshold: String,    pub category: String,pub struct SafetySettings {#[derive(Debug, Serialize, Clone)]/// Safety setting with helper functions}    pub nanos: usize    pub seconds: usize,pub struct Offset {//#[serde(rename_all = "camelCase")]#[derive(Debug, Serialize, Deserialize, Clone)]}    }        }            end_offset: Offset { seconds: end_secs, nanos: end_nanos }        Part::VideoMetadata { start_offset: Offset { seconds: start_secs, nanos: start_nanos },    pub fn offset(start_secs: usize, start_nanos: usize, end_secs: usize, end_nanos: usize) -> Self {    /// Create Offset Part for inline or uploaded files    }        Part::FileData { mime_type: mime_type.into(), file_url: file_url.into() }    pub fn file_data(mime_type: &str, file_url: &str) -> Self {    /// Create Part referencing previously uploaded file    }        }            Err(e) => Part::InlineData { mime_type: mime_type.into(), data: BASE64_STANDARD.encode(format!("{file} not found: {e}").as_bytes()) }            Ok(data) => Part::InlineData { mime_type: mime_type.into(), data: BASE64_STANDARD.encode(data.as_bytes()) },ad!�c��r&��"�
w
,
"


���#���iK�
�
�
�
]
7

�	�	�	�		����|`D"����z�[���������usrB���L�������oL*�����q	�����#[derive(Debug, Deserialize)]// Chat// Output structures*/}    }        FunctionDeclarations { name: name.into(), description: description.into(), parameters }    pub fn new(name: &str, description: &str, parameters: Option<bool>) -> Self {impl FunctionDeclarations {}    parameters: Option<bool>    description: String,    name: String,pub struct FunctionDeclarations {#[serde(rename_all = "camelCase")]#[derive(Debug, Serialize, Clone)]/*}    }        }            HarmBlockThreshold::BlockOnlyHigh => write!(f, "BLOCK_ONLY_HIGH")            HarmBlockThreshold::BlockMedAndAbove => write!(f, "BLOCK_MED_AND_ABOVE"),            HarmBlockThreshold::BlockLowAndAbove => write!(f, "BLOCK_LOW_AND_ABOVE"),            HarmBlockThreshold::BlockNone => write!(f, "BLOCK_NONE"),        match self {    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {impl std::fmt::Display for HarmBlockThreshold {}    BlockOnlyHigh,    BlockMedAndAbove,    BlockLowAndAbove,    BlockNone,pub enum HarmBlockThreshold {}    }        }            HarmCategory::HarmCategoryDangerousContent => write!(f, "HARM_CATEGORY_DANGEROUS_CONTENT")            HarmCategory::HarmCategorySexuallyExplicit => write!(f, "HARM_CATEGORY_SEXUALLY_EXPLICIT"),            HarmCategory::HarmCategoryHateSpeech => write!(f, "HARM_CATEGORY_HATE_SPEECH"),            HarmCategory::HarmCategoryHarassment => write!(f, "HARM_CATEGORY_HARASSMENT"),        match self {    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {impl std::fmt::Display for HarmCategory {}    HarmCategoryDangerousContent    HarmCategorySexuallyExplicit,    HarmCategoryHateSpeech,    HarmCategoryHarassment,pub enum HarmCategory {}    }        GenerationConfig { temperature, top_p, top_k, candidate_count, max_output_tokens, stop_sequences }    fn new(temperature: Option<f32>, top_p: Option<f32>, top_k: Option<f32>, candidate_count: usize, max_output_tokens: Option<usize>, stop_sequences: Option<Vec<String>>) -> Self {impl GenerationConfig {}    stop_sequences: Option<Vec<String>>    #[serde(skip_serializing_if = "Option::is_none")]    max_output_tokens: Option<usize>,    #[serde(skip_serializing_if = "Option::is_none")]    candidate_count: usize,    top_k: Option<f32>,    #[serde(skip_serializing_if = "Option::is_none")]    top_p: Option<f32>,    #[serde(skip_serializing_if = "Option::is_none")]    temperature: Option<f32>,    #[serde(skip_serializing_if = "Option::is_none")]pub struct GenerationConfig {#[serde(rename_all = "camelCase")]#[derive(Debug, Serialize, Clone)]}    }            .collect()            .map(|(c, t)| SafetySettings { category: c.to_string(), threshold: t.to_string() })        blocks.iter()    pub fn blocks(blocks: Vec<(HarmCategory, HarmBlockThreshold)>) -> Vec<Self> {    /// Custom thresholds for 4 types of blocks    }        ]                threshold: HarmBlockThreshold::BlockOnlyHigh.to_string() }            SafetySettings { category: HarmCategory::HarmCategoryDangerousContent.to_string(),                threshold: HarmBlockThreshold::BlockOnlyHigh.to_string() },            SafetySettings { category: HarmCategory::HarmCategorySexuallyExplicit.to_string(),                threshold: HarmBlockThreshold::BlockOnlyHigh.to_string() },            SafetySettings { category: HarmCategory::HarmCategoryHateSpeech.to_string(),                threshold: HarmBlockThreshold::BlockOnlyHigh.to_string() },            SafetySettings { category: HarmCategory::HarmCategoryHarassment.to_string(),        vec![    pub fn high_block() -> Vec<Self> {ad�r���g@9���K&�
�
�
�
]
6

��fdcE.�����lH�
�
�
�
�
�
�
t
V
5
3
2

�	�	�	�	q	P				���`0����U���v>0�����qkihC&�����r10!����\&���a;4��    #[serde(skip_serializing_if = "Option::is_none")]    /*    pub traffic_type: Option<String>,    #[serde(skip_serializing_if = "Option::is_none")]    pub total_token_count: Option<usize>,    #[serde(skip_serializing_if = "Option::is_none")]    pub candidates_token_count: Option<usize>,    #[serde(skip_serializing_if = "Option::is_none")]    pub prompt_token_count: Option<usize>,    #[serde(skip_serializing_if = "Option::is_none")]pub struct Usage {#[serde(rename_all = "camelCase")]#[derive(Debug, Deserialize, Clone)]}    }        Ok(())        write!(f, "{}/{}/{}", self.year, self.month, self.day)?;    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {impl std::fmt::Display for PublicationDate {}    pub day: usize,    pub month: usize,    pub year: usize,pub struct PublicationDate {#[derive(Debug, Deserialize, Clone)]}    }        Ok(())                }            }                writeln!(f, "    Publication Date: {publication_date}")?;            if let Some(publication_date) = &self.publication_date {            }                writeln!(f, "    License: {license}")?;            if let Some(license) = &self.license {            }                }                    writeln!(f, "    Index range: {start_index} - {end_index}")?;                if let Some(end_index) = self.end_index {            if let Some(start_index) = self.start_index {            }?;                Err(_) => Ok(writeln!(f, "    Uri: {}", uri)?)                Ok(uri) => writeln!(f, "    Uri: {:?}", String::from_utf8(uri)),            match BASE64_STANDARD.decode(uri) {            //writeln!(f, "Citation:")?;        if let Some(uri) = &self.uri {    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {impl std::fmt::Display for Citation {}    pub publication_date: Option<PublicationDate>    pub license: Option<String>,    pub uri: Option<String>,    pub end_index: Option<usize>,    pub start_index: Option<usize>,pub struct Citation {#[serde(rename_all = "camelCase")]#[derive(Debug, Deserialize, Clone)]}    pub citations: Vec<Citation>pub struct CitationMetadata {#[derive(Debug, Deserialize, Clone)]}    }        }            Ok(())        } else {                self.category, self.probability, self.blocked)            writeln!(f, "Safety Rating: {}: {} -> {:?}",        if self.blocked.is_some() {    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {impl std::fmt::Debug for OutSafety {}    pub blocked: Option<bool>    pub probability: String,    pub category: String,pub struct OutSafety {#[derive(Deserialize, Clone)]}    pub citation_metadata: Option<CitationMetadata>    #[serde(skip_serializing_if = "Option::is_none")]    pub safety_ratings: Option<Vec<OutSafety>>,    #[serde(skip_serializing_if = "Option::is_none")]    pub finish_reason: Option<String>,    #[serde(skip_serializing_if = "Option::is_none")]    pub content: Option<ResponseContent>,pub struct Candidate {#[serde(rename_all = "camelCase")]#[derive(Debug, Deserialize, Clone)]}    */    pub response_id: Option<String>,    #[serde(skip_serializing_if = "Option::is_none")]    pub create_time: Option<String>,    #[serde(skip_serializing_if = "Option::is_none")]    pub model_version: Option<String>,    #[serde(skip_serializing_if = "Option::is_none")]    /*    pub usage_metadata: Option<Usage>,    #[serde(skip_serializing_if = "Option::is_none")]    pub candidates: Vec<Candidate>,pub struct GeminiResponse {#[serde(rename_all = "camelCase")]ad40�����w)�
�
b
.
��}L�,�
�
�


�	�	�	�	O		��cA+����wB���tI                .map(|c| if c.safety_ratings.is_some() {            .map(|gr| gr.candidates.iter()        let safety_ratings: Vec<String> = res.iter()            .collect::<String>()).collect();            })                if let Some(finish) = &c.finish_reason { finish.clone() } else { "".into() }            .map(|gr| gr.candidates.iter().map(|c| {        let finish_reason: String = res.iter()            .collect::<String>()).collect();            })                }                    "".into()                } else {                    }                        "".into()                    } else {                        parts.iter().map(|p| p.text.trim().to_owned() + " ").collect::<String>()                    if let Some(parts) = &content.parts {                if let Some(content) = &c.content {            .map(|gr| gr.candidates.iter().map(|c| {        let text: String = res.iter()        // Now unpack it        let res: Vec<GeminiResponse> = serde_json::from_str(&res).unwrap();    } else {        Ok(LlmReturn::new(LlmType::GEMINI_TOOLS, function_calls, finish, triple, timing, None, None))        let finish = h.get("finish").unwrap()[0].clone();        let triple = (i.parse::<usize>().unwrap(), o.parse::<usize>().unwrap(), t.parse::<usize>().unwrap());        let (i, o, t) = (h.get("in").unwrap()[0].clone(), h.get("out").unwrap()[0].clone(), h.get("total").unwrap()[0].clone());//println!("{:?}", serde_json::from_str::<Vec<ParseFunction>>(&function_calls).unwrap());        let function_calls = serde_json::to_string(&funcs).unwrap();        let funcs = unpack_functions(h.clone());        let h = get_functions(&f, &found);        let f: serde_json::Value = serde_json::from_str(&res).unwrap();            "candidates:finishReason:${finish}".to_string()];//            "usageMetadata:${usage}".to_string(),            "usageMetadata:totalTokenCount:${total}".to_string(),            "usageMetadata:candidatesTokenCount:${out}".to_string(),            "usageMetadata:promptTokenCount:${in}".to_string(),            "candidates:content:parts:functionCall:name:${func}".to_string(),            "candidates:content:parts:functionCall:args:${args}".to_string(),        let found = vec![    } else if res.contains("\"functionCall\"") {        Ok(LlmReturn::new(LlmType::GEMINI_ERROR, res[0].error.to_string(), res[0].error.to_string(), (0, 0, 0), timing, None, None))        let res: Vec<LlmError> = serde_json::from_str(&res).unwrap();    if res.contains("\"error\":") {ad~�Q���zyZ:���/�
�
�
�
�
�
'

������T1	�����:9#�
�
�
�
�
g



�	�	�	�	�	�	�	�	i	,	�������E%��iIC0	�V60���        let messages =         let messages =    async fn test_call_gemini_logic() {    #[tokio::test]    }        gemini(messages).await;            vec![Content::text("user", "Write a creative poem about the interplay of artificial intelligence and the human spirit and provide citations")];        let messages =    async fn test_call_gemini_poem() {    #[tokio::test]    }        gemini(messages).await;            vec![Content::text("user", "Give citations for the General theory of Relativity.")];        let messages =    async fn test_call_gemini_citation() {    #[tokio::test]    }        gemini(messages).await;            vec![Content::text("user", "What is the meaning of life?")];        let messages =    async fn test_call_gemini_basic() {    #[tokio::test]    }        }            Err(e) => { println!("{e}"); assert!(false) },            Ok(ret) => { println!("{ret}"); assert!(true) },        match call_gemini(content).await {    async fn gemini(content: Vec<Content>) {    use super::*;mod tests {#[cfg(test)]}    get_client(headers).await    );            .map_err(|e| -> Box<dyn std::error::Error + Send> { Box::new(e) })?,        HeaderValue::from_str(&format!("Bearer {}", api_key))        "Authorization",    headers.insert(    // Create api key header    let mut headers: HeaderMap = HeaderMap::new();    // Create headers    let api_key: String = String::from_utf8_lossy(&output.stdout).trim().to_string();        .expect("Failed to execute command");        .output()        .arg("print-access-token")        .arg("auth")    let output = Command::new("gcloud")    // Extract API Key informationasync fn get_gemini_client() -> Result<Client, Box<dyn std::error::Error + Send>> {}    }        contents    } else {        [Content::system(system), contents].concat()    if let Some(system) = system {pub fn add_system_content(system: Option<&str>, contents: Vec<Content>) -> Vec<Content> {/// Add 'system' content to other content}    }                          ))                          if safety_ratings.is_empty() { None } else { Some(safety_ratings) }                          if citations.is_empty() { None } else { Some(citations) },        Ok(LlmReturn::new(LlmType::GEMINI, text, finish_reason, usage, timing,            .fold(String::new(), |s, l| s + l + "\n");            .filter(|l| !l.starts_with("```"))        let text = text.lines()        // Remove any comments            });                s                }                    s.2 += if let Some(n) = m.total_token_count { n } else { 0 };