[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:
2025-10-22 14:15:13 +09:00
parent 595f4bd473
commit a3a8503842
3 changed files with 85 additions and 35 deletions

View File

@@ -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 디스패치');
};

View File

@@ -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,

View File

@@ -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: ✅ 리소스 정리 완료');
}
}