通过Firebase云功能访问ChatGPT API

use*_*158 6 javascript cors firebase google-cloud-functions openai-api

下面是一些使用 ChatGPT API 的简单 Firebase 云函数的代码。部署此代码并从我的应用程序访问它会导致 CORS 错误。

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",
  };
});
Run Code Online (Sandbox Code Playgroud)

当我使用函数模拟器从我的应用程序访问该云函数时,它可以完美运行。仅当我将其部署到云并尝试使用它时,才会出现 CORS 错误。

另外,我helloWorld在这个函数旁边部署了一个函数,这样我就可以检查我的整个函数设置是否没有问题,并且它也工作得很好。此外,当我进入云函数控制台并直接测试该函数时,它也可以工作。因此,这个问题显然与专门通过云函数生产环境和应用程序访问 API 有关。

更新:这是客户端代码和确切的错误:

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()
    );
  }
Run Code Online (Sandbox Code Playgroud)

错误:

从源“http://localhost:5173”获取“https://us-central1-my-documentation.cloudfunctions.net/getSummary”的访问已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。如果不透明响应满足您的需求,请将请求模式设置为“no-cors”以在禁用 CORS 的情况下获取资源。

use*_*158 2

onCall解决此问题的最佳方法是在出现 CORS 问题时避免使用。反而:

  1. 为新的 Firestore 系列命名。
  2. 设置一个云函数,该函数通过在该集合中创建新文档来触发。
  3. 将与 OpenAI API 对话的逻辑放在云函数中。收到响应后,将其写入 Firestore 中的集合(无论您想要在何处)。
  4. 来自客户:
    1. 当您想要提出请求时,请写信至上述集合。
    2. 订阅云函数写入的集合。

总之,来自客户端的新请求会导致这种级联:

  1. 写入 Firestore 集合以获取请求。
  2. 云函数读取该文档,加上 API 调用和任何其他必要的逻辑。
  3. 写入 Firestore 集合以获取响应。
  4. 客户端上响应该文档更新的更新。

需要这种替代方法的原因是onCall云函数与 Firestore 事件触发的云函数具有不同的 CORS 行为。