サーバーを建てずにChatKitを試す
OpenAIが用意したReact Componentを使って、AIチャットをWebアプリに組み込みやすくなった
ただしChatKitを試すには、client secretを発行するサーバーを自力で用意する必要がある
なるべくデータベースやサーバーを建てずに、素早くChatKitを試したい
未ログインでもclient secretを発行できるようにする
client secretを発行するには、
user IDが必要 漏れるとチャット履歴を見られてしまう可能性もあるため、厳重に扱う
推測できないランダムなIDをクライアントサイドで生成することで、データベースを建てずにuserIDを用意する
現時点でのChatKitはベータ版のため、無保証という前提のうえでお試しする
https://openai.com/policies/service-terms/#:~:text=.-,2.%20Beta%20Services,-This%20section%20governs
参考情報
reCAPTCHAを使うきっかけになりました
openAI APIの使い方を読み取れます
reCAPTCHA
未ログインでもChatKitのclient secretを発行できる代わりに、botを排除してOpenAI APIを大量利用させないようにする
Cloud Run functions
CORSを設定する
reCAPTCHA tokenを検証する
ChatKitのclient secretを発行する
package.json{ "type": "module", "dependencies": { "@google-cloud/functions-framework": "^3.0.0", "@google-cloud/recaptcha-enterprise": "^6.3.1", "openai": "^6.5.0", "zod": "^4.1.12" }}index.jsimport functions from "@google-cloud/functions-framework";import { RecaptchaEnterpriseServiceClient } from "@google-cloud/recaptcha-enterprise";import OpenAI from "openai";import { z } from "zod";
const { ALLOWED_ORIGINS, CHATKIT_WORKFLOW_ID, RECAPTCHA_SITE_KEY } = process.env;
const openai = new OpenAI();const recaptchaClient = new RecaptchaEnterpriseServiceClient();
functions.http("index", async (req, res) => { try { if (!ALLOWED_ORIGINS) { throw new Error("ALLOWED_ORIGINS is not set"); } const origin = req.get("Origin"); if (ALLOWED_ORIGINS.split(",").includes(origin)) { res.set("Access-Control-Allow-Origin", origin); res.set("Access-Control-Allow-Methods", "POST"); res.set("Access-Control-Allow-Headers", "Content-Type"); }
if (req.method === "OPTIONS") { res.status(204).send(""); return; }
if (req.method !== "POST") { res.status(405).send("Method Not Allowed"); return; }
const { data } = z .object({ recaptchaToken: z.string().max(4096), userID: z.string().max(64), }) .safeParse(req.body); if (!data) { res.status(400).send("Invalid request body"); return; }
if (!RECAPTCHA_SITE_KEY) { throw new Error("RECAPTCHA_SITE_KEY is not set"); } const [assessmentResponse] = await recaptchaClient.createAssessment({ assessment: { event: { siteKey: RECAPTCHA_SITE_KEY, token: data.recaptchaToken, }, }, parent: recaptchaClient.projectPath("(Google Cloudプロジェクト名)"), }); if (!assessmentResponse.tokenProperties.valid) { console.log( `The CreateAssessment call failed because the token was: ${assessmentResponse.tokenProperties.invalidReason}` ); res.status(403).send(""); return; } if (assessmentResponse.tokenProperties.action !== "GET_CLIENT_SECRET") { console.log( "The action attribute in your reCAPTCHA tag does not match the action you are expecting to score" ); res.status(403).send(""); return; } console.log( `The reCAPTCHA score is: ${assessmentResponse.riskAnalysis.score}` ); for (const reason of assessmentResponse.riskAnalysis.reasons) { console.log(reason); } if (assessmentResponse.riskAnalysis.score < 0.5) { res.status(403).send(""); return; }
if (!CHATKIT_WORKFLOW_ID) { throw new Error("CHATKIT_WORKFLOW_ID is not set"); } const chatSession = await openai.beta.chatkit.sessions.create({ user: data.userID, workflow: { id: CHATKIT_WORKFLOW_ID }, });
res.status(200).json({ clientSecret: chatSession.client_secret, }); } catch (exception) { console.error(exception); res.status(500).send(""); }}); OpenAI APIやreCAPTCHAを使うための環境変数をセットする
クライアントサイド
reCAPTCHAを導入する
userIDを生成する
推測できないランダムなIDである必要がある
crypto.randomUUID() などを使う Cloud Run functionからChatKitのclient secretを受け取る
index.html<script src="https://www.google.com/recaptcha/enterprise.js?render=(reCAPTCHA site key)"></script><script src="https://cdn.platform.openai.com/deployments/chatkit/chatkit.js" async></script>chat.tsxexport const Chat: FunctionComponent = () => { const { control } = useChatKit({ api: { getClientSecret: async () => { await new Promise<void>((resolve) => grecaptcha.enterprise.ready(resolve), ); const recaptchaToken = await grecaptcha.enterprise.execute( "(reCAPTCHA site key)", { action: "GET_CLIENT_SECRET" }, );
const response = await fetch( "(Cloud Run functionのエンドポイント)", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ recaptchaToken, userID: (生成したuserID), }), }, ); if (!response.ok) { throw new Error( `Failed to create session: ${response.status} ${response.statusText}`, ); } const { clientSecret } = await response.json();
return clientSecret; }, }, });
return <ChatKit control={control} />;};ChatKitを使って、校正さんに相談機能を作ることができた