1
+ use std:: error:: Error ;
2
+ use dioxus:: prelude:: Signal ;
3
+ use futures:: StreamExt ;
4
+ use tracing:: { error, info} ;
5
+ use async_openai_wasm:: Client ;
6
+ use async_openai_wasm:: config:: OpenAIConfig ;
7
+ use async_openai_wasm:: types:: { AssistantStreamEvent , CreateAssistantRequest , CreateAssistantRequestArgs , FunctionObject , MessageDeltaContent , RunObject , SubmitToolOutputsRunRequest , ToolsOutputs } ;
8
+ use crate :: { API_BASE , API_KEY } ;
9
+ use dioxus:: prelude:: * ;
10
+
11
+
12
+ pub const TEMPERATURE : & str = "57" ;
13
+ pub const RAIN_PROBABILITY : & str = "0.06" ;
14
+
15
+ pub fn get_client ( ) -> Client < OpenAIConfig > {
16
+ let config = OpenAIConfig :: new ( )
17
+ . with_api_key ( API_KEY ) ;
18
+ let config = if API_BASE != "..." {
19
+ config. with_api_base ( API_BASE )
20
+ } else {
21
+ config
22
+ } ;
23
+
24
+ Client :: with_config ( config)
25
+ }
26
+
27
+ pub async fn handle_requires_action ( client : & Client < OpenAIConfig > , run_object : RunObject , reply_signal : Signal < String > ) {
28
+ let mut tool_outputs: Vec < ToolsOutputs > = vec ! [ ] ;
29
+ if let Some ( ref required_action) = run_object. required_action {
30
+ for tool in & required_action. submit_tool_outputs . tool_calls {
31
+ if tool. function . name == "get_current_temperature" {
32
+ info ! ( "get_current_temperature" ) ;
33
+ tool_outputs. push ( ToolsOutputs {
34
+ tool_call_id : Some ( tool. id . clone ( ) ) ,
35
+ output : Some ( TEMPERATURE . into ( ) ) ,
36
+ } )
37
+ } else if tool. function . name == "get_rain_probability" {
38
+ info ! ( "get_rain_probability" ) ;
39
+ tool_outputs. push ( ToolsOutputs {
40
+ tool_call_id : Some ( tool. id . clone ( ) ) ,
41
+ output : Some ( RAIN_PROBABILITY . into ( ) ) ,
42
+ } )
43
+ } else {
44
+ error ! ( "Unknown tool: {}" , tool. function. name) ;
45
+ unreachable ! ( ) ;
46
+ }
47
+ }
48
+
49
+ if let Err ( e) = submit_tool_outputs ( client, run_object, tool_outputs, reply_signal) . await {
50
+ error ! ( "Error on submitting tool outputs: {e}" ) ;
51
+ }
52
+ }
53
+ }
54
+
55
+ pub async fn submit_tool_outputs (
56
+ client : & Client < OpenAIConfig > ,
57
+ run_object : RunObject ,
58
+ tool_outputs : Vec < ToolsOutputs > ,
59
+ mut reply_signal : Signal < String > ,
60
+ ) -> Result < ( ) , Box < dyn Error > > {
61
+ let mut event_stream = client
62
+ . threads ( )
63
+ . runs ( & run_object. thread_id )
64
+ . submit_tool_outputs_stream (
65
+ & run_object. id ,
66
+ SubmitToolOutputsRunRequest {
67
+ tool_outputs,
68
+ stream : Some ( true ) ,
69
+ } ,
70
+ )
71
+ . await ?;
72
+
73
+ while let Some ( event) = event_stream. next ( ) . await {
74
+ match event {
75
+ Ok ( event) => {
76
+ if let AssistantStreamEvent :: ThreadMessageDelta ( delta) = event {
77
+ if let Some ( contents) = delta. delta . content {
78
+ for content in contents {
79
+ // only text is expected here and no images
80
+ if let MessageDeltaContent :: Text ( text) = content {
81
+ if let Some ( text) = text. text {
82
+ if let Some ( text) = text. value {
83
+ info ! ( "After submitted tool results: {}" , text) ;
84
+ reply_signal. with_mut ( |reply| {
85
+ reply. push_str ( & text) ;
86
+ } ) ;
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ }
93
+ }
94
+ Err ( e) => {
95
+ error ! ( "Error: {e}" ) ;
96
+ }
97
+ }
98
+ }
99
+
100
+ Ok ( ( ) )
101
+ }
102
+
103
+ pub fn create_assistant_request ( ) -> CreateAssistantRequest {
104
+ CreateAssistantRequestArgs :: default ( )
105
+ . instructions ( "You are a weather bot. Use the provided functions to answer questions." )
106
+ . model ( "gpt-4o" )
107
+ . tools ( vec ! [
108
+ FunctionObject {
109
+ name: "get_current_temperature" . into( ) ,
110
+ description: Some ( "Get the current temperature for a specific location" . into( ) ) ,
111
+ parameters: Some ( serde_json:: json!(
112
+ {
113
+ "type" : "object" ,
114
+ "properties" : {
115
+ "location" : {
116
+ "type" : "string" ,
117
+ "description" : "The city and state, e.g., San Francisco, CA"
118
+ } ,
119
+ "unit" : {
120
+ "type" : "string" ,
121
+ "enum" : [ "Celsius" , "Fahrenheit" ] ,
122
+ "description" : "The temperature unit to use. Infer this from the user's location."
123
+ }
124
+ } ,
125
+ "required" : [ "location" , "unit" ]
126
+ }
127
+ ) ) ,
128
+ } . into( ) ,
129
+ FunctionObject {
130
+ name: "get_rain_probability" . into( ) ,
131
+ description: Some ( "Get the probability of rain for a specific location" . into( ) ) ,
132
+ parameters: Some ( serde_json:: json!(
133
+ {
134
+ "type" : "object" ,
135
+ "properties" : {
136
+ "location" : {
137
+ "type" : "string" ,
138
+ "description" : "The city and state, e.g., San Francisco, CA"
139
+ }
140
+ } ,
141
+ "required" : [ "location" ]
142
+ }
143
+ ) ) ,
144
+ } . into( ) ,
145
+ ] )
146
+ . build ( )
147
+ . expect ( "failed to build CreateAssistantRequestArgs" )
148
+ }
0 commit comments