Web Speech API로 TTS 및 STT 구현하기
Text-to-Speech (TTS)
Speech-to-Text (STT)
마이크 권한 상태: 확인 중...
인식된 텍스트:
TTS 코드
html
1
2
3
4
5
6
7
8
9
10
<div class="container">
<h2>Speech-to-Text (STT)</h2>
<p id="status-message">마이크 권한 상태:
<span id="permission-status">확인 중...</span>
</p>
<button id="start-record-button">녹음 시작</button>
<button id="stop-record-button" disabled>녹음 중지</button>
<p>인식된 텍스트: <span id="recognized-text"></span></p>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
const speakButton = document.getElementById('speak-button');
const pauseButton = document.getElementById('pause-button');
const resumeButton = document.getElementById('resume-button');
const stopButton = document.getElementById('stop-button');
const ttsText = document.getElementById('tts-text');
let currentSpeech = null; // 현재 진행 중인 SpeechSynthesisUtterance 객체
// TTS 시작
speakButton.addEventListener('click', () => {
const text = ttsText.value.trim();
if (!text) {
alert("읽을 텍스트를 입력하세요.");
return;
}
// 현재 진행 중인 TTS가 있다면 중지
if (window.speechSynthesis.speaking || window.speechSynthesis.paused) {
window.speechSynthesis.cancel();
}
// 새로운 TTS 시작
currentSpeech = new SpeechSynthesisUtterance(text);
currentSpeech.lang = 'ko-KR'; // 한국어 설정
currentSpeech.lang = 'ko-KR'; // 한국어 설정
currentSpeech.rate = 1; // 음성 속도, 0.1 ~ 10 사이의 값
currentSpeech.pitch = 1; // 음높이, 0 ~ 2 사이의 값
currentSpeech.volume = 1; // 음량, 0 ~ 1 사이의 값
// TTS가 끝날 때 버튼 상태 초기화
currentSpeech.onend = () => {
speakButton.disabled = false;
pauseButton.disabled = true;
resumeButton.disabled = true;
stopButton.disabled = true;
};
window.speechSynthesis.speak(currentSpeech);
// 버튼 상태 업데이트
speakButton.disabled = true;
pauseButton.disabled = false;
resumeButton.disabled = true;
stopButton.disabled = false;
});
// TTS 일시 중지
pauseButton.addEventListener('click', () => {
if (window.speechSynthesis.speaking) {
window.speechSynthesis.pause();
pauseButton.disabled = true;
resumeButton.disabled = false;
}
});
// TTS 다시 재생
resumeButton.addEventListener('click', () => {
if (window.speechSynthesis.paused) {
window.speechSynthesis.resume();
pauseButton.disabled = false;
resumeButton.disabled = true;
}
});
// TTS 중지
stopButton.addEventListener('click', () => {
if (window.speechSynthesis.speaking || window.speechSynthesis.paused) {
window.speechSynthesis.cancel();
speakButton.disabled = false;
pauseButton.disabled = true;
resumeButton.disabled = true;
stopButton.disabled = true;
}
});
STT 코드
html
1
2
3
4
5
6
7
8
<div class="container">
<h2>Text-to-Speech (TTS)</h2>
<textarea id="tts-text" rows="3" cols="50" placeholder="여기에 텍스트를 입력하세요"></textarea><br>
<button id="speak-button">읽기</button>
<button id="pause-button" disabled>일시 중지</button>
<button id="resume-button" disabled>다시 재생</button>
<button id="stop-button" disabled>중지</button>
</div>
먼저 textarea 태그에 TTS 를 적용시킬 텍스트를 입력 받을 준비를 합니다. button 을 눌러 입력한 텍스트를 재생시키위한 코드를 작성합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
recognition.lang = 'ko-KR'; // 한국어 설정
recognition.continuous = true; // 연속 모드 활성화
recognition.interimResults = false; // 중간 결과 비활성화
const startButtonRec = document.getElementById('start-record-button');
const stopButtonRec = document.getElementById('stop-record-button');
const recognizedText = document.getElementById('recognized-text');
const permissionStatusSpan = document.getElementById('permission-status');
startButtonRec.addEventListener('click', () => {
recognition.start();
startButtonRec.disabled = true;
stopButtonRec.disabled = false;
});
stopButtonRec.addEventListener('click', () => {
recognition.stop();
startButtonRec.disabled = false;
stopButtonRec.disabled = true;
});
recognition.addEventListener('result', (event) => {
const transcript = event.results[0][0].transcript; // 인식된 텍스트
recognizedText.textContent = transcript;
});
recognition.addEventListener('end', () => {
currentSpeech = new SpeechSynthesisUtterance(recognizedText.textContent);
window.speechSynthesis.speak(currentSpeech);
setTimeout(()=>{
recognizedText.textContent = '';
}, 1000); // 1초 후에 빈 텍스트로 업데이트
});
// 마이크 권한 확인 및 상태 업데이트
async function checkMicrophonePermission() {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
if (stream) {
updateUI('granted');
}
} catch (error) {
updateUI('denied');
}
}
// UI 업데이트 함수
function updateUI(status) {
if (status === 'granted') {
permissionStatusSpan.textContent = '허용됨';
permissionStatusSpan.style.color = 'green';
startButtonRec.disabled = false;
stopButtonRec.disabled = true;
} else if (status === 'denied') {
permissionStatusSpan.textContent = '거부됨';
permissionStatusSpan.style.color = 'red';
startButtonRec.disabled = true;
stopButtonRec.disabled = true;
} else {
permissionStatusSpan.textContent = '알 수 없음';
permissionStatusSpan.style.color = 'orange';
startButtonRec.disabled = true;
stopButtonRec.disabled = true;
}
}
// 권한 변경 감지
async function monitorPermissionChanges() {
try {
const permissionStatus = await navigator.permissions.query({ name: 'microphone' });
updateUI(permissionStatus.state); // 초기 상태 설정
// 권한 변경 이벤트 리스너 등록
permissionStatus.onchange = () => {
updateUI(permissionStatus.state);
};
} catch (error) {
console.error('권한 상태를 확인할 수 없습니다.', error);
updateUI('unknown');
}
}
// 윈도우 로드 시 실행
window.addEventListener('load', () => {
checkMicrophonePermission(); // 권한 초기 확인
monitorPermissionChanges(); // 권한 변경 감지
});
마이크 권한을 허용할때만 STT가 실행되게 합니다.
🧐 오늘의 소감은?
플러터에서 패키지로 받아서 사용했던 것처럼 node.js 에서 패키지 받아서 사용하는 줄 알았는데 Web Speech API가 있어서 자바스크립트 내에서 해결을 할 수 있어서 신기했습니다. 물론 네이버 클로바처럼 자연스러운 말투는 아니지만 나름 만족하면서 기능구현했습니다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.