git: 065e40e5f9b3 - main - misc/py-kokoro: Add programs; Add model URL to WWW; Add to pkg-descr

From: Yuri Victorovich <yuri_at_FreeBSD.org>
Date: Wed, 18 Mar 2026 16:43:49 UTC
The branch main has been updated by yuri:

URL: https://cgit.FreeBSD.org/ports/commit/?id=065e40e5f9b35adbd23c4fbae602f0bdf34bb67b

commit 065e40e5f9b35adbd23c4fbae602f0bdf34bb67b
Author:     Yuri Victorovich <yuri@FreeBSD.org>
AuthorDate: 2026-03-18 16:03:30 +0000
Commit:     Yuri Victorovich <yuri@FreeBSD.org>
CommitDate: 2026-03-18 16:43:47 +0000

    misc/py-kokoro: Add programs; Add model URL to WWW; Add to pkg-descr
    
    Programs:
    * bin/kokoro-text-to-audio - speaks a given text
    * bin/kokoro-text-to-wav   - converts a given text to a WAV file
---
 misc/py-kokoro/Makefile                      | 19 ++++++++++--
 misc/py-kokoro/files/kokoro-text-to-audio.py | 44 ++++++++++++++++++++++++++++
 misc/py-kokoro/files/kokoro-text-to-wav.py   | 42 ++++++++++++++++++++++++++
 misc/py-kokoro/pkg-descr                     |  3 ++
 4 files changed, 105 insertions(+), 3 deletions(-)

diff --git a/misc/py-kokoro/Makefile b/misc/py-kokoro/Makefile
index 38e460daedaa..0deca2a331f4 100644
--- a/misc/py-kokoro/Makefile
+++ b/misc/py-kokoro/Makefile
@@ -1,12 +1,14 @@
 PORTNAME=	kokoro
 DISTVERSION=	0.9.4
+PORTREVISION=	1
 CATEGORIES=	misc python # machine-learning
 MASTER_SITES=	PYPI
 PKGNAMEPREFIX=	${PYTHON_PKGNAMEPREFIX}
 
 MAINTAINER=	yuri@FreeBSD.org
 COMMENT=	Text-to-speech inference library for Kokoro-82M model
-WWW=		https://github.com/hexgrad/kokoro
+WWW=		https://github.com/hexgrad/kokoro \
+		https://huggingface.co/hexgrad/Kokoro-82M
 
 LICENSE=	APACHE20
 LICENSE_FILE=	${WRKSRC}/LICENSE
@@ -20,17 +22,28 @@ RUN_DEPENDS=	${PYTHON_PKGNAMEPREFIX}huggingface-hub>0:misc/py-huggingface-hub@${
 		${PYTHON_PKGNAMEPREFIX}pytorch>0:misc/py-pytorch@${PY_FLAVOR} \
 		${PYTHON_PKGNAMEPREFIX}spacy>0:textproc/py-spacy@${PY_FLAVOR} \
 		${PYTHON_PKGNAMEPREFIX}transformers>=0:misc/py-transformers@${PY_FLAVOR}
-TEST_DEPENDS=	${PYTHON_PKGNAMEPREFIX}ipython>0:devel/ipython@${PY_FLAVOR} \
+# extra run dependencies for kokoro-text-to-audio and kokoro-text-to-wav
+RUN_DEPENDS+=	${PYTHON_PKGNAMEPREFIX}ipython>0:devel/ipython@${PY_FLAVOR} \
 		${PYTHON_PKGNAMEPREFIX}SoundFile>0:audio/py-SoundFile@${PY_FLAVOR} \
 		mpv:multimedia/mpv
 
 USES=		python
-USE_PYTHON=	autoplist concurrent pep517
+USE_PYTHON=	pep517 concurrent autoplist
 
 NO_ARCH=	yes
 
+PLIST_FILES=	bin/kokoro-text-to-audio \
+		bin/kokoro-text-to-wav
+
 TEST_ENV=	${MAKE_ENV} PYTHONPATH=${STAGEDIR}${PYTHONPREFIX_SITELIBDIR}
 
+post-install:
+	${INSTALL_SCRIPT} ${FILESDIR}/kokoro-text-to-audio.py ${STAGEDIR}${PREFIX}/bin/kokoro-text-to-audio
+	${INSTALL_SCRIPT} ${FILESDIR}/kokoro-text-to-wav.py ${STAGEDIR}${PREFIX}/bin/kokoro-text-to-wav
+	@${REINPLACE_CMD} -i '' 's|%%PYTHON%%|${PYTHON_CMD}|' \
+		${STAGEDIR}${PREFIX}/bin/kokoro-text-to-audio \
+		${STAGEDIR}${PREFIX}/bin/kokoro-text-to-wav
+
 do-test:
 	@cd ${WRKSRC} && \
 		${SETENV} ${TEST_ENV} ${PYTHON_CMD} ${FILESDIR}/example.py && \
diff --git a/misc/py-kokoro/files/kokoro-text-to-audio.py b/misc/py-kokoro/files/kokoro-text-to-audio.py
new file mode 100644
index 000000000000..71cb682737d6
--- /dev/null
+++ b/misc/py-kokoro/files/kokoro-text-to-audio.py
@@ -0,0 +1,44 @@
+#!%%PYTHON%%
+
+import sys
+import os
+import shutil
+import subprocess
+from datetime import datetime
+from kokoro import KPipeline
+import soundfile as sf
+
+def main():
+    if len(sys.argv) != 2:
+        print("Usage: kokoro-text-to-audio <text>", file=sys.stderr)
+        sys.exit(1)
+    
+    text = sys.argv[1]
+    
+    timestamp = datetime.now().strftime("%Y%m%d%H%M%S%f")
+    temp_dir = f"/tmp/kokoro-{timestamp}"
+    temp_wav = os.path.join(temp_dir, "output.wav")
+    
+    try:
+        os.makedirs(temp_dir, exist_ok=True)
+        
+        pipeline = KPipeline(lang_code='a')
+        generator = pipeline(text, voice='af_heart')
+        
+        audio_data = None
+        for _, _, audio in generator:
+            audio_data = audio
+        
+        if audio_data is not None:
+            sf.write(temp_wav, audio_data, 24000)
+            subprocess.run(['mpv', temp_wav], check=True)
+        else:
+            print("Error: No audio generated", file=sys.stderr)
+            sys.exit(1)
+    
+    finally:
+        if os.path.exists(temp_dir):
+            shutil.rmtree(temp_dir)
+
+if __name__ == '__main__':
+    main()
diff --git a/misc/py-kokoro/files/kokoro-text-to-wav.py b/misc/py-kokoro/files/kokoro-text-to-wav.py
new file mode 100644
index 000000000000..3b14fa09c6c9
--- /dev/null
+++ b/misc/py-kokoro/files/kokoro-text-to-wav.py
@@ -0,0 +1,42 @@
+#!%%PYTHON%%
+
+import sys
+import os
+import shutil
+from datetime import datetime
+from kokoro import KPipeline
+import soundfile as sf
+
+def main():
+    if len(sys.argv) != 3:
+        print("Usage: kokoro-text-to-wav <text> <wav-output-file>", file=sys.stderr)
+        sys.exit(1)
+    
+    text = sys.argv[1]
+    output_file = sys.argv[2]
+    
+    timestamp = datetime.now().strftime("%Y%m%d%H%M%S%f")
+    temp_dir = f"/tmp/kokoro-{timestamp}"
+    
+    try:
+        os.makedirs(temp_dir, exist_ok=True)
+        
+        pipeline = KPipeline(lang_code='a')
+        generator = pipeline(text, voice='af_heart')
+        
+        audio_data = None
+        for _, _, audio in generator:
+            audio_data = audio
+        
+        if audio_data is not None:
+            sf.write(output_file, audio_data, 24000)
+        else:
+            print("Error: No audio generated", file=sys.stderr)
+            sys.exit(1)
+    
+    finally:
+        if os.path.exists(temp_dir):
+            shutil.rmtree(temp_dir)
+
+if __name__ == '__main__':
+    main()
diff --git a/misc/py-kokoro/pkg-descr b/misc/py-kokoro/pkg-descr
index a551be6f5900..7692605e9411 100644
--- a/misc/py-kokoro/pkg-descr
+++ b/misc/py-kokoro/pkg-descr
@@ -6,3 +6,6 @@ and the Hugging Face ecosystem. The library supports multiple languages
 and voices through the Misaki grapheme-to-phoneme engine.
 
 For full English language support, install textproc/py-phonemizer separately.
+
+Kokoro is the fastest production quality English Text-To-Speech convertor
+available as of early 2026.