Accessing ChatGPT API through Firebase Cloud Function
Asked Answered
C

3

7

Below is some code for a simple Firebase Cloud Function that hits the ChatGPT API. Deploying this code and accessing it from my app results in a CORS error.

import * as functions from "firebase-functions";
import {defineString} from "firebase-functions/v2/params";
import {Configuration, OpenAIApi} from "openai";

const openAIKey = defineString("OPEN_API_KEY");

export const getSummary = functions.https.onCall(async (data) => {
  const configuration = new Configuration({
    apiKey: openAIKey.value(),
  });
  const openai = new OpenAIApi(configuration);
  const completion = await openai.createChatCompletion({
    model: "gpt-3.5-turbo",
    messages: [
      {
        role: "user",
        content: data.prompt,
      },
    ],
  });
  const [choice] = completion.data.choices;
  return {
    response: choice.message ?? "no response",
  };
});

This cloud function works perfectly when I access it from my app using the functions emulator. I only get the CORS error when I deploy it to the cloud and try to use it.

Also, I have a helloWorld function deployed alongside this one so that I can check that there's nothing wrong with my whole functions setup, and it works fine also. Furthermore, when I go into my Cloud Functions Console and test the function directly, it also works. So the issue clearly has to do with accessing the API specifically via the cloud function production environment and specifically from the app.

Update: Here's the client code and the exact error:

const getSummary = httpsCallable(functions, "getSummary");
async function askGPT() {
    const result = await getSummary({
      prompt: "Please summarize the question in the following text. Phrase your response in the form of a question, and use Markdown for any formatting you might need.\n\n" + question.text
    });
    question.question_summary = (
      (question.question_summary ?? "") // @ts-ignore
      + (result?.data?.response?.content || "").trim()
    );
  }

error:

Access to fetch at 'https://us-central1-my-documentation.cloudfunctions.net/getSummary' from origin 'http://localhost:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Countryman answered 4/3, 2023 at 17:54 Comment(8)
Also posted on groups.google.com/g/firebase-talk/c/vt8ILxFv-4YStack
Could you post the code that calls the function, and also the exact error message?Datnow
Sure; I added them to to question.Countryman
As the issue seems to be with CORS error and using response tokens did not solve the issue. Try contact Firebase support.Motherless
Were you able to fix this? I'm just getting 400 error.Description
Yes, sort of. I think the problem is just that Firebase onCall functions reach out to other APIs as you, subjecting you to the same CORS restrictions you would have calling from the client. The way around this is to write to Firestore from the client and then make your cloud function an onCreate. Then you can write back to Firestore and pick it up in the client with a subscription.Countryman
Have you addressed this issue?Tinhorn
Yes, I added an answer in case it's helpful to other folks.Countryman
C
2

The best solution to this problem is to avoid using onCall when you have CORS issues. Instead:

  1. Come up with a name for a new Firestore collection.
  2. Set up a cloud function that is triggered by the creation of a new document in that collection.
  3. Put the logic that talks to the OpenAI API in the cloud function. When you have the response, write it to a collection in Firestore (wherever you want).
  4. From the client:
    1. Write to the aforementioned collection when you want to make a request.
    2. Subscribe to the collection that the cloud function writes to.

All together, a new request from the client causes this cascade:

  1. A write to the Firestore collection for requests.
  2. A cloud function read of that document, plus an API call and any other necessary logic.
  3. A write to a Firestore collection for responses.
  4. An update on the client in response to that document update.

The reason this alternative approach is required is that an onCall cloud function has different CORS behavior than a cloud function triggered by a Firestore event.

Countryman answered 26/5, 2023 at 15:0 Comment(0)
D
0

Here you can see examples of "onCall" type response and here another one with "fetch" and "stream".

Discord answered 1/6, 2023 at 13:56 Comment(0)
E
0

Make sure you have your openai dependency installed locally on your project under the package.json file.

Otherwise, install it using:

npm i openai
Emera answered 31/12, 2023 at 4:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.