irodori-TTS for 読み分けちゃん / アプリ開発者の方へ
アプリを開くと、パソコンの中に OpenAI 互換の読み上げ API が立ちます。Python の知識は要りません。
Aratako 氏の音声合成 Irodori-TTS は、日本語の声を参照音声とキャプション(演技指示)から作れる、とてもよくできたモデルです。 ただ、そのまま使うには Python や CUDA の準備が要り、配信ソフトの利用者には敷居が高いものでした。
このアプリは、その敷居を無くすためのものです。インストールして開くだけで、Irodori-TTS がパソコンの中で動き、 配信ソフト 読み分けちゃん2 から読み上げに使えます。そして同じ口を、ほかのアプリからも使えるように開けてあります。
Irodori-TTS の開発趣旨(MIT ライセンスと Ethical Restrictions)に沿って使う方には、機能を開放します。 読み分けちゃん2 だけのための口ではありません。自分のツール・ゲーム・配信の仕掛けから、どうぞ呼んでください。
このアプリは非公式です。Aratako 氏とは関係がありません。API についての質問や不具合は、Aratako 氏ではなく X の @yomiwakechan へお願いします。
http://127.0.0.1:18088 に HTTP の口が立ちます。アプリを閉じると止まります。
あなたのアプリは、利用者にこのアプリを開いておいてもらうだけで済みます(自分で IrodoriTtsYwk.Launcher.exe を起動してもかまいません。窓が出たまま残ります)。127.0.0.1 にしてください。localhost だと IPv6 を先に試す分、毎回 1〜2 秒遅くなります。Authorization ヘッダを付けても無視されます。fetch することは、いまはできません(CORS のヘッダを返しません)。ネイティブのアプリやスクリプトから呼んでください。本文を送ると、wav(48 kHz・モノラル)が返ります。
curl -X POST http://127.0.0.1:18088/v1/audio/speech ^
-H "Content-Type: application/json" ^
-d "{\"model\":\"irodori-tts\",\"input\":\"こんにちは。\",\"voice\":\"デフォルト\",\"response_format\":\"wav\"}" ^
-o out.wav
$body = @{
model = "irodori-tts"; input = "こんにちは。"; voice = "デフォルト"; response_format = "wav"
irodori = @{ caption = "明るく"; num_steps = 40 }
} | ConvertTo-Json
Invoke-WebRequest -Uri "http://127.0.0.1:18088/v1/audio/speech" -Method Post `
-ContentType "application/json; charset=utf-8" -Body ([Text.Encoding]::UTF8.GetBytes($body)) `
-OutFile out.wav
import json, urllib.request
body = {"model": "irodori-tts", "input": "こんにちは。", "voice": "デフォルト",
"response_format": "wav", "irodori": {"caption": "明るく", "num_steps": 40}}
req = urllib.request.Request(
"http://127.0.0.1:18088/v1/audio/speech",
data=json.dumps(body, ensure_ascii=False).encode("utf-8"),
headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=120) as res, open("out.wav", "wb") as f:
f.write(res.read())
using var http = new HttpClient { BaseAddress = new Uri("http://127.0.0.1:18088/") };
var json = """{"model":"irodori-tts","input":"こんにちは。","voice":"デフォルト","response_format":"wav"}""";
using var res = await http.PostAsync("v1/audio/speech",
new StringContent(json, Encoding.UTF8, "application/json"));
res.EnsureSuccessStatusCode();
await File.WriteAllBytesAsync("out.wav", await res.Content.ReadAsByteArrayAsync());
OpenAI の公式クライアントも使えます。base_url を http://127.0.0.1:18088/v1 に向け、api_key は何でもよく、
model="irodori-tts"・response_format="wav" を必ず指定してください(既定の mp3 は 400 になります)。
| 口 | 何をするか |
|---|---|
GET /health | 生きているか。モデルを読み込む前でも 200 を返します(下の「作法」を参照)。 |
GET /ywk/status | このアプリの版・読み込みの状態(runtime.loaded)・実際に動いている GPU(device)・声の数・いま走っている合成の数(requests.in_flight)・GPU メモリ。
このアプリかどうかは、この口が 200 を返すかで見分けます(もとの Irodori-TTS-Server には無い口です)。 |
GET /params | 指定できる全パラメータの一覧=既定値・範囲・型・説明。固定表を持たず、これを読んで組んでください。モデルを読み込む前でも 200 です。 |
GET /v1/audio/voices | 声の一覧(OpenAI 互換の形)。「デフォルト」が必ず先頭にあります。 |
GET /ywk/voices | 同じ一覧に、表示名・件数・一覧が壊れているときの理由(error)を添えたもの。 |
POST /v1/audio/speech | 読み上げ。本文と声を送ると wav が 1 本返ります。 |
POST /ywk/voices/import | 声を増やす(v2.0.7 から)。お手本の音声ファイルの中身と名前を送ると、このアプリがそれを声として登録します(下の「声」を参照)。 |
GET /ywk/voices/import/{id} | 上で送った 1 件が登録できたか(queued/registering/done/failed)。 |
/ywk/warmup と /ywk/voices/precompute はアプリの内部が使う口です。呼ばないでください。
もとの Irodori-TTS-Server の声の登録・削除の口(POST/PUT/DELETE /v1/audio/voices)は閉じてあります。
自分のアプリから声を増やしたいときは POST /ywk/voices/import を使ってください(下の「声」を参照)。
/docs(Swagger UI)はもとの Irodori-TTS-Server のまま開けます。
GET /health が 200 でも、モデルはまだ裏で読み込み中のことがあります。GET /ywk/status の runtime.loaded が true になってから読み上げを送ってください。
アプリを開いてから 20〜70 秒ほどかかります(GPU によります)。2 秒おきに見るのがちょうどよいです。runtime は {loaded, loading, error} の 3 つで、error に文が入ったら「読み込めなかった」です。理由の 1 行をそのまま利用者に見せてかまいません(パスは入りません)。{"model": "irodori-tts",
"input": "本文(1〜4096 字)",
"voice": "声の名前(一覧の id)",
"response_format": "wav",
"speed": 1.0,
"irodori": {"caption": "明るく", "num_steps": 40, "seed": 1234}}
model は "irodori-tts" 固定です。voice は一覧から名前で選びます。省くと「デフォルト」(参照音声なしの、Irodori-TTS 自身の声)になります。response_format は wav だけです(mp3 などにする ffmpeg を同梱していないため)。irodori の中に入れます。優先順は「irodori の中 > トップレベル > アプリの既定」です。
既定に戻したいときは、その項目を送らないでください(null や空文字も「未指定」と読みます)。speed(0.25〜4.0)と irodori.duration_scale はどちらか一方だけ送ってください(両方送ると掛け合わさります)。irodori.seconds を指定すると、長い本文の自動分割が切れて、出力がその秒数ちょうどに引き伸ばされます。ふつうは送らないでください。X-Irodori-Seed(使われた乱数の種)が付きます。同じ音を再現したいときは irodori.seed に入れて送り直してください。EMOJI_ANNOTATIONS.md)はそのまま効きます(綴りの揺れ=肌の色や VS16 の有無は正しい形に直します)。
それ以外の絵文字は取り除いてから読み上げます(取り除いた数は応答ヘッダ X-Ywk-Emoji-Removed)。取り除いた結果、読む文字が残らなければ、
400 ではなく 200 の無音の wav(PCM 16 bit・モノラル・X-Ywk-Silent: 1)が返ります。空白だけの本文は今までどおり 400 です。もとの Irodori-TTS-Server は、知らない項目名や範囲外の値を黙って無視します(綴りを間違えると「なぜか効かない」になります)。
このアプリはそれを 400 で止めます。エラーの本文は必ずこの形で、code で機械的に見分けられます。
{"error": {"message": "unknown field: num_step",
"type": "invalid_request_error",
"param": "num_step",
"code": "ywk_unknown_field"}}
code | 意味 |
|---|---|
ywk_unknown_field | 知らない項目名(トップレベルでも irodori の中でも) |
ywk_out_of_range | 範囲外(範囲は /params の min/max と同じ) |
ywk_type_error・ywk_invalid_enum | 型違い・選択肢に無い値 |
ywk_literal_top_level | t_schedule_mode・decode_mode・cfg_guidance_mode は irodori の中にだけ置けます |
ywk_voice_and_no_ref・ywk_voice_and_reference | voice と、参照音声を直接指す項目(no_ref・ref_wav など)を同時に送った |
ywk_unsupported_response_format | wav 以外を求めた |
ywk_unknown_voice | 一覧に無い声の名前 |
ywk_unknown_model・ywk_empty_input | model が違う・本文が空白だけ |
ywk_runtime_unavailable(503) | 読み込み中に待ちきれなかった・読み込みに失敗している |
ywk_upstream_error・ywk_server_error | そのほかの失敗(GPU のメモリ不足など) |
エラーの本文に、利用者のパソコンのパスは入りません。message はそのまま記録に残して構いませんが、利用者に見せる文は code から組んでください。
GET /ywk/status の requests.in_flight で、いま走っている数が分かります。stream_format: "sse")を分割して受け取る仕掛けも通してありますが、1 本の wav を受け取る形をおすすめします。GET /params が、指定できる項目を既定値・範囲・説明つきで返します。既定値はアプリの設定を反映した「いま効いている値」なので、
固定表を持たず、この応答から画面を組んでください。よく使うのはこのあたりです。
項目(irodori の中) | 意味 | 既定 |
|---|---|---|
caption | キャプション(演技指示)。「明るく」「落ち着いて」など自由文。空なら未指定。 | "" |
num_steps | 品質。少ないほど速く、多いほど丁寧(アプリの「低品質(高速)」は 10・「高品質」は 40)。 | 40 |
cfg_scale_text | 本文への追従の強さ(発音・滑舌が弱いときに少し上げる)。 | 3.0 |
cfg_scale_caption | キャプションの効きの強さ。 | 3.0 |
cfg_scale_speaker | 参照音声(声の似せ方)の強さ。 | /params を参照 |
seed | 乱数の種。同じ種=同じ音。省くと毎回変わる。 | なし |
speed(トップレベル) | 速さ 0.25〜4.0。 | 1.0 |
応答の schema(いまは 1)は、項目を消したり意味を変えたりするときにだけ上げます。項目が増えるだけなら上げません。知らない項目は無視してください。
このアプリの版は GET /ywk/status の version で分かります。
GET /v1/audio/voices か GET /ywk/voices で取ります。id がそのまま表示名で、日本語です(例:琴葉茜(関西弁))。voice を省いたときもこれになります。POST /ywk/voices/import を使ってください。ywk_unknown_voice で返ります。preset(同梱の声か)・no_ref(参照なしか)が付きます。参照音声のパスは返しません。お手本の音声(参照音声)をファイルの中身ごと送ると、このアプリがそれを声として登録します。 パスではなく中身を送るので、別のパソコンで動いているこのアプリにも送れます。
POST /ywk/voices/import
Content-Type: application/json
{"display_name": "私の声",
"audio_base64": "<音声ファイルの中身を base64 にしたもの>",
"format": "wav",
"caption": "落ち着いて",
"client": "myapp"}
受け取ると 202 で {"id": "…", "state": "queued", "display_name": "…"} が返ります。
この時点では、まだ声は増えていません。GET /ywk/voices/import/<id> を 1〜2 秒おきに読み、
state が done になってから GET /ywk/voices を読み直してください。そこに display_name の声がいます。
{"id": "…", "state": "queued|registering|done|failed",
"display_name": "私の声", "error": null, "received_at": "2026-09-24T12:34:56Z"}
done までは数秒です。Radeon(ROCm)では、声ごとの下ごしらえをするぶんもう数秒〜十数秒かかります。queued のまま止まります。自分の側でも期限を持ってください。format は wav・mp3・flac・ogg・opus のどれかです。中身と食い違うと 400 になります。display_name がそのまま声の名前(読み上げの voice に送る id)になります。64 字まで・日本語可。「デフォルト」など参照なしを指す名前は使えません。caption(演技指示の既定)と client(送った側の名乗り)は省けます。client は「どのアプリから来たか」として、このアプリの声の説明に残ります。state が failed になり、error に理由が 1 行入ります。その場合は同じ名前で送り直せます。| 番号 | code | 意味 |
|---|---|---|
| 415 | ywk_import_json_only | Content-Type が application/json ではない(multipart では受けません) |
| 403 | ywk_browser_origin | Origin か Referer が付いている=ウェブページからは送れません |
| 413 | ywk_import_too_large | 音声が 32 MiB を超えている |
| 400 | ywk_import_bad_audio | base64 が解けない・中身が format と違う |
| 400 | ywk_import_bad_name | 名前が空・64 字超・制御文字・使えない名前 |
| 409 | ywk_voice_exists | 同じ名前の声が既にある(受け取って待っている分も含みます) |
| 404 | ywk_import_unknown | GET /ywk/voices/import/<id> の id が無い |
この口は受け取るだけで、声の一覧を書き換えるのはこのアプリ自身です。だから JSON でしか受けず、
Origin/Referer の付いた要求を断り、32 MiB で止めます。利用者の音声ファイルを扱う面を、
鍵なしでウェブページから触れる形にしないためです。
この読み上げで作った音声は、Aratako 氏の Irodori-TTS-v4.1-Small の利用条件に従います。 コードとモデルは MIT ライセンスで、加えて次の Ethical Restrictions があります(原文はモデルカードにあります)。