サーバーを建てずにChatKitを試す

サーバーを建てずにChatKitを試す

OpenAIが用意したReact Componentを使って、AIチャットをWebアプリに組み込みやすくなった

ただしChatKitを試すには、client secretを発行するサーバーを自力で用意する必要がある

なるべくデータベースやサーバーを建てずに、素早くChatKitを試したいhata6502

未ログインでもclient secretを発行できるようにする
client secretを発行するには、 user IDが必要
漏れるとチャット履歴を見られてしまう可能性もあるため、厳重に扱う
推測できないランダムなIDをクライアントサイドで生成することで、データベースを建てずにuserIDを用意するhata6502

現時点でのChatKitはベータ版のため、無保証という前提のうえでお試しする

参考情報
reCAPTCHAを使うきっかけになりました
openAI APIの使い方を読み取れます



reCAPTCHA
未ログインでもChatKitのclient secretを発行できる代わりに、botを排除してOpenAI APIを大量利用させないようにする

Cloud Run functions
CORSを設定する
reCAPTCHA tokenを検証する
ChatKitのclient secretを発行する
package.json
Copied!
{
"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.js
Copied!
import 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
Copied!
<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.tsx
Copied!
export 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を使って、校正さんに相談機能を作ることができた
Powered by Helpfeel