11package com .google .firebase .example .ailogic .java ;
22
33import androidx .lifecycle .ViewModel ;
4+
45import com .google .common .util .concurrent .FutureCallback ;
56import com .google .common .util .concurrent .Futures ;
67import com .google .common .util .concurrent .ListenableFuture ;
910import com .google .firebase .ai .java .ChatFutures ;
1011import com .google .firebase .ai .java .GenerativeModelFutures ;
1112import com .google .firebase .ai .type .Content ;
13+ import com .google .firebase .ai .type .FunctionCallPart ;
14+ import com .google .firebase .ai .type .FunctionResponsePart ;
1215import com .google .firebase .ai .type .GenerateContentResponse ;
16+ import com .google .firebase .ai .type .Schema ;
17+ import com .google .firebase .ai .type .TextPart ;
18+ import com .google .firebase .ai .type .Tool ;
19+ import com .google .firebase .ai .type .FunctionDeclaration ;
20+
1321import java .util .Arrays ;
22+ import java .util .Collections ;
1423import java .util .List ;
24+ import java .util .Map ;
1525import java .util .concurrent .Executor ;
26+ import java .util .concurrent .Executors ;
27+
28+ import kotlinx .serialization .json .JsonElement ;
29+ import kotlinx .serialization .json .JsonElementKt ;
30+ import kotlinx .serialization .json .JsonObject ;
31+ import kotlinx .serialization .json .JsonPrimitive ;
32+
1633import org .reactivestreams .Publisher ;
1734import org .reactivestreams .Subscriber ;
1835import org .reactivestreams .Subscription ;
1936
2037public class CommonSnippets extends ViewModel {
2138 private Executor executor ;
22- private GenerativeModel ai = FirebaseAI .getInstance ()
23- .generativeModel ("gemini-2.5-flash" );
39+ private GenerativeModel ai = FirebaseAI .getInstance ().generativeModel ("gemini-2.5-flash" );
2440 private GenerativeModelFutures model = GenerativeModelFutures .from (ai );
2541
2642 public void chat () {
@@ -55,18 +71,21 @@ void chatNonStreaming() {
5571
5672 // Send the message
5773 ListenableFuture <GenerateContentResponse > response = chat .sendMessage (message );
58- Futures .addCallback (response , new FutureCallback <GenerateContentResponse >() {
59- @ Override
60- public void onSuccess (GenerateContentResponse result ) {
61- String resultText = result .getText ();
62- System .out .println (resultText );
63- }
64-
65- @ Override
66- public void onFailure (Throwable t ) {
67- t .printStackTrace ();
68- }
69- }, executor );
74+ Futures .addCallback (
75+ response ,
76+ new FutureCallback <GenerateContentResponse >() {
77+ @ Override
78+ public void onSuccess (GenerateContentResponse result ) {
79+ String resultText = result .getText ();
80+ System .out .println (resultText );
81+ }
82+
83+ @ Override
84+ public void onFailure (Throwable t ) {
85+ t .printStackTrace ();
86+ }
87+ },
88+ executor );
7089 // [END chat_non_streaming]
7190 }
7291
@@ -96,39 +115,155 @@ void chatStreaming() {
96115 Content message = messageBuilder .build ();
97116
98117 // Send the message
99- Publisher <GenerateContentResponse > streamingResponse =
100- chat .sendMessageStream (message );
118+ Publisher <GenerateContentResponse > streamingResponse = chat .sendMessageStream (message );
101119
102120 final String [] fullResponse = {"" };
103121
104- streamingResponse .subscribe (new Subscriber <GenerateContentResponse >() {
122+ streamingResponse .subscribe (
123+ new Subscriber <GenerateContentResponse >() {
105124
106- @ Override
107- public void onNext (GenerateContentResponse generateContentResponse ) {
108- String chunk = generateContentResponse .getText ();
109- fullResponse [0 ] += chunk ;
110- }
125+ @ Override
126+ public void onNext (GenerateContentResponse generateContentResponse ) {
127+ String chunk = generateContentResponse .getText ();
128+ fullResponse [0 ] += chunk ;
129+ }
111130
131+ @ Override
132+ public void onComplete () {
133+ System .out .println (fullResponse [0 ]);
134+ }
112135
113- @ Override
114- public void onComplete () {
115- System .out .println (fullResponse [0 ]);
116- }
136+ // ... other methods omitted for brevity
117137
118- // ... other methods omitted for brevity
138+ // [START_EXCLUDE]
139+ @ Override
140+ public void onSubscribe (Subscription s ) {
141+ }
119142
120- // [START_EXCLUDE]
121- @ Override
122- public void onSubscribe ( Subscription s ) {
143+ @ Override
144+ public void onError ( Throwable t ) {
145+ }
123146
124- }
147+ // [END_EXCLUDE]
148+ });
149+ // [END chat_streaming]
150+ }
125151
126- @ Override
127- public void onError (Throwable t ) {
152+ public void functionCalling () {
153+ // [START function_calling_create_function_declaration]
154+ FunctionDeclaration fetchWeatherTool =
155+ new FunctionDeclaration (
156+ "fetchWeather" ,
157+ "Get the weather conditions for a specific city on a specific date." ,
158+ Map .of (
159+ "location" ,
160+ Schema .obj (
161+ Map .of (
162+ "city" , Schema .str ("The city of the location." ),
163+ "state" , Schema .str ("The US state of the location." ))),
164+ "date" ,
165+ Schema .str (
166+ "The date for which to get the weather. "
167+ + "Date must be in the format: YYYY-MM-DD." )),
168+ Collections .emptyList ());
169+ // [END function_calling_create_function_declaration]
128170
129- }
130- // [END_EXCLUDE]
131- });
132- // [END chat_streaming]
171+ // [START function_calling_generate_function_call]
172+ String prompt = "What was the weather in Boston on October 17, 2024?" ;
173+ ChatFutures chatFutures = model .startChat ();
174+ // Send the user's question (the prompt) to the model using multi-turn chat.
175+ ListenableFuture <GenerateContentResponse > response =
176+ chatFutures .sendMessage (new Content ("user" , List .of (new TextPart (prompt ))));
177+
178+ ListenableFuture <JsonObject > handleFunctionCallFuture =
179+ Futures .transform (
180+ response ,
181+ result -> {
182+ for (FunctionCallPart functionCall : result .getFunctionCalls ()) {
183+ if (functionCall .getName ().equals ("fetchWeather" )) {
184+ Map <String , JsonElement > args = functionCall .getArgs ();
185+ JsonObject locationJsonObject = JsonElementKt .getJsonObject (args .get ("location" ));
186+ String city =
187+ JsonElementKt .getContentOrNull (
188+ JsonElementKt .getJsonPrimitive (locationJsonObject .get ("city" )));
189+ String state =
190+ JsonElementKt .getContentOrNull (
191+ JsonElementKt .getJsonPrimitive (locationJsonObject .get ("state" )));
192+ Location location = new Location (city , state );
193+
194+ String date =
195+ JsonElementKt .getContentOrNull (
196+ JsonElementKt .getJsonPrimitive (args .get ("date" )));
197+ return fetchWeather (location , date );
198+ }
199+ }
200+ return null ;
201+ },
202+ Executors .newSingleThreadExecutor ());
203+ // [END function_calling_generate_function_call]
204+
205+ // [START function_calling_pass_back_function_response]
206+ ListenableFuture <GenerateContentResponse > modelResponseFuture =
207+ Futures .transformAsync (
208+ handleFunctionCallFuture ,
209+ // Send the response(s) from the function back to the model
210+ // so that the model can use it to generate its final response.
211+ functionCallResult ->
212+ chatFutures .sendMessage (
213+ new Content (
214+ "function" ,
215+ List .of (new FunctionResponsePart ("fetchWeather" , functionCallResult )))),
216+ Executors .newSingleThreadExecutor ());
217+
218+ Futures .addCallback (
219+ modelResponseFuture ,
220+ new FutureCallback <GenerateContentResponse >() {
221+ @ Override
222+ public void onSuccess (GenerateContentResponse result ) {
223+ if (result .getText () != null ) {
224+ // Log the text response.
225+ System .out .println (result .getText ());
226+ }
227+ }
228+
229+ @ Override
230+ public void onFailure (Throwable t ) {
231+ // handle error
232+ }
233+ },
234+ Executors .newSingleThreadExecutor ());
235+ // [END function_calling_pass_back_function_response]
236+ }
237+
238+ // [START function_calling_write_function]
239+ // This function calls a hypothetical external API that returns
240+ // a collection of weather information for a given location on a given date.
241+ // `location` is an object of the form { city: string, state: string }
242+ public JsonObject fetchWeather (Location location , String date ) {
243+
244+ // TODO(developer): Write a standard function that would call to an external weather API.
245+
246+ // For demo purposes, this hypothetical response is hardcoded here in the expected format.
247+ return new JsonObject (
248+ Map .of (
249+ "temperature" ,
250+ JsonElementKt .JsonPrimitive (38 ),
251+ "chancePrecipitation" ,
252+ JsonElementKt .JsonPrimitive ("56%" ),
253+ "cloudConditions" ,
254+ JsonElementKt .JsonPrimitive ("partlyCloudy" )
255+ )
256+ );
257+ }
258+ // [END function_calling_write_function]
259+ }
260+
261+ class Location {
262+ public String city ;
263+ public String state ;
264+
265+ public Location (String city , String state ) {
266+ this .city = city ;
267+ this .state = state ;
133268 }
134269}
0 commit comments