Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,23 @@ let history = [
]
let chat = model.startChat(history: history)
```

## Flutter (Dart)

Seed the session with `Content.text` (user role) and `Content.model` entries,
then send new user messages:

```dart
import 'package:firebase_ai/firebase_ai.dart';

// [AGENT] Replace '<latest_supported_model>' with the latest model from https://firebase.google.com/docs/ai-logic/models.md.txt
final model = FirebaseAI.googleAI().generativeModel(model: '<latest_supported_model>');

final chat = model.startChat(history: [
Content.text('Hello, I am a user.'),
Content.model([TextPart('Hello! How can I help you today?')]),
]);

final response = await chat.sendMessage(Content.text('What is CBT?'));
print(response.text);
```
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,62 @@ print(finalResponse.text ?? "No text in response.")
> `let tool = Tool.functionDeclarations([...])` no longer compiles. Pass the
> array literal `tools: [.functionDeclarations([...])]` as above; it works on
> both old and new SDK versions.

## Flutter (Dart)

Function arguments arrive as `Map<String, Object?>` on `functionCall.args`, and
`Content.functionResponses` (or `Content.functionResponse` for a single call)
wraps your results for the follow-up turn:

```dart
import 'package:firebase_ai/firebase_ai.dart';

// Step 1: the app-side function the model can ask you to run.
Future<Map<String, Object?>> getStockPrice(String symbol) async {
// TODO(developer): Call a real stock price API. Hardcoded for demo purposes.
return {'symbol': symbol, 'price': 189.84};
}

// Step 2: describe the function to the model.
final getStockPriceTool = FunctionDeclaration(
'getStockPrice',
'Get the current stock price for a given symbol.',
parameters: {
'symbol': Schema.string(description: 'The stock symbol, e.g. AAPL'),
},
);

// Step 3: provide the declaration when creating the model.
// [AGENT] Replace '<latest_supported_model>' with the latest model from https://firebase.google.com/docs/ai-logic/models.md.txt
final model = FirebaseAI.googleAI().generativeModel(
model: '<latest_supported_model>',
tools: [Tool.functionDeclarations([getStockPriceTool])],
);

Future<String> askStockPrice() async {
// Step 4: send the prompt in a chat session and run any requested call(s).
final chat = model.startChat();
var response = await chat.sendMessage(
Content.text('What is the stock price of Apple?'),
);

final functionResponses = <FunctionResponse>[];
for (final functionCall in response.functionCalls) {
if (functionCall.name == 'getStockPrice') {
final symbol = functionCall.args['symbol']! as String;
final functionResult = await getStockPrice(symbol);
functionResponses.add(
FunctionResponse(functionCall.name, functionResult, id: functionCall.id),
);
Comment thread
AustinBenoit marked this conversation as resolved.
}
}

// Step 5: return all function results in a single turn so the model can write its final answer.
if (functionResponses.isNotEmpty) {
response = await chat.sendMessage(
Content.functionResponses(functionResponses),
);
}
return response.text ?? 'No text in response';
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,72 @@ guard let uiImage = UIImage(data: inlineDataPart.data) else {
fatalError("Failed to convert data to UIImage.")
}
```

## Flutter (Dart)

Create the model with `ResponseModalities.image` and read the bytes from
`response.inlineDataParts` (for example to show them with `Image.memory`):

```dart
import 'package:firebase_ai/firebase_ai.dart';

// Create a `GenerativeModel` instance with a Gemini model that supports image output.
// [AGENT] Replace '<latest_supported_image_model>' with the latest image model from https://firebase.google.com/docs/ai-logic/models.md.txt
final model = FirebaseAI.googleAI().generativeModel(
model: '<latest_supported_image_model>',
generationConfig: GenerationConfig(
// Configure the model to respond with images only.
responseModalities: [ResponseModalities.image],
// Specify aspect ratio and image size (both optional) in an image config.
// The default is a square (1:1) image at 1024x1024.
imageConfig: ImageConfig(
aspectRatio: ImageAspectRatio.landscape16x9,
imageSize: ImageSize.size2K,
),
),
);

// Provide a text prompt instructing the model to generate an image
final prompt = [Content.text('Generate an image of the Eiffel Tower with fireworks in the background.')];

// To generate an image, call `generateContent` with the text input
final response = await model.generateContent(prompt);
if (response.inlineDataParts.isNotEmpty) {
final imageBytes = response.inlineDataParts.first.bytes;
// Process the image
} else {
// Handle the case where no images were generated
print('Error: No images were generated.');
}
```

### Edit an image

Wrap the image bytes in an `InlineDataPart` with their MIME type and send them
with a `TextPart` in a single `Content.multi` to the same image-capable `model`:

```dart
import 'dart:io';
import 'package:firebase_ai/firebase_ai.dart';

Comment thread
AustinBenoit marked this conversation as resolved.
// Prepare an image for the model to edit
final image = await File('scones.jpg').readAsBytes();
final imagePart = InlineDataPart('image/jpeg', image);

// Provide a text prompt instructing the model to edit the image
final prompt = TextPart('Edit this image to make it look like a cartoon');

// To edit the image, call `generateContent` with the image and text input
final response = await model.generateContent([
Content.multi([imagePart, prompt]),
]);

// Handle the generated image
if (response.inlineDataParts.isNotEmpty) {
final imageBytes = response.inlineDataParts.first.bytes;
// Process the image
} else {
// Handle the case where no images were generated
print('Error: No images were generated.');
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,41 @@ print(response.text ?? "No text in response.")
Cloud Storage for Firebase URL (Agent Platform Gemini API provider only): pass
`FileDataPart(uri: "gs://bucket-name/path/image.jpg", mimeType: "image/jpeg")`
in place of the `InlineDataPart`.

## Flutter (Dart)

Build an `InlineDataPart(mimeType, bytes)` and combine it with a `TextPart` in a
single `Content.multi` message:

```dart
import 'dart:io';
import 'package:firebase_ai/firebase_ai.dart';

// [AGENT] Replace '<latest_supported_model>' with the latest model from https://firebase.google.com/docs/ai-logic/models.md.txt
final model = FirebaseAI.googleAI().generativeModel(model: '<latest_supported_model>');

// Provide a text prompt to include with the image
final prompt = TextPart("What's in the picture?");
// Prepare the image for input (any Uint8List works, e.g. from image_picker)
final image = await File('image0.jpg').readAsBytes();
final imagePart = InlineDataPart('image/jpeg', image);
// To generate text output, call generateContent with the image and text
final response = await model.generateContent([
Content.multi([imagePart, prompt]),
]);
print(response.text);
```

Other media types only differ in the MIME type passed to `InlineDataPart`:

```dart
final audio = await File('audio0.mp3').readAsBytes();
final audioPart = InlineDataPart('audio/mpeg', audio); // or 'application/pdf', 'video/mp4'
final response = await model.generateContent([
Content.multi([audioPart, TextPart("Transcribe what's said in this audio recording.")]),
]);
```

Cloud Storage for Firebase URL (Agent Platform Gemini API provider only): use
`FileData('image/jpeg', 'gs://bucket-name/path/image.jpg')` in place of the
`InlineDataPart` inside `Content.multi`.
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,9 @@ if #available(iOS 27.0, macOS 27.0, *) {
removed in `firebase-ios-sdk` v13.0.0 in favor of `GeminiLanguageModel` above
(or standard cloud `ai.generativeModel(modelName:)` on earlier OS versions).
See https://firebase.google.com/docs/ai-logic/hybrid.md.txt.

## Flutter (Dart)

Hybrid on-device inference is not available via Firebase AI Logic on Flutter
(including Flutter web); the `firebase_ai` package always calls the cloud-hosted
Gemini API. See https://firebase.google.com/docs/ai-logic/hybrid.md.txt.
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,46 @@ if let candidate = response.candidates.first,
}
}
```

## Flutter (Dart)

Pass `Tool.googleSearch()` in `tools`. Show `renderedContent` with a WebView
plugin (for example `webview_flutter`).

```dart
import 'package:firebase_ai/firebase_ai.dart';

// [AGENT] Replace '<latest_supported_model>' with the latest model from https://firebase.google.com/docs/ai-logic/models.md.txt
final model = FirebaseAI.googleAI().generativeModel(
model: '<latest_supported_model>',
// Provide Google Search as a tool that the model can use to generate its response.
tools: [
Tool.googleSearch(),
],
);

final response = await model.generateContent([Content.text("Who won the euro 2024?")]);

// Get the model's response
final text = response.text;

// Get the grounding metadata
final groundingMetadata = response.candidates.firstOrNull?.groundingMetadata;

// REQUIRED - display Google Search suggestions
// (renderedContent contains HTML and CSS for the search widget)
final renderedContent = groundingMetadata?.searchEntryPoint?.renderedContent;
if (renderedContent != null) {
// TODO(developer): Display Google Search suggestions using a WebView
}

// REQUIRED - display sources
final groundingChunks = groundingMetadata?.groundingChunks;
if (groundingChunks != null) {
for (var chunk in groundingChunks) {
final title = chunk.web?.title; // for example, "uefa.com"
final uri = chunk.web?.uri; // for example, "https://vertexaisearch.cloud.google.com..."
// TODO(developer): show sources in the UI
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,26 @@ for try await chunk in contentStream {
}
}
```

## Flutter (Dart)

`generateContentStream` returns a Dart `Stream<GenerateContentResponse>`;
consume it with `await for`. For a chat session call
`chat.sendMessageStream(Content.text('...'))` and consume it the same way.

```dart
import 'package:firebase_ai/firebase_ai.dart';

// [AGENT] Replace '<latest_supported_model>' with the latest model from https://firebase.google.com/docs/ai-logic/models.md.txt
final model = FirebaseAI.googleAI().generativeModel(model: '<latest_supported_model>');

// Provide a prompt that contains text
final prompt = [Content.text('Write a story about a magic backpack.')];
// To stream generated text output, call generateContentStream with the text input
final response = model.generateContentStream(prompt);
await for (final chunk in response) {
// `text` is null for non-text chunks, so guard before appending.
final text = chunk.text;
if (text != null) print(text); // Update UI incrementally
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,50 @@ let response = try await model.generateContent(prompt)
// `response.text` is a JSON string that conforms to the schema.
let deck = try JSONDecoder().decode(Deck.self, from: Data((response.text ?? "{}").utf8))
```

## Flutter (Dart)

Build the schema with `Schema.object` / `Schema.array` / `Schema.enumString` and
pass it in `GenerationConfig`. Put `optionalProperties` on the object that owns
the optional field.

```dart
import 'dart:convert';
import 'package:firebase_ai/firebase_ai.dart';

// Provide a JSON schema object using a standard format.
// Later, pass this schema object into `responseSchema` in the generation config.
final jsonSchema = Schema.object(
properties: {
'characters': Schema.array(
items: Schema.object(
properties: {
'name': Schema.string(),
'age': Schema.integer(),
'species': Schema.string(),
'accessory': Schema.enumString(enumValues: ['hat', 'belt', 'shoes']),
},
optionalProperties: ['accessory'],
),
),
},
);

// [AGENT] Replace '<latest_supported_model>' with the latest model from https://firebase.google.com/docs/ai-logic/models.md.txt
final model = FirebaseAI.googleAI().generativeModel(
model: '<latest_supported_model>',
// In the generation config, set the `responseMimeType` to `application/json`
// and pass the JSON schema object into `responseSchema`.
generationConfig: GenerationConfig(
responseMimeType: 'application/json',
responseSchema: jsonSchema,
),
);

final prompt = "For use in a children's card game, generate 10 animal-based characters.";
final response = await model.generateContent([Content.text(prompt)]);

// `response.text` is a JSON string that conforms to the schema.
final json = jsonDecode(response.text ?? '{}') as Map<String, dynamic>;
final characters = json['characters'] as List<dynamic>;
```
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,62 @@ let configuredModel = FirebaseAI.firebaseAI(backend: .googleAI()).generativeMode
safetySettings: safetySettings
)
```

## Flutter (Dart)

Call `generativeModel` and pass prompts as a list of `Content`. `response.text`
is nullable, so provide a fallback.

```dart
import 'package:firebase_ai/firebase_ai.dart';

Future<String> generateText(String prompt) async {
final googleAI = FirebaseAI.googleAI();

// [AGENT] Replace '<latest_supported_model>' with the latest model from https://firebase.google.com/docs/ai-logic/models.md.txt
final model = googleAI.generativeModel(
model: '<latest_supported_model>',
);

final response = await model.generateContent([Content.text(prompt)]);
return response.text ?? 'No response';
}
```

### Optional: Custom Generation Config & Safety Settings

Pass an optional `GenerationConfig` as the `generationConfig:` named argument
and a list of `SafetySetting`s as `safetySettings:` when calling
`generativeModel`. The Dart `SafetySetting` constructor has **three positional
parameters** (`category`, `threshold`, `method`); the third is a nullable
`HarmBlockMethod` that you can pass as `null`.

```dart
import 'package:firebase_ai/firebase_ai.dart';

Future<String> generateConfiguredText(String prompt) async {
final googleAI = FirebaseAI.googleAI();

// Set optional parameter values in a `GenerationConfig`.
// IMPORTANT: Example values shown here. Make sure to update for your use case.
final generationConfig = GenerationConfig(
maxOutputTokens: 200,
stopSequences: ['red'],
);

// Third positional argument is an optional HarmBlockMethod; pass null.
final safetySettings = [
SafetySetting(HarmCategory.harassment, HarmBlockThreshold.high, null),
SafetySetting(HarmCategory.hateSpeech, HarmBlockThreshold.medium, null),
];

final configuredModel = googleAI.generativeModel(
model: '<latest_supported_model>',
generationConfig: generationConfig,
safetySettings: safetySettings,
);

final response = await configuredModel.generateContent([Content.text(prompt)]);
return response.text ?? 'No response';
}
```
Loading
Loading