[251022] fix: webSpeech관련 로그 추가
🕐 커밋 시간: 2025. 10. 22. 14:15:12 📊 변경 통계: • 총 파일: 3개 • 추가: +55줄 • 삭제: -33줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/webSpeechActions.js ~ com.twin.app.shoptime/src/hooks/useWebSpeech.js ~ com.twin.app.shoptime/src/services/webSpeech/WebSpeechService.js 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선 • API 서비스 레이어 개선 • 소규모 기능 개선 • 코드 정리 및 최적화
This commit is contained in:
@@ -10,12 +10,12 @@ import webSpeechService from '../services/webSpeech/WebSpeechService';
|
||||
export const initializeWebSpeech =
|
||||
(config = {}) =>
|
||||
(dispatch) => {
|
||||
console.log('[WebSpeechActions] Initializing Web Speech...');
|
||||
console.log('[VoiceInput]-[WebSpeech] ACTION-INIT: 초기화 시작');
|
||||
|
||||
// 지원 여부 확인
|
||||
if (!webSpeechService.isSupported) {
|
||||
const error = 'Web Speech API is not supported in this browser';
|
||||
console.error('[WebSpeechActions]', error);
|
||||
console.error('[VoiceInput]-[WebSpeech] ACTION-INIT: ❌ Web Speech API 미지원');
|
||||
dispatch({
|
||||
type: types.WEB_SPEECH_ERROR,
|
||||
payload: { error, message: error },
|
||||
@@ -32,6 +32,7 @@ export const initializeWebSpeech =
|
||||
});
|
||||
|
||||
if (!initialized) {
|
||||
console.error('[VoiceInput]-[WebSpeech] ACTION-INIT: ❌ 초기화 실패');
|
||||
dispatch({
|
||||
type: types.WEB_SPEECH_ERROR,
|
||||
payload: { error: 'Failed to initialize', message: 'Failed to initialize Web Speech' },
|
||||
@@ -41,13 +42,16 @@ export const initializeWebSpeech =
|
||||
|
||||
// 이벤트 핸들러 등록
|
||||
webSpeechService.on('start', () => {
|
||||
console.log('[VoiceInput]-[WebSpeech] ACTION-EVENT: WEB_SPEECH_START 디스패치');
|
||||
dispatch({
|
||||
type: types.WEB_SPEECH_START,
|
||||
});
|
||||
});
|
||||
|
||||
webSpeechService.on('result', (result) => {
|
||||
console.log('[WebSpeechActions] Result:', result);
|
||||
console.log(
|
||||
`[VoiceInput]-[WebSpeech] ACTION-EVENT: WEB_SPEECH_INTERIM_RESULT 디스패치 - isFinal=${result.isFinal}, text="${result.transcript}"`
|
||||
);
|
||||
|
||||
// ✅ continuous: true 모드에서는 중간 final result를 무시하고
|
||||
// 항상 interim result만 사용 (15초 타이머로 제어)
|
||||
@@ -62,7 +66,9 @@ export const initializeWebSpeech =
|
||||
});
|
||||
|
||||
webSpeechService.on('error', (errorInfo) => {
|
||||
console.error('[WebSpeechActions] Error:', errorInfo);
|
||||
console.error(
|
||||
`[VoiceInput]-[WebSpeech] ACTION-EVENT: WEB_SPEECH_ERROR 디스패치 - error="${errorInfo.error}"`
|
||||
);
|
||||
dispatch({
|
||||
type: types.WEB_SPEECH_ERROR,
|
||||
payload: errorInfo,
|
||||
@@ -70,11 +76,13 @@ export const initializeWebSpeech =
|
||||
});
|
||||
|
||||
webSpeechService.on('end', () => {
|
||||
console.log('[VoiceInput]-[WebSpeech] ACTION-EVENT: WEB_SPEECH_END 디스패치');
|
||||
dispatch({
|
||||
type: types.WEB_SPEECH_END,
|
||||
});
|
||||
});
|
||||
|
||||
console.log('[VoiceInput]-[WebSpeech] ACTION-INIT: ✅ WEB_SPEECH_INITIALIZED 디스패치');
|
||||
dispatch({
|
||||
type: types.WEB_SPEECH_INITIALIZED,
|
||||
});
|
||||
@@ -86,10 +94,11 @@ export const initializeWebSpeech =
|
||||
* 음성 인식 시작
|
||||
*/
|
||||
export const startWebSpeech = () => (dispatch) => {
|
||||
console.log('[WebSpeechActions] Starting recognition...');
|
||||
console.log('[VoiceInput]-[WebSpeech] ACTION-START: 음성 인식 시작 요청');
|
||||
const started = webSpeechService.start();
|
||||
|
||||
if (!started) {
|
||||
console.error('[VoiceInput]-[WebSpeech] ACTION-START: ❌ 음성 인식 시작 실패');
|
||||
dispatch({
|
||||
type: types.WEB_SPEECH_ERROR,
|
||||
payload: { error: 'Failed to start', message: 'Failed to start recognition' },
|
||||
@@ -101,7 +110,7 @@ export const startWebSpeech = () => (dispatch) => {
|
||||
* 음성 인식 중지
|
||||
*/
|
||||
export const stopWebSpeech = () => (dispatch) => {
|
||||
console.log('[WebSpeechActions] Stopping recognition...');
|
||||
console.log('[VoiceInput]-[WebSpeech] ACTION-STOP: 음성 인식 중지 요청');
|
||||
webSpeechService.stop();
|
||||
};
|
||||
|
||||
@@ -109,7 +118,7 @@ export const stopWebSpeech = () => (dispatch) => {
|
||||
* 음성 인식 중단
|
||||
*/
|
||||
export const abortWebSpeech = () => (dispatch) => {
|
||||
console.log('[WebSpeechActions] Aborting recognition...');
|
||||
console.log('[VoiceInput]-[WebSpeech] ACTION-ABORT: 음성 인식 중단 (즉시) 요청');
|
||||
webSpeechService.abort();
|
||||
};
|
||||
|
||||
@@ -117,19 +126,21 @@ export const abortWebSpeech = () => (dispatch) => {
|
||||
* 리소스 정리
|
||||
*/
|
||||
export const cleanupWebSpeech = () => (dispatch) => {
|
||||
console.log('[WebSpeechActions] Cleaning up...');
|
||||
console.log('[VoiceInput]-[WebSpeech] ACTION-CLEANUP: 리소스 정리 요청');
|
||||
webSpeechService.cleanup();
|
||||
dispatch({
|
||||
type: types.WEB_SPEECH_CLEANUP,
|
||||
});
|
||||
console.log('[VoiceInput]-[WebSpeech] ACTION-CLEANUP: ✅ WEB_SPEECH_CLEANUP 디스패치');
|
||||
};
|
||||
|
||||
/**
|
||||
* STT 텍스트 초기화 (이전 음성 인식 결과 제거)
|
||||
*/
|
||||
export const clearSTTText = () => (dispatch) => {
|
||||
console.log('[WebSpeechActions] Clearing STT text...');
|
||||
console.log('[VoiceInput]-[WebSpeech] ACTION-CLEAR: STT 텍스트 초기화 요청');
|
||||
dispatch({
|
||||
type: types.VOICE_CLEAR_STATE,
|
||||
});
|
||||
console.log('[VoiceInput]-[WebSpeech] ACTION-CLEAR: ✅ VOICE_CLEAR_STATE 디스패치');
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@ export const useWebSpeech = (isActive, onSTTText, config = {}) => {
|
||||
// Web Speech 초기화
|
||||
useEffect(() => {
|
||||
if (isActive) {
|
||||
console.log('[useWebSpeech] Initializing Web Speech API');
|
||||
console.log('[VoiceInput]-[WebSpeech] HOOK-INIT: useWebSpeech Hook 초기화 시작');
|
||||
dispatch(
|
||||
initializeWebSpeech({
|
||||
lang: config.lang || 'en-US',
|
||||
@@ -38,7 +38,9 @@ export const useWebSpeech = (isActive, onSTTText, config = {}) => {
|
||||
// Cleanup on unmount only
|
||||
return () => {
|
||||
if (isActive) {
|
||||
console.log('[useWebSpeech] Cleaning up Web Speech API (unmount)');
|
||||
console.log(
|
||||
'[VoiceInput]-[WebSpeech] HOOK-CLEANUP: useWebSpeech Hook 언마운트 - 정리 시작'
|
||||
);
|
||||
dispatch(cleanupWebSpeech());
|
||||
}
|
||||
};
|
||||
@@ -47,7 +49,9 @@ export const useWebSpeech = (isActive, onSTTText, config = {}) => {
|
||||
// STT 텍스트 수신 처리
|
||||
useEffect(() => {
|
||||
if (lastSTTText && sttTimestamp) {
|
||||
console.log('[useWebSpeech] STT text received:', lastSTTText);
|
||||
console.log(
|
||||
`[VoiceInput]-[WebSpeech] HOOK-STT: STT 텍스트 수신 - "${lastSTTText}", timestamp=${sttTimestamp}`
|
||||
);
|
||||
if (onSTTText) {
|
||||
onSTTText(lastSTTText);
|
||||
}
|
||||
@@ -56,10 +60,12 @@ export const useWebSpeech = (isActive, onSTTText, config = {}) => {
|
||||
|
||||
// 음성 인식 시작/중지 함수 반환
|
||||
const startListening = useCallback(() => {
|
||||
console.log('[VoiceInput]-[WebSpeech] HOOK-FUNC: startListening() 호출');
|
||||
dispatch(startWebSpeech());
|
||||
}, [dispatch]);
|
||||
|
||||
const stopListening = useCallback(() => {
|
||||
console.log('[VoiceInput]-[WebSpeech] HOOK-FUNC: stopListening() 호출');
|
||||
dispatch(stopWebSpeech());
|
||||
}, [dispatch]);
|
||||
|
||||
@@ -67,8 +73,7 @@ export const useWebSpeech = (isActive, onSTTText, config = {}) => {
|
||||
// - 브라우저가 SpeechRecognition API를 지원하는지만 확인
|
||||
// - 마이크 접근 불가 등의 에러는 error 필드로 별도 처리
|
||||
const isSupported =
|
||||
typeof window !== 'undefined' &&
|
||||
!!(window.SpeechRecognition || window.webkitSpeechRecognition);
|
||||
typeof window !== 'undefined' && !!(window.SpeechRecognition || window.webkitSpeechRecognition);
|
||||
|
||||
return {
|
||||
isInitialized: webSpeech.isInitialized,
|
||||
|
||||
@@ -36,8 +36,10 @@ class WebSpeechService {
|
||||
* @param {number} config.maxAlternatives - 대체 결과 최대 개수
|
||||
*/
|
||||
initialize(config = {}) {
|
||||
console.log('[VoiceInput]-[WebSpeech] INITIALIZE: 초기화 시작');
|
||||
|
||||
if (!this.isSupported) {
|
||||
console.error('[WebSpeech] Speech Recognition not supported');
|
||||
console.error('[VoiceInput]-[WebSpeech] INITIALIZE: ❌ Speech Recognition 미지원');
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -53,10 +55,11 @@ class WebSpeechService {
|
||||
// 이벤트 핸들러 등록
|
||||
this.setupEventHandlers();
|
||||
|
||||
console.log('[WebSpeech] Initialized with config:', {
|
||||
console.log('[VoiceInput]-[WebSpeech] INITIALIZE: ✅ 초기화 완료', {
|
||||
lang: this.recognition.lang,
|
||||
continuous: this.recognition.continuous,
|
||||
interimResults: this.recognition.interimResults,
|
||||
maxAlternatives: this.recognition.maxAlternatives,
|
||||
});
|
||||
|
||||
return true;
|
||||
@@ -68,7 +71,7 @@ class WebSpeechService {
|
||||
setupEventHandlers() {
|
||||
// 음성 인식 시작
|
||||
this.recognition.onstart = () => {
|
||||
console.log('[WebSpeech] Recognition started');
|
||||
console.log('[VoiceInput]-[WebSpeech] ONSTART: ✅ 음성 인식 시작됨');
|
||||
this.isListening = true;
|
||||
if (this.callbacks.onStart) {
|
||||
this.callbacks.onStart();
|
||||
@@ -83,12 +86,17 @@ class WebSpeechService {
|
||||
let finalTranscript = '';
|
||||
let interimTranscript = '';
|
||||
|
||||
console.log('[WebSpeech] 🎤 onresult 이벤트 - results.length:', results.length);
|
||||
console.log(
|
||||
`[VoiceInput]-[WebSpeech] ONRESULT: 🎤 이벤트 발생 - results.length=${results.length}, timestamp=${new Date().toISOString()}`
|
||||
);
|
||||
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
const transcript = results[i][0].transcript;
|
||||
const isFinal = results[i].isFinal;
|
||||
console.log(`[WebSpeech] [${i}] isFinal: ${isFinal}, transcript: "${transcript}"`);
|
||||
const confidence = results[i][0].confidence;
|
||||
console.log(
|
||||
`[VoiceInput]-[WebSpeech] ONRESULT: [${i}] isFinal=${isFinal}, confidence=${(confidence * 100).toFixed(1)}%, text="${transcript}"`
|
||||
);
|
||||
|
||||
if (isFinal) {
|
||||
finalTranscript += transcript + ' ';
|
||||
@@ -102,13 +110,9 @@ class WebSpeechService {
|
||||
const isFinal = lastResult.isFinal;
|
||||
const confidence = lastResult[0].confidence;
|
||||
|
||||
console.log('[WebSpeech] 📝 Result Summary:', {
|
||||
fullTranscript,
|
||||
finalTranscript: finalTranscript.trim(),
|
||||
interimTranscript: interimTranscript.trim(),
|
||||
isFinal,
|
||||
confidence,
|
||||
});
|
||||
console.log(
|
||||
`[VoiceInput]-[WebSpeech] ONRESULT: 📝 결과 요약 - isFinal=${isFinal}, confidence=${(confidence * 100).toFixed(1)}%, full="${fullTranscript}"`
|
||||
);
|
||||
|
||||
if (this.callbacks.onResult) {
|
||||
this.callbacks.onResult({
|
||||
@@ -127,7 +131,9 @@ class WebSpeechService {
|
||||
|
||||
// 에러 처리
|
||||
this.recognition.onerror = (event) => {
|
||||
console.error('[WebSpeech] Recognition error:', event.error);
|
||||
console.error(
|
||||
`[VoiceInput]-[WebSpeech] ONERROR: ❌ 에러 발생 - error="${event.error}", timestamp=${new Date().toISOString()}`
|
||||
);
|
||||
this.isListening = false;
|
||||
|
||||
if (this.callbacks.onError) {
|
||||
@@ -140,7 +146,9 @@ class WebSpeechService {
|
||||
|
||||
// 음성 인식 종료
|
||||
this.recognition.onend = () => {
|
||||
console.log('[WebSpeech] Recognition ended');
|
||||
console.log(
|
||||
`[VoiceInput]-[WebSpeech] ONEND: ⏹️ 음성 인식 종료됨 - timestamp=${new Date().toISOString()}`
|
||||
);
|
||||
this.isListening = false;
|
||||
|
||||
if (this.callbacks.onEnd) {
|
||||
@@ -181,22 +189,28 @@ class WebSpeechService {
|
||||
* 음성 인식 시작
|
||||
*/
|
||||
start() {
|
||||
console.log(
|
||||
'[VoiceInput]-[WebSpeech] START: 음성 인식 시작 요청 - timestamp=' + new Date().toISOString()
|
||||
);
|
||||
|
||||
if (!this.recognition) {
|
||||
console.error('[WebSpeech] Recognition not initialized. Call initialize() first.');
|
||||
console.error(
|
||||
'[VoiceInput]-[WebSpeech] START: ❌ 초기화되지 않음 - initialize() 먼저 호출 필요'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isListening) {
|
||||
console.warn('[WebSpeech] Already listening');
|
||||
console.warn('[VoiceInput]-[WebSpeech] START: ⚠️ 이미 리스닝 중');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
this.recognition.start();
|
||||
console.log('[WebSpeech] Starting recognition...');
|
||||
console.log('[VoiceInput]-[WebSpeech] START: ⏳ recognition.start() 호출됨');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('[WebSpeech] Failed to start:', error);
|
||||
console.error('[VoiceInput]-[WebSpeech] START: ❌ 실패 - ' + error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -205,20 +219,25 @@ class WebSpeechService {
|
||||
* 음성 인식 중지
|
||||
*/
|
||||
stop() {
|
||||
console.log(
|
||||
'[VoiceInput]-[WebSpeech] STOP: 음성 인식 중지 요청 - timestamp=' + new Date().toISOString()
|
||||
);
|
||||
|
||||
if (!this.recognition) {
|
||||
console.warn('[VoiceInput]-[WebSpeech] STOP: ⚠️ 초기화되지 않음');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.isListening) {
|
||||
console.warn('[WebSpeech] Not listening');
|
||||
console.warn('[VoiceInput]-[WebSpeech] STOP: ⚠️ 현재 리스닝 중이 아님');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.recognition.stop();
|
||||
console.log('[WebSpeech] Stopping recognition...');
|
||||
console.log('[VoiceInput]-[WebSpeech] STOP: ⏳ recognition.stop() 호출됨');
|
||||
} catch (error) {
|
||||
console.error('[WebSpeech] Failed to stop:', error);
|
||||
console.error('[VoiceInput]-[WebSpeech] STOP: ❌ 실패 - ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,9 +245,17 @@ class WebSpeechService {
|
||||
* 음성 인식 중단 (즉시 종료)
|
||||
*/
|
||||
abort() {
|
||||
console.log(
|
||||
'[VoiceInput]-[WebSpeech] ABORT: 음성 인식 중단 (즉시) - timestamp=' +
|
||||
new Date().toISOString()
|
||||
);
|
||||
|
||||
if (this.recognition) {
|
||||
this.recognition.abort();
|
||||
this.isListening = false;
|
||||
console.log('[VoiceInput]-[WebSpeech] ABORT: ✅ recognition.abort() 호출됨');
|
||||
} else {
|
||||
console.warn('[VoiceInput]-[WebSpeech] ABORT: ⚠️ 초기화되지 않음');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,13 +263,20 @@ class WebSpeechService {
|
||||
* 리소스 정리
|
||||
*/
|
||||
cleanup() {
|
||||
console.log(
|
||||
'[VoiceInput]-[WebSpeech] CLEANUP: 리소스 정리 시작 - timestamp=' + new Date().toISOString()
|
||||
);
|
||||
|
||||
this.abort();
|
||||
|
||||
this.callbacks = {
|
||||
onResult: null,
|
||||
onError: null,
|
||||
onStart: null,
|
||||
onEnd: null,
|
||||
};
|
||||
|
||||
console.log('[VoiceInput]-[WebSpeech] CLEANUP: ✅ 리소스 정리 완료');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user