vrishv commited on
Commit
5adb4c2
·
verified ·
1 Parent(s): a7d947c

Narration: all 28 English Kokoro voices, British pronunciation for the British ones

Browse files
Files changed (3) hide show
  1. README.md +1 -1
  2. app.py +10 -1
  3. tts_worker.py +15 -2
README.md CHANGED
@@ -55,7 +55,7 @@ models:
55
 
56
  **Transcribe tab (speech to text, speech recognition, automatic speech recognition):** Whisper large v3 turbo (openai) writes down speech from a file or the microphone, in its own language or translated to English.
57
 
58
- **Narration tab (text to speech, speech generation, machine speech):** Kokoro (hexgrad) reads your text aloud in a choice of eight voices.
59
 
60
  **Describe tab:** three ways to describe what you have.
61
 
 
55
 
56
  **Transcribe tab (speech to text, speech recognition, automatic speech recognition):** Whisper large v3 turbo (openai) writes down speech from a file or the microphone, in its own language or translated to English.
57
 
58
+ **Narration tab (text to speech, speech generation, machine speech):** Kokoro (hexgrad) reads your text aloud in a choice of 28 English voices, American and British.
59
 
60
  **Describe tab:** three ways to describe what you have.
61
 
app.py CHANGED
@@ -82,9 +82,18 @@ LISTEN_MODEL = "laion/clap-htsat-unfused" # Recognises genre, mood, instrum
82
  SPEECH_MODEL = "openai/whisper-large-v3-turbo" # Speech to text
83
  VOICE = "af_heart" # Kokoro voice
84
  VOICE_RATE = 24000
 
85
  VOICES = {"Heart (woman)": "af_heart", "Bella (woman)": "af_bella", "Nicole (woman, soft)": "af_nicole",
86
  "Sarah (woman)": "af_sarah", "Adam (man)": "am_adam", "Michael (man)": "am_michael",
87
- "Fenrir (man, deep)": "am_fenrir", "Puck (man, lively)": "am_puck"}
 
 
 
 
 
 
 
 
88
  MAX_NARRATION_CHARS = 3000
89
  WORDS_PER_SECOND = 2.5
90
 
 
82
  SPEECH_MODEL = "openai/whisper-large-v3-turbo" # Speech to text
83
  VOICE = "af_heart" # Kokoro voice
84
  VOICE_RATE = 24000
85
+ # All 28 English voices of Kokoro. The first eight keep the names they had when there were only eight.
86
  VOICES = {"Heart (woman)": "af_heart", "Bella (woman)": "af_bella", "Nicole (woman, soft)": "af_nicole",
87
  "Sarah (woman)": "af_sarah", "Adam (man)": "am_adam", "Michael (man)": "am_michael",
88
+ "Fenrir (man, deep)": "am_fenrir", "Puck (man, lively)": "am_puck",
89
+ "Alloy (woman)": "af_alloy", "Aoede (woman)": "af_aoede", "Jessica (woman)": "af_jessica",
90
+ "Kore (woman)": "af_kore", "Nova (woman)": "af_nova", "River (woman)": "af_river", "Sky (woman)": "af_sky",
91
+ "Echo (man)": "am_echo", "Eric (man)": "am_eric", "Liam (man)": "am_liam", "Onyx (man)": "am_onyx",
92
+ "Santa (man)": "am_santa",
93
+ "Alice (British woman)": "bf_alice", "Emma (British woman)": "bf_emma",
94
+ "Isabella (British woman)": "bf_isabella", "Lily (British woman)": "bf_lily",
95
+ "Daniel (British man)": "bm_daniel", "Fable (British man)": "bm_fable",
96
+ "George (British man)": "bm_george", "Lewis (British man)": "bm_lewis"}
97
  MAX_NARRATION_CHARS = 3000
98
  WORDS_PER_SECOND = 2.5
99
 
tts_worker.py CHANGED
@@ -14,13 +14,26 @@ os.dup2(2, 1)
14
  import numpy as np
15
  from kokoro import KPipeline
16
 
17
- pipe = KPipeline(lang_code="a", device="cpu") # Kokoro is tiny (82M) and fast enough on the CPU
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  for line in sys.stdin:
20
  try:
21
  job = json.loads(line)
22
  chunks = [np.asarray(audio, dtype=np.float32)
23
- for _, _, audio in pipe(job["text"], voice=job["voice"], speed=float(job["speed"]))]
24
  np.save(job["out"], np.concatenate(chunks) if chunks else np.zeros(0, dtype=np.float32))
25
  answer = {"ok": True}
26
  except Exception as e:
 
14
  import numpy as np
15
  from kokoro import KPipeline
16
 
17
+ pipes = {"a": KPipeline(lang_code="a", device="cpu")} # Kokoro is tiny (82M) and fast enough on the CPU
18
+
19
+
20
+ def pipe_for(voice):
21
+ """American pronunciation for the af_/am_ voices, British for bf_/bm_. Both share one copy of the model."""
22
+ code = "b" if voice.startswith("b") else "a"
23
+ if code not in pipes:
24
+ try:
25
+ pipes[code] = KPipeline(lang_code=code, model=pipes["a"].model)
26
+ except Exception as e:
27
+ print(f"British pronunciation unavailable, using American: {type(e).__name__}: {e}", file=sys.stderr)
28
+ pipes[code] = pipes["a"]
29
+ return pipes[code]
30
+
31
 
32
  for line in sys.stdin:
33
  try:
34
  job = json.loads(line)
35
  chunks = [np.asarray(audio, dtype=np.float32)
36
+ for _, _, audio in pipe_for(job["voice"])(job["text"], voice=job["voice"], speed=float(job["speed"]))]
37
  np.save(job["out"], np.concatenate(chunks) if chunks else np.zeros(0, dtype=np.float32))
38
  answer = {"ok": True}
39
  except Exception as e: