🦔
Gemini ProのAPIを使ってみた
概要
2024/05/17時点での内容です。
生成AIを使用して、SNSでの投稿に対して自動で応答するbotを作ろうと思い、比較的安そうなGemini Proを使用することにしました。
Geminiはアップデートが速く、ライブラリを使用するとついて行けないタイミングがあること、公式が生のAPIの叩き方を提供してくれていることから、APIを生で叩くようにしました。
- 使用技術
- Go(1.21)
- Gemini Pro 1.5 flash
実装
特に難しいことはなく、リクエストボディを組み立ててGoのhttpライブラリからリクエストを送信しています。
token, err := google.DefaultTokenSource(context.Background(), "https://www.googleapis.com/auth/cloud-platform")
response, err := resty.New().
SetTimeout(1 * time.Minute).
R().
SetHeaders(map[string]string{
"Content-Type": "application/json",
"Authorization": fmt.Sprintf("Bearer %v", token),
}).
SetBody(map[string]any{
"contents": v.createRequestContent(*input),
"generation_config": map[string]float32{
"maxOutputTokens": 4096,
"temperature": 0.8,
"topP": 0.8,
},
"safetySettings": []map[string]string{
{"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_ONLY_HIGH"},
{"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_ONLY_HIGH"},
{"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_ONLY_HIGH"},
{"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_ONLY_HIGH"},
},
}).
Post(fmt.Sprintf("https://us-central1-aiplatform.googleapis.com/v1/projects/%v/locations/us-central1/publishers/google/models/gemini-pro:generateContent", os.Getenv("GOOGLE_CLOUD_PROJECT_ID")))
悩んだ点として、APIを叩くためのアクセストークンの取得があります。CLIではgcloud auth print-access-token
で取得できますが、プログラム上で取得する方法がわかりづらかったです。
実行するアカウント/サービスアカウントにはVertex AI User
相当のロールが必要です。
なお、PythonやNode.jsのライブラリではライブラリ上でいい感じにやってくれるので不要です。
レスポンス
下記のレスポンスが返ってきます。
エンドポイントがgenerateContent
の場合、candidateは1つで返ってくるようです。
{
"candidates": [
{
"content": {
"role": "model",
"parts": [
{
"text": "こんにちは! 👋 何かお困りですか? 😊 お気軽にご質問ください。 😄 \n"
}
]
},
"finishReason": "STOP",
"safetyRatings": [
{
"category": "HARM_CATEGORY_HATE_SPEECH",
"probability": "NEGLIGIBLE",
"probabilityScore": 0.16545822,
"severity": "HARM_SEVERITY_NEGLIGIBLE",
"severityScore": 0.04401865
},
{
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
"probability": "NEGLIGIBLE",
"probabilityScore": 0.05350215,
"severity": "HARM_SEVERITY_NEGLIGIBLE",
"severityScore": 0.06928941
},
{
"category": "HARM_CATEGORY_HARASSMENT",
"probability": "NEGLIGIBLE",
"probabilityScore": 0.1625129,
"severity": "HARM_SEVERITY_NEGLIGIBLE",
"severityScore": 0.052716404
},
{
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
"probability": "NEGLIGIBLE",
"probabilityScore": 0.12689333,
"severity": "HARM_SEVERITY_NEGLIGIBLE",
"severityScore": 0.03120282
}
]
}
],
"usageMetadata": {
"promptTokenCount": 1,
"candidatesTokenCount": 20,
"totalTokenCount": 21
}
}
エンドポイントがstreamGenerateContent
の場合、candidatesは複数返ってきます。
テキストが複数に分割されて生成されているため、使用する際は繋げる必要があります。
[{
"candidates": [
{
"content": {
"role": "model",
"parts": [
{
"text": "こんにちは"
}
]
}
}
]
}
,
{
"candidates": [
{
"content": {
"role": "model",
"parts": [
{
"text": "! 👋 何かお困りですか? 😊 \n"
}
]
},
"safetyRatings": [
{
"category": "HARM_CATEGORY_HATE_SPEECH",
"probability": "NEGLIGIBLE",
"probabilityScore": 0.17881244,
"severity": "HARM_SEVERITY_NEGLIGIBLE",
"severityScore": 0.06278921
},
{
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
"probability": "NEGLIGIBLE",
"probabilityScore": 0.0715912,
"severity": "HARM_SEVERITY_NEGLIGIBLE",
"severityScore": 0.06928941
},
{
"category": "HARM_CATEGORY_HARASSMENT",
"probability": "NEGLIGIBLE",
"probabilityScore": 0.20386598,
"severity": "HARM_SEVERITY_NEGLIGIBLE",
"severityScore": 0.06536579
},
{
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
"probability": "NEGLIGIBLE",
"probabilityScore": 0.11920293,
"severity": "HARM_SEVERITY_NEGLIGIBLE",
"severityScore": 0.034293946
}
]
}
]
}
,
{
"candidates": [
{
"content": {
"role": "model",
"parts": [
{
"text": ""
}
]
},
"finishReason": "STOP"
}
],
"usageMetadata": {
"promptTokenCount": 1,
"candidatesTokenCount": 13,
"totalTokenCount": 14
}
}
]
safetyRatingsは、生成されたテキストがセーフティに対してどれくらいの数値になっているかが格納されています。
finishReasonは終了の理由が設定されています。ここの値を見て分岐すると良さそうです。
Discussion