Upload 3 files
Browse files- Dockerfile +16 -2
- tts.py +12 -33
Dockerfile
CHANGED
|
@@ -9,7 +9,9 @@
|
|
| 9 |
FROM python:3.11-slim
|
| 10 |
|
| 11 |
# Whisper needs ffmpeg to read audio files, this installs it at the
|
| 12 |
-
# system level since it can't come from pip.
|
|
|
|
|
|
|
| 13 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 14 |
build-essential \
|
| 15 |
ffmpeg \
|
|
@@ -26,6 +28,19 @@ WORKDIR /home/user/app
|
|
| 26 |
COPY --chown=user requirements.txt .
|
| 27 |
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
| 28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
RUN python - <<'PY'
|
| 30 |
from huggingface_hub import hf_hub_download
|
| 31 |
import os
|
|
@@ -49,7 +64,6 @@ hf_hub_download(
|
|
| 49 |
print("WavTokenizer files downloaded.")
|
| 50 |
PY
|
| 51 |
|
| 52 |
-
|
| 53 |
COPY --chown=user . .
|
| 54 |
|
| 55 |
ENV ENVIRONMENT=production
|
|
|
|
| 9 |
FROM python:3.11-slim
|
| 10 |
|
| 11 |
# Whisper needs ffmpeg to read audio files, this installs it at the
|
| 12 |
+
# system level since it can't come from pip. build-essential is needed
|
| 13 |
+
# because some packages in requirements.txt compile C extensions during
|
| 14 |
+
# install, and the slim base image has no compiler by default.
|
| 15 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 16 |
build-essential \
|
| 17 |
ffmpeg \
|
|
|
|
| 28 |
COPY --chown=user requirements.txt .
|
| 29 |
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
| 30 |
|
| 31 |
+
# YarnGPT downloads its WavTokenizer checkpoint itself on first import,
|
| 32 |
+
# using a bare requests.get() call with no error checking. If that
|
| 33 |
+
# download hiccups at runtime (inside the running container, on the
|
| 34 |
+
# app's first request), it silently saves a corrupted or partial file
|
| 35 |
+
# and the app fails later with a confusing, unrelated error.
|
| 36 |
+
#
|
| 37 |
+
# This downloads the exact same two files ahead of time, at build time,
|
| 38 |
+
# using huggingface_hub's properly tested download function instead. If
|
| 39 |
+
# this fails, the build fails clearly, right here, instead of the app
|
| 40 |
+
# failing mysteriously after it's already live. YarnGPT's own downloader
|
| 41 |
+
# checks whether the file already exists before downloading, so it will
|
| 42 |
+
# find these already in place and skip straight past its own fragile
|
| 43 |
+
# download step.
|
| 44 |
RUN python - <<'PY'
|
| 45 |
from huggingface_hub import hf_hub_download
|
| 46 |
import os
|
|
|
|
| 64 |
print("WavTokenizer files downloaded.")
|
| 65 |
PY
|
| 66 |
|
|
|
|
| 67 |
COPY --chown=user . .
|
| 68 |
|
| 69 |
ENV ENVIRONMENT=production
|
tts.py
CHANGED
|
@@ -10,8 +10,15 @@ Nigerian Pidgin uses MMS-TTS (facebook/mms-tts-pcm) instead, since YarnGPT
|
|
| 10 |
has no Pidgin support. MMS-TTS is the only free option found with a
|
| 11 |
dedicated Pidgin checkpoint.
|
| 12 |
|
| 13 |
-
Note
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
Performance note: YarnGPT's own generate_speech() function reloads its
|
| 17 |
full model from disk on every call, which is too slow for a live app.
|
|
@@ -27,21 +34,6 @@ import scipy.io.wavfile
|
|
| 27 |
from transformers import VitsModel, AutoTokenizer
|
| 28 |
from yarngpt.core import load_model_and_tokenizer, SPEAKER_MAPPING, AVAILABLE_SPEAKERS
|
| 29 |
|
| 30 |
-
import yarngpt
|
| 31 |
-
import yarngpt.core
|
| 32 |
-
import inspect
|
| 33 |
-
|
| 34 |
-
import audiotokenizer
|
| 35 |
-
import inspect
|
| 36 |
-
print("AudioTokenizer file:", audiotokenizer.__file__)
|
| 37 |
-
source = inspect.getsource(audiotokenizer)
|
| 38 |
-
print(source[:8000])
|
| 39 |
-
|
| 40 |
-
print("YarnGPT:", yarngpt.__file__)
|
| 41 |
-
print("MODEL_PATH:", yarngpt.core.MODEL_PATH)
|
| 42 |
-
print("CONFIG_PATH:", yarngpt.core.CONFIG_PATH)
|
| 43 |
-
print(inspect.getsource(yarngpt.core.load_model_and_tokenizer))
|
| 44 |
-
|
| 45 |
# Default speaker used for each YarnGPT-supported language.
|
| 46 |
YARNGPT_SPEAKERS = {
|
| 47 |
"english": "idera",
|
|
@@ -71,26 +63,13 @@ def _get_pidgin_model():
|
|
| 71 |
_pidgin_model = VitsModel.from_pretrained("facebook/mms-tts-pcm")
|
| 72 |
return _pidgin_model, _pidgin_tokenizer
|
| 73 |
|
|
|
|
| 74 |
def preload_models():
|
|
|
|
|
|
|
| 75 |
_get_yarngpt_model()
|
| 76 |
_get_pidgin_model()
|
| 77 |
|
| 78 |
-
|
| 79 |
-
# ===== DEBUG START =====
|
| 80 |
-
import audiotokenizer
|
| 81 |
-
|
| 82 |
-
print(audiotokenizer.__file__)
|
| 83 |
-
|
| 84 |
-
from pathlib import Path
|
| 85 |
-
|
| 86 |
-
model = Path("/home/user/.yarngpt/models/wavtokenizer_large_speech_320_24k.ckpt")
|
| 87 |
-
print("Exists:", model.exists())
|
| 88 |
-
|
| 89 |
-
if model.exists():
|
| 90 |
-
print("Size:", model.stat().st_size)
|
| 91 |
-
with open(model, "rb") as f:
|
| 92 |
-
print("First 100 bytes:", f.read(100))
|
| 93 |
-
# ===== DEBUG END =====
|
| 94 |
|
| 95 |
def _generate_yarngpt_speech(text, speaker, language, temperature=0.1, repetition_penalty=1.1, max_length=4000):
|
| 96 |
"""
|
|
|
|
| 10 |
has no Pidgin support. MMS-TTS is the only free option found with a
|
| 11 |
dedicated Pidgin checkpoint.
|
| 12 |
|
| 13 |
+
Note on the WavTokenizer checkpoint: YarnGPT downloads this itself on
|
| 14 |
+
first import, using a bare requests.get() with no error checking, which
|
| 15 |
+
can silently save a corrupted file if the download hiccups. The
|
| 16 |
+
Dockerfile pre-downloads the same two files at build time using
|
| 17 |
+
huggingface_hub's properly tested download function instead, so by the
|
| 18 |
+
time this file is imported, YarnGPT finds them already in place and
|
| 19 |
+
skips its own fragile download step. Locally (not in Docker), the first
|
| 20 |
+
import still triggers YarnGPT's own download as normal, this only
|
| 21 |
+
matters for the deployed container.
|
| 22 |
|
| 23 |
Performance note: YarnGPT's own generate_speech() function reloads its
|
| 24 |
full model from disk on every call, which is too slow for a live app.
|
|
|
|
| 34 |
from transformers import VitsModel, AutoTokenizer
|
| 35 |
from yarngpt.core import load_model_and_tokenizer, SPEAKER_MAPPING, AVAILABLE_SPEAKERS
|
| 36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
# Default speaker used for each YarnGPT-supported language.
|
| 38 |
YARNGPT_SPEAKERS = {
|
| 39 |
"english": "idera",
|
|
|
|
| 63 |
_pidgin_model = VitsModel.from_pretrained("facebook/mms-tts-pcm")
|
| 64 |
return _pidgin_model, _pidgin_tokenizer
|
| 65 |
|
| 66 |
+
|
| 67 |
def preload_models():
|
| 68 |
+
"""Loads both TTS backends into memory ahead of time. Call this once
|
| 69 |
+
when the Flask app starts, so the first real request isn't slow."""
|
| 70 |
_get_yarngpt_model()
|
| 71 |
_get_pidgin_model()
|
| 72 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
|
| 74 |
def _generate_yarngpt_speech(text, speaker, language, temperature=0.1, repetition_penalty=1.1, max_length=4000):
|
| 75 |
"""
|