Flutter中文网

Flutter中文网

Flutter AI:将Google Gemini API集成到Flutter中

52
2024-06-28

前提条件

检查可用区域

先检查Gemini API可用区域,并准备对应的VPN。注意区域后方[1]代表Gemini API 的免费层级未在此区域推出

申请API KEY

访问Google AI Studio点击左上角Get API Key

1719903762109.png

这里我使用是免费计划,速率限制如下

15 RPM(每分钟请求数)

100 万个 TPM(每分钟令牌数)

1500 RPD(每日请求数)

不适用上下文缓存

基础使用

引用插件

导入插件google_generative_ai,并引入头文件

google_generative_ai: ^0.4.3
import 'package:google_generative_ai/google_generative_ai.dart';

根据纯文本输入生成文本

    var model = GenerativeModel(model: 'gemini-1.5-flash', apiKey: 'APIKEY');
    final content = [Content.text('写一个睡前故事')];
    final response = await model.generateContent(content);
    print(response.text);
/*
在一片宁静的森林深处,住着一个小小的萤火虫,名叫露西。露西非常喜欢夜晚,因为那时她可以闪着自己小小的灯,照亮周围的黑暗。

有一天晚上,露西在草丛中飞舞,看到一只迷路的小兔子,它惊慌失措地哭着,因为它找不到回家的路。露西飞到小兔子身边,用自己微弱的光亮照亮了周围的树木,让小兔子能看清楚路。

“别害怕,”露西说,“我会帮助你找到回家的路。”

露西带着小兔子飞过草丛,穿过树林,最后来到了一片开满鲜花的草地上。小兔子看到了自己的家,高兴地跳了起来。

“谢谢你,露西!”小兔子说,“你真是个善良的小萤火虫!”

露西微笑着说:“不用谢,帮助别人是我最开心的事情。”

小兔子回家后,露西继续在森林里飞舞,她闪着自己小小的灯,照亮了黑夜,也照亮了所有需要帮助的人。

这个晚上,森林里充满了温暖和光明。露西知道,只要她继续闪亮,就能给所有迷路的人带来希望和勇气。

露西回到了自己的草丛,闭上眼睛,进入了甜蜜的梦乡。她梦见了美丽的森林,梦见了快乐的小动物,也梦见了所有她帮助过的人。

露西,这个小小的萤火虫,用自己的微弱光亮照亮了整个夜晚,也照亮了所有需要帮助的人的心。

晚安,小宝贝们,也愿你们做个好梦。
*/

据文本和图片输入生成文本

    var model = GenerativeModel(model: 'gemini-1.5-flash', apiKey: 'APIKEY');
    final (firstImage, secondImage) = await (
    rootBundle.load('assets/image0.png'),
    rootBundle.load('assets/image1.png')
    ).wait;
    final prompt = TextPart("这两种图片有什么不同?");
    final imageParts = [
      DataPart('image/png', firstImage.buffer.asUint8List()),
      DataPart('image/png', secondImage.buffer.asUint8List()),
    ];
    final response = await model.generateContent([
      Content.multi([prompt, ...imageParts])
    ]);
    print(response.text);

	//输出:第一张图片中没有鱼,第二张图片中有一条黄色的鱼在湖里。

1719903785325.png

这里表现的差点意思,没有找出所有差别

建立多轮对话

借助 Gemini,可以跨多个回合构建自由形式的对话。该 SDK 通过管理对话状态来简化该过程,无需自行存储对话历史记录。

通过调用 startChat() 初始化对话。然后,使用 sendMessage() 发送一条新的用户消息,此消息也会将此消息和响应附加到聊天记录。

与对话内容相关联的 role 有两种可能的选项:

  • user:提供提示的角色。此值是 sendMessage 调用的默认值,如果传递了其他角色,函数将抛出异常。

  • model:提供响应的角色。使用现有的 history 调用 startChat() 时,可以使用此角色。

    final model = GenerativeModel(
        model: 'gemini-1.5-flash',
        apiKey: 'APIKEY',
        generationConfig: GenerationConfig(maxOutputTokens: 100));
    final chat = model.startChat(history: [
      Content.text('你好,我的房子里有两只狗'),
      Content.model([TextPart('很高兴见到你。你想知道什么?')])
    ]);
    var content = Content.text('我的房子里有几只爪子?');
    var response = await chat.sendMessage(content);
    print(response.text);
//输出:每只狗有四只爪子,所以两只狗就有八只爪子。

使用流式传输加快互动速度

默认情况下,模型会在完成整个生成过程后返回响应。通过不等待整个结果,可以实现更快的互动,使用流式传输来处理部分结果。

final model = GenerativeModel(model: 'gemini-1.5-flash', apiKey: 'APIKEY');
final (firstImage, secondImage) = await (
rootBundle.load('assets/image0.png'),
rootBundle.load('assets/image1.png')
).wait;
final prompt = TextPart("这两种图片有什么不同?");
final imageParts = [
  DataPart('image/png', firstImage.buffer.asUint8List()),
  DataPart('image/png', secondImage.buffer.asUint8List()),
];
final response = model.generateContentStream([
  Content.multi([prompt, ...imageParts])
]);
await for (final chunk in response) {
  print(chunk.text);
}
//flutter: 第一
//flutter: 张图片里,湖里没有鱼。
//flutter: 第二张图片里,湖里
//flutter: 有一条黄色的鱼。

进阶用法

进阶用法没有实际尝试,以下代码来自官方文档

调用函数

函数调用可让您更轻松地从生成模型获取结构化数据输出。然后,您可以使用这些输出来调用其他 API,并将相关响应数据返回给模型。换句话说,函数调用可帮助您将生成模型连接到外部系统,以便生成的内容包含最新且准确的信息。如需了解详情,请参阅函数调用教程

使用嵌入

嵌入是一种用于将信息表示为数组中的浮点数列表的技术。借助 Gemini,您能够以矢量化形式表示文本(字词、句子和文本块),从而更轻松地比较和对比嵌入。例如,主题或情感相似的两个文本应该具有相似的嵌入,这些嵌入可以通过余弦相似度等数学比较技术来识别。

结合使用 embedding-001 模型和 embedContent 方法(或 batchEmbedContent 方法)生成嵌入。以下示例为单个字符串生成嵌入:

final model = GenerativeModel(model: 'embedding-001', apiKey: apiKey);
final content = Content.text('The quick brown fox jumps over the lazy dog.');
final result = await model.embedContent(content);
print(result.embedding.values);

计算词元数量

使用长提示时,在向模型发送任何内容之前统计词元数量可能会很有用。以下示例展示了如何针对各种用例使用 countTokens()

// For text-only input
final tokenCount = await model.countTokens(Content.text(prompt));
print('Token count: ${tokenCount.totalTokens}');
// For text-and-image input (multimodal)
final tokenCount = await model.countTokens([
  Content.multi([prompt, ...imageParts])
]);
print('Token count: ${tokenCount.totalTokens}');
// For multi-turn conversations (like chat)
final prompt = Content.text(message);
final allContent = [...chat.history, prompt];
final tokenCount = await model.countTokens(allContent);
print('Token count: ${tokenCount.totalTokens}');

用于控制内容生成的选项

您可以通过配置模型参数和使用安全设置来控制内容生成。

请注意,将 generationConfigsafetySettings 传递给模型请求方法(如 generateContent)将完全替换与 getGenerativeModel 中传递的相同名称的配置对象。

配置模型参数

您发送到模型的每个提示都包含参数值,用于控制模型如何生成回答。对于不同的参数值,模型会生成不同的结果。详细了解模型参数。此配置在模型实例的生命周期内保持不变。

final generationConfig = GenerationConfig(
  stopSequences: ["red"],
  maxOutputTokens: 200,
  temperature: 0.9,
  topP: 0.1,
  topK: 16,
);
final model = GenerativeModel(
  // The Gemini 1.5 models are versatile and work with most use cases
  model: 'gemini-1.5-flash',
  apiKey: apiKey,
  generationConfig: generationConfig,
);

使用安全设置

您可以使用安全设置来调整获得可能被视为有害响应的可能性。默认情况下,安全设置会在所有维度上屏蔽不安全内容的中等和/或高概率。详细了解安全设置

设置一项安全设置的方法如下:

final safetySettings = [
  SafetySetting(HarmCategory.harassment, HarmBlockThreshold.high)
];
final model = GenerativeModel(
  // The Gemini 1.5 models are versatile and work with most use cases
  model: 'gemini-1.5-flash',
  apiKey: apiKey,
  safetySettings: safetySettings,
);

还可以设定多项安全设置:

final safetySettings = [
  SafetySetting(HarmCategory.harassment, HarmBlockThreshold.high),
  SafetySetting(HarmCategory.hateSpeech, HarmBlockThreshold.high),
];

常见报错

Unhandled Exception: Instance of 'UnsupportedUserLocation'

Geimni API不支持该区域。检查可用区域,使用可用区域的VPN。

User location is not supported for the API use without a billing account linked.

Geimni API在该区域不支持免费计划,有两种解决方案。

如果要使用免费计划,参照文章开头提到的,选择可用区域中后面没有[1]的。

不需要免费计划的话,去Google控制台点击结算,添加付款信息。这里可能也有很多问题,不支持大陆信用卡、找到了可用信用卡保存的时候报错OR_BACR2_34,本文不讨论这个问题。