Google Gemini 的 PHP 客户端 API
要求
要完成快速指南,请确保你的开发环境满足以下需求:
设置
安装
首先,通过 Composer 包管理器安装 Gemini:
composer require google-gemini-php/client
请确保允许 php-http/discovery
Composer 插件运行,或者如果你的项目还没有整合 PSR-18 客户端,请手动安装此客户端。
composer require guzzlehttp/guzzle
设置 API key
要使用 Gemini API,你需要一个 API 密钥。如果你还没有该密钥,请在 Google AI Studio 中创建。
用法
与 Gemini API 交互:
$yourApiKey = getenv('YOUR_API_KEY');
$client = Gemini::client($yourApiKey);
$result = $client->geminiPro()->generateContent('Hello');
$result->text(); // Hello! How can I assist you today?
如果需要,可以配置并创建一个独立的客户端。
$yourApiKey = getenv('YOUR_API_KEY');
$client = Gemini::factory()
->withApiKey($yourApiKey)
->withBaseUrl('https://generativelanguage.example.com/v1') // default: https://generativelanguage.googleapis.com/v1/
->withHttpHeader('X-My-Header', 'foo')
->withQueryParam('my-param', 'bar')
->withHttpClient(new \GuzzleHttp\Client([])) // default: HTTP client found using PSR-18 HTTP Client Discovery
->withStreamHandler(fn(RequestInterface $request): ResponseInterface => $client->send($request, [
'stream' => true // Allows to provide a custom stream handler for the http client.
]))
->make();
Chat 资源
纯文本输入
从给定输入消息的模型中生成响应。如果输入仅包含文本,请使用 gemini-pro
模型。
$yourApiKey = getenv('YOUR_API_KEY');
$client = Gemini::client($yourApiKey);
$result = $client->geminiPro()->generateContent('Hello');
$result->text(); // Hello! How can I assist you today?
文本和图像输入
如果输入包含文本和图像,请使用 gemini-pro-vision
模型。
$result = $client
->geminiProVision()
->generateContent([
'What is this picture?',
new Blob(
mimeType: MimeType::IMAGE_JPEG,
data: base64_encode(
file_get_contents('https://storage.googleapis.com/generativeai-downloads/images/scones.jpg')
)
)
]);
$result->text(); // The picture shows a table with a white tablecloth. On the table are two cups of coffee, a bowl of blueberries, a silver spoon, and some flowers. There are also some blueberry scones on the table.
多回合对话 (Chat)
使用 Gemini,可以跨多个回合构建自由形式的对话。
$chat = $client
->geminiPro()
->startChat(history: [
Content::parse(part: 'The stories you write about what I have to say should be one line. Is that clear?'),
Content::parse(part: 'Yes, I understand. The stories I write about your input should be one line long.', role: Role::MODEL)
]);
$response = $chat->sendMessage('Create a story set in a quiet village in 1600s France');
echo $response->text(); // Amidst rolling hills and winding cobblestone streets, the tranquil village of Beausoleil whispered tales of love, intrigue, and the magic of everyday life in 17th century France.
$response = $chat->sendMessage('Rewrite the same story in 1600s England');
echo $response->text(); // In the heart of England's lush countryside, amidst emerald fields and thatched-roof cottages, the village of Willowbrook unfolded a tapestry of love, mystery, and the enchantment of ordinary days in the 17th century.
gemini-pro-vision
模型(适用于文本和图像输入)还未优化多回合对话。此项聊天用例请确保使用 gemini-pro 和纯文本输入。
流式生成内容
默认情况下,模型在完成整个生成处理后返回一个响应。你可以通过不等待整个结果来实现更快的交互,而是使用流处理部分结果。
$stream = $client
->geminiPro()
->streamGenerateContent('Write long a story about a magic backpack.');
foreach ($stream as $response) {
echo $response->text();
}
Token 计数
当使用长提示时,在向模型发送任何内容之前对 token 进行计数可能会很有用。
$response = $client
->geminiPro()
->countTokens('Write a story about a magic backpack.');
echo $response->totalTokens; // 9
配置
发送给模型的每个提示都包括控制模型如何生成响应的参数值。该模型可以针对不同的参数值生成不同的结果。了解有关模型参数的更多信息。
此外,你可以使用安全设置来调整可能被认为有害的反应的可能性。默认情况下,安全设置会阻止所有维度上具有中等和/或高概率的不安全内容。了解有关安全设置的详细信息。
use Gemini\Data\GenerationConfig;
use Gemini\Enums\HarmBlockThreshold;
use Gemini\Data\SafetySetting;
use Gemini\Enums\HarmCategory;
$safetySettingDangerousContent = new SafetySetting(
category: HarmCategory::HARM_CATEGORY_DANGEROUS_CONTENT,
threshold: HarmBlockThreshold::BLOCK_ONLY_HIGH
);
$safetySettingHateSpeech = new SafetySetting(
category: HarmCategory::HARM_CATEGORY_HATE_SPEECH,
threshold: HarmBlockThreshold::BLOCK_ONLY_HIGH
);
$generationConfig = new GenerationConfig(
stopSequences: [
'Title',
],
maxOutputTokens: 800,
temperature: 1,
topP: 0.8,
topK: 10
);
$generativeModel = $client
->geminiPro()
->withSafetySetting($safetySettingDangerousContent)
->withSafetySetting($safetySettingHateSpeech)
->withGenerationConfig($generationConfig)
->generateContent("Write a story about a magic backpack.");
Embedding 资源
Embedding 是一种用于将信息表示为数组中的浮点数列表的技术。使用 Gemini,可以以矢量化的形式表示文本(单词、句子和文本块),从而更容易比较和对比 Embedding。例如,共享相似主题或情感的两个文本应该具有相似的 Embedding,这可以通过数学比较技术(如余弦相似通过 embedContents
和 batchEmbedContents
来使用 embedding-001
模型:
$response = $client
->embeddingModel()
->embedContent("Write a story about a magic backpack.");
print_r($response->embedding->values);
//[
// [0] => 0.008624583
// [1] => -0.030451821
// [2] => -0.042496547
// [3] => -0.029230341
// [4] => 0.05486475
// [5] => 0.006694871
// [6] => 0.004025645
// [7] => -0.007294857
// [8] => 0.0057651913
// ...
//]
模型
List 模型
使用 list 模型,以查看可用的 Gemini 模型:
$response = $client->models()->list();
$response->models;
//[
// [0] => Gemini\Data\Model Object
// (
// [name] => models/gemini-pro
// [version] => 001
// [displayName] => Gemini Pro
// [description] => The best model for scaling across a wide range of tasks
// ...
// )
// [1] => Gemini\Data\Model Object
// (
// [name] => models/gemini-pro-vision
// [version] => 001
// [displayName] => Gemini Pro Vision
// [description] => The best image understanding model to handle a broad range of applications
// ...
// )
// [2] => Gemini\Data\Model Object
// (
// [name] => models/embedding-001
// [version] => 001
// [displayName] => Embedding 001
// [description] => Obtain a distributed representation of a text.
// ...
// )
//]
Get 模型
获取模型的信息,比如版本、显示名、输入 token 限制等。
$response = $client->models()->retrieve(ModelType::GEMINI_PRO);
$response->model;
//Gemini\Data\Model Object
//(
// [name] => models/gemini-pro
// [version] => 001
// [displayName] => Gemini Pro
// [description] => The best model for scaling across a wide range of tasks
// ...
//)
疑难解答
超时
向 API 发送请求时可能会遇到超时。默认超时时间取决于使用的 HTTP 客户端。
你可以通过配置 HTTP 客户端并将其传递到工厂来增加超时时间。
此示例说明了如何使用Guzzle 增加超时时间。
Gemini::factory()
->withApiKey($apiKey)
->withHttpClient(new \GuzzleHttp\Client(['timeout' => $timeout]))
->make();
测试
该包提供了 Gemini\Client
类的伪实现,允许你伪装 API 响应。
要测试代码,请确保在测试用例中使用 Gemini\Testing\ClientFake
类替换 Gemini\Client
类。
所有的响应都有一个 fake()
方法,允许你只提供用例相关的参数创建响应对象。
use Gemini\Testing\ClientFake;
use Gemini\Responses\GenerativeModel\GenerateContentResponse;
$client = new ClientFake([
GenerateContentResponse::fake([
'candidates' => [
[
'content' => [
'parts' => [
[
'text' => 'success',
],
],
],
],
],
]),
]);
$result = $fake->geminiPro()->generateContent('test');
expect($result->text())->toBe('success');
在流式响应的情况下,你可以选择提供一个包含伪响应数据的资源。
use Gemini\Testing\ClientFake;
use Gemini\Responses\GenerativeModel\GenerateContentResponse;
$client = new ClientFake([
GenerateContentResponse::fakeStream(),
]);
$result = $client->geminiPro()->streamGenerateContent('Hello');
expect($response->getIterator()->current())
->text()->toBe('In the bustling city of Aethelwood, where the cobblestone streets whispered');
在请求发送完后,有各种方法确保发送预期的请求:
// assert list models request was sent
$fake->models()->assertSent(callback: function ($method) {
return $method === 'list';
});
// or
$fake->assertSent(resource: Models::class, callback: function ($method) {
return $method === 'list';
});
$fake->geminiPro()->assertSent(function (string $method, array $parameters) {
return $method === 'generateContent' &&
$parameters[0] === 'Hello';
});
// or
$fake->assertSent(resource: GenerativeModel::class, model: ModelType::GEMINI_PRO, callback: function (string $method, array $parameters) {
return $method === 'generateContent' &&
$parameters[0] === 'Hello';
});
// assert 2 generative model requests were sent
$client->assertSent(resource: GenerativeModel::class, model: ModelType::GEMINI_PRO, callback: 2);
// or
$client->geminiPro()->assertSent(2);
// assert no generative model requests were sent
$client->assertNotSent(resource: GenerativeModel::class, model: ModelType::GEMINI_PRO);
// or
$client->geminiPro()->assertNotSent();
// assert no requests were sent
$client->assertNothingSent();
要编写预期 API 请求失败的测试,可以提供一个 Throwable
对象作为响应。
$client = new ClientFake([
new ErrorException([
'message' => 'The model `gemini-basic` does not exist',
'status' => 'INVALID_ARGUMENT',
'code' => 400,
]),
]);
// the `ErrorException` will be thrown
$client->geminiPro()->generateContent('test');