1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use openai_api_rs::v1::api::Client;
use openai_api_rs::v1::chat_completion::{self, ChatCompletionRequest, FunctionCallType};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::{env, vec};

fn get_coin_price(coin: &str) -> f64 {
    let coin = coin.to_lowercase();
    match coin.as_str() {
        "btc" | "bitcoin" => 10000.0,
        "eth" | "ethereum" => 1000.0,
        _ => 0.0,
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new(env::var("OPENAI_API_KEY").unwrap().to_string());

    let mut properties = HashMap::new();
    properties.insert(
        "coin".to_string(),
        Box::new(chat_completion::JSONSchemaDefine {
            schema_type: Some(chat_completion::JSONSchemaType::String),
            description: Some("The cryptocurrency to get the price of".to_string()),
            enum_values: None,
            properties: None,
            required: None,
            items: None,
        }),
    );

    let req = ChatCompletionRequest::new(
        chat_completion::GPT3_5_TURBO_0613.to_string(),
        vec![chat_completion::ChatCompletionMessage {
            role: chat_completion::MessageRole::user,
            content: String::from("What is the price of Ethereum?"),
            name: None,
            function_call: None,
        }],
    )
    .functions(vec![chat_completion::Function {
        name: String::from("get_coin_price"),
        description: Some(String::from("Get the price of a cryptocurrency")),
        parameters: chat_completion::FunctionParameters {
            schema_type: chat_completion::JSONSchemaType::Object,
            properties: Some(properties),
            required: Some(vec![String::from("coin")]),
        },
    }])
    .function_call(FunctionCallType::Auto);

    // debug reuqest json
    // let serialized = serde_json::to_string(&req).unwrap();
    // println!("{}", serialized);

    let result = client.chat_completion(req)?;

    match result.choices[0].finish_reason {
        chat_completion::FinishReason::stop => {
            println!("Stop");
            println!("{:?}", result.choices[0].message.content);
        }
        chat_completion::FinishReason::length => {
            println!("Length");
        }
        chat_completion::FinishReason::function_call => {
            println!("FunctionCall");
            #[derive(Serialize, Deserialize)]
            struct Currency {
                coin: String,
            }
            let function_call = result.choices[0].message.function_call.as_ref().unwrap();
            let name = function_call.name.clone().unwrap();
            let arguments = function_call.arguments.clone().unwrap();
            let c: Currency = serde_json::from_str(&arguments)?;
            let coin = c.coin;
            if name == "get_coin_price" {
                let price = get_coin_price(&coin);
                println!("{} price: {}", coin, price);
            }
        }
        chat_completion::FinishReason::content_filter => {
            println!("ContentFilter");
        }
        chat_completion::FinishReason::null => {
            println!("Null");
        }
    }
    Ok(())
}

// OPENAI_API_KEY=xxxx cargo run --package openai-api-rs --example function_call