Supabase Edge Functionsで Gemini API を使ってみる

Supabase Edge Functionsとは
Denoが動くFaaS。
ちょっとした関数をサーバーサイドで処理してくれるサービス。
月500,000回のリクエストまでは無料枠。
このスクラップではローカル環境の Supabase Edge Functionsで動かす。
Gemini APIとは
生成AIのGeminiをNode.js等で動かすことができるAPI。
現在(2025年1月18日)時点では、Gemini 2.0 Flashを使うのが良いらしい。

参考動画
Supabaseの中の人が Supabase Edge Functions x Gemini APIによるデモ動画を出している。これを元にやっていく。

Supabase Edge Functionsの準備をする
supabase functions new gemini
このコマンドを叩くと、Supabase CLIによって gemini という Edge Functions の実行ファイルが生成される。
ちなみに生成されたファイルは
supabase functions serve
を叩けば動く状態になる。
詳細な動かし方は生成したフォルダの index.ts の最下部にコメントアウトで書かれているので、そこを参考にすると良いだろう。
/* To invoke locally:
1. Run `supabase start` (see: https://supabase.com/docs/reference/cli/supabase-start)
2. Make an HTTP request:
curl -i --location --request POST 'http://127.0.0.1:54321/functions/v1/gemini' \
--header 'Authorization: Bearer hogehogehogehogeohoge' \
--header 'Content-Type: application/json' \
--data '{"name":"Functions"}'
*/
CURLでもいいですし、 http://127.0.0.1:54321/functions/v1/gemini にブラウザでアクセスしても良し。

Gemini APIの準備をする
こちらのページにアクセスする。
ボタンを押してAPIキーを発行しておく。
たったこれだけ。

Supabase Edge FunctionsにGeminiが動くように記述をしてみよう
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
import { GoogleGenerativeAI } from "npm:@google/generative-ai";
const genAI = new GoogleGenerativeAI("【ここにAPIキー】");
const model = genAI.getGenerativeModel({ model: "gemini-2.0-flash-exp" });
Deno.serve(async (req) => {
const prompt = `Geminiさん、こんにちは!`;
const result = await model.generateContent(prompt);
console.log(result.response.text());
const data = {};
return new Response(JSON.stringify(data), { headers: { "Content-Type": "application/json" } });
});
とりあえず上記のコードとしておく。
プロンプトは「Geminiさん、こんにちは!」としており、これに対する返答を見てみることにする。
では、 supabase functions serve
を実行して、http://127.0.0.1:54321/functions/v1/gemini
にアクセスしてみると、コンソールに
と出てきました。
これでGeminiと疎通できていることが確認できた。
あとは prompt を整えたり、 .getGenerativeModel()
のオプション周りを指定して欲しいデータを受け取れるようにするだけ。
ちなみに、 const model = genAI.getGenerativeModel({ model: "gemini-2.0-flash-exp" });
は「Gemini 2.0 Flash」を使うことを宣言している。他のモデル(例えば Gemini 1.5 Proなど)を使いたい場合は gemini-1.5-pro
とすることで変更できる。
モデル一覧は https://ai.google.dev/gemini-api/docs/models/gemini?hl=ja#model-variations こちらの、「モデルバリエーション」という欄の小文字の文字列として掲載されており、これをコードに入れれば自由に指定できる。

Geminiの回答を必ずJSON形式にする方法
アプリケーションとして処理した結果を受け取る場合、必ずJSON形式で返ってきてくれた方が都合が良い。Gemini APIにはJSON形式で返すように指示できる機能が備わっている。
公式ドキュメントに書かれている通り。
import { GoogleGenerativeAI, SchemaType } from "npm:@google/generative-ai";
const model = genAI.getGenerativeModel({
model: "gemini-2.0-flash-exp",
generationConfig: {
responseMimeType: "application/json",
responseSchema: {
type: SchemaType.ARRAY,
items: {
type: SchemaType.OBJECT,
properties: {
"aiueo": {
type: SchemaType.STRING,
nullable: false
}
},
required: ["aiueo"]
}
}
}
});
この場合、
[
{
"aiueo": "ここに何らかの値が入ってくれる"
}
]
という形式で返してくれることになる。
他にどんな指定ができるかは上記をチェックしよう。
ちなみに、 type: SchemaType.ARRAY の場合は、itemsが必要。配列の型を指定しないと動かないので注意。 string[] っぽい感じでデータがほしければ、
items: {
type: SchemaType.OBJECT,
properties: {
hoge: {
type: SchemaType.ARRAY,
items: {
type: SchemaType.STRING
}
}
}
}
という形になる。上記の場合は hogeというキーに対して stirng[] なデータが入ることになる。
required: ["aiueo"]
では、aiueoというキーは必ず入れておいてくれっていう指示になる(はず)

独り言
「LLMは言葉のOS」とも表現できると思った。
コンピュータも機械語を使ってプログラミングすることは99.9%の人はしない。それは難しい上に生産的ではないから。難しいものを簡単に使えるようにしてくれたものがOSである。
言葉を分析するAIも一般人には作るのが難しい。難しいものを使えるようにしてくれたものがGeminiなどの生成AIである。
そういう意味では基本的な基盤を提供してくれる訳だから、LLMはOSと同じ位置づけだと表現できる。
日本語を入力してその回答をもらおうとしたとき文字化けしてうまく返答がもらえないのですがどうすればいいか教えてほしいです
curlで
--data '{"query":"こんにちわ"}'
みたいにして
Deno.serve(async (req) => {
try {
const { query } = await req.json() ...
これをconsole.logで表示すると文字化けしていてプロンプトとして認識されずHelloと英語でgeminiに返されてしまうのですが

curlから叩いていないので正確なことは分かりませんが、
console.log(query); でまずはデータが正しく渡っているか確認しておいた方が良いかもしれませんね。あとは、いきなりデータを渡さずに
僕の環境では、
const formData = await req.formData();
const myText = formData.get("my-test") as string;
という形でデータを受け取っています。
formから <input type="text" name="my-test" />
の中身を受け取っているようなイメージです。
あとはモデル名の指定でしょうか。
このスクラップを書いていた時点では gemini-2.0-flash-exp
がモデル名でしたが、現在は gemini-2.0-flash
になっています。
const model = genAI.getGenerativeModel({ model: "gemini-2.0-flash" });
もしかするとコイツが原因だったりするのかもしれませんね。
curl検証で時間を費やしましたが、curlで動かしてないとのことで自分も本来使用するDartの方で動かした所正常に動作しました。以前curlはよくわかりませんが無駄な時間から救われました、ありがとうございます!