Firebase Functionsを使ってChatGPTのAPIを作る

# はじめに

ChatGPTのAPI Keyを見えないようにしながらAPIを呼び出すためには、呼び出す用のエンドポイントを作成する必要があります。

https://qiita.com/AS_atsushi/items/c959bfd60704cc7c08f4

しかし、そのためにサーバーをデプロイするのは少し大変。

そこで、**Firebase Functionsを用いてサーバーレスでエンドポイントを作成**していきましょう！

# Firebaseプロジェクトの作成

Firebaseを開きます。

https://firebase.google.com/?hl=ja

プロジェクトを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/3b46c482-ad53-9e72-68d5-989763af81c1.png)

プロジェクトに名前をつけます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/91df73e7-41cf-1ef1-fa4f-6e24e3f43f33.png)


今回は`Analytics`は必要ありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/31828f9b-a838-1f4f-5062-d0b922e270f2.png)

Functionsは課金プランでしか使えないので、支払い情報を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/6659a258-dd3b-5028-737b-5a4579dba8ea.png)

支払いアカウントを追加すると、以下のような画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/7fd8aaf8-277d-f979-731b-63abac48af08.png)

# Firebaseプロジェクトとローカルを繋ぎこむ

先にFirebase CLIをダウンロードしておきます。

```
npm install -g firebase-tools
```

次にプロジェクトを作成するディレクトリに移動したら、以下を実行します。

```
firebase init
```

`Functions ...`を、↑↓キーで移動し、Spaceで選択します。

![スクリーンショット 2024-12-17 20.53.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/9c53f3dd-808a-20d1-bb16-283cdb6b7cd6.png)

先ほど作成したプロジェクトを登録したいので、`Use an existing project`を選択します。

![スクリーンショット 2024-12-17 20.54.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/384715e0-503f-bb2e-d3b3-445082b46169.png)

↑↓キーで、先ほど作成したプロジェクトを選択します。

![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_2823873_fb7d78c8-97c5-fdb6-6f23-40ae9366ca33のコピー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/b8f6cc90-2330-b749-c76b-154eb261579d.jpeg)

今回はJavaScriptを選択します。

![スクリーンショット 2024-12-17 20.55.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/48321dc5-d49a-89f2-01d2-4419c1345536.png)

するとプロジェクトの生成が始まります。うまくいけば、以下のように表示されます。

![スクリーンショット 2024-12-17 20.55.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/a22bfaa4-abfd-b12c-7f63-b45abd5f24bc.png)

ここまでくると、プロジェクトのファイルが生成されます。

![スクリーンショット 2024-12-19 17.36.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/faf8a94c-ff02-f476-a8ec-4d7d892538a4.png)

# パッケージを追加

functionsに移動します。

```
cd functions
```

npmで、dotenvとopenaiを追加します。

```
npm install dotenv openai
```

# コードを書こう

functionsの中のpackage.jsonを開きます。

![スクリーンショット 2024-12-19 17.45.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/d2cf9c4e-792b-33ca-a3b9-d6cdde3c1381.png)

4行目に以下を追加します。

```json
"name": "functions",
"description": "Cloud Functions for Firebase",
"type": "module",←この行を追加
```

また、下の方にある行も変更します。

```json
"main": "index.js",
↓以下に変更
"main": "index.mjs",
```

保存したら、functionsの中のindex.jsを開きます。

![スクリーンショット 2024-12-19 17.37.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/1ff43823-0a38-6d7f-308c-5bcd734e0c25.png)

ファイル名を`index.mjs`に変更します。

![スクリーンショット 2024-12-19 17.48.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/74b4856f-8641-f3ad-99fa-47cacdbf7b96.png)

以下のコードに書き換えます。

```javascript:index.mjs
import 'dotenv/config';
import { onRequest } from "firebase-functions/v2/https";
import OpenAIApi from "openai";

import {setGlobalOptions} from "firebase-functions/v2";
setGlobalOptions({
  region: "asia-northeast1",
});

const client = new OpenAIApi({
  apiKey: process.env["OPENAI_API_KEY"]
});

export const chatgpt = onRequest(async (req, res) => {
  // CORS対策(必要に応じて調整)
  res.set('Access-Control-Allow-Origin', '*');
  res.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  res.set('Access-Control-Allow-Headers', '*');

  if (req.method === 'OPTIONS') {
    res.status(204).send('');
    return;
  }

  if (req.method !== "POST") {
    return res.status(405).send({ error: "Only POST method is allowed." });
  }

  const prompt = req.body.prompt;
  if (!prompt) {
    return res.status(400).send({ error: "Prompt is required." });
  }

  try {
    const response = await client.chat.completions.create({
      model: "gpt-3.5-turbo",
      messages: [{ role: "user", content: prompt }]
    });

    const result = response.choices[0].message.content;
    return res.status(200).send({ result });
  } catch (error) {
    console.error("OpenAI API error:", error);
    return res.status(500).send({ error: "Internal server error." });
  }
});
```

最後に、**functionsの中に** `.env`というファイルを作成します。

![スクリーンショット 2024-12-19 17.49.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/494b56f7-bf7d-1067-4f05-9b6c61335ad6.png)

.envに、ChatGPTのAPI Keyを入力します。

```:.env
OPENAI_API_KEY=(あなたのAPI Key)
```

# デプロイする

`FirebaseFunctions-Sample`ディレクトリに戻ります。

```
cd ..
```

デプロイのコマンドをうちます。

```
firebase deploy --only functions
```

デプロイが成功すると「✔  Deploy complete!」と表示されます。

このとき、デプロイしたエンドポイントのURLは以下から確認できます。

```
✔  functions[chatgpt(asia-northeast1)] Successful create operation.
Function URL (chatgpt(asia-northeast1)): (ここにURLが書かれている)
i  functions: cleaning up build files...
```

また、Firebase側でも表示を確認することができます。

![Capture-2024-12-19-175509.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/29b02662-2d19-cfc4-19af-67838c50d0ce.png)

# デプロイ前にテストをしたい場合

以下のコマンドを打つと、localhostで実行できるようになります。

```
firebase emulators:start --only functions
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/0b9e714e-1cc9-a466-cf3d-7a5b589c9036.png)

# まとめ

Firebase Functions、個人利用くらいならほぼ無料で使えるのでみなさんどんどん使っていきましょう！
資料も少ないので、もし改善点等ありましたら教えていただけますと幸いです！