README
¶
âš Go Gemini Client
ð¯ æŠèŠ: Net Armor çµ±ååãã€ããªãã Gemini ã¯ã©ã€ã¢ã³ã
Go Gemini Client ã¯ãshouni/netarmor ããªãã©ã€åºç€ã«æ¡çšãããGoogle Gemini API / Vertex AI åãã® Go ã©ã€ãã©ãªã§ãã
ã²ãšã€ã®ã¯ã©ã€ã¢ã³ãã§ãAPI Key æ¹åŒã® Gemini API (Google AI Studio) ãšãGoogle Cloud èªèšŒã䜿ã Vertex AI ãåãæ¿ããŠå©çšã§ããŸããããã¹ãçæã ãã§ãªããGCS URI ã File API ã䜿ã£ããã«ãã¢ãŒãã«å ¥åãç»åã»é³å£°ã¬ã¹ãã³ã¹ãLyria ã«ãã鳿¥œçæãVeo ã«ããåç»çæãæ±ããããã«èšèšãããŠããŸãã
ð ç¹åŸŽãšèšèšææ³
ð€ ãã€ããªããã»ããã¯ãšã³ãã»ãµããŒã
- Dual Backend:
APIKeyæ¹åŒãšProjectID/LocationIDæ¹åŒã®äž¡æ¹ã«å¯Ÿå¿ã - Vertex AI 飿º: Cloud Run ãªã©ã®ç°å¢ã§ã¯ãµãŒãã¹ã¢ã«ãŠã³ãã Application Default Credentials ãå©çšã§ããŸãã
- GCS çŽæ¥åç
§: Vertex AI ã§ã¯
gs://URI ãgemini.Attachment{URI: ...}ãšããŠçŽæ¥ããã³ããã«å«ããããŸãã
ð¡ïž å
ç¢ãª AI ã¯ã©ã€ã¢ã³ã (gemini)
- é«åºŠãªãªãã©ã€æŠç¥:
netarmorã® retry ãå©çšããäžæçãªãããã¯ãŒã¯é害ã API åŽã®äžéæ§ãšã©ãŒãææ°ããã¯ãªãã§å詊è¡ããŸãã - ãªãã©ã€äžèŠãšã©ãŒã®å€å®: ã»ãŒããã£ãã£ã«ã¿ã«ãããããã¯ã空ã¬ã¹ãã³ã¹ãªã©ãå詊è¡ããŠã解決ãã«ãã API ã¬ã¹ãã³ã¹ãšã©ãŒãèå¥ããŸãã
- 決å®è«çãªå¶åŸ¡:
Seedã«ãããçæçµæã®åçŸæ§ãå¿ èŠãšããã¯ãŒã¯ãããŒããµããŒãããŸãã - åå®å
šãªãšã©ãŒå€å®: èšå®äžåãå
¥åäžåã¯ã»ã³ããã«ãšã©ãŒãšããŠå
¬éããŠããã
errors.Isã§å€å®ã§ããŸãã - SDK åãæŒãããªãå
¥å£:
GenerateWithAttachmentsãšgemini.Attachmentã䜿ãã°ããã«ãã¢ãŒãã«çæã»æ§é ååºåã»å®å šèšå®ã»æèéã®ãããã genai SDK ã import ããã«æžããŸããã¢ãã¯ã 1 ã¡ãœããã§æžã¿ãŸãã - ã¹ããªãŒãã³ã°çæ:
GenerateContentStream/GenerateWithAttachmentsStream/GenerateWithPartsStreamã§iter.Seq2ã«ãããã£ã³ã¯åäœã®ã¬ã¹ãã³ã¹ãåãåããŸãã - ããŒã¯ã³æ°ã®äºåèšæž¬:
CountTokens/CountTokensWithAttachments/CountTokensWithPartsã§ãå®éã«çæããã«ããã³ããã®ããŒã¯ã³æ°ãèŠç©ãããŸãã
ð é«åºŠãªãªãœãŒã¹ç®¡ç
- File API ãµããŒã: ãã¡ã€ã«ã¢ããããŒãåŸãå©çšå¯èœãª
Activeç¶æ ã«ãªããŸã§èªåã§ããŒãªã³ã°ããŸãã - èªåã¯ãªãŒã³ã¢ãã: Active åã«å€±æãã File API ãªããžã§ã¯ãã¯ããã¯ã°ã©ãŠã³ãã§åé€ã詊ã¿ãŸãã
- ã¬ã¹ãã³ã¹æœåº: ããã¹ããçæç»åãçæé³å£°ãMIME type ä»ãã®æ·»ä» (
Attachments)ãããŒã¯ã³äœ¿çšé (Usage) ãgemini.Responseã«ãŸãšããŠè¿ããŸãã
ð¬ Veo åç»çæ (veo)
- é·æéå®è¡ãªãã¬ãŒã·ã§ã³ã®å®èµ°: æåœããå®äºãŸã§ã®ããŒãªã³ã°ãã¿ã€ã ã¢ãŠããäžæçãªå€±æã®èš±å®¹ããŸãšããŠæ±ããŸããæåœ (
Submit) ãšå®äºåŸ ã¡ (Wait) ã¯å¥ã®å®è¡ã«åããããŸãã - å ¥åã®äºåæ€èšŒ: Veo ã䜵çšã§ããªãå ¥åïŒvideo ãš image ãªã©ïŒãéä¿¡åã«åŒŸããŸãã
- genai éäŸå:
gemini.VideoGeneratorã® 2 ã¡ãœãããæ³šå ¥ããã ããªã®ã§ããã¹ã㯠SDK ãèªèšŒãäžèŠã§ãã
ð ã¯ã€ãã¯ã¹ã¿ãŒã
ã€ã³ã¹ããŒã«
go get github.com/shouni/go-gemini-client
1. Gemini API ã¢ãŒã (API Key æ¹åŒ)
package main
import (
"context"
"fmt"
"log"
"github.com/shouni/go-gemini-client/gemini"
)
func main() {
ctx := context.Background()
client, err := gemini.NewClient(ctx, gemini.Config{
APIKey: "YOUR_GEMINI_API_KEY",
})
if err != nil {
log.Fatal(err)
}
resp, err := client.GenerateContent(ctx, "gemini-3.6-flash", "Goã§çã俳å¥ãæžããŠ")
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Text)
}
2. Vertex AI ã¢ãŒã (Cloud Run / GCS 飿º)
client, err := gemini.NewClient(ctx, gemini.Config{
ProjectID: "your-google-cloud-project-id",
LocationID: "asia-northeast1",
})
if err != nil {
return err
}
Vertex AI ã¢ãŒãã§ã¯ãGoogle Cloud åŽã®èªèšŒæ å ±ãå©çšããŸããCloud Run ãªã©ã®ç°å¢ã§ã¯ API Key ãã¢ããªã±ãŒã·ã§ã³ã«æãããã«éçšã§ããŸãã
ð§© ãã«ãã¢ãŒãã«çæ
GenerateWithAttachments ã¯ãããã¹ããšæ·»ä»ïŒç»åã»é³å£°ã»PDF ãªã©ïŒã genai SDK ã®åã䜿ããã«æž¡ããå
¥å£ã§ããgemini.Attachment ã¯ãã€ãåãš URI åç
§ã®ã©ã¡ãã衚çŸã§ããŸãã
resp, err := client.GenerateWithAttachments(ctx, "gemini-3.6-flash",
"ãã®ç»åã®å
å®¹ãæ¥æ¬èªã§èŠçŽããŠãã ãã",
[]gemini.Attachment{
// Vertex AI ã§ã¯ gs:// ãçŽæ¥åç
§ã§ããFile API ã® files/... ãåãåœ¢ã§æž¡ããŸãã
{URI: "gs://my-bucket/sample.jpg", MIMEType: "image/jpeg"},
// ãã€ãåãéãå Žå㯠Data ã䜿ããŸãïŒURI ãšã¯æä»ïŒã
// {MIMEType: "image/png", Data: pngBytes},
},
gemini.GenerateOptions{SystemPrompt: "ç°¡æœã«åçããŠãã ããã"})
if err != nil {
return err
}
fmt.Println(resp.Text)
æ·»ä»ã®æ±ãã¯æ¬¡ã®ãšããã§ãã
DataãšURIã¯æä»ã§ãäž¡æ¹èšå®ãããšErrInvalidAttachmentã«ãªããŸãDataãéãå ŽåMIMETypeã¯å¿ é ãURIãåç §ããå Žåã¯ä»»æïŒçç¥ãããšãµãŒããŒåŽã®å€å®ã«å§ããŸãïŒ- ã©ã¡ãã空ã®èŠçŽ ã¯èªã¿é£ã°ãããŸããåç §ç»åããããã°æž¡ãã圢ã§çµã¿ç«ãŠãåŒã³åºãåŽãã空èŠçŽ ã®é€å»ãæ¯åæžããã«æžã¿ãŸã
- ããã³ããã空ã§ãæ·»ä»ãããã°éä¿¡ã§ããŸãïŒé³å£°ã ããæž¡ããŠè§£æãããçšéïŒ
- æ·»ä»ãç¡ãããã¹ãçæã§ã䜿ããŸãã
attachmentsã«nilãæž¡ãã°ãããã³ãã +GenerateOptionsãã®å ¥å£ã«ãªããGenerateContentïŒãªãã·ã§ã³ç¡ãïŒãšGenerateWithPartsïŒgenai äŸåïŒã®éãåããŸã
ããã³ããã¯æ·»ä»ããåã«çœ®ãããŸããGCS URI ãšã€ã³ã©ã€ã³ããŒã¿ãä»»æã®é åºã§æ··åšãããããSystem instruction ã Part åäœã§çµã¿ç«ãŠããããšãã£ãå Žå㯠GenerateWithParts ã§å
¬åŒ SDK ã® genai.Part ãçŽæ¥æž¡ããŠãã ããã
resp, err := client.GenerateWithParts(ctx, "gemini-3.6-flash", []*genai.Part{
{FileData: &genai.FileData{URI: "gs://my-bucket/sample.jpg", MIMEType: "image/jpeg"}},
{Text: "ãã®ç»åã®å
å®¹ãæ¥æ¬èªã§èŠçŽããŠãã ãã"},
}, gemini.GenerateOptions{})
ðŒïž ç»åã»é³å£°ã¬ã¹ãã³ã¹
ResponseMIMEType ã« image/* ãŸã㯠audio/* ãæå®ãããšãã¬ã¹ãã³ã¹ã¢ããªãã£ãèªåèšå®ãããŸããInline data 㯠Response.Images ãŸã㯠Response.Audios ã«æ ŒçŽãããŸãã
MIME type ãå¿
èŠãªå Žå㯠Response.Attachments ã䜿ããŸããImages / Audios ã¯ãã€ãåã ããªã®ã§ãä¿åæã®æ¡åŒµåã Content-Type ãæ±ºããã«ã¯æ¬æ¥ RawResponse ã蟿ãå¿
èŠããããŸãããAttachments ã¯è¿åŽé ã®ãŸãŸ gemini.AttachmentïŒMIME type + ãã€ãåïŒã§åãåããŸãã
seed := int64(1234)
resp, err := client.GenerateWithParts(ctx, "gemini-3.1-flash-image", []*genai.Part{
{Text: "éãæãç«ã®ã¹ããã«ãŒç»åãçæããŠ"},
}, gemini.GenerateOptions{
ResponseMIMEType: "image/png",
AspectRatio: "1:1",
ImageSize: "1K",
Seed: &seed,
})
if err != nil {
return err
}
if len(resp.Images) > 0 {
// resp.Images[0] contains image bytes.
}
for _, attachment := range resp.Attachments {
// attachment.MIMEType ã§ä¿åæã®æ¡åŒµåã Content-Type ãæ±ºããããŸãã
_ = attachment
}
gemini.Response ã®äžèº«
| ãã£ãŒã«ã | å 容 |
|---|---|
Text |
æ¬æãæèããŒããé€ãå šããã¹ãããŒãã®é£çµã§ãã |
Images / Audios |
ã€ã³ã©ã€ã³ããŒã¿ã®ãã€ãåã MIME type ã§æ¯ãåãããã®ã§ãã |
Attachments |
ã€ã³ã©ã€ã³ããŒã¿ã MIME type ä»ãã§è¿åŽé ã«ä¿æããŸãïŒImages / Audios ã®äžäœéåïŒã |
Thoughts |
æèãµããªãIncludeThoughts ã true ã§ã¢ãã«ãè¿ããå Žåã®ã¿èšå®ãããText ã«ã¯å«ãŸããŸããã |
Usage |
ããŒã¯ã³äœ¿çšéïŒ*gemini.TokenUsageïŒãPromptTokenCount / CandidatesTokenCount / TotalTokenCount ã«å ãã課é察象㮠ThoughtsTokenCount ãæã¡ãŸãã |
RawResponse |
genai SDK ã®çã¬ã¹ãã³ã¹ãäžèšã§è¶³ããªãå Žåã®éãéã§ãã |
ð€ File API
Gemini API ã® File API ã䜿ãå Žåã¯ãã¢ããããŒãåŸã«ãã¡ã€ã«ã Active ã«ãªããŸã§èªåã§åŸ
æ©ããŸãã
UploadFile 㯠gemini.UploadedFile{URI, Name} ãè¿ããŸããURI ã¯çæãªã¯ãšã¹ãããåç
§ããå€ãName 㯠DeleteFile ã«æž¡ãèå¥åã§ãçšéãéãããæ§é äœã§è¿ããŠããŸãã
f, err := os.Open("movie.mp4")
if err != nil {
return err
}
defer f.Close()
uploaded, err := client.UploadFile(ctx, f, "video/mp4", "movie.mp4")
if err != nil {
return err
}
defer client.DeleteFile(context.Background(), uploaded.Name)
resp, err := client.GenerateWithParts(ctx, "gemini-3.6-flash", []*genai.Part{
{
FileData: &genai.FileData{
URI: uploaded.URI,
MIMEType: "video/mp4",
},
},
{Text: "ãã®åç»ãèŠçŽããŠãã ãã"},
}, gemini.GenerateOptions{})
ð¶ ã¹ããªãŒãã³ã°çæ
GenerateContentStream / GenerateWithAttachmentsStream / GenerateWithPartsStream ã¯ãgenai SDK ã® iter.Seq2 ããã®ãŸãŸ gemini.Response ã®ã¹ããªãŒã ã«å€æããŠè¿ããŸãããã£ã³ã¯åäœã§ãšã©ãŒãçºçããå Žåã¯ããã®ãã£ã³ã¯ã® error æ»ãå€ãšããŠäŒæããŸãïŒã¹ããªãŒã éå§åŸã®ãªãã©ã€ã¯è¡ããŸããïŒã
seq, err := client.GenerateContentStream(ctx, "gemini-3.6-flash", "Goã«ã€ããŠ3è¡ã§èª¬æããŠ")
if err != nil {
return err
}
for resp, err := range seq {
if err != nil {
return err
}
fmt.Print(resp.Text)
}
æ·»ä»ä»ãã®çæãã¹ããªãŒãã³ã°ã§åãåãå Žå㯠GenerateWithAttachmentsStream ã䜿ããŸããå
¥åã®æ€èšŒã¯ GenerateWithAttachments ãšåãã§ãã¹ããªãŒã éå§åã«å€±æããŸãã
seq, err := client.GenerateWithAttachmentsStream(ctx, "gemini-3.6-flash",
"ãã®ç»åã®å
容ã宿³ããŠãã ãã",
[]gemini.Attachment{{URI: "gs://my-bucket/sample.jpg", MIMEType: "image/jpeg"}},
gemini.GenerateOptions{})
ð¢ ããŒã¯ã³æ°ã®èšæž¬
CountTokens / CountTokensWithAttachments / CountTokensWithParts ã¯ãå®éã«çæãè¡ããã«ããã³ããã®ããŒã¯ã³æ°ã ããèšæž¬ããŸããäºåã®ã³ã¹ãèŠç©ãããã³ã³ããã¹ãé·ã®æ€èšŒã«äœ¿ããŸãã
total, err := client.CountTokens(ctx, "gemini-3.6-flash", "Goã«ã€ããŠ3è¡ã§èª¬æããŠ")
if err != nil {
return err
}
fmt.Println("æšå®ããŒã¯ã³æ°:", total)
ç»åãé³å£°ã¯ããã¹ãããããŒã¯ã³æ°ãèªã¿ã«ãããéãåã«æž¬ãããã®ã¯ããããã¡ãã§ããæ·»ä»ãå«ããèŠç©ãã㯠CountTokensWithAttachments ã§ãgenai SDK ã import ããã«è¡ããŸãã
total, err := client.CountTokensWithAttachments(ctx, "gemini-3.6-flash", "ãã®åç»ãèŠçŽããŠ",
[]gemini.Attachment{{URI: "gs://my-bucket/clip.mp4", MIMEType: "video/mp4"}})
çæã¬ã¹ãã³ã¹èªäœã®ããŒã¯ã³äœ¿çšé㯠Response.Usage ããåç
§ã§ããŸãïŒPromptTokenCount / CandidatesTokenCount / TotalTokenCountãããã³æèã«æ¶è²»ããã ThoughtsTokenCountïŒãæèæ©èœã䜿ãå ŽåãThoughtsTokenCount ã課é察象ã§ãã
ð¬ Veo åç»çæ (veo)
veo ããã±ãŒãžã¯ Veo ã«ããåç»çæãæ±ããŸããåç»çæã¯é·æéå®è¡ãªãã¬ãŒã·ã§ã³ã§ãæåœããŠããå®äºãŸã§ããŒãªã³ã°ãç¶ããå¿
èŠããããŸããã1åŸåŸ©ãã€ãã gemini ãããã©ãåŸ
ã€ããã veo ãæã¡ãŸãã
client, err := gemini.NewClient(ctx, gemini.Config{ProjectID: "my-project", LocationID: "us-central1"})
if err != nil {
return err
}
videoClient, err := veo.New(client,
veo.WithPollInterval(10*time.Second),
veo.WithPollTimeout(15*time.Minute),
)
if err != nil {
return err
}
result, err := videoClient.Generate(ctx, "veo-3.1-generate-001", veo.Request{
Prompt: "a slow dolly-in on a coastal cliffside at dawn",
Image: &veo.Media{URI: "gs://bucket/keyframe.png", MIMEType: "image/png"},
DurationSec: 8,
AspectRatio: "16:9",
OutputGCSURI: "gs://bucket/videos/",
})
if err != nil {
return err
}
video, _ := result.First() // video.URI ã«çæãããåç»ã® GCS URI ãå
¥ããŸã
Result 㯠OperationNameïŒèª²éã倱æã®è¿œè·¡çšïŒãVideosãFilteredCount / FilteredReasonsïŒå®å
šæ§ããªã·ãŒã§é€å€ãããæ¬æ°ãšçç±ïŒãæã¡ãŸãã1 æ¬ãçæãããªãã£ãå Žå㯠Generate ã ErrNoVideoGenerated ãè¿ããããFilteredCount ãéãŒãã§ Videos ãé空ãªã®ã¯ãè€æ°æ¬ãèŠæ±ããŠäžéšã ãé€å€ãããã±ãŒã¹ã§ãã
veo.New 㯠gemini.VideoGeneratorïŒStartVideo / PollVideo ã® 2 ã¡ãœããïŒãåãåãã ããªã®ã§ããã¹ãã§ã¯ genai SDK ã GCP èªèšŒãç¡ãã§ããŒãªã³ã°æåãæ€èšŒã§ããŸãã
å ¥åã®çµã¿åãã
Veo ã¯å
¥å系統ã䜵çšã§ããŸãããStartVideo 㯠API ã確å®ã«æåŠããçµã¿åãããéä¿¡åã« ErrInvalidVideoInput ã§åŒŸããŸãã
| äœ¿ãæ©èœ | èšå®ãããã£ãŒã«ã |
|---|---|
| image-to-video | Image |
| first/last frame è£é | Image + LastFrame |
| reference-to-video | ReferencesïŒImage / Video / LastFrame ãšã¯æä»ïŒ |
| video extensionïŒç¶ç¶çæïŒ | VideoïŒImage ãšã¯æä»ïŒ |
References ã«æž¡ã veo.Reference ã¯ãç»åã®äœ¿ããæ¹ã Type ã§æå®ããŸããgemini.VideoReferenceAssetïŒè¢«åäœãç»å Žããããæå€§3æïŒãš gemini.VideoReferenceStyleïŒç»é¢šãåæ ãããïŒããéžã³ãæªæå®ã¯ API ã®ããã©ã«ãã«å§ããŸãã
çæãã©ã¡ãŒã¿ã¯ veo.Request ã®ä»¥äžã®ãã£ãŒã«ãã§æå®ããŸãããŒãå€ã¯ãããããAPI ã®ããã©ã«ãã«å§ãããã®æå³ã§ãã
| ãã£ãŒã«ã | åœ¹å² |
|---|---|
Prompt |
çææç€ºãImage / Video ã®ããããç¡ãå Žåã¯å¿
é ã§ãã |
DurationSec |
çæããåç»ã®ç§æ°ãåãä»ããããå€ã¯ã¢ãã«ãšå ¥åã®çµã¿åããã§ç°ãªããŸãã |
AspectRatio / Resolution |
"16:9" / "9:16"ã"720p" / "1080p" ãªã©ãæå®ããŸãã |
NegativePrompt |
çæã«å«ããããªãèŠçŽ ãæå®ããŸãã |
GenerateAudio |
é³å£°ãåæçæãããïŒ*boolïŒãnil ã§ API ã®ããã©ã«ãã |
Seed |
åçŸæ§ã®ããã®ã·ãŒãïŒ*int64ïŒãint32 ã®ç¯å²å€ã¯ ErrInvalidSeed ã§ãã |
NumberOfVideos |
çæããæ¬æ°ã0 ã§ API ã®ããã©ã«ãïŒéåžž 1 æ¬ïŒã |
OutputGCSURI |
ä¿åå ã® GCS ãã±ãããæªæå®ãªãçµæã¯ãã€ãåã§è¿ããŸãïŒé·å°ºã§ã¯å¿çã倧ãããªãããéåžžã¯æå®ããŸãïŒã |
ããŒãªã³ã°ã®æã¡æ¹
gemini.PollVideo 㯠1 åã®åãåããã«åŸ¹ãããªãã©ã€ãæããŸãããããŒãªã³ã°èªäœãç¹°ãè¿ãã®ä»çµã¿ãªã®ã§ããã®å
éšã§ããã«ããã¯ãªããå¹ããããš 1 åã®åãåããã«æ°åç§ãããããäºéã®åŸ
ã¡ã«ãªããèšå®ããããŒãªã³ã°ééãšã¿ã€ã ã¢ãŠããæå³ã倱ãããã§ããäžæçãªå€±æãäœåãŸã§èš±å®¹ãããã¯ãééãšã¿ã€ã ã¢ãŠããæã£ãŠãã veo.Client ã®å€æã§ãWithMaxPollErrorsïŒæ¢å® 10 åïŒã§èª¿æŽããŸãã
äžæ¹ãæåœïŒStartVideoïŒã«ã¯ Config ã®ãªãã©ã€èšå®ãå¹ããŸããã¬ãŒãå¶éãäžæçãªãµãŒããŒãšã©ãŒã§ 1 æ¬åã®çæãèœã¡ãã®ãé²ãããã§ãã
Generate ã¯æåœãšå®äºåŸ
ã¡ããŸãšããŠè¡ããŸãããSubmit ãš Wait ã«åããŠãåŒã¹ãŸããå®è¡æéã«äžéã®ãããžã§ãåºç€ã§ãæåœã ãæžãŸããŠäžæŠæ»ããæ¬¡ã®å®è¡ã§ãªãã¬ãŒã·ã§ã³åãæž¡ããŠåŸ
ã¡ãåéããããšãã£ãäœ¿ãæ¹ãã§ããŸãã
// å®è¡ 1: æåœããŠãªãã¬ãŒã·ã§ã³åãä¿åããïŒå®äºã¯åŸ
ããªãïŒ
name, err := videoClient.Submit(ctx, "veo-3.1-generate-001", veo.Request{Prompt: "..."})
// å®è¡ 2: ä¿åããååã§åŸ
ã¡ãåéãã
result, err := videoClient.Wait(ctx, name)
SDK æªå¯Ÿå¿ãã£ãŒã«ãã®éä¿¡
SDK ããŸã åãšããŠæããªããã¬ãã¥ãŒæ©èœã¯ã2 ã€ã®æ¹æ³ã§ãªã¯ãšã¹ãããã£ãžå·®ã蟌ããŸããããããæ§é ã¯ããã¯ãšã³ãã® REST API ã«äžèŽãããå¿ èŠãããã忀æ»ãæ€èšŒãå¹ããŸãããSDK ã察å¿ããŠããé ç®ã¯éåžžã®ãã£ãŒã«ãã䜿ã£ãŠãã ããã
| ãã£ãŒã«ã | çšé |
|---|---|
Request.ExtraBody |
ããã£ãžããŒãžããå€ãããŒãžãååž°ããã®ã¯ãããå士ã®ãšãã ãã§ãåãããŒã®å€ãé åãªãäžžããšçœ®ãæãããŸã |
Request.ModifyRequestBody |
çµã¿ç«ãŠæžã¿ããã£ãåãåã£ãŠæžãæãã颿°ãExtraBody ã®ããŒãžåŸã«åŒã°ããŸã |
Vertex AI ã®ãªã¯ãšã¹ã㯠{"instances": [...], "parameters": {...}} ãšãã圢ãªã®ã§ãinstances ã®èŠçŽ ãžå€ãè¶³ãããå Žåã« ExtraBody ã䜿ããš instances é
åããšçœ®ãæãããprompt ãç»åå
¥åãæ¶ããŸãããã®çšéã§ã¯ ModifyRequestBody ã䜿ã£ãŠãã ããã
req.ModifyRequestBody = func(body map[string]any) map[string]any {
instances, _ := body["instances"].([]any)
if len(instances) > 0 {
if instance, ok := instances[0].(map[string]any); ok {
instance["audio"] = map[string]any{"gcsUri": "gs://bucket/bgm.mp3"}
}
}
return body
}
ã©ã¡ããå¹ãã®ã¯ãSDK ãæ¢ã«å©ããŠãããšã³ããã€ã³ãã®ããã£ãããããå Žåã ãã§ãããšã³ããã€ã³ãèªäœã SDK ã«ç¡ãå ŽåïŒgenai v1.66.0 æç¹ã® Interactions API ãªã©ïŒã¯æããŸããã
âïž è©³çŽ°èšå® (gemini.Config)
| èšå®é ç® | åœ¹å² | ããã©ã«ãå€ |
|---|---|---|
APIKey |
Gemini API ããŒãGoogle AI Studio / Gemini API ã§å©çšããŸãã | - |
ProjectID |
Google Cloud ãããžã§ã¯ã IDãVertex AI ã§å©çšããŸãã | - |
LocationID |
Vertex AI ã®ãªãŒãžã§ã³ãäŸ: asia-northeast1, us-central1 |
- |
MaxRetries |
æå€§ãªãã©ã€åæ° | 1 |
InitialDelay |
ãªãã©ã€éå§æã®åŸ æ©æé | 30s |
MaxDelay |
ãªãã©ã€åŸ æ©æéã®äžé | 120s |
FilePollingInterval |
File API ã®ç¶æ 確èªéé | 2s |
FilePollingTimeout |
File API ã®ç¶æ 確èªã¿ã€ã ã¢ãŠã | 60s |
HTTPClient |
genai SDK ã䜿ã HTTP ã¯ã©ã€ã¢ã³ããã¿ã€ã ã¢ãŠãããããã·ãSSRF å¯Ÿçæžã¿ã¯ã©ã€ã¢ã³ãïŒsecurenet.NewSafeHTTPClient çïŒã®æ³šå
¥ã«äœ¿ããŸã |
SDK æ¢å® |
OnRetry |
ãªãã©ã€çŽåã«åŒã°ããéç¥é¢æ° | ãªã |
APIKey ãš ProjectID / LocationID ã¯æä»çã§ããVertex AI ã䜿ãå Žå㯠ProjectID ãš LocationID ã®äž¡æ¹ãæå®ããŠãã ããã
HTTPClient ãæå®ããŠãèªèšŒã¯å€±ãããŸãããgenai SDK 㯠HTTP ã¯ã©ã€ã¢ã³ããæž¡ããããš Application Default Credentials ã®æ€åºãã¹ãããããèªèšŒããããä»ããã«éä¿¡ããŠããŸããŸããïŒVertex AI ã§ã¯å
šãªã¯ãšã¹ãã 401 CREDENTIALS_MISSING ã«ãªããŸãïŒãæ¬ã©ã€ãã©ãªãèªèšŒæ
å ±ãä»ãçŽããŸããæž¡ããã€ã³ã¹ã¿ã³ã¹èªäœã¯å€æŽãããè€è£œã䜿ããããåãã¯ã©ã€ã¢ã³ããä»ã®çšéãšå
±æããŠãæ§ããŸããã
𧪠çæãªãã·ã§ã³ (gemini.GenerateOptions)
ãŒãå€ãæå³ãæã€é
ç®ïŒTemperature: 0 = æã決å®çãThinkingBudget: 0 = æèç¡å¹ïŒã¯ã
ãæªèšå®ããšåºå¥ãããããã€ã³ã¿åã§ããèšå®ã«ã¯ gemini.Ptr ãã«ããŒã䜿ããŸãã
| èšå®é ç® | åœ¹å² |
|---|---|
SystemPrompt |
System instruction ãæå®ããŸãã |
Temperature |
åºåã®ã©ã³ãã æ§ïŒ*float32ïŒãPtr[float32](0) ã§æãæ±ºå®çãnil ã§ SDK ããã©ã«ãã |
TopP / TopK |
ãµã³ããªã³ã°ç¯å²ã®å¶åŸ¡ïŒ*float32ïŒãnil ã§ SDK ããã©ã«ãã |
MaxOutputTokens |
çæããæå€§ããŒã¯ã³æ°ã0 ã§ SDK ããã©ã«ãã |
StopSequences |
çæãæã¡åãæååã®ãªã¹ãã |
ThinkingBudget |
æèããŒã¯ã³ã®äžéïŒ*int32ïŒãPtr[int32](0) ã§æèãç¡å¹åãã³ã¹ããšã¬ã€ãã³ã·ãæããŸããnil ã§ã¢ãã«æ¢å®ãæå¹ç¯å²ã¯ã¢ãã«äŸåã§ãã |
ThinkingLevel |
æèéã®æ®µéæå®ïŒgemini.ThinkingMinimal / ThinkingLow / ThinkingMedium / ThinkingHighïŒãã¢ãã«éäŸåã§ç§»æ€æ§ãé«ãæ¹ã®æå®æ¹æ³ã§ããThinkingBudget ãšäœµçšããå Žåã¯ãã¡ããåªå
ãããŸãã |
IncludeThoughts |
true ã«ãããšæèãµããªã Response.Thoughts ã«å
¥ããŸãïŒText ã«ã¯å«ãŸããŸããïŒã |
AspectRatio |
ç»åçææã®ã¢ã¹ãã¯ãæ¯ãæå®ããŸãã |
ImageSize |
ç»åçææã®ãµã€ãºãæå®ããŸãã |
Seed |
åçŸæ§ã®ããã®ã·ãŒãå€ãint32 ã®ç¯å²å
ã§ããå¿
èŠããããŸãã |
PersonGeneration |
Vertex AI ç»åçæã§ã®äººç©çæããªã·ãŒãæå®ããŸãã |
SafetySettings |
å®å
šãã£ã«ã¿ã®èšå®ãgemini.NewSafetySettings(gemini.SafetyBlockNone) ã§æ§ç¯ã§ããŸãã |
ResponseMIMEType |
image/png ã audio/wav ãªã©ãæåŸ
ããã¬ã¹ãã³ã¹ MIME type ãæå®ããŸãã |
ResponseSchema |
æ§é ååºåïŒconstrained decodingïŒã®ã¹ããŒãïŒ*gemini.SchemaïŒãapplication/json ãšäœµçšãããšãåºåãææ³ã¬ãã«ã§ã¹ããŒãã«å¶çŽãããŸãã |
ResponseJSONSchema |
æšæºç㪠JSON Schema ã«ããæ§é ååºåã$ref ãå«ãè€éãªã¹ããŒãã§ ResponseSchema ãããŸãæ©èœããªãå Žåã®ä»£æ¿ã§ãã䜵çšããå Žåã¯ãã¡ããåªå
ãããŸãã |
æšæºçãª4ã€ã®ããŒã ã«ããŽãªïŒæŽåã»ãã€ãã»æ§ç衚çŸã»å±éºè¡çºïŒãã¹ãŠã«åäžã®éŸå€ãé©çšãããå Žåã¯ãgemini.NewSafetySettings(threshold) ãã«ããŒã䜿ããš SafetySettings ãç°¡æœã«æ§ç¯ã§ããŸããéŸå€ãããã¯ãšã³ããçšéã«å¿ããŠã©ãéžã¶ãã¯åŒã³åºãåŽã®å€æã«å§ããŠããŸãïŒVertex AI 㯠SafetyOff ãåãä»ããŸããïŒã
opts := gemini.GenerateOptions{
SafetySettings: gemini.NewSafetySettings(gemini.SafetyBlockNone),
}
æ§é ååºåã®ã¹ããŒã㯠gemini.Schema ãš gemini.TypeObject ãªã©ã®å宿°ã§æžããŸãïŒgenai.Schema ã®å¥åãªã®ã§ãgenai ã®å€ããã®ãŸãŸæž¡ãããšãã§ããŸãïŒã
opts := gemini.GenerateOptions{
ResponseMIMEType: "application/json",
ResponseSchema: &gemini.Schema{
Type: gemini.TypeObject,
Properties: map[string]*gemini.Schema{
"title": {Type: gemini.TypeString},
"keywords": {Type: gemini.TypeArray, Items: &gemini.Schema{Type: gemini.TypeString}},
},
Required: []string{"title"},
},
}
ResponseJSONSchema ã® map[string]any ãšéãããã£ãŒã«ãåãã³ã³ãã€ã«æã«æ€æ»ãããŸãïŒ"propertise" ã®ãããªç¶Žãééããé»ã£ãŠç¡èŠãããŸããïŒã$ref ãå«ããªã©ããã®åã§è¡šçŸããããªãã¹ããŒãã®å Žåã ã ResponseJSONSchema ãéžãã§ãã ããã
éŸå€ã¯ gemini.SafetyBlockNone / SafetyBlockLowAndAbove / SafetyBlockMediumAndAbove / SafetyBlockOnlyHigh / SafetyOff ããéžã¹ãŸããåæ§ã«æèéã gemini.ThinkingMinimal / ThinkingLow / ThinkingMedium / ThinkingHigh ãçšæããŠããããããã䜿ãã°èšå®å€ãéžã¶ããã ãã« genai SDK ã import ããå¿
èŠã¯ãããŸããã
ãšã©ãŒã®åé¡
çæå€±æã®çç±ã¯ errors.Is / errors.AsType ã§å€å¥ã§ããŸãããããã¯ã¯ãªãã©ã€ããŠã解決ããªããããããã³ããã®èŠçŽããå¿
èŠã§ãã
resp, err := client.GenerateContent(ctx, model, prompt)
switch {
case errors.Is(err, gemini.ErrBlocked):
// å®å
šãã£ã«ã¿çã§ãããã¯ãããã詳现ãªçç±ã¯ FinishReason ãåç
§
if apiErr, ok := errors.AsType[*gemini.APIResponseError](err); ok {
slog.Warn("blocked", "reason", apiErr.FinishReason)
}
case errors.Is(err, gemini.ErrEmptyResponse):
// åè£ã 1 ä»¶ãè¿ããªãã£ã
}
æ§é ååºåã®åŸåŠç
ResponseSchema + ResponseMIMEType: "application/json" ã«ããæ§é ååºåïŒconstrained decodingïŒã䜿ã£ãŠããã¢ãã«ãå®çµãã JSON ã®åŸã«äœåãªéãæ¬åŒ§ã説æããã¹ããç¶ãè¶³ãããšãå®éã«ãããŸããjson.Unmarshal ã®å段㧠gemini.CleanJSONResponse(raw) ãéããšãããããæ«å°Ÿãã€ãºãé€å»ã»è£æ£ã§ããŸãããããã¬ãã«ãé
åïŒ[...]ïŒã®ã¹ããŒãã«ã察å¿ããŠããŸãã
resp, err := client.GenerateWithParts(ctx, model, parts, opts)
// ...
var out MyStruct
jsonStr := gemini.CleanJSONResponse(resp.Text)
if err := json.Unmarshal([]byte(jsonStr), &out); err != nil {
// ...
}
ð ãšã©ãŒãã³ããªã³ã°
æ¬ã©ã€ãã©ãªã§ã¯ã以äžã®ã»ã³ããã«ãšã©ãŒããšã¯ã¹ããŒãããŠããŸããerrors.Is ã䜿ã£ãŠå€å®ã§ããŸãã
ErrConfigRequired:APIKeyãŸãã¯ProjectID/LocationIDã®ããããèšå®ãããŠããªãå ŽåãErrExclusiveConfig:APIKeyãšProjectID/LocationIDãåæã«èšå®ãããŠããå ŽåãErrIncompleteVertexConfig:ProjectIDãŸãã¯LocationIDã®çæ¹ã ããèšå®ãããŠããå ŽåãErrEmptyPrompt: ããã³ããã空ã®å ŽåãErrEmptyModelName: ã¢ãã«åã空ã®å ŽåãErrEmptyParts: çæããŒãã空ã®å ŽåãErrInvalidPart: çæããŒãã« nil ãå«ãŸããŠããå ŽåãErrInvalidSeed:Seedãint32ã®ç¯å²å€ã®å ŽåãErrInvalidAttachment: æ·»ä»ã®æå®ãäžæ£ãªå ŽåïŒDataãšURIã®äœµçšãDataã« MIME type ãç¡ãå ŽåïŒãErrEmptyOperationName: ãªãã¬ãŒã·ã§ã³åã空ã®å ŽåãErrInvalidVideoInput: åç»çæã®å ¥åã®çµã¿åããã API ã®åãä»ããªããã®ã ã£ãå ŽåãErrVideoGenerationFailed: åç»çæã®ãªãã¬ãŒã·ã§ã³ã倱æãšããŠå®äºããå ŽåïŒVideoOperation.Failureã«èŒããŸãïŒãErrBlocked: å®å šãã£ã«ã¿çã«ããçæããããã¯ãããå Žåã詳现ã¯APIResponseError.FinishReasonãåç §ããŸããErrEmptyResponse: åè£ã 1 ä»¶ãå«ãŸããªãã¬ã¹ãã³ã¹ãè¿ãããå Žåã
ErrBlocked / ErrEmptyResponse 㯠*APIResponseError ãšããŠè¿ããUnwrap ããããã®ã»ã³ããã«ãè¿ããã errors.Is ã§åé¡ã§ããŸããã©ã¡ããå詊è¡ã§ã¯è§£æ±ºããªãããããªãã©ã€å¯Ÿè±¡å€ã§ãã
veo ããã±ãŒãžã¯ä»¥äžãå
¬éããŠããŸãã
veo.ErrGeneratorRequired:veo.Newã« nil ã®çæã¯ã©ã€ã¢ã³ããæž¡ããå Žåãveo.ErrMissingOperationName: å®äºåŸ ã¡ã«å¿ èŠãªãªãã¬ãŒã·ã§ã³åãç¡ãå Žåãveo.ErrNoVideoGenerated: æåã§å®äºããã®ã«åç»ã 1 æ¬ãè¿ããªãã£ãå ŽåïŒå®å šæ§ããªã·ãŒã«ããé€å€ãå žåïŒãveo.ErrPollFailed: çæç¶æ³ã®ç¢ºèªãé£ç¶ããŠå€±æããå®äºãåŸ ãŠãªããªã£ãå Žåã
ð ã€ã³ã¿ãŒãã§ãŒã¹
*gemini.Client ã¯ãããããã¹ãŠæºãããŸããå©çšåŽã¯å¿
èŠãªç¯å²ã ãã«äŸåãããšãã¢ãã¯ãå°ãããªããŸãã
| ã€ã³ã¿ãŒãã§ãŒã¹ | ã¡ãœãã | genai å |
|---|---|---|
ContentGenerator |
GenerateContent |
å«ãŸãªã |
MultimodalGenerator |
GenerateWithAttachments |
å«ãŸãªã |
BackendInspector |
IsVertexAI |
å«ãŸãªã |
FileManager |
UploadFile / DeleteFile |
å«ãŸãªã |
MultimodalModel |
äžèš 3 ã€ïŒçæã»ãã¡ã€ã«ç®¡çã»ããã¯ãšã³ãå€å®ïŒã®éå | å«ãŸãªã |
MultimodalStreamGenerator |
GenerateContentStream / GenerateWithAttachmentsStream |
å«ãŸãªã |
MultimodalTokenCounter |
CountTokens / CountTokensWithAttachments |
å«ãŸãªã |
VideoGenerator |
StartVideo / PollVideo |
å«ãŸãªã |
Generator |
GenerateWithParts + IsVertexAI |
å«ã |
GenerativeModel |
Generator + FileManager |
å«ã |
StreamGenerator |
GenerateContentStream / GenerateWithPartsStream |
å«ã |
TokenCounter |
CountTokens / CountTokensWithParts |
å«ã |
Generator 系㯠genai.Part ãã·ã°ããã£ã«æã€ãããå®è£
ã»ã¢ãã¯ããåŽã genai SDK ãåç
§ããããšã«ãªããŸããPart ãçŽæ¥çµã¿ç«ãŠãå¿
èŠããªããã° MultimodalGenerator / MultimodalModel ãéžãã§ãã ããã
ð ããã±ãŒãžæ§æ
| ããã±ãŒãž | åœ¹å² |
|---|---|
github.com/shouni/go-gemini-client/gemini |
Gemini / Vertex AI ã¯ã©ã€ã¢ã³ãããªãã©ã€ãFile APIãã¬ã¹ãã³ã¹æœåºã |
github.com/shouni/go-gemini-client/lyria |
æè©çæ â äœæ²ã¬ã·ãçæ â Lyria é³å£°çæã® 3 段ãlyria.New 㯠gemini.MultimodalGenerator ãåãåããŸããæ®µã®éã«å質ã²ãŒããæãã®ã¯å©çšåŽã®å€æã®ãããäžæ¬å®è¡ã®å
¥å£ã¯çšæããŠããŸããã |
github.com/shouni/go-gemini-client/veo |
Veo åç»çæã®æåœãšå®äºåŸ
ã¡ãveo.New 㯠gemini.VideoGenerator ãåãåããŸãã |
ð€ äŸåé¢ä¿ (Dependencies)
- google.golang.org/genai - Google Gemini å ¬åŒ SDK
- shouni/netarmor - ãããã¯ãŒã¯ã»ãã¥ãªã㣠& ãªãã©ã€æŠç¥
ð ã©ã€ã»ã³ã¹ (License)
ãã®ãããžã§ã¯ã㯠MIT License ã®äžã§å ¬éãããŠããŸãã
Directories
¶
| Path | Synopsis |
|---|---|
|
Package gemini ã¯ãGemini API / Vertex AI åãã® genai SDK ãã©ãããã ãªãã©ã€ãFile APIã¢ããããŒããåããã¯ã©ã€ã¢ã³ããæäŸããŸãã
|
Package gemini ã¯ãGemini API / Vertex AI åãã® genai SDK ãã©ãããã ãªãã©ã€ãFile APIã¢ããããŒããåããã¯ã©ã€ã¢ã³ããæäŸããŸãã |
|
Package lyria ã¯ãæè©çæã»æ¥œæ²èšèšã»Lyriaã«ããé³å£°çæãæãã 鳿¥œçæã¯ãŒã¯ãããŒãæäŸããŸãã
|
Package lyria ã¯ãæè©çæã»æ¥œæ²èšèšã»Lyriaã«ããé³å£°çæãæãã 鳿¥œçæã¯ãŒã¯ãããŒãæäŸããŸãã |
|
Package veo ã¯ãVeo ã«ããåç»çæãæ±ãã¯ã©ã€ã¢ã³ããæäŸããŸãã
|
Package veo ã¯ãVeo ã«ããåç»çæãæ±ãã¯ã©ã€ã¢ã³ããæäŸããŸãã |