<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>김신건의 로그 - 위키 / voice</title><description>&apos;voice&apos; 카테고리 위키 페이지 최신 업데이트</description><link>https://shinkeonkim.com/</link><language>ko-KR</language><item><title>[Voice AI] Speech-to-Speech: OpenAI Realtime, Gemini Live, Moshi</title><link>https://shinkeonkim.com/wiki/voice/speech-to-speech-realtime/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/voice/speech-to-speech-realtime/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;S2S (Speech-to-Speech)&lt;/strong&gt; = STT → LLM → TTS &lt;em&gt;직렬 파이프라인 우회&lt;/em&gt;, &lt;em&gt;오디오 → 오디오&lt;/em&gt; 직접 처리. 톤/감정 보존 + &amp;#x3C; 300ms latency.&lt;/p&gt;
&lt;h2 id=&quot;주요-모델&quot;&gt;주요 모델&lt;/h2&gt;








































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;모델&lt;/th&gt;&lt;th&gt;출시&lt;/th&gt;&lt;th&gt;한국어&lt;/th&gt;&lt;th&gt;latency&lt;/th&gt;&lt;th&gt;특징&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;OpenAI Realtime API (GPT-4o)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;2024-10&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;232ms 평균&lt;/td&gt;&lt;td&gt;WebRTC + WebSocket, function calling 일부&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Gemini Live (2.5)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;2024-12&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;&amp;#x3C; 500ms&lt;/td&gt;&lt;td&gt;Google AI Studio, multimodal&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Moshi (Kyutai)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;2024-09&lt;/td&gt;&lt;td&gt;영어&lt;/td&gt;&lt;td&gt;160ms&lt;/td&gt;&lt;td&gt;OSS, full-duplex, 자체 호스팅&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Hume EVI 2&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;2024&lt;/td&gt;&lt;td&gt;영어&lt;/td&gt;&lt;td&gt;700ms&lt;/td&gt;&lt;td&gt;emotion 인식&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;openai-realtime-api&quot;&gt;OpenAI Realtime API&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Browser[&quot;Browser (WebRTC)&quot;] --&gt;|오디오 stream| RT[OpenAI Realtime]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    RT --&gt;|오디오 stream| Browser&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    RT -.tool calls.-&gt; Backend[Your Backend]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Backend -.tool results.-&gt; RT&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// WebRTC 연결&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; pc&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RTCPeerConnection&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 마이크 오디오 추가&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; stream&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; navigator.mediaDevices.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getUserMedia&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ audio: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;stream.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getTracks&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pc.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;addTrack&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(t, stream));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 음성 응답 받기&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pc.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ontrack&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  audioEl.srcObject &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; e.streams[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// DataChannel (이벤트, function call)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; dc&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pc.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;createDataChannel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;oai-events&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;dc.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;onmessage&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; event&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; JSON&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(e.data);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (event.type &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;response.function_call_arguments.done&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // function calling&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// SDP offer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; offer&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pc.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;createOffer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pc.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setLocalDescription&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(offer);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// OpenAI 에 offer 전송&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; resp&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; fetch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;https://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  method: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;POST&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  headers: { Authorization: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`Bearer ${&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;API_KEY&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Content-Type&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;application/sdp&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  body: offer.sdp,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pc.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setRemoteDescription&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ type: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;answer&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, sdp: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;text&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;session-이벤트&quot;&gt;Session 이벤트&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;session.update&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  &quot;session&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;modalities&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;audio&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;voice&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;alloy&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;instructions&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;You are a helpful Korean assistant. Speak naturally.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;input_audio_format&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;pcm16&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;output_audio_format&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;pcm16&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;input_audio_transcription&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;whisper-1&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;turn_detection&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;server_vad&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;&quot;threshold&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;tools&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;tool_choice&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;auto&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    &quot;temperature&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;이벤트&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;session.created&lt;/code&gt;&lt;/td&gt;&lt;td&gt;시작&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;input_audio_buffer.append&lt;/code&gt;&lt;/td&gt;&lt;td&gt;오디오 추가&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;input_audio_buffer.commit&lt;/code&gt;&lt;/td&gt;&lt;td&gt;처리 트리거&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;response.audio.delta&lt;/code&gt;&lt;/td&gt;&lt;td&gt;음성 청크&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;response.audio_transcript.delta&lt;/code&gt;&lt;/td&gt;&lt;td&gt;응답 전사&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;response.function_call_arguments.done&lt;/code&gt;&lt;/td&gt;&lt;td&gt;tool call&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;gemini-live&quot;&gt;Gemini Live&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; google &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; genai&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;client &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; genai.Client(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;API_KEY&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;config &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;response_modalities&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;AUDIO&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;system_instruction&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;당신은 친절한 한국어 어시스턴트입니다.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;speech_config&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;voice_config&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;            &quot;prebuilt_voice_config&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;voice_name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Aoede&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; client.aio.live.connect(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;model&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;gemini-2.5-flash-live&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;config) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; session:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; send_audio&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(audio_stream):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; audio_stream:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; session.send_realtime_input(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;audio&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;chunk)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; receive&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; response &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; session.receive():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; response.audio:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                play(response.audio)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; asyncio.gather(send_audio(mic), receive())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;moshi-oss-self-host&quot;&gt;Moshi (OSS, self-host)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User[User audio] --&gt;|streaming| Moshi[&quot;Moshi (7B params)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Moshi --&gt;|streaming| User&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Moshi --&gt; Mimi[&quot;Mimi audio codec&amp;#x3C;br/&gt;(12.5Hz)&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Full-duplex&lt;/em&gt;: 듣고 + 말하기 &lt;em&gt;동시&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Mimi codec&lt;/em&gt;: 12.5Hz token rate (vs Encodec 75Hz).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Self-host&lt;/em&gt; 가능 (Apache 2.0).&lt;/li&gt;
&lt;li&gt;영어 위주, 한국어 약함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;s2s-vs-streaming-cascading-비교&quot;&gt;S2S vs Streaming Cascading 비교&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    subgraph S2S&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        A1[Audio] --&gt; M1[Multimodal LLM]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        M1 --&gt; A2[Audio]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    subgraph Cascading&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        B1[Audio] --&gt; STT --&gt; LLM --&gt; TTS --&gt; B2[Audio]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;항목&lt;/th&gt;&lt;th&gt;S2S&lt;/th&gt;&lt;th&gt;Streaming Cascading&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Latency&lt;/td&gt;&lt;td&gt;&amp;#x3C; 300ms&lt;/td&gt;&lt;td&gt;&amp;#x3C; 1s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;톤/감정 보존&lt;/td&gt;&lt;td&gt;&lt;em&gt;예&lt;/em&gt;&lt;/td&gt;&lt;td&gt;손실&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Function calling&lt;/td&gt;&lt;td&gt;제한&lt;/td&gt;&lt;td&gt;&lt;em&gt;완전&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;컴포넌트 교체&lt;/td&gt;&lt;td&gt;&lt;em&gt;불가&lt;/em&gt;&lt;/td&gt;&lt;td&gt;자유&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;비용&lt;/td&gt;&lt;td&gt;높음 ($0.06-0.20/min)&lt;/td&gt;&lt;td&gt;저렴 ($0.01-0.05/min)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Privacy&lt;/td&gt;&lt;td&gt;외부 API&lt;/td&gt;&lt;td&gt;자체 가능&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;한국어&lt;/td&gt;&lt;td&gt;OpenAI Realtime 우수&lt;/td&gt;&lt;td&gt;모델 선택&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;적합-시나리오&quot;&gt;적합 시나리오&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q{용도}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|&quot;친밀한 대화 (외국어 학습)&quot;| S2S&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|&quot;complex tool calling (예약, 결제)&quot;| Cascade[Cascading streaming]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|MVP / 다국어| S2S&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|비용 critical + 대량| Cascade&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|&quot;커스텀 LLM (자체 모델)&quot;| Cascade&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;function-calling-제약&quot;&gt;Function Calling 제약&lt;/h2&gt;
&lt;p&gt;OpenAI Realtime API 의 &lt;em&gt;function calling&lt;/em&gt; 은 지원하지만:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;모델이 &lt;em&gt;function call 중 음성 응답 안 함&lt;/em&gt; (텍스트 → 음성 변환 별도 처리)&lt;/li&gt;
&lt;li&gt;복잡한 &lt;em&gt;멀티 단계 reasoning&lt;/em&gt; 은 약함&lt;/li&gt;
&lt;li&gt;&lt;em&gt;enterprise 시스템 통합&lt;/em&gt; 은 cascading 이 더 안정&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;em&gt;S2S 모델 다수가 function calling 미지원&lt;/em&gt;. &lt;em&gt;function 이 필수인 enterprise&lt;/em&gt; 는 &lt;em&gt;cascading streaming&lt;/em&gt; 채택 (arXiv 참조).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;비용-비교&quot;&gt;비용 비교&lt;/h2&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;모델&lt;/th&gt;&lt;th&gt;가격&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;OpenAI Realtime (gpt-4o)&lt;/td&gt;&lt;td&gt;input $40/M tok, output $80/M tok&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Gemini Live&lt;/td&gt;&lt;td&gt;input $0.50/M, output $2.00/M&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cascading (Whisper + GPT-4o-mini + Cartesia)&lt;/td&gt;&lt;td&gt;~$0.01/min&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;Realtime API 가 &lt;em&gt;5-10배 비싸다&lt;/em&gt;. 비용 sensitive 면 cascading.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;모든 시나리오에 S2S&lt;/strong&gt; = 비용 폭증 + function 제약. 용도 분석 후.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebRTC 설정 복잡&lt;/strong&gt; = Signaling, ICE, TURN. SDK 사용.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;한국어 발음&lt;/strong&gt; = 모델 마다 차이 큼. &lt;em&gt;audio sample&lt;/em&gt; 직접 들어보고 선택.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Realtime API 의 session 종료&lt;/strong&gt; = idle 시 자동 종료. heartbeat 필요.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[voice-agent-architecture]]&lt;/li&gt;
&lt;li&gt;[[webrtc]]&lt;/li&gt;
&lt;li&gt;[[tts-models-overview]]&lt;/li&gt;
&lt;li&gt;[[function-calling-tool-use]]&lt;/li&gt;
&lt;li&gt;[[pipecat-livekit]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>s2s</category><category>realtime-api</category><category>gpt-4o</category><category>gemini-live</category><category>moshi</category><category>voice-llm</category><author>koa (김신건)</author></item><item><title>[Voice AI] STT 모델: Whisper, Deepgram, AssemblyAI, CLOVA</title><link>https://shinkeonkim.com/wiki/voice/stt-models-overview/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/voice/stt-models-overview/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;STT (Speech-to-Text) / ASR (Automatic Speech Recognition)&lt;/strong&gt; = &lt;em&gt;음성 → 텍스트&lt;/em&gt; 변환. 2026 시점 &lt;em&gt;전사 정확도 인간 수준&lt;/em&gt;, &lt;em&gt;실시간 &amp;#x3C; 300ms&lt;/em&gt; 도 흔함.&lt;/p&gt;
&lt;h2 id=&quot;주요-모델-매트릭스-2026&quot;&gt;주요 모델 매트릭스 (2026)&lt;/h2&gt;

























































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;모델&lt;/th&gt;&lt;th&gt;종류&lt;/th&gt;&lt;th&gt;한국어&lt;/th&gt;&lt;th&gt;스트리밍&lt;/th&gt;&lt;th&gt;강점&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;OpenAI Whisper v3&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;open weights&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;&lt;em&gt;batch&lt;/em&gt; (스트리밍 별도)&lt;/td&gt;&lt;td&gt;99 언어, 견고, &lt;em&gt;self-host&lt;/em&gt; 가능&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Whisper-Live / WhisperX&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;OSS 변형&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;가능&lt;/td&gt;&lt;td&gt;자체 호스팅 + VAD&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Deepgram Nova-3&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;보통&lt;/td&gt;&lt;td&gt;&lt;em&gt;최강&lt;/em&gt; (300ms)&lt;/td&gt;&lt;td&gt;멀티턴, diarization, latency&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;AssemblyAI Universal-2&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;보통&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;다국어, multispeaker, 가격 경쟁력&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Google Speech-to-Text v2&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;한국어 정확도, telephony 특화&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Azure Speech&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;enterprise 통합&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Naver CLOVA Speech&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;&lt;em&gt;압도적&lt;/em&gt;&lt;/td&gt;&lt;td&gt;gRPC, &amp;#x3C; 1s&lt;/td&gt;&lt;td&gt;&lt;em&gt;한국어 1위&lt;/em&gt;, 도메인 사전&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Kakao i Speech&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;가능&lt;/td&gt;&lt;td&gt;한국어 + 카카오 생태계&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Faster-Whisper / Distil-Whisper&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;OSS&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;가능&lt;/td&gt;&lt;td&gt;&lt;em&gt;Whisper 의 4x 속도&lt;/em&gt; + 작은 모델&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;NVIDIA NeMo Parakeet&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;open&lt;/td&gt;&lt;td&gt;영어&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;edge, low-latency&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GPT-4o transcribe&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;가능&lt;/td&gt;&lt;td&gt;GPT-4o 의 audio 통합&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;whisper-의-위치&quot;&gt;Whisper 의 위치&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Whisper[&quot;Whisper v3 (2023, OpenAI)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Whisper --&gt; Vanilla[&quot;원본 (PyTorch)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Whisper --&gt; Faster[&quot;Faster-Whisper (CTranslate2)&amp;#x3C;br/&gt;~4x 빠름&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Whisper --&gt; Distil[&quot;Distil-Whisper&amp;#x3C;br/&gt;~6x 빠름, 49% 작음&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Whisper --&gt; WhisperX[&quot;WhisperX&amp;#x3C;br/&gt;+ word-level timestamps + diarization&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Whisper --&gt; Live[&quot;WhisperLive / WhisperLink&amp;#x3C;br/&gt;스트리밍 wrapper&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;2026 시점 &lt;em&gt;자체 호스팅 = Faster-Whisper + Silero VAD&lt;/em&gt; 가 거의 표준. Distil-Whisper 가 &lt;em&gt;영어 한정&lt;/em&gt; 으로 더 빠름.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;모델-사이즈-vs-정확도-vs-속도-whisper&quot;&gt;모델 사이즈 vs 정확도 vs 속도 (Whisper)&lt;/h2&gt;
&lt;!-- mdx-component: ChartJs --&gt;
&lt;h2 id=&quot;한국어-stt-선택-가이드&quot;&gt;한국어 STT 선택 가이드&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q{환경}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|관리형 + 한국어 최고 정확도| CLOVA[Naver CLOVA Speech]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|관리형 + 다국어 동시| Deepgram[Deepgram / AssemblyAI]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|자체 호스팅 + 적당히| Faster[Faster-Whisper large-v3]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|Edge / 모바일| Distil[Distil-Whisper small]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|음성+텍스트 통합 LLM| GPT4o[GPT-4o Realtime API]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
한국어 &lt;em&gt;전사 정확도&lt;/em&gt; = CLOVA &gt; Whisper-large-v3 &gt; Google &gt; Deepgram. 단 &lt;em&gt;latency&lt;/em&gt; 는 정반대.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;diarization-화자-분리&quot;&gt;Diarization (화자 분리)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;안녕하세요&quot;          → speaker_1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;네 안녕하세요&quot;        → speaker_2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;오늘 회의 시작합니다&quot;  → speaker_1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;도구&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;pyannote.audio&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;OSS, Hugging Face&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;WhisperX&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Whisper + pyannote&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;AssemblyAI&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API 내장&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Deepgram&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API 내장&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;api-vs-self-host&quot;&gt;API vs Self-host&lt;/h2&gt;








































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;API (Deepgram, AssemblyAI)&lt;/th&gt;&lt;th&gt;Self-host (Whisper)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Latency&lt;/td&gt;&lt;td&gt;매우 낮음 (300ms 가능)&lt;/td&gt;&lt;td&gt;GPU + 튜닝 필요&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;비용&lt;/td&gt;&lt;td&gt;분당 $0.005-0.015&lt;/td&gt;&lt;td&gt;GPU 시간&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Privacy&lt;/td&gt;&lt;td&gt;데이터 외부&lt;/td&gt;&lt;td&gt;내부&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;가용성&lt;/td&gt;&lt;td&gt;99.9% SLA&lt;/td&gt;&lt;td&gt;자체 운영&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;커스터마이즈&lt;/td&gt;&lt;td&gt;제한&lt;/td&gt;&lt;td&gt;자유 (fine-tune)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;한국어&lt;/td&gt;&lt;td&gt;CLOVA, Google&lt;/td&gt;&lt;td&gt;Whisper-large 충분&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;평가-지표&quot;&gt;평가 지표&lt;/h2&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;지표&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;WER&lt;/strong&gt; (Word Error Rate)&lt;/td&gt;&lt;td&gt;단어 단위 오류율&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CER&lt;/strong&gt; (Character Error Rate)&lt;/td&gt;&lt;td&gt;문자 단위 (한국어/중국어 적합)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;RTF&lt;/strong&gt; (Real-Time Factor)&lt;/td&gt;&lt;td&gt;처리 시간 / 오디오 시간&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TTF&lt;/strong&gt; (Time to Final)&lt;/td&gt;&lt;td&gt;발화 종료 → final transcript&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TTP&lt;/strong&gt; (Time to Partial)&lt;/td&gt;&lt;td&gt;첫 partial 까지&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Whisper batch 모드를 스트리밍처럼&lt;/strong&gt; = &lt;em&gt;전체 오디오 받고서&lt;/em&gt; 시작. 실시간 X.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;언어 자동 감지&lt;/strong&gt; = 짧은 발화에서 오류. &lt;em&gt;언어 명시&lt;/em&gt; 권장 (&lt;code&gt;language=&quot;ko&quot;&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hallucination&lt;/strong&gt; (Whisper) = 무음 / 노이즈 구간에서 &lt;em&gt;없는 문장 생성&lt;/em&gt;. VAD 전처리 필수.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sample rate&lt;/strong&gt; = 16kHz 표준. 44.1kHz / 48kHz 보내면 &lt;em&gt;내부 resampling 추가 latency&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[stt-streaming]]&lt;/li&gt;
&lt;li&gt;[[tts-models-overview]]&lt;/li&gt;
&lt;li&gt;[[voice-agent-architecture]]&lt;/li&gt;
&lt;li&gt;[[vad-silero]]&lt;/li&gt;
&lt;li&gt;[[Redis Vector Search]] (transcript indexing)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>stt</category><category>asr</category><category>voice</category><category>whisper</category><category>deepgram</category><category>assemblyai</category><author>koa (김신건)</author></item><item><title>[Voice AI] STT 스트리밍: partial vs final, endpointing, gRPC/WS</title><link>https://shinkeonkim.com/wiki/voice/stt-streaming/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/voice/stt-streaming/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;스트리밍 STT&lt;/strong&gt; = &lt;em&gt;오디오 청크&lt;/em&gt; 가 들어올 때마다 &lt;em&gt;부분 결과 (partial)&lt;/em&gt; 를 즉시 반환 + &lt;em&gt;발화 종료&lt;/em&gt; 시 &lt;em&gt;최종 결과 (final)&lt;/em&gt; 확정.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;em&gt;대화형 음성 AI 의 첫 단계&lt;/em&gt;. &lt;strong&gt;종단 지연 1초 미만&lt;/strong&gt; 의 &lt;em&gt;시작점&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;partial-vs-final&quot;&gt;partial vs final&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    autonumber&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    participant Mic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    participant STT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    participant App&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Mic-&gt;&gt;STT: chunk 1 (100ms)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    STT--&gt;&gt;App: partial: &quot;안녕&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Mic-&gt;&gt;STT: chunk 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    STT--&gt;&gt;App: partial: &quot;안녕하세&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Mic-&gt;&gt;STT: chunk 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    STT--&gt;&gt;App: partial: &quot;안녕하세요&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Mic-&gt;&gt;STT: chunk 4 (침묵)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Note over STT: endpoint 감지&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    STT--&gt;&gt;App: FINAL: &quot;안녕하세요&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    App-&gt;&gt;App: LLM 호출&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;partial (interim)&lt;/th&gt;&lt;th&gt;final&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;의미&lt;/td&gt;&lt;td&gt;&lt;em&gt;현재 추정&lt;/em&gt; (변경 가능)&lt;/td&gt;&lt;td&gt;&lt;em&gt;확정&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;빈도&lt;/td&gt;&lt;td&gt;매 100-300ms&lt;/td&gt;&lt;td&gt;endpointing 후 1회&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;정확도&lt;/td&gt;&lt;td&gt;낮음 (변경됨)&lt;/td&gt;&lt;td&gt;높음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;사용&lt;/td&gt;&lt;td&gt;UI 라이브 자막&lt;/td&gt;&lt;td&gt;LLM 호출, action&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!CAUTION]
&lt;em&gt;partial 로 LLM 호출 금지&lt;/em&gt;. &lt;em&gt;반복 호출 + 변경된 텍스트&lt;/em&gt; → 낭비 + 일관성 깨짐.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;endpointing-발화-종료-감지&quot;&gt;Endpointing (발화 종료 감지)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;사용자 침묵 → 얼마나 기다린 후 final?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;전략&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;에너지 기반 VAD&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;침묵 N ms 후 종료&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;신경망 VAD (Silero)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;음성/비음성 확률 기반&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;시맨틱 endpointing&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;문장 의미 + VAD (LiveKit 0.4)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;고정 timeout&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;무조건 N초 후&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;일반: 침묵 500-800ms 후 final&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;short: 200-400ms (빠른 대화)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;long: 1000-1500ms (사용자가 멈춤 많음)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;시맨틱-endpointing-의-가치&quot;&gt;시맨틱 endpointing 의 가치&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;❌ 순수 VAD: &quot;내 번호는 010-...&quot; [500ms 침묵] → final &quot;내 번호는 010&quot; → 사용자 끊김!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;✓ 시맨틱: &quot;내 번호는 010-1234-5678&quot; 까지 *기다림* (전화번호 패턴 인식)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;LiveKit, Pipecat 의 자체 모델&lt;/em&gt; 이 &lt;em&gt;오디오 + 텍스트&lt;/em&gt; 보고 &lt;em&gt;~300ms&lt;/em&gt; 까지 단축.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;프로토콜-websocket-vs-grpc&quot;&gt;프로토콜: WebSocket vs gRPC&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Client[Client] --&gt;|WebSocket binary frames| Server1[&quot;STT (WebSocket)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Client --&gt;|gRPC stream| Server2[&quot;STT (gRPC)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Client --&gt;|HTTP/2 + chunks| Server3[&quot;STT (HTTP/2)&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;프로토콜&lt;/th&gt;&lt;th&gt;장점&lt;/th&gt;&lt;th&gt;단점&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;WebSocket&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;브라우저 native, 단순&lt;/td&gt;&lt;td&gt;텍스트/binary 혼합 어색&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;gRPC bidi-stream&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;binary 효율적, schema&lt;/td&gt;&lt;td&gt;브라우저는 grpc-web 필요&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;HTTP/2 chunked&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;표준&lt;/td&gt;&lt;td&gt;session 관리 직접&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;2026 시점 &lt;em&gt;서버↔서버 = gRPC&lt;/em&gt; (CLOVA, Google), &lt;em&gt;브라우저↔서버 = WebSocket&lt;/em&gt; (Deepgram, AssemblyAI) 분기.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;websocket-예시-deepgram&quot;&gt;WebSocket 예시 (Deepgram)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ws&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; WebSocket&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;wss://api.deepgram.com/v1/listen?model=nova-3&amp;#x26;language=ko&amp;#x26;interim_results=true&amp;#x26;endpointing=500&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ws.binaryType &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;arraybuffer&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ws.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;onmessage&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; data&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; JSON&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(e.data);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (data.channel?.alternatives[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; transcript&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; data.channel.alternatives[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].transcript;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; isFinal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; data.is_final;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (isFinal) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      onFinalTranscript&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(transcript);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      onPartial&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(transcript);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 마이크 → WebSocket 오디오 청크&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; audioContext&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AudioContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ sampleRate: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;16000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; processor&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; audioContext.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;createScriptProcessor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2048&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;processor.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;onaudioprocess&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; pcm&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; float32To16BitPCM&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(e.inputBuffer.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getChannelData&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  ws.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(pcm);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;grpc-예시-clova-python&quot;&gt;gRPC 예시 (CLOVA, Python)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; grpc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nest_pb2, nest_pb2_grpc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; request_generator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(audio_stream):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    yield&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nest_pb2.NestRequest(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;nest_pb2.RequestType.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;CONFIG&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        config&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;nest_pb2.NestConfig(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;            language&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;ko-KR&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;            sample_rate&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;16000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;            encoding&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;nest_pb2.AudioEncoding.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;LINEAR16&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; audio_stream:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        yield&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nest_pb2.NestRequest(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;            type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;nest_pb2.RequestType.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;AUDIO&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;            audio&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;chunk,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; grpc.secure_channel(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;clovaspeech-gw.ncloud.com:443&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, creds) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; channel:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    stub &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nest_pb2_grpc.NestServiceStub(channel)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    metadata &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;authorization&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Bearer &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;token&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; response &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stub.Recognize(request_generator(audio_iter), &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;metadata&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;metadata):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; response.is_final:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;FINAL:&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, response.transcript)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;partial:&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, response.transcript)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;지표&quot;&gt;지표&lt;/h2&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;지표&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;th&gt;목표&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TTP&lt;/strong&gt; (Time-to-Partial)&lt;/td&gt;&lt;td&gt;첫 partial 까지&lt;/td&gt;&lt;td&gt;&amp;#x3C; 200ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TTF&lt;/strong&gt; (Time-to-Final)&lt;/td&gt;&lt;td&gt;발화 종료 → final&lt;/td&gt;&lt;td&gt;&amp;#x3C; 500ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TTL&lt;/strong&gt; (Time-to-Last partial)&lt;/td&gt;&lt;td&gt;마지막 partial 까지&lt;/td&gt;&lt;td&gt;&amp;#x3C; 100ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Stability&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;partial 의 변경 빈도&lt;/td&gt;&lt;td&gt;&amp;#x3C; 5%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;자세한 latency 분석은 [[latency-percentiles]].&lt;/p&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;partial 로 LLM 호출&lt;/strong&gt; = 낭비. final 까지 기다리거나 &lt;em&gt;시맨틱 endpointing&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;endpointing 너무 김 (1.5초+)&lt;/strong&gt; = 대화 어색. 사용자가 &lt;em&gt;답답함&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;endpointing 너무 짧음 (200ms)&lt;/strong&gt; = 사용자 &lt;em&gt;말끊김&lt;/em&gt;. 시맨틱 권장.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebSocket idle timeout&lt;/strong&gt; = 침묵 시 connection close. ping/pong 주기적.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;언어 자동 감지&lt;/strong&gt; = 짧은 발화 / 다국어 혼용 시 깨짐. &lt;em&gt;명시&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[stt-models-overview]]&lt;/li&gt;
&lt;li&gt;[[vad-silero]]&lt;/li&gt;
&lt;li&gt;[[turn-detection-barge-in]]&lt;/li&gt;
&lt;li&gt;[[voice-agent-architecture]]&lt;/li&gt;
&lt;li&gt;[[WebSocket]]&lt;/li&gt;
&lt;li&gt;[[gRPC]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>stt</category><category>streaming</category><category>asr</category><category>partial</category><category>final</category><category>endpointing</category><author>koa (김신건)</author></item><item><title>[Voice AI] TTS 모델: ElevenLabs, Cartesia, Edge TTS, 한국어</title><link>https://shinkeonkim.com/wiki/voice/tts-models-overview/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/voice/tts-models-overview/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;TTS (Text-to-Speech)&lt;/strong&gt; = &lt;em&gt;텍스트 → 음성&lt;/em&gt; 합성. 2026 시점 &lt;em&gt;사람과 구분 어려운 자연도&lt;/em&gt; + &lt;em&gt;&amp;#x3C; 200ms first audio&lt;/em&gt; + &lt;em&gt;voice cloning&lt;/em&gt; 표준.&lt;/p&gt;
&lt;h2 id=&quot;뉴럴-tts-구조&quot;&gt;뉴럴 TTS 구조&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Text[&quot;텍스트&quot;] --&gt; Norm[&quot;Text Normalization&amp;#x3C;br/&gt;(숫자, 약어, 발음 사전)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Norm --&gt; Front[&quot;Front-end&amp;#x3C;br/&gt;(grapheme → phoneme)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Front --&gt; Acoustic[&quot;Acoustic Model&amp;#x3C;br/&gt;(mel-spectrogram)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Acoustic --&gt; Vocoder[&quot;Vocoder&amp;#x3C;br/&gt;(mel → waveform)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Vocoder --&gt; Audio[음성 wav]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;단계&lt;/th&gt;&lt;th&gt;역할&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Normalization&lt;/td&gt;&lt;td&gt;”100$” → “백 달러”&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;G2P&lt;/td&gt;&lt;td&gt;grapheme → phoneme&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Acoustic&lt;/td&gt;&lt;td&gt;Tacotron2, FastSpeech2, VITS, Glow-TTS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Vocoder&lt;/td&gt;&lt;td&gt;HiFi-GAN, WaveNet, BigVGAN&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;통합&lt;/td&gt;&lt;td&gt;VITS, StyleTTS2 (end-to-end)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;2026 시점 &lt;em&gt;상용 TTS 는 거의 모두 end-to-end&lt;/em&gt; (acoustic + vocoder 통합). Diffusion 기반도 활발.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;주요-모델-매트릭스-2026&quot;&gt;주요 모델 매트릭스 (2026)&lt;/h2&gt;













































































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;모델&lt;/th&gt;&lt;th&gt;종류&lt;/th&gt;&lt;th&gt;한국어&lt;/th&gt;&lt;th&gt;TTFB&lt;/th&gt;&lt;th&gt;클로닝&lt;/th&gt;&lt;th&gt;강점&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ElevenLabs v3&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;200-400ms&lt;/td&gt;&lt;td&gt;&lt;em&gt;수초 샘플&lt;/em&gt;&lt;/td&gt;&lt;td&gt;자연도 1위, 다국어, 감정&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Cartesia Sonic-2&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;보통&lt;/td&gt;&lt;td&gt;&lt;strong&gt;&amp;#x3C; 90ms&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;가능&lt;/td&gt;&lt;td&gt;&lt;em&gt;최저 latency&lt;/em&gt;, 실시간 voice agent 표준&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;OpenAI TTS-1-HD / GPT-4o TTS&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;300-500ms&lt;/td&gt;&lt;td&gt;제한&lt;/td&gt;&lt;td&gt;GPT 통합&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Google Cloud TTS&lt;/strong&gt; (Studio voices)&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;300ms&lt;/td&gt;&lt;td&gt;제한&lt;/td&gt;&lt;td&gt;안정성&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Azure Speech TTS&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;200-400ms&lt;/td&gt;&lt;td&gt;Custom Neural Voice&lt;/td&gt;&lt;td&gt;enterprise&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Microsoft Edge TTS&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;무료 (비공식 API)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;보통&lt;/td&gt;&lt;td&gt;X&lt;/td&gt;&lt;td&gt;&lt;em&gt;비용 0&lt;/em&gt;, edge-tts 패키지&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Naver CLOVA Voice&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;&lt;em&gt;최우수&lt;/em&gt;&lt;/td&gt;&lt;td&gt;200-400ms&lt;/td&gt;&lt;td&gt;가능&lt;/td&gt;&lt;td&gt;한국어 1위&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Typecast&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;적당&lt;/td&gt;&lt;td&gt;강력&lt;/td&gt;&lt;td&gt;한국 voice cloning&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Coqui XTTS-v2&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;OSS&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;self-host&lt;/td&gt;&lt;td&gt;&lt;em&gt;수초 샘플&lt;/em&gt;&lt;/td&gt;&lt;td&gt;자체 호스팅 + 클로닝&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;F5-TTS&lt;/strong&gt; (2024)&lt;/td&gt;&lt;td&gt;OSS&lt;/td&gt;&lt;td&gt;보통&lt;/td&gt;&lt;td&gt;self-host&lt;/td&gt;&lt;td&gt;가능&lt;/td&gt;&lt;td&gt;flow matching, 빠름&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;MaskGCT&lt;/strong&gt; (2024)&lt;/td&gt;&lt;td&gt;OSS&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;td&gt;self-host&lt;/td&gt;&lt;td&gt;가능&lt;/td&gt;&lt;td&gt;non-autoregressive&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;StyleTTS 2&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;OSS&lt;/td&gt;&lt;td&gt;영어&lt;/td&gt;&lt;td&gt;self-host&lt;/td&gt;&lt;td&gt;가능&lt;/td&gt;&lt;td&gt;high quality&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;ttfb-time-to-first-byte-비교&quot;&gt;TTFB (Time-to-First-Byte) 비교&lt;/h2&gt;
&lt;!-- mdx-component: ChartJs --&gt;
&lt;h2 id=&quot;edge-tts-microsoft-비공식-api&quot;&gt;Edge TTS (Microsoft 비공식 API)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; edge_tts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; asyncio&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    communicate &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; edge_tts.Communicate(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        text&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;안녕하세요. 음성 합성 테스트입니다.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;        voice&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ko-KR-SunHiNeural&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; communicate.save(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;output.mp3&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 스트리밍&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; stream_tts&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(text):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    communicate &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; edge_tts.Communicate(text, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;voice&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ko-KR-InJoonNeural&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; communicate.stream():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;audio&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            yield&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;장점&lt;/th&gt;&lt;th&gt;단점&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;em&gt;무료&lt;/em&gt;&lt;/td&gt;&lt;td&gt;Microsoft 정책 변경 위험&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;다국어 (한국어 4 음성)&lt;/td&gt;&lt;td&gt;rate limit 불명확&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;빠름&lt;/td&gt;&lt;td&gt;enterprise SLA 없음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;edge-tts 패키지 1줄&lt;/td&gt;&lt;td&gt;비공식 (API 변경 가능)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;em&gt;Edge TTS 는 비공식&lt;/em&gt;. Microsoft 가 &lt;em&gt;Edge 브라우저 의 read-aloud 기능&lt;/em&gt; 을 외부 사용. 상용 서비스 사용은 위험. &lt;em&gt;PoC, 개인 프로젝트&lt;/em&gt; 에 적합.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;한국어-tts-선택&quot;&gt;한국어 TTS 선택&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q{환경}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|상용 + 한국어 자연도 최고| CLOVA[CLOVA Voice]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|상용 + 클로닝 + 한국어| Typecast&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|상용 + 다국어 + 자연도| Eleven[ElevenLabs v3]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|상용 + 최저 latency| Cartesia&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|무료 + PoC| EdgeTTS[Edge TTS]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Q --&gt;|자체 호스팅 + 클로닝| XTTS[Coqui XTTS-v2 / F5-TTS]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;voice-cloning&quot;&gt;Voice Cloning&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Sample[&quot;3-10초 음성 샘플&quot;] --&gt; Encoder[Speaker Encoder]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Encoder --&gt; Embed[&quot;Speaker Embedding (256-dim)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Text --&gt; TTS[TTS 모델]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Embed --&gt; TTS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    TTS --&gt; Output[&quot;Cloned 음성&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;도구&lt;/th&gt;&lt;th&gt;샘플 길이&lt;/th&gt;&lt;th&gt;품질&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;ElevenLabs Instant Voice&lt;/td&gt;&lt;td&gt;1분&lt;/td&gt;&lt;td&gt;&lt;em&gt;최고&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ElevenLabs Professional Voice&lt;/td&gt;&lt;td&gt;30분+&lt;/td&gt;&lt;td&gt;정밀 (스튜디오 녹음)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;XTTS-v2&lt;/td&gt;&lt;td&gt;6초&lt;/td&gt;&lt;td&gt;좋음 (OSS)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;F5-TTS&lt;/td&gt;&lt;td&gt;10초&lt;/td&gt;&lt;td&gt;빠름&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Coqui (옛)&lt;/td&gt;&lt;td&gt;10분+&lt;/td&gt;&lt;td&gt;옛&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!CAUTION]
&lt;em&gt;허락 없는 voice cloning 은 법적 / 윤리적 문제&lt;/em&gt;. 공인 / 유명인 음성 무단 사용 금지. &lt;em&gt;생성 음성에 워터마크&lt;/em&gt; 권장 (Resemble AI 의 PerthNet 등).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;발음-교정-사전-lexicon&quot;&gt;발음 교정 사전 (lexicon)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&amp;#x3C;!-- SSML --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;lexicon&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; uri&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;https://example.com/lex.pls&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&amp;#x3C;!-- lex.pls --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;lexicon&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; xmlns&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;http://www.w3.org/2005/01/pronunciation-lexicon&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;lexeme&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;grapheme&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;Karatsuba&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;grapheme&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;phoneme&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;karatsˈuːba&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;phoneme&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;lexeme&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;lexicon&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;브랜드명, 인명, 기술 용어를 &lt;em&gt;정확히 발음&lt;/em&gt;. 자세한 SSML 은 [[tts-streaming-ssml]].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;평가-지표&quot;&gt;평가 지표&lt;/h2&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;지표&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;MOS&lt;/strong&gt; (Mean Opinion Score)&lt;/td&gt;&lt;td&gt;1-5, 인간 평가&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CER&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;합성된 음성을 STT 로 다시 → 정확도&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TTFB&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;첫 오디오까지&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;RTF&lt;/strong&gt; (Real-Time Factor)&lt;/td&gt;&lt;td&gt;처리 시간 / 음성 시간 (&amp;#x3C; 1 = real-time 가능)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;WER&lt;/strong&gt; (TTS-STT round trip)&lt;/td&gt;&lt;td&gt;종합 정확도&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;TTFB 만 보고 선택&lt;/strong&gt; = 자연도 떨어지면 &lt;em&gt;사용자 외면&lt;/em&gt;. 둘 다 확인.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;숫자 발음&lt;/strong&gt; = “100” → “100” 또는 “백” 가는지 모델 마다 다름. SSML &lt;code&gt;&amp;#x3C;say-as&gt;&lt;/code&gt; 명시.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;긴 문장 한 번에&lt;/strong&gt; = 첫 오디오 지연. &lt;em&gt;문장 단위 청킹&lt;/em&gt; 후 스트리밍. 자세한 건 [[tts-streaming-ssml]].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;클로닝 음질&lt;/strong&gt; = 샘플 노이즈에 민감. &lt;em&gt;조용한 환경 + 16kHz+ 녹음&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[tts-streaming-ssml]]&lt;/li&gt;
&lt;li&gt;[[stt-models-overview]]&lt;/li&gt;
&lt;li&gt;[[voice-agent-architecture]]&lt;/li&gt;
&lt;li&gt;[[speech-to-speech-realtime]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>tts</category><category>voice-synthesis</category><category>neural-tts</category><category>voice-cloning</category><category>korean</category><author>koa (김신건)</author></item><item><title>[Voice AI] TTS 스트리밍 + SSML: TTFB, sentence aggregation, 청킹</title><link>https://shinkeonkim.com/wiki/voice/tts-streaming-ssml/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/voice/tts-streaming-ssml/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;TTS 스트리밍&lt;/strong&gt; = 텍스트 &lt;em&gt;일부만 받아도 즉시 합성&lt;/em&gt; + 오디오 &lt;em&gt;청크 단위 전송&lt;/em&gt;. &lt;em&gt;TTFB (Time-to-First-Audio)&lt;/em&gt; 최소화 = 대화 자연스러움의 핵심.&lt;/p&gt;
&lt;h2 id=&quot;ttfb-의-중요성&quot;&gt;TTFB 의 중요성&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM[LLM 토큰] --&gt;|&quot;문장 1: &apos;A.&apos;&quot;| TTS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    TTS --&gt;|즉시 합성 시작| Audio1[오디오 청크]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM --&gt;|&quot;문장 2: &apos;B.&apos;&quot;| TTS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    TTS --&gt;|병렬| Audio2[오디오 청크]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Audio1 --&gt; Speaker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Audio2 --&gt; Speaker&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;em&gt;사람 대화는 응답 &amp;#x3C; 500ms&lt;/em&gt;. TTS 가 &lt;em&gt;문장 전체 끝나고 합성 시작&lt;/em&gt; 하면 (예: 5초 응답) → 5초 + 합성 latency = &lt;em&gt;불가능&lt;/em&gt;. &lt;strong&gt;문장 단위 스트리밍&lt;/strong&gt; 필수.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;sentence-aggregation&quot;&gt;Sentence Aggregation&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    autonumber&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    participant LLM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    participant Agg as Sentence Aggregator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    participant TTS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM-&gt;&gt;Agg: &quot;안녕&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM-&gt;&gt;Agg: &quot;하세요&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM-&gt;&gt;Agg: &quot;, 오늘&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM-&gt;&gt;Agg: &quot; 날씨가&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM-&gt;&gt;Agg: &quot; 좋네요.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Note over Agg: &apos;.&apos; 감지 → 문장 완성&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agg-&gt;&gt;TTS: &quot;안녕하세요, 오늘 날씨가 좋네요.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    TTS--&gt;&gt;App: 오디오 chunk 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    TTS--&gt;&gt;App: 오디오 chunk 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM-&gt;&gt;Agg: &quot;더 도와드릴까요?&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Note over Agg: &apos;?&apos; 감지&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agg-&gt;&gt;TTS: &quot;더 도와드릴까요?&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SentenceAggregator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; __init__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.buffer &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.delimiters &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;.!?。!?&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; feed&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, token: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.buffer &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; token&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        # 문장 끝 감지&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i, ch &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; enumerate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.buffer):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ch &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.delimiters:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                # 다음 글자가 공백 또는 끝 → 문장 종료&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.buffer) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; or&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.buffer[i&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    sentence &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.buffer[:i&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;].strip()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;                    self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.buffer &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.buffer[i&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:].lstrip()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sentence&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; None&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Pipecat / LiveKit 의 &lt;em&gt;내장 sentence aggregator&lt;/em&gt;. 직접 구현도 어렵지 않음.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;ssml-speech-synthesis-markup-language&quot;&gt;SSML (Speech Synthesis Markup Language)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;speak&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; version&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;1.1&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; xml:lang&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ko-KR&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  안녕하세요. &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; time&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;300ms&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  오늘 회의는 &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;emphasis&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; level&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;strong&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;오후 3시&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;emphasis&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;입니다.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;prosody&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; rate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;slow&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; pitch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;+2st&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;천천히 또박또박 말합니다.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;prosody&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  주문 번호는 &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;say-as&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; interpret-as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;characters&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;A1B2&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;say-as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;입니다.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  금액은 &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;say-as&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; interpret-as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;currency&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; language&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ko-KR&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;1500000&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;say-as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;원입니다.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;speak&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;주요-ssml-태그&quot;&gt;주요 SSML 태그&lt;/h2&gt;

























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;태그&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;break time=&quot;500ms&quot;/&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;일시 정지&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;emphasis level=&quot;strong&quot;&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;강조 (강/중/약)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;prosody rate=&quot;slow&quot; pitch=&quot;+2st&quot; volume=&quot;loud&quot;&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;운율 (속도, 높낮이, 음량)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;say-as interpret-as=&quot;characters&quot;&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;글자 하나씩 (A1B2 → A 1 B 2)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;say-as interpret-as=&quot;currency&quot;&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;통화&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;say-as interpret-as=&quot;date&quot;&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;날짜&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;say-as interpret-as=&quot;time&quot;&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;시간&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;say-as interpret-as=&quot;telephone&quot;&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;전화번호&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;phoneme alphabet=&quot;ipa&quot; ph=&quot;kæɹətsˈuːba&quot;&gt;Karatsuba&amp;#x3C;/phoneme&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;음소 직접 명시&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;sub alias=&quot;에이아이&quot;&gt;AI&amp;#x3C;/sub&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;대체 발음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;voice name=&quot;...&quot;&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;음성 변경&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;lang xml:lang=&quot;en-US&quot;&gt;Hello&amp;#x3C;/lang&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;다국어&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;스트리밍-프로토콜&quot;&gt;스트리밍 프로토콜&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM --&gt;|토큰 stream| Agg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agg --&gt;|&quot;문장 (Server-Sent Events)&quot;| TTS_API[TTS API]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    TTS_API --&gt;|&quot;오디오 청크 (chunked HTTP / WebSocket)&quot;| Player[Audio Player]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;프로토콜&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;chunked HTTP&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Transfer-Encoding: chunked&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;SSE&lt;/strong&gt; (Server-Sent Events)&lt;/td&gt;&lt;td&gt;&lt;code&gt;text/event-stream&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;WebSocket&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;양방향, 실시간&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;gRPC stream&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;효율적, schema&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;오디오-청크-형식&quot;&gt;오디오 청크 형식&lt;/h2&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;형식&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;PCM 16-bit 16kHz&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;가장 작음 + 즉시 재생&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;MP3&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;압축 + 일반&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Opus&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;효율적 + 음질&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;AAC&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;iOS 호환성&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;WebM Opus&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;브라우저 native&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;실시간 voice agent = &lt;em&gt;PCM 또는 Opus&lt;/em&gt; 표준. MP3 는 encoder buffer 때문에 latency 추가.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;elevenlabs-스트리밍-예시&quot;&gt;ElevenLabs 스트리밍 예시&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; stream_tts&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(text, voice_id):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    url &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;https://api.elevenlabs.io/v1/text-to-speech/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;voice_id&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/stream&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    headers &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;xi-api-key&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;API_KEY&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    body &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;text&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: text,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;model_id&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;eleven_turbo_v2_5&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;voice_settings&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;stability&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;similarity_boost&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.75&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;        &quot;output_format&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;pcm_16000&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    resp &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; requests.post(url, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;body, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;headers&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;headers, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;stream&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; resp.iter_content(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;chunk_size&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1024&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        yield&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 즉시 재생기로 push&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;cartesia-스트리밍-websocket&quot;&gt;Cartesia 스트리밍 (WebSocket)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ws&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; WebSocket&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;wss://api.cartesia.ai/tts/websocket&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ws.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;JSON&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stringify&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  model_id: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;sonic-2&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  voice: { mode: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, id: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;voice_id_xyz&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  output_format: { container: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;raw&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, encoding: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;pcm_s16le&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, sample_rate: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;16000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  language: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;ko&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  transcript: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;continue&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// streaming mode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 문장 단위 push&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ws.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;JSON&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stringify&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ transcript: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;안녕하세요. &apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, continue: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ws.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;JSON&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stringify&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ transcript: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;오늘 날씨가 좋네요.&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, continue: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ws.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;onmessage&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // binary audio chunk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  player.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;feed&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(e.data);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;발음-제어-패턴&quot;&gt;발음 제어 패턴&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 숫자 → 한국어 변환&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;text &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;주문번호 1234&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ssml &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;&amp;#x3C;speak&gt;주문번호 &amp;#x3C;say-as interpret-as=&quot;characters&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;order_id&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&amp;#x3C;/say-as&gt;&amp;#x3C;/speak&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 금액&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amount &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1500000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ssml &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;&amp;#x3C;speak&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;원&amp;#x3C;/speak&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;   # 또는 say-as currency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 영문 약어&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ssml &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;&amp;#x3C;speak&gt;&amp;#x3C;sub alias=&quot;에이피아이&quot;&gt;API&amp;#x3C;/sub&gt; 키를 발급받았습니다.&amp;#x3C;/speak&gt;&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 강조&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ssml &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;&amp;#x3C;speak&gt;주문 번호는 &amp;#x3C;emphasis level=&quot;strong&quot;&gt;반드시&amp;#x3C;/emphasis&gt; 적어주세요.&amp;#x3C;/speak&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;전체 텍스트 받고 합성 시작&lt;/strong&gt; = 응답 5초 후 음성 시작. &lt;em&gt;문장 단위 streaming&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MP3 출력&lt;/strong&gt; = encoder buffer 100-300ms 추가. &lt;em&gt;PCM&lt;/em&gt; 또는 &lt;em&gt;Opus&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSML escape 안 함&lt;/strong&gt; = &lt;code&gt;&amp;#x3C;&lt;/code&gt;, &lt;code&gt;&amp;#x26;&lt;/code&gt; 가 본문에 있으면 &lt;em&gt;XML parse 에러&lt;/em&gt;. &lt;code&gt;xml.sax.saxutils.escape&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;너무 짧은 청크&lt;/strong&gt; = “안녕.” 만 합성 시 &lt;em&gt;자연도 떨어짐&lt;/em&gt;. 최소 &lt;em&gt;수 단어 단위&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;문장 분리 오인&lt;/strong&gt; = “Mr.” 의 &lt;code&gt;.&lt;/code&gt; 을 문장 종료로 인식. 약어 사전 또는 &lt;em&gt;최소 길이 + 휴리스틱&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[tts-models-overview]]&lt;/li&gt;
&lt;li&gt;[[voice-agent-architecture]]&lt;/li&gt;
&lt;li&gt;[[turn-detection-barge-in]]&lt;/li&gt;
&lt;li&gt;[[llm-serving-vllm]] (LLM 토큰 → SSE)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>tts</category><category>streaming</category><category>ssml</category><category>ttfb</category><category>prosody</category><author>koa (김신건)</author></item><item><title>[Voice AI] Turn Detection + Barge-in + AEC: 자연스러운 대화</title><link>https://shinkeonkim.com/wiki/voice/turn-detection-barge-in/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/voice/turn-detection-barge-in/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;자연스러운 음성 대화의 &lt;em&gt;3 요소&lt;/em&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Turn Detection&lt;/strong&gt; - 사용자가 &lt;em&gt;말끝났는지&lt;/em&gt; 정확히 판단&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Barge-in&lt;/strong&gt; - 에이전트가 말하는 &lt;em&gt;중에 사용자가 끼어들 수 있게&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AEC&lt;/strong&gt; - 에이전트의 &lt;em&gt;자기 음성을 자기 마이크에서 제거&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;1-turn-detection-시맨틱&quot;&gt;1. Turn Detection (시맨틱)&lt;/h2&gt;
&lt;h3 id=&quot;순수-vad-endpointing-의-한계&quot;&gt;순수 VAD endpointing 의 한계&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;내 전화번호는 010-1234-5678 입니다&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;VAD endpointing (500ms 침묵):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;내 전화번호는 010-&quot; [400ms 침묵, 사용자가 생각 중]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;→ FINAL &quot;내 전화번호는 010&quot; → 사용자 끊김!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;시맨틱-turn-detection&quot;&gt;시맨틱 Turn Detection&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Audio[Audio] --&gt; VAD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Audio --&gt; STT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    STT --&gt; Partial[Partial transcript]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD --&gt; Sil[Silence detected]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Partial --&gt; SemModel[&quot;Turn Detection Model&amp;#x3C;br/&gt;(오디오 + 텍스트)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Sil --&gt; SemModel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    SemModel --&gt; Decision{문장 종료 의도?}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Decision --&gt;|yes| End[Turn ended]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Decision --&gt;|no, 더 기다림| Wait[Continue waiting]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;오디오 prosody (운율) + 텍스트 의미&lt;/em&gt; 보고 &lt;em&gt;완성 문장인지&lt;/em&gt; 판단. ~300ms 까지 단축.&lt;/p&gt;
&lt;/blockquote&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;도구&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;LiveKit Turn Detection&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;자체 모델&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Pipecat End-of-utterance detector&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;통합&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Cartesia turn detection&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;API&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# LiveKit Agents 예시&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; livekit.agents &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; VoiceAssistant&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; livekit.plugins.turn_detector &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; EOUModel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;assistant &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; VoiceAssistant(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    vad&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;silero.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;VAD&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.load(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    stt&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;deepgram.STT(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    llm&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;openai.LLM(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    tts&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cartesia.TTS(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    turn_detector&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;EOUModel(),   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# End-of-utterance 시맨틱 모델&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    min_endpointing_delay&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    max_endpointing_delay&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3.0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;2-barge-in-끼어들기&quot;&gt;2. Barge-in (끼어들기)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sequenceDiagram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    autonumber&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User-&gt;&gt;Agent: &quot;오늘 날씨 어때?&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agent-&gt;&gt;User: &quot;오늘 서울은 맑고...&quot; (TTS 재생 중)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User-&gt;&gt;VAD: 발화 시작 (&quot;아 잠깐&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD-&gt;&gt;Agent: interruption 이벤트&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agent-&gt;&gt;TTS: cancel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agent-&gt;&gt;STT: 새 발화 처리&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User-&gt;&gt;Agent: &quot;근데 비 와?&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;barge-in-흐름&quot;&gt;Barge-in 흐름&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; VoiceAgent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; __init__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.tts_playing &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.tts_cancel &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; on_user_speech_start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.tts_playing:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            await&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.tts_cancel()       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 재생 중인 TTS 즉시 중단&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            await&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.flush_audio()       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 출력 buffer 비움&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.tts_playing &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; speak&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, text):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.tts_playing &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.tts.stream(text):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.cancel_event.is_set():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                    break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                await&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.send_audio(chunk)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        finally&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.tts_playing &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;disallow-interruptions-보호&quot;&gt;Disallow Interruptions (보호)&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Tool call (DB write 같은 되돌릴 수 없는 작업) 중에는 차단&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;@agent.function_tool&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; transfer_money&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(amount: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, to: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    with&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; disallow_interruptions():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; db.transfer(amount, to)        &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 끼어들기 금지&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;원이 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;to&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;님께 송금되었습니다.&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;em&gt;DB write&lt;/em&gt;, &lt;em&gt;외부 API 호출 (결제)&lt;/em&gt; 같은 &lt;em&gt;비가역 작업&lt;/em&gt; 중에는 &lt;em&gt;반드시 disallow_interruptions&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;3-echo-cancellation-aec&quot;&gt;3. Echo Cancellation (AEC)&lt;/h2&gt;
&lt;h3 id=&quot;문제-자기-목소리가-다시-마이크로&quot;&gt;문제: 자기 목소리가 다시 마이크로&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Speaker[스피커] --&gt; Air[공기]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Air -.echo.-&gt; Mic[마이크]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Mic --&gt; VAD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD --&gt;|에이전트 자기 목소리로 false positive| Interrupt[잘못된 interruption]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;해결-3계층&quot;&gt;해결 3계층&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    L1[1. 클라이언트: getUserMedia echoCancellation=true]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    L1 --&gt; L2[&quot;2. 디바이스: hardware AEC (이어폰 사용)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    L2 --&gt; L3[&quot;3. 서버: echo gate (TTS 재생 중 마이크 무시)&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;서버측-echo-gate&quot;&gt;서버측 Echo Gate&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; EchoGate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;&quot;&quot;TTS 재생 중 마이크 입력 무시 (or 감쇠)&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; __init__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, attenuation_db&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.tts_active &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.atten &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; **&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;attenuation_db &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; attenuate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, audio_chunk):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.tts_active:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; audio_chunk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.atten&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; audio_chunk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; on_tts_start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.tts_active &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; on_tts_end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.tts_active &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; False&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;[!CAUTION]
&lt;em&gt;순수 마이크 mute&lt;/em&gt; 면 &lt;em&gt;진짜 barge-in 도 막힘&lt;/em&gt;. &lt;em&gt;부분 감쇠 (20dB)&lt;/em&gt; + &lt;em&gt;VAD 임계값 상승&lt;/em&gt; 이 균형.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;4-sentence-aggregation-llm-토큰--tts-문장&quot;&gt;4. Sentence Aggregation (LLM 토큰 → TTS 문장)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SentenceAggregator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; feed_token&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, token):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.buffer &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; token&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.buffer.endswith(p) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;. &apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;! &apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;? &apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;。&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;!&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;?&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            sent &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.buffer.strip()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.buffer &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 사용&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; token &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; llm.stream(prompt):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    sent &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; aggregator.feed_token(token)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sent:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; audio &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tts.stream(sent):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            yield&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; audio&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;자세한 건 [[tts-streaming-ssml]].&lt;/p&gt;
&lt;h2 id=&quot;통합-흐름&quot;&gt;통합 흐름&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Mic --&gt; AEC[AEC + Noise]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    AEC --&gt; VAD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD --&gt; STT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    STT --&gt; TD[Turn Detection]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    TD --&gt;|&quot;complete utterance&quot;| LLM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LLM --&gt;|tokens| Agg[Sentence Aggregator]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Agg --&gt;|sentence| TTS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    TTS --&gt; Speaker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD -.barge-in.-&gt; Cancel[TTS cancel]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Cancel --&gt; TTS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;AEC 없이 스피커 출력&lt;/strong&gt; = 무한 루프 (자기 목소리 → STT → LLM → TTS → …). 이어폰 또는 echo gate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;순수 VAD endpointing 만&lt;/strong&gt; = 전화번호 / 주소 발화 시 끊김. 시맨틱 turn detection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Barge-in 시 TTS buffer 남음&lt;/strong&gt; = “끊었는데” 음성 1-2초 더 들림. &lt;em&gt;오디오 buffer flush&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sentence aggregation 너무 길게&lt;/strong&gt; = 첫 음성 지연. &lt;em&gt;문장 1-2개 단위&lt;/em&gt; (50-100 글자).&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[vad-silero]]&lt;/li&gt;
&lt;li&gt;[[stt-streaming]]&lt;/li&gt;
&lt;li&gt;[[tts-streaming-ssml]]&lt;/li&gt;
&lt;li&gt;[[voice-agent-architecture]]&lt;/li&gt;
&lt;li&gt;[[pipecat-livekit]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>turn-detection</category><category>barge-in</category><category>aec</category><category>duplex</category><category>voice-agent</category><author>koa (김신건)</author></item><item><title>[Voice AI] VAD: Silero, 에너지 기반, endpointing 임계값</title><link>https://shinkeonkim.com/wiki/voice/vad-silero/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/voice/vad-silero/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;VAD (Voice Activity Detection)&lt;/strong&gt; = 오디오 스트림에서 &lt;em&gt;음성 vs 비음성 (침묵, 노이즈)&lt;/em&gt; 구분. 음성 에이전트의 &lt;em&gt;발화 시작 / 종료&lt;/em&gt; 감지에 필수.&lt;/p&gt;
&lt;h2 id=&quot;종류&quot;&gt;종류&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD[VAD 종류]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD --&gt; Energy[&quot;Energy-based&amp;#x3C;br/&gt;(RMS, ZCR)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD --&gt; Spectral[Spectral feature]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD --&gt; Neural[&quot;Neural network&amp;#x3C;br/&gt;(Silero, Marble)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD --&gt; Webrtc[&quot;WebRTC VAD&amp;#x3C;br/&gt;(GMM)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Energy --&gt; Simple[&quot;단순, 빠름, 노이즈에 약함&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Neural --&gt; Robust[&quot;robust, 정확, 작은 모델&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;VAD&lt;/th&gt;&lt;th&gt;정확도&lt;/th&gt;&lt;th&gt;속도&lt;/th&gt;&lt;th&gt;노이즈 견고성&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Energy (RMS)&lt;/td&gt;&lt;td&gt;낮음&lt;/td&gt;&lt;td&gt;&lt;em&gt;매우 빠름&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;X&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WebRTC VAD (GMM)&lt;/td&gt;&lt;td&gt;보통&lt;/td&gt;&lt;td&gt;빠름&lt;/td&gt;&lt;td&gt;보통&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Silero VAD&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;em&gt;높음&lt;/em&gt;&lt;/td&gt;&lt;td&gt;빠름 (2MB)&lt;/td&gt;&lt;td&gt;&lt;em&gt;우수&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Marble VAD&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;매우 높음&lt;/td&gt;&lt;td&gt;보통&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Whisper VAD&lt;/td&gt;&lt;td&gt;매우 높음&lt;/td&gt;&lt;td&gt;&lt;em&gt;느림&lt;/em&gt;&lt;/td&gt;&lt;td&gt;우수&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;silero-vad-사실상-표준&quot;&gt;Silero VAD (사실상 표준)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; torch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;torch.set_num_threads(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;model, utils &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; torch.hub.load(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    repo_or_dir&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;snakers4/silero-vad&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    model&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;silero_vad&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    onnx&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;False&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 32ms 청크 (16kHz, 512 sample) 단위로 처리&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; is_speech&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(audio_chunk: torch.Tensor) -&gt; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;&quot;&quot;0.0 ~ 1.0 (음성 확률)&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; model(audio_chunk, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;16000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).item()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 실시간 처리&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;chunk_size &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 512&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;   # 32ms at 16kHz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;threshold &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0.5&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # 0.5 이상 → 음성&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; audio_stream:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    prob &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; is_speech(chunk)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; prob &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; threshold:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        on_voice_active()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        on_silence()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;silero-vad-특징&quot;&gt;Silero VAD 특징&lt;/h3&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;속성&lt;/th&gt;&lt;th&gt;값&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;모델 크기&lt;/td&gt;&lt;td&gt;&lt;em&gt;2MB&lt;/em&gt; (ONNX)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;입력&lt;/td&gt;&lt;td&gt;32ms 청크 (512 samples at 16kHz)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;추론 시간&lt;/td&gt;&lt;td&gt;&lt;em&gt;&amp;#x3C; 1ms&lt;/em&gt; on CPU&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;정확도&lt;/td&gt;&lt;td&gt;96%+ on LibriSpeech&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;라이센스&lt;/td&gt;&lt;td&gt;MIT&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
2026 시점 &lt;em&gt;voice agent VAD 의 사실상 표준&lt;/em&gt;. Silero VAD 가 &lt;em&gt;Pipecat, LiveKit Agents, faster-whisper-streaming&lt;/em&gt; 등의 &lt;em&gt;기본&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;endpointing-발화-종료-결정&quot;&gt;Endpointing (발화 종료 결정)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Audio[오디오 stream] --&gt; VAD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD --&gt; State{현재 상태}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    State --&gt;|음성 중| Speak[Speaking]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    State --&gt;|침묵 N ms 누적| End[Speech ended → final transcript trigger]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Speak --&gt;|침묵 시작| Track[Silence tracker]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Track --&gt;|N ms 경과| End&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Track --&gt;|다시 음성| Speak&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; EndpointDetector&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; __init__&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, silence_threshold_ms&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;700&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.silence_ms &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.threshold &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; silence_threshold_ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.in_speech &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; feed&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(self, vad_prob: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, chunk_ms: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 32&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        is_voice &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; vad_prob &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; is_voice:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.silence_ms &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;            self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.in_speech &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; True&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.in_speech:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;                self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.silence_ms &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk_ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.silence_ms &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.threshold:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;                    self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.in_speech &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                    return&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;speech_ended&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; None&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;endpointing-임계값-튜닝&quot;&gt;Endpointing 임계값 튜닝&lt;/h2&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;시나리오&lt;/th&gt;&lt;th&gt;silence ms&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;빠른 대화 (FAQ 봇)&lt;/td&gt;&lt;td&gt;300-500ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;일반 대화&lt;/td&gt;&lt;td&gt;&lt;em&gt;500-800ms&lt;/em&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;사용자가 천천히 말함 (고연령)&lt;/td&gt;&lt;td&gt;1000-1500ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;전화번호 / 주소 dictation&lt;/td&gt;&lt;td&gt;&lt;em&gt;시맨틱 endpointing&lt;/em&gt; (순수 VAD 부적합)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!CAUTION]
&lt;em&gt;순수 VAD endpointing 의 한계&lt;/em&gt;: “내 번호는 010…” [짧은 침묵] → final → 사용자 끊김. &lt;em&gt;시맨틱 turn detection&lt;/em&gt; 으로 보완. 자세한 건 [[turn-detection-barge-in]].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;노이즈-감쇠-전처리&quot;&gt;노이즈 감쇠 전처리&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Mic --&gt; NS[&quot;Noise Suppression&amp;#x3C;br/&gt;(RNNoise, Krisp, getUserMedia)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    NS --&gt; VAD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD --&gt; STT&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;도구&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;getUserMedia({ noiseSuppression: true })&lt;/code&gt;&lt;/td&gt;&lt;td&gt;브라우저 내장&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;RNNoise&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;OSS, 신경망 기반&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Krisp SDK&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;상용, 고성능&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;DeepFilterNet&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;OSS, real-time&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;vad-실패-시나리오&quot;&gt;VAD 실패 시나리오&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Fail[VAD 실패 케이스]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Fail --&gt; Bg[&quot;배경 음성 (TV, 다른 사람)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Fail --&gt; Whisper[&quot;속삭임&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Fail --&gt; Music[배경 음악]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Fail --&gt; NonSpeech[&quot;기침, 한숨, 침묵 호흡&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Fail --&gt; Bg --&gt; Sol1[&quot;방향성 마이크 + 화자 분리&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Fail --&gt; Whisper --&gt; Sol2[&quot;임계값 낮춤&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Fail --&gt; Music --&gt; Sol3[&quot;음악 vs 음성 분류기&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;getusermedia-옵션&quot;&gt;getUserMedia 옵션&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; stream&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; navigator.mediaDevices.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getUserMedia&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  audio: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    echoCancellation: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    noiseSuppression: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    autoGainControl: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    sampleRate: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;16000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    channelCount: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;브라우저 내장 신호처리&lt;/em&gt; 가 기본. 일부 OS 는 &lt;em&gt;덮어쓰기 안 됨&lt;/em&gt; (Chrome 의 hardware AEC).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;vad--stt-통합-패턴&quot;&gt;VAD + STT 통합 패턴&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Mic --&gt; VAD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD --&gt;|음성 시작| Open[STT WebSocket 연결]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD --&gt;|음성 청크| Forward[STT 로 전달]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD --&gt;|침묵 N ms| Close[STT close → final]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Close --&gt; LLM&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; voice_pipeline&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(mic_stream):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    vad &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; SileroVAD()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    endpoint &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; EndpointDetector(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;silence_threshold_ms&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;700&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    stt_ws &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    async&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; mic_stream:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        prob &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; vad.predict(chunk)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; prob &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0.5&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; and&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stt_ws:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            stt_ws &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connect_stt()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stt_ws:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stt_ws.send(chunk)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            transcript &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stt_ws.recv()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; transcript.is_final:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                yield&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; transcript.text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; endpoint.feed(prob)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;speech_ended&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; stt_ws.close()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            stt_ws &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; None&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;에너지 기반 VAD 의 한계&lt;/strong&gt; = 카페 / 키보드 소리에 활성. Silero 권장.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;임계값 0.5 그대로&lt;/strong&gt; = 환경에 따라 조정. &lt;em&gt;조용한 곳&lt;/em&gt; 은 0.3, &lt;em&gt;시끄러운 곳&lt;/em&gt; 은 0.7.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VAD 없이 STT&lt;/strong&gt; = 침묵 동안 &lt;em&gt;전사 못 끝남&lt;/em&gt; + 비용 폭증.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;chunk size 가 16/32ms 가 아님&lt;/strong&gt; = Silero 가 &lt;em&gt;512 samples (32ms at 16kHz)&lt;/em&gt; 만 받음. resampling 필요.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[turn-detection-barge-in]]&lt;/li&gt;
&lt;li&gt;[[stt-streaming]]&lt;/li&gt;
&lt;li&gt;[[voice-agent-architecture]]&lt;/li&gt;
&lt;li&gt;[[webrtc]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>vad</category><category>silero</category><category>voice-activity</category><category>endpointing</category><category>audio</category><author>koa (김신건)</author></item><item><title>[Voice] Neural TTS 내부: Tacotron, FastSpeech, VITS, HiFi-GAN</title><link>https://shinkeonkim.com/wiki/voice/tts-internals-neural/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/voice/tts-internals-neural/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;Neural TTS 의 &lt;em&gt;진화&lt;/em&gt;: 2단계 (acoustic + vocoder) → end-to-end. 2026 시점 &lt;em&gt;VITS 계열 + Flow matching&lt;/em&gt; 이 상용 표준.&lt;/p&gt;
&lt;p&gt;개요는 [[tts-models-overview]] 참고. 본 페이지는 &lt;em&gt;내부 아키텍처 + 코드&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;2단계-파이프라인-전통&quot;&gt;2단계 파이프라인 (전통)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Text[&quot;텍스트&quot;] --&gt; Front[&quot;Front-end (G2P, normalization)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Front --&gt; Phone[&quot;Phonemes&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Phone --&gt; Acoustic[&quot;Acoustic Model&amp;#x3C;br/&gt;(text → mel spectrogram)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Acoustic --&gt; Mel[&quot;Mel-spectrogram&amp;#x3C;br/&gt;(80 × T)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Mel --&gt; Vocoder[&quot;Vocoder&amp;#x3C;br/&gt;(mel → waveform)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Vocoder --&gt; Audio[&quot;오디오 (24kHz)&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;단계&lt;/th&gt;&lt;th&gt;대표 모델&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;G2P&lt;/td&gt;&lt;td&gt;Sequence-to-sequence, Phonemizer&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Acoustic&lt;/td&gt;&lt;td&gt;Tacotron 2, FastSpeech 2, Glow-TTS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Vocoder&lt;/td&gt;&lt;td&gt;WaveNet, WaveRNN, HiFi-GAN, BigVGAN&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;tacotron-2-2017-2018&quot;&gt;Tacotron 2 (2017-2018)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Char[&quot;Character embedding&quot;] --&gt; CNN[&quot;Conv layers&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    CNN --&gt; BiLSTM[&quot;Bidirectional LSTM&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    BiLSTM --&gt; Attn[&quot;Location-sensitive Attention&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Attn --&gt; Dec[&quot;LSTM Decoder (autoregressive)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Dec --&gt; Mel[&quot;Mel spectrogram&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Mel --&gt; WN[&quot;WaveNet vocoder&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    WN --&gt; Audio&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Autoregressive&lt;/strong&gt;: 매 mel frame 순차 생성.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Attention alignment&lt;/strong&gt;: text ↔ audio 매핑 학습.&lt;/li&gt;
&lt;li&gt;단점: &lt;em&gt;느림 (real-time factor &gt; 1)&lt;/em&gt;, &lt;em&gt;robustness 문제&lt;/em&gt; (repetition, skipping).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;fastspeech-2-2020&quot;&gt;FastSpeech 2 (2020)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Phone[&quot;Phonemes&quot;] --&gt; PE[&quot;Position encoding&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    PE --&gt; Enc[&quot;Transformer Encoder&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Enc --&gt; Dur[&quot;Duration Predictor&amp;#x3C;br/&gt;(각 phoneme 몇 frame?)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Enc --&gt; P[&quot;Pitch Predictor&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Enc --&gt; E[&quot;Energy Predictor&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Dur --&gt; Expand[&quot;Length Regulator&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    P &amp;#x26; E --&gt; Expand&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Expand --&gt; Dec[&quot;Transformer Decoder&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Dec --&gt; Mel&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Non-autoregressive&lt;/strong&gt;: &lt;em&gt;병렬 생성&lt;/em&gt; → 수십 배 빠름.&lt;/li&gt;
&lt;li&gt;Duration predictor 로 &lt;em&gt;길이 예측&lt;/em&gt; (attention 없음).&lt;/li&gt;
&lt;li&gt;Pitch/Energy 예측으로 &lt;em&gt;운율 제어&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;vits-2021-상용-표준&quot;&gt;VITS (2021, 상용 표준)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Variational Inference with adversarial learning for end-to-end Text-to-Speech&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Text[&quot;Text&quot;] --&gt; Enc[&quot;Text Encoder&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Audio[&quot;Audio (training)&quot;] --&gt; PostEnc[&quot;Posterior Encoder&amp;#x3C;br/&gt;(linear spec)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Enc --&gt; Prior[&quot;Prior distribution&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    PostEnc --&gt; Post[&quot;Posterior distribution&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Prior --&gt; Flow[&quot;Normalizing Flow&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Post --&gt; Flow&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Flow --&gt; z[&quot;Latent z&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    z --&gt; Decoder[&quot;HiFi-GAN Decoder&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Decoder --&gt; Waveform[&quot;Audio waveform&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;핵심 아이디어&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;End-to-end&lt;/strong&gt;: Mel intermediate 없이 &lt;em&gt;바로 waveform&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VAE + Flow + GAN&lt;/strong&gt; 결합.&lt;/li&gt;
&lt;li&gt;Duration predictor + Stochastic (자연스러움).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;상용 TTS 의 표준 base&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Coqui XTTS-v2 사용&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; TTS&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.api &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; TTS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tts &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; TTS(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    model_name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;tts_models/multilingual/multi-dataset/xtts_v2&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    progress_bar&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;False&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).to(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;cuda&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tts.tts_to_file(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    text&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;안녕하세요. 음성 합성 테스트입니다.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    speaker_wav&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;reference_voice.wav&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# voice cloning&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    language&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ko&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    file_path&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;output.wav&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;hifi-gan-vocoder&quot;&gt;HiFi-GAN (Vocoder)&lt;/h2&gt;
&lt;p&gt;Mel → waveform 변환. &lt;strong&gt;Generator + Multi-scale + Multi-period Discriminator&lt;/strong&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Mel[&quot;Mel (80 × T)&quot;] --&gt; Gen[&quot;Generator&amp;#x3C;br/&gt;(dilated convolutions + upsampling)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Gen --&gt; Wave[&quot;Waveform (24kHz)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Wave -.학습 시.-&gt; MSD[&quot;Multi-Scale Discriminator&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Wave -.학습 시.-&gt; MPD[&quot;Multi-Period Discriminator&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;학습: adversarial + mel loss + feature matching.&lt;/li&gt;
&lt;li&gt;추론: &lt;em&gt;생성기만&lt;/em&gt; 사용. real-time factor &amp;#x3C; 1.&lt;/li&gt;
&lt;li&gt;Quality: WaveNet 수준, 100x 빠름.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;styletts-2-2023&quot;&gt;StyleTTS 2 (2023)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Text --&gt; Enc[&quot;Text Encoder&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Style[&quot;Reference audio&amp;#x3C;br/&gt;(voice + style)&quot;] --&gt; SE[&quot;Style Encoder&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Enc --&gt; Dur[&quot;Duration + Prosody Predictor&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    SE --&gt; Dur&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Dur --&gt; Diff[&quot;Style Diffusion Model&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Diff --&gt; Dec[&quot;Decoder + HiFi-GAN&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Dec --&gt; Audio&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Diffusion + adversarial&lt;/strong&gt; hybrid.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Voice cloning&lt;/em&gt; 3초 sample.&lt;/li&gt;
&lt;li&gt;Human-level quality (MOS 4.5+).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;flow-matching-tts-f5-tts-2024&quot;&gt;Flow Matching TTS (F5-TTS, 2024)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Noise[&quot;Random noise&quot;] --&gt; ODE[&quot;Flow Matching ODE&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Text --&gt; ODE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Ref[&quot;Reference audio (선택)&quot;] --&gt; ODE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ODE --&gt; Audio[&quot;Audio&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Diffusion 의 &lt;em&gt;더 효율적&lt;/em&gt; 변형.&lt;/li&gt;
&lt;li&gt;3-shot voice cloning.&lt;/li&gt;
&lt;li&gt;자체 호스팅 친화 (Apache 2.0).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;text-normalization&quot;&gt;Text Normalization&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 숫자, 기호, 약어 → 발음 가능 형태&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;$5&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    → &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;다섯 달러&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;100&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;   → &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;백&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; 또는 &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;일영영&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;AI&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    → &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;에이아이&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;3:30&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  → &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;세 시 삼십 분&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Python: normalize&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; re&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; normalize_kr&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(text):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    text &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; re.sub(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#85E89D;font-weight:bold&quot;&gt;\$&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;(\d&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;lambda&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; m: number_to_kor(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(m.group(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos; 달러&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, text)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    text &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; re.sub(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;(\d&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#DBEDFF&quot;&gt;원&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;lambda&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; m: number_to_kor(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(m.group(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos; 원&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, text)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    text &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; text.replace(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;AI&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;에이아이&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    text &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; text.replace(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;API&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;에이피아이&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;g2p-grapheme-to-phoneme&quot;&gt;G2P (Grapheme-to-Phoneme)&lt;/h2&gt;
&lt;p&gt;한국어:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;안녕하세요&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;→ 발음: &quot;안녕하세요&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;→ IPA: /an.njʌŋ.ha.se.jo/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;라이브러리:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;g2pK&lt;/strong&gt; (한국어) - Rule-based&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;phonemizer&lt;/strong&gt; (다국어) - eSpeak&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KoG2P&lt;/strong&gt; - Sequence-to-sequence&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; g2pk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; G2p&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;g2p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; G2p()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(g2p(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;안녕하세요&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# &quot;안녕하세요&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(g2p(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hello 안녕&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))           &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# &quot;헬로 안녕&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(g2p(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;2026년 6월&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))           &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# &quot;이천이십육년 육월&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;prosody-제어-ssml&quot;&gt;Prosody 제어 (SSML)&lt;/h2&gt;
&lt;p&gt;자세한 SSML 은 [[tts-streaming-ssml]].&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 모델에 직접 prosody 전달&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;audio &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tts.synthesize(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    text&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;안녕하세요&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    speaker_id&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;female-1&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    speed&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,        &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 20% 빠르게&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    pitch&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,         &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 반음 2 up&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    energy&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 10% 큰 소리&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;voice-cloning-few-shot&quot;&gt;Voice Cloning (few-shot)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# XTTS-v2 (6초 sample 로 cloning)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tts.tts_to_file(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    text&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;한 번도 만난 적 없는 사람의 목소리를 합성합니다.&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    speaker_wav&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;unknown_person_6sec.wav&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# ← 그 사람 음성 sample&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    language&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ko&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    file_path&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;cloned.wav&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;내부:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Speaker encoder → 256-dim embedding.&lt;/li&gt;
&lt;li&gt;TTS generator 가 embedding 조건 삽입.&lt;/li&gt;
&lt;li&gt;새 텍스트 + 그 embedding → 합성.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;normalization 없이&lt;/strong&gt; = “$100” → “달러 백” 같이 이상. Front-end 처리 필수.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;G2P 무시&lt;/strong&gt; = 한자, 영어 발음 이상. g2pK 등.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VITS 학습 데이터 편향&lt;/strong&gt; = &lt;em&gt;특정 speaker&lt;/em&gt; 만 자연스러움. Multi-speaker 학습.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vocoder 만 교체&lt;/strong&gt; = mismatch → 음질 나빠짐. 함께 학습 필요.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[tts-models-overview]]&lt;/li&gt;
&lt;li&gt;[[tts-streaming-ssml]]&lt;/li&gt;
&lt;li&gt;[[stt-internals-whisper]] (STT 대칭)&lt;/li&gt;
&lt;li&gt;[[voice-agent-architecture]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>tts</category><category>neural-tts</category><category>vits</category><category>hifi-gan</category><category>transformer</category><author>koa (김신건)</author></item><item><title>[Voice] Whisper 내부: encoder-decoder, log-mel, tokenizer</title><link>https://shinkeonkim.com/wiki/voice/stt-internals-whisper/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/voice/stt-internals-whisper/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Whisper&lt;/strong&gt; = OpenAI 의 &lt;em&gt;encoder-decoder Transformer&lt;/em&gt; STT. 680K 시간 다국어 supervised training. 2022 공개, 2023 v2, 2023 v3.&lt;/p&gt;
&lt;p&gt;개요는 [[stt-models-overview]] 참고. 본 페이지는 &lt;em&gt;내부 아키텍처 + 코드&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;아키텍처&quot;&gt;아키텍처&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart TB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Audio[&quot;30s audio (16kHz mono)&quot;] --&gt; LMS[&quot;Log-Mel Spectrogram&amp;#x3C;br/&gt;(80 channels × 3000 frames)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    LMS --&gt; Enc[&quot;Transformer Encoder&amp;#x3C;br/&gt;(N layers, self-attention)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Enc --&gt; KV[&quot;Encoder hidden states&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    KV --&gt; Dec[&quot;Transformer Decoder&amp;#x3C;br/&gt;(cross-attention to encoder)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Tokens[&quot;Special + text tokens&quot;] --&gt; Dec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Dec --&gt; Out[&quot;다음 token 예측&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;모델-사이즈&quot;&gt;모델 사이즈&lt;/h2&gt;















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;모델&lt;/th&gt;&lt;th&gt;Layers&lt;/th&gt;&lt;th&gt;Width&lt;/th&gt;&lt;th&gt;Heads&lt;/th&gt;&lt;th&gt;Params&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;tiny&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;384&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;39M&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;base&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;512&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;74M&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;small&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;768&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;244M&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;medium&lt;/td&gt;&lt;td&gt;24&lt;/td&gt;&lt;td&gt;1024&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;769M&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;large-v3&lt;/td&gt;&lt;td&gt;32&lt;/td&gt;&lt;td&gt;1280&lt;/td&gt;&lt;td&gt;20&lt;/td&gt;&lt;td&gt;1550M&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;log-mel-spectrogram&quot;&gt;Log-Mel Spectrogram&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; numpy &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; np&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; librosa&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 16kHz, 30초 = 480000 samples&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;audio, sr &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; librosa.load(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;sample.wav&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;sr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;16000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;audio &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; audio[:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;16000&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 30&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 30초 padding/trim&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Log-mel spectrogram&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;mel &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; librosa.feature.melspectrogram(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    y&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;audio,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    sr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;16000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    n_fft&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;400&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# window 25ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    hop_length&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;160&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# stride 10ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    n_mels&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;80&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 80 mel channels&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;log_mel &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; np.log10(np.clip(mel, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1e-10&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# shape: (80, 3000)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;파라미터&lt;/th&gt;&lt;th&gt;값&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Window&lt;/td&gt;&lt;td&gt;25ms (400 samples at 16kHz)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Hop&lt;/td&gt;&lt;td&gt;10ms (160 samples)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Mel channels&lt;/td&gt;&lt;td&gt;80&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input size&lt;/td&gt;&lt;td&gt;80 × 3000&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;encoder-self-attention&quot;&gt;Encoder (self-attention)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;mel (80, 3000) → conv1d → conv1d → transformer layers&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;양방향 self-attention&lt;/em&gt; (모든 시간대 봄).&lt;/li&gt;
&lt;li&gt;Output: &lt;code&gt;(1500, d_model)&lt;/code&gt; (2x downsample).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;decoder-autoregressive&quot;&gt;Decoder (autoregressive)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;|startoftranscript|&gt; &amp;#x3C;|ko|&gt; &amp;#x3C;|transcribe|&gt; &amp;#x3C;|notimestamps|&gt; &quot;안&quot; &quot;녕&quot; &quot;하세요&quot; &amp;#x3C;|endoftext|&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;각 토큰 예측:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;cross-attention&lt;/strong&gt;: encoder hidden states 참조.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;causal self-attention&lt;/strong&gt;: 옛 토큰만 봄.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;special-tokens&quot;&gt;Special Tokens&lt;/h2&gt;





































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Token&lt;/th&gt;&lt;th&gt;의미&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;`&amp;#x3C;&lt;/td&gt;&lt;td&gt;startoftranscript&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;`&amp;#x3C;&lt;/td&gt;&lt;td&gt;en&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;`&amp;#x3C;&lt;/td&gt;&lt;td&gt;transcribe&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;`&amp;#x3C;&lt;/td&gt;&lt;td&gt;translate&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;`&amp;#x3C;&lt;/td&gt;&lt;td&gt;notimestamps&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;`&amp;#x3C;&lt;/td&gt;&lt;td&gt;0.00&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;`&amp;#x3C;&lt;/td&gt;&lt;td&gt;endoftext&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;timestamp-생성&quot;&gt;Timestamp 생성&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 예 (with timestamps):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;startoftranscript&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ko&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;transcribe&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;|&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.00&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; 안녕하세요 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;|&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.50&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;|&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.50&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; 오늘 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;|&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2.00&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;|&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2.00&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; 날씨가 좋네요 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;|&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3.50&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;endoftext&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;모델이 timestamp token 을 다른 vocab 처럼&lt;/em&gt; 예측. 정확도는 word-level ~200ms 오차.&lt;/p&gt;
&lt;h2 id=&quot;30초-chunking&quot;&gt;30초 chunking&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; transcribe_long_audio&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(audio, model):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    chunk_size &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 30&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 16000&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;   # 30초&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    stride &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 25&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 16000&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        # 25초 (5초 overlap)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    results &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; start &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(audio), stride):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        chunk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; audio[start:start &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chunk_size]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        chunk &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pad_or_trim(chunk, chunk_size)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        mel &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; log_mel_spectrogram(chunk)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; model.decode(mel, options)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        results.append(result)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; merge_with_overlap(results)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Whisper 는 &lt;em&gt;30초 단위&lt;/em&gt; 만 처리. 긴 오디오는 &lt;em&gt;chunking + overlap&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;hallucination-문제&quot;&gt;Hallucination 문제&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;무음 구간 → 모델이 *없는 문장 생성*&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;해결&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;VAD 전처리&lt;/strong&gt; (Silero) - 무음 제거&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Temperature 0&lt;/strong&gt; - 결정론적&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;compression_ratio_threshold&lt;/strong&gt; - 반복 감지&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;logprob_threshold&lt;/strong&gt; - 확신 낮으면 skip&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; model.transcribe(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    audio,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    language&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;ko&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    temperature&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    compression_ratio_threshold&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2.4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    logprob_threshold&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1.0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    no_speech_threshold&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0.6&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# VAD 임계&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    condition_on_previous_text&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;False&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# hallucination 방지&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;faster-whisper-ctranslate2&quot;&gt;Faster-Whisper (CTranslate2)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; faster_whisper &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; WhisperModel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;model &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; WhisperModel(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;large-v3&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    device&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;cuda&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    compute_type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;float16&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 또는 int8_float16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;segments, info &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; model.transcribe(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;audio.wav&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    language&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;ko&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    beam_size&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    vad_filter&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 내장 Silero VAD!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;    vad_parameters&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;min_silence_duration_ms&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; seg &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; segments:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;seg.start&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:.2f&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; → &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;seg.end&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:.2f&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;seg.text&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;최적화&lt;/th&gt;&lt;th&gt;배속&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;CTranslate2&lt;/td&gt;&lt;td&gt;~4x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;INT8 quantization&lt;/td&gt;&lt;td&gt;+2x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Beam search skip (greedy)&lt;/td&gt;&lt;td&gt;+1.5x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VAD filter&lt;/td&gt;&lt;td&gt;노이즈 절감&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;distil-whisper&quot;&gt;Distil-Whisper&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Teacher (large-v3) → Distillation → Student&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Decoder layers 축소 (32 → 2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- ~6x 빠름, 49% 작음&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- 영어 정확도 유지, 다국어 약함&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;streaming-whisperlive-whisperlink&quot;&gt;Streaming (WhisperLive, WhisperLink)&lt;/h2&gt;
&lt;p&gt;Whisper 는 &lt;em&gt;batch 모델&lt;/em&gt; → streaming 은 &lt;em&gt;별도 wrapper&lt;/em&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;mermaid&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;flowchart LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Mic --&gt; Buffer[&quot;Buffer (수 초)&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Buffer --&gt; VAD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    VAD --&gt;|&quot;음성 감지&quot;| Chunk[&quot;30초 chunk&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Chunk --&gt; Whisper&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Whisper --&gt; Merge[&quot;overlap merge&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Merge --&gt; Text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;partial transcript&lt;/em&gt; 를 30초 chunk 마다 갱신.&lt;/li&gt;
&lt;li&gt;Overlap 으로 문장 경계 매끄럽게.&lt;/li&gt;
&lt;li&gt;완전 real-time 은 아님 (500ms-1.5s 지연).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;vocab-multilingual-tokenizer&quot;&gt;Vocab (Multilingual Tokenizer)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# GPT-2 style BPE (Byte-Pair Encoding)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;tokenizer.encode(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;안녕하세요&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# → [23283, 9573, 7539, ...] (subword tokens)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(tokenizer.vocab)   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 51864 tokens&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Multilingual model = &lt;em&gt;다국어 subword 학습&lt;/em&gt;. 한국어도 자연스러운 tokenization.&lt;/p&gt;
&lt;h2 id=&quot;흔한-함정&quot;&gt;흔한 함정&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;긴 오디오 그대로 넣음&lt;/strong&gt; = 30초 이상 무시. Chunking 필수.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VAD 없이&lt;/strong&gt; = 무음 구간 hallucination.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;condition_on_previous_text=True&lt;/code&gt; (기본)&lt;/strong&gt; = 옛 오류가 다음 chunk 로 전파.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CTranslate2 없이 batch&lt;/strong&gt; = 4배 느림. Faster-whisper 권장.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[stt-models-overview]]&lt;/li&gt;
&lt;li&gt;[[stt-streaming]]&lt;/li&gt;
&lt;li&gt;[[vad-silero]]&lt;/li&gt;
&lt;li&gt;[[llm-serving-vllm]] (Transformer 서빙)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>whisper</category><category>stt</category><category>asr</category><category>transformer</category><category>encoder-decoder</category><author>koa (김신건)</author></item></channel></rss>