logo
홈블로그소개
4,925

Built with Next.js, Bun, Tailwind CSS and Shadcn/UI

·개인정보처리방침
AIWeb

Phonon TTS: 텍스트 정규화와 오프라인 음성 배포 설계

Toma
2026년 11월 6일
약 17분
목차
🔊 Phonon TTS: 텍스트 정규화와 오프라인 음성 배포 설계
🧩 Phonon은 무엇이고, 무엇이 아닌가
📦 작은 가중치와 작은 서비스는 다르다
⚙️ 텍스트가 소리로 바뀌는 과정
🔤 가장 놓치기 쉬운 부분: 숫자를 읽는 능력은 어디에 있는가
📝 공식 문서 예제와 실행 결과를 구분하기
📍 on-device라고 해도 실행 위치는 확인해야 한다
🔀 ptts와 Transformers를 고르는 기준
⏱️ 첫 오디오 지연과 사용자가 듣기까지의 시간
🛠️ 적용 제안: 영어 안내문을 오프라인으로 읽는 앱
🔎 공개 활용에서 확인한 것과 확인하지 못한 것
🔌 Micdrop: 별도 음성 서버 없는 Node integration
🏠 Gladys: 모델의 streaming이 앱 전체의 streaming은 아니다
⚠️ 도입 전에 확인할 제약
🇰🇷 언어 옵션과 공개 checkpoint 지원은 다르다
📜 코드·가중치·음성 복제의 조건을 따로 보기
🧵 단어가 맞아도 장문의 억양은 틀릴 수 있다
⚖️ 더 단순한 대안은 없는가
✅ 정리
Sources
이전 포스트Go JSON v2: 문법과 데이터 의미를 나눠 안전하게 API 이전하기

목차

🔊 Phonon TTS: 텍스트 정규화와 오프라인 음성 배포 설계
🧩 Phonon은 무엇이고, 무엇이 아닌가
📦 작은 가중치와 작은 서비스는 다르다
⚙️ 텍스트가 소리로 바뀌는 과정
🔤 가장 놓치기 쉬운 부분: 숫자를 읽는 능력은 어디에 있는가
📝 공식 문서 예제와 실행 결과를 구분하기
📍 on-device라고 해도 실행 위치는 확인해야 한다
🔀 ptts와 Transformers를 고르는 기준
⏱️ 첫 오디오 지연과 사용자가 듣기까지의 시간
🛠️ 적용 제안: 영어 안내문을 오프라인으로 읽는 앱
🔎 공개 활용에서 확인한 것과 확인하지 못한 것
🔌 Micdrop: 별도 음성 서버 없는 Node integration
🏠 Gladys: 모델의 streaming이 앱 전체의 streaming은 아니다
⚠️ 도입 전에 확인할 제약
🇰🇷 언어 옵션과 공개 checkpoint 지원은 다르다
📜 코드·가중치·음성 복제의 조건을 따로 보기
🧵 단어가 맞아도 장문의 억양은 틀릴 수 있다
⚖️ 더 단순한 대안은 없는가
✅ 정리
Sources

🔊 Phonon TTS: 텍스트 정규화와 오프라인 음성 배포 설계

음성을 출력하는 기능을 만들 때 모델 파일이 작다는 이유만으로 도입을 결정하기는 어렵습니다. 어떤 기기에서 실행하는지, 숫자를 어떻게 읽는지, 첫 실행과 재생까지 얼마나 기다리는지를 함께 봐야 합니다.

2026년 11월 5일 Hugging Face에 공개된 Phonon 해설은 on-device TTS의 구현과 integration을 자세히 소개합니다.[11] 모델의 open-weight 공개 자체는 10월 20일이므로, 오늘 처음 출시된 모델로 소개하는 글은 아닙니다.[12]

💡 💡 핵심: 음성 모델과 전처리기, 실행 위치, 재생 경로를 분리해서 판단하세요. Phonon을 쓰지 않더라도 로컬 AI 기능의 도입을 검토할 때 가져갈 수 있는 기준입니다.

🧩 Phonon은 무엇이고, 무엇이 아닌가

Phonon은 텍스트를 음성으로 바꾸는 Text-to-Speech 모델군입니다.[53] 영어용 Phonon 31m과 영어·프랑스어·독일어·스페인어·포르투갈어를 위한 40m 계열이 있으며, 범용 LLM이나 음성 인식 모델이 아닙니다.[53]

31m English의 모델 카드는 31M이라는 parameter 수에서 audio tokenizer를 제외한다고 명시합니다.[53] 또한 64.5 MB는 q8 가중치 파일의 크기이며, 프로그램 전체의 실행 메모리 요구량이라는 설명이 아닙니다.[53]

실행을 담당하는 ptts는 별도 runtime입니다.[54] Rust로 작성되어 PyTorch 없이 동작하며 브라우저, 앱, 로컬 서버 등의 연결 경로를 제공합니다.[54]

📦 작은 가중치와 작은 서비스는 다르다

Micdrop의 Node.js integration 문서는 Phonon을 로드해 합성하는 Node process의 메모리를 약 450 MB로 보고합니다.[16] 이는 해당 integration의 관찰값이지, 모든 Phonon 실행 환경의 최소 RAM이나 고정 사용량은 아닙니다.

도입 판단 의견: 가중치 다운로드 크기, tokenizer·codec을 포함한 모델 구성, runtime과 애플리케이션의 메모리를 따로 예산에 넣으세요. 작은 파일 하나를 내려받는 문제와 서비스를 계속 운영하는 문제는 다릅니다.

⚙️ 텍스트가 소리로 바뀌는 과정

공식 설명을 역할별로 나누면 다음 흐름입니다.[12][15]

  1. 텍스트 준비: 언어에 맞게 숫자·기호 등을 정리하고 텍스트를 tokenize합니다.[53]
  2. 목소리 조건 전달: 미리 계산된 speaker latent와 텍스트가 모델의 입력이 됩니다.[15]
  3. 음성 표현 생성: causal Transformer와 flow-matching head가 짧은 오디오 표현을 순차 생성합니다.[12]
  4. 파형 복호화: Mimi decoder가 표현을 24 kHz PCM 오디오로 바꿉니다.[12]
  5. 전송·재생: 애플리케이션이 출력 chunk를 받아 재생합니다.[54] Micdrop은 생성된 frame을 client에 전달하는 경로를 설명합니다.[16]

공식 발표에서 생성의 한 단위는 80 ms 분량의 음성입니다.[12] 80 ms는 생성되는 오디오의 길이이지, 한 요청의 실제 처리 시간이 80 ms라는 뜻이 아닙니다.

전체 문장을 완성한 뒤 파일을 돌려주는 방식과 달리, chunk를 내보내는 경로에서는 뒤쪽 음성을 생성하는 동안 앞부분을 재생할 수 있습니다.[53][54]

🔤 가장 놓치기 쉬운 부분: 숫자를 읽는 능력은 어디에 있는가

Phonon의 Transformers 문서는 tokenizer가 금액·숫자·주소를 언어에 맞는 읽기 표현으로 풀어 쓰지 않는다고 명시합니다.[15] 이 작업에는 ptts의 text normalization을 사용하거나 입력을 직접 풀어 쓰라고 안내합니다.[15]

📝 공식 문서 예제와 실행 결과를 구분하기

문서 예제에서 It is 21°C는 tokenizer만 통과하면 숫자와 기호가 그대로 남지만, Gradium runtime의 정규화 결과는 It is 21 degrees Celsius.로 제시됩니다.[15] 여기서 확인한 것은 문서에 적힌 전처리 예시이며, 이 글에서 음성을 생성하거나 청취한 결과가 아닙니다.

따라서 같은 checkpoint라도 전처리기를 바꾸면 모델이 받는 텍스트가 달라질 수 있습니다.[15][53] “이 모델은 날짜와 금액을 잘 읽는다”는 소개를 가중치만의 성질로 이해해서는 안 됩니다.

설계 제안: 버전 번호, 날짜, 금액, 주문번호, 이메일을 별도의 검증 문장으로 관리하세요. 예를 들어 3.10을 버전으로 읽어야 하는지 소수로 읽어야 하는지부터 제품 요구사항으로 정하는 방식입니다. 이는 제안 입력이지 검증된 합성 출력이 아닙니다.

📍 on-device라고 해도 실행 위치는 확인해야 한다

공식 ptts README의 브라우저 package는 WebAssembly 기반 경로를 제공하며, 첫 로드에서 파일을 다운로드하고 cache합니다.[54] 반면 Micdrop은 Node process의 worker thread에서 합성을 수행합니다.[16]

즉 사용자의 브라우저에서 합성하는 구조와 우리 서버의 Node에서 합성하는 구조는 다릅니다.[16][54] 서버에 둔 Node integration을 연결했다는 이유로 사용자 텍스트가 사용자 기기 밖으로 나가지 않는다고 설명하면 안 됩니다.

🔀 ptts와 Transformers를 고르는 기준

11월 5일 해설은 ptts를 기기의 단일 stream 실행에, Transformers를 GPU의 batched generation과 torch.compile을 활용한 처리량 중심 경로에 대응시킵니다.[11] 같은 모델을 다루더라도 두 구현을 같은 성능·운영 조건으로 비교하는 글은 아닙니다.

별도로 공개된 ExecuTorch WebGPU conversion은 방문자의 GPU에서 실행되는 브라우저 demo를 위한 변환본입니다.[17] 이 문서는 WebGPU가 활성화된 브라우저를 요구하고, 공식 runtime의 숫자·날짜 정규화는 애플리케이션이 담당해야 한다고 안내합니다.[17]

편집 의견: 처음에는 목표 실행 위치 하나만 정하세요. “웹도 되고 모바일도 된다”는 지원 목록보다 우리 앱이 사용할 runtime·backend·모델 파일의 조합이 먼저입니다.

⏱️ 첫 오디오 지연과 사용자가 듣기까지의 시간

Micdrop은 모델 파일이 이미 cache된 MacBook Pro M2, 단일 CPU core라는 조건에서 모델 로드와 첫 단어에 0.70.9초, 문장의 첫 오디오에 30100 ms를 보고합니다.[16] integration 작성자의 측정이며, 제가 재현한 수치나 모든 기기에서의 성능 보장이 아닙니다.

이 수치를 첫 다운로드부터 사용자가 소리를 듣기까지의 전체 시간으로 바꾸어 읽을 수는 없습니다. 문서 자체도 최초 다운로드와 cache, 로드, 문장 합성을 구분하고 있습니다.[16]

🛠️ 적용 제안: 영어 안내문을 오프라인으로 읽는 앱

다음은 고객 사례가 아니라 설계 제안입니다. 연결이 불안정한 장소에서 짧은 영어 안내문을 읽는 앱을 가정합니다.

  • 모델·목소리 파일을 미리 준비하고, 다운로드 실패와 실행 준비 완료를 UI에서 구분합니다.
  • 앱 시작 시 준비 시간과 준비 후 문장을 요청했을 때의 시간을 따로 기록합니다.
  • 입력 수신, 첫 chunk 생성, 재생 시작의 시점을 각각 측정합니다.
  • 금액·식별자·장문을 검증하고, 음성 실패 시 안내문 텍스트는 그대로 제공합니다.

동시 요청도 따로 봐야 합니다. Micdrop 문서는 모델·언어·precision 조합의 instance를 공유하고 한 worker에서 문장을 차례로 처리한다고 설명합니다.[16] worker를 사용해 event loop를 막지 않는 것과 여러 통화를 동시에 합성하는 것은 같은 보장이 아닙니다.[16]

🔎 공개 활용에서 확인한 것과 확인하지 못한 것

🔌 Micdrop: 별도 음성 서버 없는 Node integration

Micdrop 문서는 @micdrop/phonon이 Node worker thread에서 runtime을 실행하며 별도 sidecar 서버가 필요 없다고 설명합니다.[16] 이는 공개 integration의 구조를 확인한 사례이며, 대규모 운영 처리량이나 고객 도입 성과를 검증한 결과는 아닙니다.

🏠 Gladys: 모델의 streaming이 앱 전체의 streaming은 아니다

10월 26일 Gladys 커뮤니티 글의 작성자는 Node integration이 별도의 공식 ptts-openai-server container를 제어해 MP3를 받는 구성을 공개했습니다.[24] 첫 설치 뒤에는 offline으로 동작하는 구조라고 설명합니다.[24]

같은 글에서 작성자는 당시 integration에 streaming을 추가하는 것을 개선 방향으로 제시하고, Raspberry Pi 4에서는 합성이 실시간보다 느렸다고 보고합니다.[24] 또한 소수 기기에서 시험한 beta이므로 경보·보안 같은 중요한 알림에는 사용하지 말라고 경고합니다.[24]

다른 이용자가 QNAP NAS에서 안내 음성을 출력했다고 쓴 후속 댓글도 확인했습니다.[24] 이는 이용자 보고이며 독립적으로 재현한 시험은 아닙니다. 게시자가 적은 부정확해 보이는 하드웨어 용량은 검증하지 못해 인용하지 않았습니다.

이 사례에서 가져갈 설계 교훈은 명확합니다. 모델이 stream을 만들 수 있어도 중간 integration이 완성된 파일을 기다린다면, 그 앱의 조기 재생까지 보장되지는 않습니다.[24]

⚠️ 도입 전에 확인할 제약

🇰🇷 언어 옵션과 공개 checkpoint 지원은 다르다

확인한 공개 모델군의 언어는 영어·프랑스어·독일어·스페인어·포르투갈어입니다.[15][53] 한국어를 요구하는 앱이라면 이 공개 모델군을 그대로 채택할 근거가 부족합니다.

ptts v0.6.0 release note에는 ko를 포함한 추가 언어 코드 처리가 등장하지만, 해당 언어로 학습된 checkpoint가 필요하다고 명시합니다.[32] runtime이 언어 코드를 받아들인다고 영어 가중치가 한국어를 말할 수 있게 되는 것은 아닙니다.[32][53]

📜 코드·가중치·음성 복제의 조건을 따로 보기

ptts 코드는 MIT 또는 Apache-2.0이지만 모델 가중치는 별도 조건입니다.[54] Phonon 31m English는 Apache 2.0으로 상업적 이용을 허용하고, 40m 계열은 CC BY-NC 4.0으로 안내되어 있습니다.[15][53]

또한 공식 문서의 로컬 음성 재생은 로컬 voice cloning까지 뜻하지 않습니다. Transformers 문서는 speaker codec이 공개되지 않아 녹음으로부터 목소리를 복제할 수 없다고 설명하며, Gradium은 Studio에서 목소리를 만들고 파일을 내려받는 별도 절차를 안내합니다.[15][54] 실제 사람의 목소리를 복제할 때에는 당사자 동의를 얻으라고 모델 카드가 명시합니다.[53]

🧵 단어가 맞아도 장문의 억양은 틀릴 수 있다

공개 issue #318에서는 Core ML의 짧은 prefill에 맞춰 긴 문장을 나누며 원래 없던 문장 끝이 들린다는 사용자 보고가 있었습니다.[28] 보고자는 모든 단어가 읽혀 ASR 검사만으로는 문제를 놓칠 수 있다고 설명합니다.[28]

후속 PR #326은 기본 export의 prefill을 48에서 200 token으로 늘리고 문장 묶음 처리를 조정했으며, 11월 3일 merge된 것을 확인했습니다.[52] PR은 첫 오디오와 메모리의 추가 비용, 기존 48-token bundle은 기존처럼 동작한다는 점도 설명합니다.[52]

그러나 maintainer 댓글은 release bundle의 재export를 다음 release 작업으로 구분합니다.[29] 이번 조회의 GitHub latest stable은 v0.6.0, 10월 30일 발행이었고 해당 Core ML asset의 수정 시각도 같은 날이었습니다.[32] 코드 merge를 기존 다운로드 bundle의 수정 완료로 간주하지 마세요. 이 글에서는 bundle을 내려받아 내용까지 검증하지 않았습니다.

⚖️ 더 단순한 대안은 없는가

웹 앱에서 기본 읽어주기만 필요하다면 Web Speech API부터 검토할 수 있습니다. MDN은 SpeechSynthesis가 기기에서 사용할 수 있는 voice 조회와 발화 시작·일시정지 등을 제공한다고 설명합니다.[33]

선택 기준에 대한 의견은 다음과 같습니다.

  • 기기별 기본 목소리로 충분하다면, 모델 배포를 추가하기 전에 Web Speech API로 요구사항을 확인합니다. 실제 voice와 offline 여부는 대상 환경에서 따로 확인해야 합니다.
  • 이미 쓰는 hosted TTS가 요구 언어와 품질을 충족하고 텍스트의 외부 전송이 허용된다면, 기존 경로를 유지하는 편이 변경 범위를 줄입니다.
  • 특정 목소리의 일관성이나 네트워크 없는 합성이 핵심이라면, 모델·전처리·재생 경로를 직접 관리할 비용까지 포함해 Phonon을 비교합니다.

로컬 실행이 항상 더 저렴하거나 더 빠르다고 결론 내릴 수는 없습니다. 이 글의 권고는 요청당 요금만이 아니라 초기 다운로드, 기기 자원, 업데이트와 장애 대응까지 비교하자는 것입니다.

💡 🔍 검증 범위: 자료 확인일은 2026-11-06입니다. 공식 발표·기술 문서, Micdrop·ExecuTorch의 integration 문서, Gladys의 전체 공개 게시물, GitHub issue와 후속 댓글·PR·release metadata를 대조했습니다. 모델 카드는 revision 92741c5b07d085ff840e26fea8ce43110b87852f로 고정했습니다. 모델 설치·합성·청취·benchmark 재현은 수행하지 않았습니다. 공개 측정과 사용자 보고는 읽었지만 실제 안정성·우리 환경의 성능을 독립 검증한 글은 아닙니다.

✅ 정리

Phonon에서 가져갈 핵심은 작은 모델의 수치보다 텍스트 전처리, 실행 위치, 음성 전달 방식이 최종 기능을 바꾼다는 점입니다.[15][16][24]

도입은 필요한 언어와 license를 확인하는 것부터 시작하세요. 그다음 한 실행 경로에서 첫 준비와 warm 요청을 나눠 측정하고, 숫자와 장문을 실제로 들어 보며, 문제가 나면 텍스트로 돌아갈 수 있도록 설계하는 것이 이 글의 권장 순서입니다.

Sources

[11] https://huggingface.co/blog/phonon-tts — A Closer Look at Phonon TTS — Hugging Face / Gradium

[12] https://gradium.ai/blog/release-phonon-open-weight — Open-Sourcing Phonon — Gradium official announcement

[15] https://huggingface.co/docs/transformers/model_doc/gradium_phonon_tts — Gradium Phonon TTS — Transformers technical documentation

[16] https://micdrop.dev/docs/ai-integration/provided-integrations/phonon.md — Phonon TTS in Node.js — Micdrop integration documentation

[17] https://huggingface.co/executorch-community/Phonon-31M-EN-ExecuTorch-WebGPU/raw/main/README.md — Phonon 31M for ExecuTorch WebGPU — conversion model card

[24] https://community.gladysassistant.com/t/phonon-tts-une-voix-100-locale-pour-gladys/11421.json — Phonon TTS for Gladys — complete public discussion (JSON)

[28] https://api.github.com/repos/gradium-ai/xn-ptts/issues/318 — Core ML long-sentence prosody — user report, issue 318

[29] https://api.github.com/repos/gradium-ai/xn-ptts/issues/318/comments?per_page=100&page=1 — Issue 318 — complete maintainer follow-up comments

[32] https://api.github.com/repos/gradium-ai/xn-ptts/releases/latest — ptts latest stable release and asset metadata — GitHub API

[33] https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis — SpeechSynthesis — MDN Web API reference

[52] https://api.github.com/repos/gradium-ai/xn-ptts/pulls/326 — Core ML prefill correction — merged PR 326

[53] https://huggingface.co/gradium/phonon-31m-en/raw/92741c5b07d085ff840e26fea8ce43110b87852f/README.md — Phonon 31M English — pinned model card

[54] https://raw.githubusercontent.com/gradium-ai/xn-ptts/ee395caac058950cbcabfa3785c63630942f31ed/README.md — ptts — pinned runtime README