2026-10-16

AS1102TL NAS 跑 kokoro 生成日語 mp3 語音檔

參考資料 ----

kokoro


以 mobaXterm 管理員權限登入 AS1102TL

要生成日語,需要 pyopenjtalk,下載並在 NAS 上進行編譯。
 
# 先在 AppCentral 找到 Entware 並安裝,這是 NAS 的套件管理
# 安裝的所有二進位檔、函式庫與標頭檔全都統一存放在 /opt(即 /volume1/.@plugins/AppCentral/entware/opt/)底下。
user$  opkg  update
user$  opkg  install  gcc  make  cmake

# The scripts cygdb, cython and cythonize are installed in '/volume1/.@plugins/AppCentral/python3/bin' which is not on PATH.

user$  export  TMPDIR=/volume1/tmp
user$  ~/.local/bin/pip3  install  cython  unidic-lite  --only-binary=:all:  --no-cache-dir


# 因為 pyopenjtalk 沒有提供適用於 ARM64 Linux + Python 3.12 的現成 Wheel 檔
# 所以要手動下載重新編譯
user$  cd /volume1/
# 建立暫存目錄 tmp
user$  mkdir  tmp
user$  cd  tmp
user$  mkdir  build_pyopenjtalk
user$  cd  build_pyopenjtalk
user$  ~/.local/bin/pip3  download  pyopenjtalk  --no-binary  :all:
# 本筆記下載了 pyopenjtalk-0.4.1.tar.gz
# 解壓縮
user$  tar  -xzf  pyopenjtalk-0.4.1.tar.gz
# 解壓縮的檔案放在 pyopenjtalk-0.4.1 目錄

user$  cd  /volume1/tmp/build_pyopenjtalk/pyopenjtalk-0.4.1/pyopenjtalk

# 這指令會將 openjtalk.pyx 生成 openjtalk.cpp
user$  python3  -m  cython  --cplus  openjtalk.pyx

# 以文字編輯軟體打開 openjtalk.cpp,如:vscode, notepad++...等,將這幾行插入 openjtalk.cpp 的第一列,再存檔
#include <unistd.h>
#include <limits.h>
#ifndef SSIZE_MAX
#define SSIZE_MAX LONG_MAX
#endif pyopenjtalk/openjtalk.cpp

# 可透過 head -n 6 pyopenjtalk/openjtalk.cpp 確認前幾行已包含這些定義。

user$  export  PATH=/opt/bin:$PATH
user$  export  CC=/opt/bin/gcc
user$  export  CXX=/opt/bin/g++
user$  export  TMPDIR=/volume1/tmp

# 這步驟會消耗蠻多時間...請耐心等候
user$  ~/.local/bin/pip3  install  .  --no-build-isolation  --no-cache-dir

# 日語假名/羅馬字轉換工具
user$  ~/.local/bin/pip3  install  jaconv  mojimoji  --no-cache-dir
 


合成日語 tts_jp.py
 
import os
import warnings
import io
import onnxruntime as ort
import soundfile as sf
from kokoro_onnx import Kokoro
from pydub import AudioSegment
from pydub.utils import which
from misaki import ja


# 限制執行緒數量,避免在 1GB RAM NAS 上過載
os.environ["OMP_NUM_THREADS"] = "2"
os.environ["ORT_NUM_THREADS"] = "2"

warnings.filterwarnings("ignore", category=UserWarning, module="joblib")

# 將靜態 ffmpeg 所在目錄放到環境變數 PATH 最前端
FFMPEG_DIR = "/volume1/Web/kokoro/ffmpeg-7.0.2-arm64-static"
os.environ["PATH"] = FFMPEG_DIR + ":" + os.environ.get("PATH", "")

# 明確指定使用支援 libmp3lame 的 ffmpeg 執行檔路徑
AudioSegment.converter = os.path.join(FFMPEG_DIR, "ffmpeg")
AudioSegment.ffmpeg = os.path.join(FFMPEG_DIR, "ffmpeg")


# 檔案路徑設定
MODEL_PATH = "/volume1/Web/kokoro/kokoro-v1.0.onnx"
VOICES_PATH = "/volume1/Web/kokoro/voices-v1.0.bin"
OUTPUT_MP3 = "/volume1/Web/mp3/lee_mood.mp3"


# 目標字串
text_input = "各作品はいくつかの世界設定を共有している。例外もあるが正式な作品のクレジットにはサンライズの共同筆名である矢立肇と、シリーズ第1作を手掛けた富野由悠季の名義を入れることが慣習となっている。"
text_input = "ガンダム(IP)は、映像作品を中心に、ガンプラなどのトイホビー、コンピュータゲーム、専門雑誌やコミックなどの書籍、ネットワークコンテンツ、アミューズメント施設など、さまざまな分野に展開する多角的な戦略を通じて、日本を代表するIPへと成長を遂げている。"

# 初始化 Kokoro ONNX
kokoro = Kokoro(model_path=MODEL_PATH, voices_path=VOICES_PATH)

# 初始化日語音素處理器 (Misaki G2P)
g2p = ja.JAG2P()
res = g2p(text_input)
phonemes = res[0] if isinstance(res, tuple) else res

# 將中文轉為 Kokoro 需要的音素格式
print(f"轉換音素結果: {phonemes}")

# 呼叫 create,傳入音素
print("正在合成語音...")
samples, sample_rate = kokoro.create(
    text=phonemes,
    voice="jf_nezumi",
    speed=1.0,
    is_phonemes=True
)


# 轉存為 MP3
# 先在記憶體中建立輕量 WAV 緩衝區,再由 pydub 調用 ffmpeg 封裝成 MP3
wav_buffer = io.BytesIO()
sf.write(wav_buffer, samples, sample_rate, format="WAV")
wav_buffer.seek(0)

audio_seg = AudioSegment.from_wav(wav_buffer)
audio_seg.export(OUTPUT_MP3, format="mp3", bitrate="192k")

print(f"完成!音訊已輸出至: {OUTPUT_MP3}")
 


相關筆記 ----


沒有留言:

張貼留言