Gemini API を Goで使ってみる

無料枠があるので、Gemini API を Goで使ってみる

Gemini API クイックスタートを参考に。

https://ai.google.dev/gemini-api/docs/quickstart?hl=ja&lang=go


<hr>

# できたもの
プロンプトや画像の読み込みはコード内に直接書き込んでいます。

```
// プロンプト: ONEPIECEの作者は？
go run main.go
ONE PIECEの作者は **尾田栄一郎** です。
```

```
// プロンプト: ２つの画像の違いを教えて
go run main.go
1枚目はルフィ、2枚目はゾロです。
```

```
// プロンプト(user): こんにちは、赤い果物は何がありますか？
// プロンプト(model): いちごやりんごがあります。
// プロンプト: その中で小さいのはどちらですか？
go run main.go
いちごはリンゴよりも小さいです。
```

```
// プロンプト: モンキー・D・ルフィが食べた悪魔の実について説明して
go run main.go
	モン
キー・D・ルフィが食べた悪魔の実は、 **ゴムゴムの実
** です。

ゴムゴムの実は、 **超人系悪魔の実** に
分類されます。この実の能力者は、**体がゴムのように伸び縮みする**ようになります。

**能力の詳細:**

* **体の伸縮:**
 ルフィはゴムのように腕や足を伸ばしたり、縮めたりできます。これにより、敵に届きにくい場所からの攻撃や、狭い場所での
移動が可能です。
* **衝撃吸収:** ゴムの性質により、ルフィは衝撃を吸収することができ、強い攻撃を受けてもダメージを軽減することができます。
* **防御力向上:** 体を硬くすることで、攻撃
を受け止めたり、防御力を高めることができます。
* **弾力性:**  ルフィはゴムの弾力性を活かして、敵の攻撃を跳ね返したり、高い場所から落下してもダメージを受けないようにすることができます
。
* **特殊能力:** ルフィはゴムゴムの能力を活用して、独自の攻撃技を開発しています。例えば、**ゴムゴムの銃**、**ゴムゴムのピストル**、**ゴムゴムのロケット**などがあります。

**弱点:**

* **水に弱い:**
悪魔の実の能力者は、水に弱いです。水に沈むと、通常の体力よりも大幅に弱くなってしまいます。
* **海楼石:** 海楼石は悪魔の実の能力を無効化する性質を持つため、ルフィは海楼石に触れると能力が使えなくなります。


**その他:**

* ゴムゴムの実は、ルフィが幼少期にシャンクスからもらったものです。
* ルフィはゴムゴムの実の能力を使って、海賊王になることを目指しています。

ルフィのゴムゴムの実の能力は、彼の冒険の鍵となる重要な
要素です。彼はこの能力を駆使して、様々な敵と戦い、多くの仲間と出会ってきました。

```


### 料金について

https://ai.google.dev/pricing?hl=ja

### 使うモデル
Gemini 1.5 Flash
テキストや画像等マルチモーダルに対応している

### Goのバージョン

```
go version go1.23.0 darwin/arm64
```



# API Keyの発行
Google AI Studioですぐに発行できる

https://ai.google.dev/aistudio?hl=ja

ローカルの環境変数`GEMINI_API_KEY`に設定した


# ソースコード

genaiというパッケージを使ってAPI操作を行う
型を知りたい時などはドキュメントを参考にした⇩

https://pkg.go.dev/cloud.google.com/go/vertexai@v0.13.0/genai


4種類の関数を作った
f1: テキスト入力でテキストを生成
f2: テキストと画像の入力からテキストを生成
f3: チャット中のテキスト生成
f4: ストリーミングでのテキスト生成

```main.go
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/google/generative-ai-go/genai"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"
)

func main() {
	ctx := context.Background()

	if err := run(ctx); err != nil {
		fmt.Fprintln(os.Stderr, "Error:", err)
		os.Exit(1)
	}
}

func run(ctx context.Context) error {
	return f1(ctx)
}

func printCandidates(cs []*genai.Candidate) {
	for _, c := range cs {
		for _, p := range c.Content.Parts {
			fmt.Println((p))
		}
	}
}

// テキストのみの入力からテキストを生成する
// https://ai.google.dev/gemini-api/docs/text-generation?hl=ja&lang=go#generate-text-from-text
func f1(ctx context.Context) error {
	client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY")))
	if err != nil {
		return err
	}
	defer client.Close()

	model := client.GenerativeModel("gemini-1.5-flash")

	prompt := genai.Text("ONEPIECEの作者は？")

	resp, err := model.GenerateContent(ctx, prompt)
	if err != nil {
		return err
	}

	printCandidates(resp.Candidates)

	return nil
}

// テキストと画像の入力からテキストを生成する
// https://ai.google.dev/gemini-api/docs/text-generation?hl=ja&lang=go#generate-text-from-text-and-image
func f2(ctx context.Context) error {
	client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY")))
	if err != nil {
		return err
	}
	defer client.Close()

	model := client.GenerativeModel("gemini-1.5-flash")

	imgData1, err := os.ReadFile("onepiece01_luffy.png")
	if err != nil {
		return err
	}

	imgData2, err := os.ReadFile("onepiece02_zoro_bandana.png")
	if err != nil {
		return err
	}

	prompt := []genai.Part{
		genai.ImageData("png", imgData1),
		genai.ImageData("png", imgData2),
		genai.Text("２つの画像の違いを教えて"),
	}

	resp, err := model.GenerateContent(ctx, prompt...)
	if err != nil {
		return err
	}

	printCandidates(resp.Candidates)

	return nil
}

// インタラクティブなチャットを作成する
// https://ai.google.dev/gemini-api/docs/text-generation?hl=ja&lang=go#chat
func f3(ctx context.Context) error {
	client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY")))
	if err != nil {
		return err
	}
	defer client.Close()

	model := client.GenerativeModel("gemini-1.5-flash")

	cs := model.StartChat()

	cs.History = []*genai.Content{
		{
			Parts: []genai.Part{
				genai.Text("こんにちは、赤い果物は何がありますか？"),
			},
			Role: "user",
		},
		{
			Parts: []genai.Part{
				genai.Text("いちごやりんごがあります。"),
			},
			Role: "model",
		},
	}

	resp, err := cs.SendMessage(ctx, genai.Text("その中で小さいのはどちらですか？"))
	if err != nil {
		return err
	}

	printCandidates(resp.Candidates)

	return nil
}

// テキスト ストリームを生成する(結果全体を待たない)
// https://ai.google.dev/gemini-api/docs/text-generation?hl=ja&lang=go#generate-a-text-stream
func f4(ctx context.Context) error {
	client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY")))
	if err != nil {
		return err
	}
	defer client.Close()

	model := client.GenerativeModel("gemini-1.5-flash")

	prompt := genai.Text("モンキー・D・ルフィが食べた悪魔の実について説明して")

	iter := model.GenerateContentStream(ctx, prompt)
	for {
		resp, err := iter.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		printCandidates(resp.Candidates)
	}

	return nil
}
```