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 本返ります。 |
/ywk/warmup と /ywk/voices/precompute はアプリの内部が使う口です。呼ばないでください。
声の登録・削除の口(POST/PUT/DELETE /v1/audio/voices)は、この配布では閉じてあります(下の「声」を参照)。
/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 に入れて送り直してください。もとの 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 を省いたときもこれになります。ywk_unknown_voice で返ります。preset(同梱の声か)・no_ref(参照なしか)が付きます。参照音声のパスは返しません。この読み上げで作った音声は、Aratako 氏の Irodori-TTS-v4.1-Small の利用条件に従います。 コードとモデルは MIT ライセンスで、加えて次の Ethical Restrictions があります(原文はモデルカードにあります)。