This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

superconfig / pkgs / kokoro / stdout-support.patch
5.8 kB 153 lines
1--- a/kokoro/__main__.py 2025-12-21 20:28:56.595838972 +0100 2+++ b/kokoro/__main__.py 2025-12-21 20:50:06.842504063 +0100 3@@ -3,7 +3,10 @@ 4 python3 -m kokoro --text "The sky above the port was the color of television, tuned to a dead channel." -o file.wav --debug 5 6 echo "Bom dia mundo, como vão vocês" > text.txt 7-python3 -m kokoro -i text.txt -l p --voice pm_alex > audio.wav 8+python3 -m kokoro -i text.txt -l p --voice pm_alex -o output.wav 9+ 10+# Streaming from stdin to stdout (pipe to mpv): 11+ollama run llama3 "tell me a joke" | python3 -m kokoro -o - --stream | mpv --demuxer=rawaudio --demuxer-rawaudio-rate=24000 --demuxer-rawaudio-format=s16le --demuxer-rawaudio-channels=1 - 12 13 Common issues: 14 pip not installed: `uv pip install pip` 15@@ -13,6 +16,7 @@ 16 """ 17 18 import argparse 19+import sys 20 import wave 21 from pathlib import Path 22 from typing import Generator, TYPE_CHECKING 23@@ -47,22 +51,58 @@ 24 yield from pipeline(text, voice=voice, speed=speed, split_pattern=r"\n+") 25 26 27+def write_wav_audio(wav_file, text: str, kokoro_language: str, voice: str, speed=1) -> None: 28+ """Write audio frames to an open wav file handle.""" 29+ wav_file.setnchannels(1) # Mono audio 30+ wav_file.setsampwidth(2) # 2 bytes per sample (16-bit audio) 31+ wav_file.setframerate(24000) # Sample rate 32+ 33+ for result in generate_audio( 34+ text, kokoro_language=kokoro_language, voice=voice, speed=speed 35+ ): 36+ logger.debug(result.phonemes) 37+ if result.audio is None: 38+ continue 39+ audio_bytes = (result.audio.numpy() * 32767).astype(np.int16).tobytes() 40+ wav_file.writeframes(audio_bytes) 41+ 42+ 43 def generate_and_save_audio( 44- output_file: Path, text: str, kokoro_language: str, voice: str, speed=1 45+ output_file: str, text: str, kokoro_language: str, voice: str, speed=1 46+) -> None: 47+ if output_file == "-": 48+ # Write to stdout 49+ with wave.open(sys.stdout.buffer, "wb") as wav_file: 50+ write_wav_audio(wav_file, text, kokoro_language, voice, speed) 51+ else: 52+ with wave.open(str(Path(output_file).resolve()), "wb") as wav_file: 53+ write_wav_audio(wav_file, text, kokoro_language, voice, speed) 54+ 55+ 56+def stream_audio_raw( 57+ input_stream, kokoro_language: str, voice: str, speed: float 58 ) -> None: 59- with wave.open(str(output_file.resolve()), "wb") as wav_file: 60- wav_file.setnchannels(1) # Mono audio 61- wav_file.setsampwidth(2) # 2 bytes per sample (16-bit audio) 62- wav_file.setframerate(24000) # Sample rate 63- 64- for result in generate_audio( 65- text, kokoro_language=kokoro_language, voice=voice, speed=speed 66- ): 67+ """Stream audio as raw PCM s16le to stdout, processing stdin line by line.""" 68+ from kokoro import KPipeline 69+ 70+ if not voice.startswith(kokoro_language): 71+ logger.warning(f"Voice {voice} is not made for language {kokoro_language}") 72+ 73+ pipeline = KPipeline(lang_code=kokoro_language) 74+ output = sys.stdout.buffer 75+ 76+ for line in input_stream: 77+ line = line.rstrip('\n\r') 78+ if not line: 79+ continue 80+ logger.debug(f"Processing line: {line!r}") 81+ for result in pipeline(line, voice=voice, speed=speed, split_pattern=r"\n+"): 82 logger.debug(result.phonemes) 83 if result.audio is None: 84 continue 85 audio_bytes = (result.audio.numpy() * 32767).astype(np.int16).tobytes() 86- wav_file.writeframes(audio_bytes) 87+ output.write(audio_bytes) 88+ output.flush() 89 90 91 def main() -> None: 92@@ -83,8 +123,8 @@ 93 "-o", 94 "--output-file", 95 "--output_file", 96- type=Path, 97- help="Path to output WAV file", 98+ type=str, 99+ help="Path to output WAV file (use - for stdout)", 100 required=True, 101 ) 102 parser.add_argument( 103@@ -107,6 +147,11 @@ 104 help="Speech speed", 105 ) 106 parser.add_argument( 107+ "--stream", 108+ action="store_true", 109+ help="Stream mode: read stdin line-by-line, output raw PCM s16le 24kHz mono (for piping to mpv)", 110+ ) 111+ parser.add_argument( 112 "--debug", 113 action="store_true", 114 help="Print DEBUG messages to console", 115@@ -118,6 +163,20 @@ 116 117 lang = args.language or args.voice[0] 118 119+ # Streaming mode: read stdin line by line, output raw PCM 120+ if args.stream: 121+ if args.output_file != "-": 122+ logger.warning("Streaming mode always outputs to stdout, ignoring output file") 123+ if args.text: 124+ raise Exception("Cannot use --text with --stream, use stdin") 125+ if args.input_file: 126+ with open(args.input_file) as f: 127+ stream_audio_raw(f, lang, args.voice, args.speed) 128+ else: 129+ stream_audio_raw(sys.stdin, lang, args.voice, args.speed) 130+ return 131+ 132+ # Non-streaming mode: read all input, output WAV 133 if args.text is not None and args.input_file is not None: 134 raise Exception("You cannot specify both 'text' and 'input_file'") 135 elif args.text: 136@@ -126,14 +185,13 @@ 137 file: Path = args.input_file 138 text = file.read_text() 139 else: 140- import sys 141- print("Press Ctrl+D to stop reading input and start generating", flush=True) 142+ print("Press Ctrl+D to stop reading input and start generating", file=sys.stderr, flush=True) 143 text = '\n'.join(sys.stdin) 144 145 logger.debug(f"Input text: {text!r}") 146 147- out_file: Path = args.output_file 148- if not out_file.suffix == ".wav": 149+ out_file: str = args.output_file 150+ if out_file != "-" and not out_file.endswith(".wav"): 151 logger.warning("The output file name should end with .wav") 152 generate_and_save_audio( 153 output_file=out_file,