import React, { useEffect, useRef, useState } from 'react';
import * as SpeechSDK from 'microsoft-cognitiveservices-speech-sdk';
interface CustomSTTProps {
uneeqInstance: any;
azureKey: string;
azureRegion: string;
}
export function CustomSTTMicrophone({ uneeqInstance, azureKey, azureRegion }: CustomSTTProps) {
const [isListening, setIsListening] = useState(false);
const [transcript, setTranscript] = useState('');
const recognizerRef = useRef<SpeechSDK.SpeechRecognizer | null>(null);
const startListening = async () => {
const speechConfig = SpeechSDK.SpeechConfig.fromSubscription(azureKey, azureRegion);
speechConfig.speechRecognitionLanguage = 'en-US';
const audioConfig = SpeechSDK.AudioConfig.fromDefaultMicrophoneInput();
const recognizer = new SpeechSDK.SpeechRecognizer(speechConfig, audioConfig);
recognizerRef.current = recognizer;
// 中間結果(UI フィードバック用)
recognizer.recognizing = (_, event) => {
setTranscript(event.result.text);
};
// 最終結果 - デジタルヒューマンへ送信
recognizer.recognized = (_, event) => {
if (event.result.reason === SpeechSDK.ResultReason.RecognizedSpeech) {
const text = event.result.text;
setTranscript(text);
// デジタルヒューマンへ送信
uneeqInstance.chatPrompt(text, true);
// 送信後にトランスクリプトをクリア
setTimeout(() => setTranscript(''), 500);
}
};
recognizer.canceled = (_, event) => {
console.error('Recognition canceled:', event.errorDetails);
setIsListening(false);
};
await recognizer.startContinuousRecognitionAsync();
setIsListening(true);
};
const stopListening = async () => {
await recognizerRef.current?.stopContinuousRecognitionAsync();
recognizerRef.current = null;
setIsListening(false);
};
// デジタルヒューマンが発話中は自動ミュート
useEffect(() => {
const handleUneeqMessage = (event: CustomEvent) => {
const msg = event.detail;
if (msg.uneeqMessageType === 'AvatarStartedSpeaking') {
stopListening();
} else if (msg.uneeqMessageType === 'AvatarStoppedSpeaking') {
startListening();
}
};
window.addEventListener('UneeqMessage', handleUneeqMessage as EventListener);
return () => {
window.removeEventListener('UneeqMessage', handleUneeqMessage as EventListener);
};
}, []);
return (
<div className="custom-stt-controls">
<button
onClick={isListening ? stopListening : startListening}
className={isListening ? 'listening' : 'muted'}
>
{isListening ? 'Stop Listening' : 'Start Listening'}
</button>
{transcript && (
<div className="transcript">
{transcript}
</div>
)}
</div>
);
}