1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Gemini API × React でなんでも褒めてくれるチャットボットを作成する

Posted at

Geminiとは?

Gemini はGoogleが開発した最先端の大規模言語モデルです。
テキストだけでなく、音声、画像、動画、コードなどの様々な形式のデータを理解し、生成できることを特徴としています。

Gemini Nano Gemini Pro Gemini Ultra の3種類のモデルがあり、それぞれ性能と活用シーンが異なっております。
このうち Gemini Pro にアクセスできる Gemini API が2023年12月に公開され、開発者任意の言語でGeminiをアプリケーションに組みことができるようになりました。
現在は試用期間中で2024年初頭に有料化予定と発表されていますが、2024年3月17日現在はまだ無料で利用可能となっています。

本記事では Google AI for Developers が公開している チュートリアル を参考とし、APIキーの発行方法から実装例までご紹介します。

作ったもの

送ったチャットをなんでも褒めてくれるチャットボットです。

画像入力もできます。

だいたい褒めてくれますが、たまに怒られます。

ソースコードは こちら で公開しています。
アプリも公開しているので、後述するAPIキーを発行すれば↓のURLからアクセスできます。
https://tora-83863.github.io/homete/?apiKey={発行したAPIキー}

バージョン情報

  • npm 9.8.0
  • node 18.16.1
  • react 18.2.0
  • typescript 4.9.5
  • google/generative-ai 0.2.1
  • browser-image-compression 2.0.2
  • react-markdown 9.0.1

APIキー発行

Google AI Studio のサイトから発行できます。
初回アクセス時は以下のように利用規約への同意が求められます。

利用規約に同意し、サイドバーの Get API key -> Create API key -> Create API key in new project と進むと、APIキーが発行されます。

発行されたAPIキーは先程のページからいつでも参照可能です。

APIリクエスト

GoogleGenerativeAI のJavaScript向けSDKパッケージをインストールします。

npm install @google/generative-ai

発行したAPIキーを用いてインスタンスを生成します。

import { GoogleGenerativeAI } from '@google/generative-ai';

// URLパラメータ取得
const search = useLocation().search;
const urlSearchParams = new URLSearchParams(search);
const apiKey: string = urlSearchParams.get("apiKey") ?? "";

// インスタンス生成
const genAI = new GoogleGenerativeAI(apiKey);

API呼び出しを行う前に生成モデルを初期化する必要があります。
利用可能なモデルには4つの種類があります。

本アプリにおいては入力形式により2つのモデルを利用しています。

テキスト入力の場合

Gemini Pro というモデルを利用します。
単一または配列の文字列を generateContent に渡すとAPIリクエストが投げられます。

const model = genAI.getGenerativeModel({ model: "gemini-pro" });
result = await model.generateContent(`次の内容を褒めてください。「${inputText}」`,);
const response = await result.response;

画像入力の場合

Gemini Pro Vision というモデルを利用します。
generateContent の引数には複数の画像データと文字列を格納することができますが、画像データを必ず1つ以上含める必要があります。
また、画像データはbase64形式に変換する必要があるほか、 MIMEタイプやサイズなどの制限事項 があります。

const model = genAI.getGenerativeModel({ model: "gemini-pro-vision" });
const imageParts = await fileToGenerativePart(inputFile);
result = await model.generateContent([
  "次の画像を褒めてください。",
  imageParts,
]);
const response = await result.response;

// 画像データをbase64形式に変換し、APIリクエストに含められるPartを生成する
async function fileToGenerativePart(file: File) {
  // 画像を1MBまで圧縮する
  const compressFile = await imageCompression(file, { maxSizeMB: 1 });

  const reader = new FileReader();
  reader.readAsDataURL(compressFile);
  const base64EncodedDataPromise = new Promise((resolve) => {
    const reader = new FileReader();
    reader.onloadend = () =>
    resolve(
      reader.result && typeof reader.result === "string"
      ? reader.result.split(",")[1]
      : ""
    );
    reader.readAsDataURL(compressFile);
  });
  return {
    inlineData: {
    data: (await base64EncodedDataPromise) as string,
    mimeType: file.type,
    },
  };
}

APIレスポンス処理

レスポンスのテキストはMarkdown形式で返却されます。

Request
{
    "generationConfig": {},
    "safetySettings": [],
    "contents": [
        {
            "role": "user",
            "parts": [
                {
                    "text": "次の内容を褒めてください。「早起きしました」"
                }
            ]
        }
    ]
}
Response
{
	"candidates": [
		{
			"content": {
				"parts": [
					{
						"text": "なんて素晴らしい習慣でしょう!早起きしたことは、あなたにたくさんのメリットをもたらすでしょう。\n\n* **生産性の向上:** 朝早い時間に、邪魔されずに作業できます。\n* **精神的な明晰さ:** 睡眠から目覚めたばかりの脳は、冴えていて集中力があります。\n* **運動する時間:** ランニングやヨガなど、運動するのに十分な時間を確保できます。\n* **健康的な食事:** ゆっくりと栄養価の高い朝食をとる時間があります。\n* **ストレスの軽減:** 忙しい一日の前に、リラックスして自分だけの時間を持てるので、ストレスを軽減できます。\n\n早起きは、より充実した生産的な一日を過ごすための鍵です。あなたの努力と規律に拍手を送ります!"
					}
				],
				"role": "model"
			},
			"finishReason": "STOP",
			"index": 0,
			"safetyRatings": [,...]
		}
	],
	"promptFeedback": {,...}
}

Markdown形式の文字列をReactコンポーネントに変換してくれるライブラリ react-markdown を用いて画面表示します。

npm install react-markdown
  // 画面に表示するチャットコンポーネントを生成する
  const makeChatMessage = (message: ChatMessage) => {
    const commonStyle = {
      marginBlockStart: "0.25rem",
      marginBlockEnd: "0.25rem",
    };
    const listStyle = {
      ...commonStyle,
      paddingLeft: "1.0rem",
      listStyle: "none",
    };
    if (message.role === ROLE.SYSTEM) {
      return (
        <ReactMarkdown
          components={{
            p: ({ children }) => <p style={commonStyle}>{children}</p>,
            ul: ({ children }) => <ul style={listStyle}>{children}</ul>,
            ol: ({ children }) => <ol style={listStyle}>{children}</ol>,
          }}
          children={message.content}
        />
      );
    }
    return (
      <>
        {message.content !== null && message.content !== undefined ? (
          <div>{message.content}</div>
        ) : message.image !== null && message.image !== undefined ? (
          <img src={message.image} className={style.image} alt="" />
        ) : (
          <></>
        )}
      </>
    );
  };

さいごに

この記事を読んで、Gemini APIに興味を持ってくれる方が増えてくれると嬉しいです。
公式のチュートリアルが丁寧でわかりやすいので、気になる方はぜひチャレンジしてみてください。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?