React
事前準備
1. SDK スクリプトの追加
public/index.html
ファイルの <head>
タグ内に SDK スクリプトを追加します。
public/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
{/* ... その他のメタタグやリンク ... */}
<title>React + Klleon Chat SDK</title>
{/* TODO: {VERSION} を実際の SDK バージョンに変更してください(例: 1.2.0)
*/}
<script src="https://web.sdk.klleon.io/{VERSION}/klleon-chat.umd.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
2. TypeScript 型サポート(任意)
Klleon Chat SDK は TypeScript 型定義を提供しています。プロジェクトに型定義ファイル(.d.ts)を含めることで、window.KlleonChat
グローバルオブジェクトや SDK メソッド、Web コンポーネントの props に対する型推論と自動補完が利用可能になります。
React 例(App.tsx
)
CSS スタイル
custom.css
.base-react-example-page {
width: 100%;
height: 100%;
.header {
margin-bottom: 30px;
}
.loading-text {
position: absolute;
font-size: 1.5em;
color: #555;
padding: 50px;
}
.start-chat-button {
width: 150px;
height: 50px;
background-color: #0c5ef0;
color: #fff;
border-radius: 10px;
font-size: 16px;
font-weight: 600;
border: none;
cursor: pointer;
}
.sdk-container {
display: flex;
width: 100%;
height: 720px;
gap: 0px 24px;
.avatar-container {
flex: 1;
}
.chat-control-container {
display: flex;
flex-direction: column;
flex: 1;
gap: 24px 0px;
.chat-container {
flex: 1;
border-radius: 24px;
}
.chat-echo-container {
display: flex;
flex-direction: column;
.echo-input {
width: 100%;
height: 40px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 0 10px;
font-size: 16px;
margin-bottom: 10px;
}
.echo-button {
width: 100%;
height: 40px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 0 10px;
background-color: #0c5ef0;
color: #fff;
font-size: 16px;
font-weight: 600;
cursor: pointer;
&:disabled {
background-color: #ccc;
color: #fff;
cursor: not-allowed;
}
}
}
}
}
}
src/App.tsx
import { ChatData, Status } from "@site/src/types/global";
import { useEffect, useRef, useState, CSSProperties } from "react";
// TODO: 実際の SDK キーとアバター ID に置き換えてください。
const SDK_KEY = "YOUR_SDK_KEY";
const AVATAR_ID = "YOUR_AVATAR_ID";
interface AvatarProps {
videoStyle?: CSSProperties;
volume?: number;
}
interface ChatProps {
delay?: number;
type?: "voice" | "text";
isShowCount?: boolean;
}
function App() {
const [echoText, setEchoText] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [isChatStarted, setIsChatStarted] = useState(false);
const avatarContainerRef = useRef<HTMLElement & AvatarProps>(null);
const chatContainerRef = useRef<HTMLElement & ChatProps>(null);
useEffect(() => {
if (avatarContainerRef.current) {
avatarContainerRef.current.videoStyle = {
borderRadius: "24px",
objectFit: "cover",
};
avatarContainerRef.current.volume = 100;
}
if (chatContainerRef.current) {
chatContainerRef.current.delay = 10;
chatContainerRef.current.type = "text";
chatContainerRef.current.isShowCount = true;
console.log("chat-container の props を ref 経由で設定しました。");
}
}, []);
const startChat = async () => {
setIsChatStarted(true);
const KlleonChat = window.KlleonChat;
console.log("SDK の読み込み確認済み。初期化を試みます...");
KlleonChat.onStatusEvent((status: Status) => {
console.log(`SDK Status Event: ${status}`);
setIsLoading(status !== "VIDEO_CAN_PLAY");
});
KlleonChat.onChatEvent((chatData: ChatData) => {
console.log("SDK Chat Event:", chatData);
});
try {
await KlleonChat.init({
sdk_key: SDK_KEY,
avatar_id: AVATAR_ID,
log_level: "debug",
});
console.log("SDK 初期化成功!");
} catch (error) {
console.error(`SDK 初期化失敗: ${(error as Error).message || error}`);
setIsLoading(false);
} finally {
setIsLoading(false);
}
};
const handleEcho = () => {
window.KlleonChat.echo(echoText);
setEchoText("");
};
return (
<div className="base-react-example-page">
{!isChatStarted && (
<button
onClick={startChat}
disabled={isLoading}
className="start-chat-button"
>
チャット開始
</button>
)}
<div className="sdk-container">
{isLoading && (
<span className="loading-text">Klleon アバター読み込み中...</span>
)}
<avatar-container
ref={avatarContainerRef}
class="avatar-container" // className は使用不可、class 属性を使用
/>
<div className="chat-control-container">
<chat-container ref={chatContainerRef} class="chat-container" />
<div className="chat-echo-container">
<input
type="text"
value={echoText}
onChange={(e) => setEchoText(e.target.value)}
placeholder="echo 内容を入力..."
disabled={isLoading}
className="echo-input"
/>
<button
onClick={handleEcho}
disabled={isLoading}
className="echo-button"
>
echo 送信
</button>
</div>
</div>
</div>
</div>
);
}
export default App;