1717package com .google .adk .models ;
1818
1919import static com .google .common .base .StandardSystemProperty .JAVA_VERSION ;
20+ import static net .javacrumbs .futureconverter .java8guava .FutureConverter .toListenableFuture ;
2021
2122import com .google .adk .Version ;
2223import com .google .common .collect .ImmutableMap ;
24+ import com .google .common .util .concurrent .Futures ;
25+ import com .google .common .util .concurrent .ListenableFuture ;
2326import com .google .errorprone .annotations .CanIgnoreReturnValue ;
2427import com .google .genai .Client ;
2528import com .google .genai .ResponseStream ;
3235import com .google .genai .types .LiveConnectConfig ;
3336import com .google .genai .types .Part ;
3437import io .reactivex .rxjava3 .core .Flowable ;
38+ import io .reactivex .rxjava3 .core .Scheduler ;
39+ import io .reactivex .rxjava3 .core .Single ;
40+ import io .reactivex .rxjava3 .schedulers .Schedulers ;
3541import java .util .ArrayList ;
3642import java .util .List ;
3743import java .util .Objects ;
3844import java .util .Optional ;
39- import java .util .concurrent .CompletableFuture ;
45+ import java .util .concurrent .ExecutionException ;
4046import org .slf4j .Logger ;
4147import org .slf4j .LoggerFactory ;
4248
@@ -205,6 +211,23 @@ public Gemini build() {
205211 }
206212 }
207213
214+ private static <T > Single <T > toSingle (ListenableFuture <T > future , Scheduler scheduler ) {
215+ return Single .create (
216+ emitter -> {
217+ future .addListener (
218+ () -> {
219+ try {
220+ emitter .onSuccess (Futures .getDone (future ));
221+ } catch (ExecutionException e ) {
222+ emitter .onError (e .getCause ());
223+ }
224+ },
225+ scheduler ::scheduleDirect );
226+
227+ emitter .setCancellable (() -> future .cancel (false ));
228+ });
229+ }
230+
208231 @ Override
209232 public Flowable <LlmResponse > generateContent (LlmRequest llmRequest , boolean stream ) {
210233 llmRequest =
@@ -218,14 +241,17 @@ public Flowable<LlmResponse> generateContent(LlmRequest llmRequest, boolean stre
218241
219242 if (stream ) {
220243 logger .debug ("Sending streaming generateContent request to model {}" , effectiveModelName );
221- CompletableFuture <ResponseStream <GenerateContentResponse >> streamFuture =
222- apiClient .async .models .generateContentStream (
223- effectiveModelName , llmRequest .contents (), config );
244+ ListenableFuture <ResponseStream <GenerateContentResponse >> streamFuture =
245+ toListenableFuture (
246+ apiClient .async .models .generateContentStream (
247+ effectiveModelName , llmRequest .contents (), config ));
224248
225249 return Flowable .defer (
226250 () ->
227251 processRawResponses (
228- Flowable .fromFuture (streamFuture ).flatMapIterable (iterable -> iterable )))
252+ toSingle (streamFuture , Schedulers .io ())
253+ .toFlowable ()
254+ .flatMapIterable (iterable -> iterable )))
229255 .filter (
230256 llmResponse ->
231257 llmResponse
@@ -243,12 +269,16 @@ public Flowable<LlmResponse> generateContent(LlmRequest llmRequest, boolean stre
243269 .orElse (false ));
244270 } else {
245271 logger .debug ("Sending generateContent request to model {}" , effectiveModelName );
246- return Flowable .fromFuture (
247- apiClient
248- .async
249- .models
250- .generateContent (effectiveModelName , llmRequest .contents (), config )
251- .thenApplyAsync (LlmResponse ::create ));
272+ final LlmRequest finalLlmRequest = llmRequest ;
273+ return toSingle (
274+ toListenableFuture (
275+ apiClient
276+ .async
277+ .models
278+ .generateContent (effectiveModelName , finalLlmRequest .contents (), config )
279+ .thenApplyAsync (LlmResponse ::create )),
280+ Schedulers .io ())
281+ .toFlowable ();
252282 }
253283 }
254284
0 commit comments