Supabase と Deno の入門をしたくて、OpenAI APIを叩くサーバーレス関数を Supabase Edge Functions で実装してみたという記事。
この記事の内容としては、以下のYouTube動画の内容とほぼ同じ。
完成形のリポジトリはこちら
目次
Supabase とは?
Firebaseに似たオープンソースのクラウドサービス。データベース、認証、ストレージなど、多くの機能を提供している。Firebaseと比較して、よりカスタマイズ性が高く、価格もリーズナブル。
前準備
今回は、OpenAI の API を使用するので事前にAPIキーを作成しておく必要がある。詳細は省く。
Supabaseのセットアップ方法
- SupabaseのWebサイトにアクセスし、アカウントを作成する。
- Dashboardからプロジェクトを作成する。
- プロジェクトの設定画面で、APIキーを取得する。
- Edge Functionsを有効にする。
- 必要に応じて、データベースや認証、ストレージなどの機能を有効にする。
- 以上で、Supabaseのセットアップが完了する。
Supabase CLIのインストール
Supabase CLIをインストールする。
$ npm install -g supabase
Supabaseプロジェクトの作成
Supabaseにログインし、プロジェクトを作成する。(プロジェクト名は任意)
$ supabase init openai-edge-functions
Edge Functionsの作成
コマンド実行後に プロジェクト直下に supabase/functions/openai/index.ts が作成される。
$ supabase functions new openai
index.ts
// Follow this setup guide to integrate the Deno language server with your editor:
// https://deno.land/manual/getting_started/setup_your_environment
// This enables autocomplete, go to definition, etc.
import { serve } from "https://deno.land/[email protected]/http/server.ts"
console.log("Hello from Functions!")
serve(async (req) => {
const { name } = await req.json()
const data = {
message: `Hello ${name}!`,
}
return new Response(
JSON.stringify(data),
{ headers: { "Content-Type": "application/json" } },
)
})
// To invoke:
// curl -i --location --request POST 'http://localhost:54321/functions/v1/' \
// --header 'Authorization: Bearer xxxx' \
// --header 'Content-Type: application/json' \
// --data '{"name":"Functions"}'
セットアップはこれで完了。セットアップ完了までのコミットはこちら
OpenAI APIを叩く関数の実装
OpenAI の APIキーを設定
プロジェクト直下に .env.local ファイルを作成して、環境変数にAPIキーを設定する。
※ APIキーなので、 .env.local は .gitignore に追加しておくこと!!
OPENAI_API_KEY=xxxx
VSCode上での Denoセットアップ
ちなみに、VSCodeを使用して Deno を実装する場合は、以下の拡張が必須レベルで便利である。
この拡張機能を使うと、後述する Deno によるライブラリインポートのキャッシュ取得とエディター上のコード補完が可能となる。
筆者は、まずプロジェクト直下に以下の .vscode/setting.json を用意した。
{
"deno.enable": true,
"deno.unstable": false
}
この後、Macなら、「Cmd + Shift + P」 で表示されたフォームに “Deno cache” と入力したら Deno: Cache Dependencies と表示されるのでそちらをクリックすると、VSCode上でライブラリがキャッシュとして取得され、エディター上でコード補完ができるようになる。
関数の実装
ここからいよいよ OpenAI Completion API を使って、LLM と対話ができる関数を Deno で実装していく。
まずは、ライブラリインポート部分を追加
import "https://deno.land/x/[email protected]/mod.ts"
import { getLogger } from "https://deno.land/[email protected]/log/mod.ts"
import { serve } from "https://deno.land/[email protected]/http/server.ts"
import { Configuration, OpenAIApi } from "https://esm.sh/[email protected]"
OpenAI APIクライアントの初期化
const configuration = new Configuration({
apiKey: Deno.env.get("OPENAI_API_KEY"),
});
const openai = new OpenAIApi(configuration);
OpenAI APIをリクエストする通信部分の追加
serve(async (req) => {
const { query } = await req.json();
try {
const response = await openai.createCompletion({
model: "text-davinci-003",
prompt: query,
max_tokens: 256,
temperature: 0,
});
const {
data: {
id,
choices: [{ text }]
},
} = response;
return new Response(
JSON.stringify({ id, text }),
{ headers: { "Content-Type": "application/json" } },
)
} catch (error) {
const logger = getLogger()
logger.error(error)
return new Response(
JSON.stringify({ error }),
{ headers: { "Content-Type": "application/json" } },
)
}
})
実際の追加実装はこちら
ローカルで検証
実際にLLMと対話できるかローカル上で、検証する。
Supabase は、ローカル上で今回作成した関数をエミュレートできるので、実際に何か質問文をクエリパラメーターにしてリクエストしてみる。
まずは、関数を起動する
$ supabase start
Setting up Edge Functions runtime...
Seeding data supabase/seed.sql...
Started supabase local development setup.
API URL: http://localhost:54321
GraphQL URL: http://localhost:54321/graphql/v1
DB URL: postgresql://postgres:postgres@localhost:54322/postgres
Studio URL: http://localhost:54323
Inbucket URL: http://localhost:54324
JWT secret: super-secret-jwt-token-with-at-least-32-characters-long
anon key: xxx
service_role key: xxx
$ supabase functions serve --env-file .env.local openai
Starting supabase/functions/openai
Serving supabase/functions/openai
Watcher Process started.
Check file:///home/deno/functions/openai/index.ts
Listening on <http://localhost:8000/>
LLMと対話できるか curl で叩いて検証
$ curl -i --location --request POST 'http://localhost:54321/functions/v1/' \
--header 'Authorization: Bearer xxxx' \
--header 'Content-Type: application/json' \
--data '{"query":"日本で一番面積が大きい都道府県はどこですか?"}'
HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
date: Sun, 30 Apr 2023 09:08:09 GMT
vary: Accept-Encoding
X-Kong-Upstream-Latency: 2178
X-Kong-Proxy-Latency: 7
Via: kong/2.8.1
{"id":"cmpl-7AxKKdp1u6RlgNQut7u0wE8Vgd1xa","text":"\n\n日本で一番面積が大きい都道府県は、北海道です。"}%
できた 🎉