Skip to content

feat: 短テキスト合成品質改善 (Strategy A/B/C) を全7ランタイムに実装 - #337

Merged
ayutaz merged 5 commits into
devfrom
feat/short-text-mitigation
Apr 9, 2026
Merged

feat: 短テキスト合成品質改善 (Strategy A/B/C) を全7ランタイムに実装#337
ayutaz merged 5 commits into
devfrom
feat/short-text-mitigation

Conversation

@ayutaz

@ayutaz ayutaz commented Apr 9, 2026

Copy link
Copy Markdown
Owner

Summary

VITSアーキテクチャの構造的制限により、短いテキスト入力で音声が崩れる問題に対し、ランタイム側の推論コードで3つの緩和策を全7ランタイムに実装。

  • Strategy A (Silence Padding + Post-trim): phoneme_ids < 40 の場合、pause トークンで前後パディング → 合成後にRMSベースで無音トリム
  • Strategy B (Dynamic Scales Adjustment): 短入力時に noise_scale/noise_w を自動低減し Duration Predictor の確率的変動を抑制
  • Strategy C (SSML/Silence Auto-injection): 10文字以下のテキストに前後300msの無音を自動挿入 (SSML対応4ランタイム + C# audio-level)

Changes

対応ランタイム (32ファイル, +6,937行)

ランタイム Strategy A Strategy B Strategy C テスト
Python (runtime) 26件
Python (infer_onnx) N/A 38件
Rust 33件
C# 61件
Go 55件
C++ N/A 42件
WASM/JS N/A 37件
Docker API - - - 12件
Docker WebUI - - - 10件

共通仕様 (docs/spec/short-text-contract.toml)

パラメータ
min_phoneme_ids 40
noise_scale_floor 0.5
noise_w_floor 0.4
trim_threshold_rms 0.01
trim_min_samples 2205 (22050Hz × 0.1s)
short_text_chars 10
break_time_ms 300

レビュー指摘修正 (2nd commit)

  • infer_onnx: Strategy B がパディング後に実行される順序バグを修正
  • C++: phoneme timing にパディング前の IDs を使用するよう修正
  • C++: trimSilence の partial window 処理を追加
  • Go: padProsodyFeatures の off-by-one バグを修正
  • WASM/JS: prosody padding の参照共有を修正
  • Python runtime: PAD ID を定数化
  • Docker: SSML <speak> チェックを追加
  • RMS比較演算子: > に全ランタイム統一

Test plan

  • Python runtime テスト (src/python_run/tests/test_short_text_mitigation.py) — 26件
  • Python infer_onnx テスト (src/python/tests/test_infer_onnx.py) — 38件
  • Rust テスト (cargo test -p piper-plus) — 33件 (short-text関連)
  • C# テスト (dotnet test src/csharp/PiperPlus.sln) — 61件 (short-text関連)
  • Go テスト (cd src/go && go test ./piperplus/) — 55件
  • C++ テスト (CMake build + test) — 42件
  • WASM/JS テスト (node --test src/wasm/openjtalk-web/test/js/) — 37件
  • Docker API テスト (docker/python-inference/test_openai_api.py) — 12件
  • Docker WebUI テスト (docker/webui/test_app.py) — 10件
  • 短いテキスト (「こんにちは。」等) での音声合成品質を手動確認

Copilot AI review requested due to automatic review settings April 9, 2026 12:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

短いテキスト入力で VITS 合成が崩れる/0秒になる問題を、推論側の共通ロジックで緩和するために、Strategy A/B/C(padding + trim、scale 調整、短文への無音注入)を複数ランタイムへ実装し、仕様・テスト・Docker/UI の警告まで含めて整備するPRです。

Changes:

  • Strategy A/B を各ランタイムの推論パスに追加(短音素列の padding + 合成後トリム、短入力時の noise_scale/noise_w 自動低減)
  • Strategy C を SSML 対応/非対応ランタイムに合わせて実装(SSML <break> ラップ or 音声レベル無音パディング)
  • 仕様契約(TOML)・詳細ドキュメント・ランタイム別テストを追加/更新

Reviewed changes

Copilot reviewed 31 out of 32 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
src/wasm/openjtalk-web/types/index.d.ts WASM/JS 向け short-text ヘルパー型定義を追加
src/wasm/openjtalk-web/test/js/test-short-text-mitigation.js WASM/JS Strategy A/B の単体+統合テストを追加
src/wasm/openjtalk-web/test/js/test-piper-plus.js 既存テストが short-text 緩和策の影響を受けないよう調整
src/wasm/openjtalk-web/test/js/test-piper-plus-synthesize-flow.js synthesize フロー検証を short-text 回避条件に合わせて更新
src/wasm/openjtalk-web/test/js/test-piper-plus-boundary.js 境界系テストを short-text 回避条件に合わせて更新
src/wasm/openjtalk-web/src/index.js WASM/JS の synthesize に Strategy A/B を実装
src/rust/piper-core/src/voice.rs Rust の synthesize_text に Strategy C(SSMLラップ)を追加
src/rust/piper-core/src/short_text.rs Rust Strategy C(短文 SSML <break> ラップ)を新規追加
src/rust/piper-core/src/lib.rs short_text モジュール公開・一部定数再export
src/rust/piper-core/src/engine.rs Rust Engine に Strategy A/B(pad/trim/scale)を実装+テスト追加
src/python/tests/test_infer_onnx.py infer_onnx の A/B/trim のテスト追加・順序バグ回帰テスト追加
src/python/piper_train/infer_onnx.py infer_onnx CLI に Strategy A/B と post-trim を実装
src/python_run/tests/test_short_text_mitigation.py Python runtime の A/B/C のテストを新規追加
src/python_run/piper/voice.py Python runtime の Strategy A/B/C を実装(stream + ids_to_raw)
src/go/piperplus/synthesize.go Go の Synthesize で Strategy C(音声レベル無音パディング)を適用
src/go/piperplus/short_text.go Go の short-text(A/B/C)ヘルパーを新規追加
src/go/piperplus/engine.go Go Engine の推論入力に Strategy A/B と post-trim を適用
src/csharp/PiperPlus.Core/Inference/ShortTextProcessor.cs C# の Strategy A/B/C ユーティリティを新規追加
src/csharp/PiperPlus.Core/Inference/PiperSession.cs C# ONNX 推論パスに Strategy A/B + post-trim を統合
src/csharp/PiperPlus.Core.Tests/ShortTextProcessorTests.cs C# ShortTextProcessor の網羅テストを新規追加
src/csharp/PiperPlus.Cli/Program.cs C# CLI で Strategy C(短文検出→音声レベル無音パディング)を適用
src/cpp/tests/test_short_text_mitigation.cpp C++ Strategy A/B/trim/タイミング回りのテストを新規追加
src/cpp/tests/CMakeLists.txt C++ テストターゲットへ short-text テストを追加
src/cpp/piper.cpp C++ 推論パスに Strategy A/B + post-trim + timing修正を実装
docs/spec/short-text-contract.toml 全ランタイム共通の short-text 仕様(契約)を追加
docs/features/short-text-synthesis.md 課題背景・戦略・運用ガイドのドキュメントを追加
docker/webui/test_app.py WebUI の short-text 判定関数を import せず検証するテストを追加
docker/webui/app.py WebUI で short-text 警告表示+判定関数を追加
docker/python-inference/test_openai_api.py API で short-text warning header を検証するテストを追加
docker/python-inference/inference.py API で short-text warning header を返す処理を追加
CLAUDE.md short-text 改善の概要と参照先を追記

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/wasm/openjtalk-web/src/index.js
Comment thread src/rust/piper-core/src/short_text.rs
Comment thread src/csharp/PiperPlus.Core/Inference/ShortTextProcessor.cs
Comment thread src/csharp/PiperPlus.Core/Inference/ShortTextProcessor.cs Outdated
Comment thread src/csharp/PiperPlus.Core/Inference/ShortTextProcessor.cs Outdated
Comment thread src/rust/piper-core/src/engine.rs
Comment thread src/python_run/piper/voice.py Outdated
Comment thread docker/webui/app.py Outdated
Comment thread docker/python-inference/inference.py Outdated
Comment thread docs/features/short-text-synthesis.md Outdated
ayutaz added 3 commits April 9, 2026 21:58
VITSアーキテクチャの構造的制限により、短いテキスト入力で音声が崩れる
問題に対し、ランタイム側の推論コードで3つの緩和策を実装。

Strategy A: Silence Padding + Post-trim
  - phoneme_ids < 40 の場合、pause トークンで前後パディング
  - 合成後にRMSベースで無音をトリム

Strategy B: Dynamic Scales Adjustment
  - 短入力時に noise_scale/noise_w を自動低減
  - Duration Predictor の確率的変動を抑制

Strategy C: SSML <break> Auto-injection (SSML対応4ランタイム)
  - 10文字以下のテキストに <break time="300ms"/> を自動挿入

対応ランタイム:
  - Python (runtime + infer_onnx): A+B+C
  - Rust: A+B+C
  - C#: A+B+C
  - Go: A+B+C
  - C++: A+B
  - WASM/JS: A+B
  - Docker API/WebUI: 警告表示 (Strategy E)

テスト追加: 計250件以上 (全ランタイム合計)
仕様: docs/spec/short-text-contract.toml
バグ修正:
- Python infer_onnx: Strategy B がパディング後に実行される順序バグを修正
  (original_len パラメータ追加で対応)
- C++: extractTimingsFromDurations にパディング前の originalPhonemeIds を渡すよう修正
- C++: trimSilence の partial window (末尾非倍数サンプル) 処理を追加
- Go: padProsodyFeatures の単一要素入力での off-by-one バグを修正
- WASM/JS: prosody padding の参照共有を修正 (fill → map で独立配列化)
- Python runtime: PAD ID を phoneme_id_map.get() から定数 0 に変更
- Docker API/WebUI: _is_short_text() に <speak> SSML チェックを追加
- RMS比較演算子を > に統一 (infer_onnx, C# が >= だった)

機能追加:
- C#: Strategy C を audio-level silence padding として統合
  (WrapShortTextWithBreaks を検出器として使用 + PadSilenceForShortText)

テスト追加: 計60件
- Python infer_onnx: 統合テスト7件
- Go: 境界条件・エッジケーステスト21件
- C++: phoneme timing + partial window テスト10件
- C#: PadSilenceForShortText テスト10件
- WASM/JS: prosody参照独立性テスト1件
- Docker WebUI: test_app.py 新規作成 (10件)
- Docker API: SSMLチェックテスト2件 (inference.py)

ドキュメント更新:
- docs/features/short-text-synthesis.md: Implementation Status を実装済みに更新
- docs/spec/short-text-contract.toml: 全ランタイムの実装状況を反映
- ruff format: inference.py, infer_onnx.py を整形
- rustfmt: engine.rs のフォーマット修正
- Go lint: engine.go の不要な nil チェック除去 (staticcheck S1031)
- Go: Durations をパディング前の長さにトリム (integration-test修正)
- C++: SingleSentenceNoCrossfadeEffect テストのテキストを
  パディング非トリガーの長さに変更
@ayutaz
ayutaz force-pushed the feat/short-text-mitigation branch from 3602dc6 to fc4f3dc Compare April 9, 2026 12:59
ayutaz added 2 commits April 9, 2026 22:06
SSML検出の改善 (6ファイル):
- <speak> に加えて <speak (属性付き) も検出するよう統一
  (C#, Go, Python runtime, Docker API/WebUI)

XMLエスケープ追加 (2ファイル):
- Rust: &/</> を手動エスケープしてからSSMLテンプレートに挿入
- C#: SecurityElement.Escape() を使用

trimSilence partial window修正 (2ファイル):
- Rust: 末尾partial windowのRMSチェックを追加
- WASM/JS: 同様のpartial window処理を追加

その他の統一修正:
- Python runtime: 空白判定をASCIIのみからUnicode対応に変更
  (str.isspace())
- Python runtime: int16正規化値を32767→32768に統一
- WASM/JS: padPhonemeIdsのprosodyFeatures判定を
  falsy→null比較に修正
- ドキュメント: パラメータ名をcontract.tomlと一致させる

テスト追加: C# 4件, Rust 3件, Go 1件, Python 1件
Streaming_vs_OneShot と CallbackStreaming_vs_OneShot テストが
短テキスト対策 (MIN_PHONEME_IDS=40) のパディングにより
one-shot と streaming の出力サンプル数比率が 0.784 に低下して失敗。
テキストを長文に変更してパディングを回避。
@ayutaz
ayutaz merged commit 7233428 into dev Apr 9, 2026
88 checks passed
@ayutaz
ayutaz deleted the feat/short-text-mitigation branch April 9, 2026 15:12
ayutaz added a commit that referenced this pull request May 3, 2026
* docs: 監査結果に基づくドキュメント全面同期

v1.11.0 以降の実装変更 (#321 OpenAI互換API, #331 Voice Cloning/SSML, #337 短文品質, #342 HTS voice除去, #349/#367 phoneme timing/streaming, #361 FastAPI移行, #366 arm64 Docker) が
CHANGELOG・多言語 README・docstring に未反映だった部分を一括同期。新規に C# CLI/Core README を追加。

- ルート CHANGELOG: Unreleased に #360-#366 (FastAPI移行/arm64 Docker/短文崩壊修正/Wyoming HA等) を追記
- 多言語 README 9 ファイル (DE/ES/FR/HI/KO/PT/RU/SV/ZH): Voice Cloning/SSML/Phoneme Timing/Strategy A/B/C/FastAPI を反映
- C# CLI/Core README 新規作成 (src/csharp/PiperPlus.Cli/, PiperPlus.Core/)
- WASM CHANGELOG: [0.3.1] セクション追加 + [0.4.0] 日付修正 (0.3.0 と同日問題解消)
- docstring 補強: http_server.py FastAPI エンドポイント / inference.py OpenAI 互換 API
- HTS voice 残存言及を削除 (windows-setup.md)
- --language-balanced-sampling help を 6 言語対応に更新 (バイリンガル時代の遺物修正)
- Go README: Docker multi-arch (amd64/arm64) + serve サブコマンドのセクション追加
- pretrained-models.md: つくよみちゃん 6lang-v2 / 6lang ベースモデルの詳細追記
- huggingface-space/docker/README: 言語表記/Go arm64 表記の整合修正

* docs: 二次監査で発見した取り残しを追加修正

前回コミット (f212aba) では多言語 README 9 ファイルを更新したが、
ベースとなる README.md (日本語) と README_EN.md には Voice Cloning / SSML / 短文品質改善の bullets を入れ忘れていた。
また Rust piper-core/src/lib.rs のクレートドキュメントが「7 言語 (KO 含むが SV を欠く)」のまま、
8 言語 G2P + 6 言語学習済みモデルという最新の状態を反映していなかった。

- README.md / README_EN.md のインターフェースセクション末尾に Voice Cloning / SSML / 短文品質改善 (Strategy A/B/C) の 3 bullets を追加 (多言語版と同等内容)
- src/rust/piper-core/src/lib.rs:4 のクレートドキュメントを「8 言語 G2P (JA/EN/ZH/KO/ES/FR/PT/SV)、学習済みモデルは 6 言語」に修正

二次監査で誤指摘と判明した項目はスキップ:
- WASM g2p test の "all 7 non-JA languages" は JA を除いた 7 言語の意味で正しい (ALL_NON_JA = en/zh/ko/es/fr/pt/sv)
- C# CLI README の --debug/--quiet/--version はすでに L66 に記載済み

* docs: 低優先度の取り残し項目をすべて対応

二次監査で「低優先度・別 PR 推奨」と棚上げした 5 項目に対応。レガシー API
(BILINGUAL/espeak) の意図と廃止予定を明示し、サンプル/パッケージのバージョン
管理状況をユーザーが誤解しないようドキュメント化する目的。

- Go (src/go/piperplus/config.go): PhonemeTypeEspeak / PhonemeTypeBilingual に
  Deprecated コメント追加 (CONTRIBUTING.md "espeak-ng Policy" / PR #218 への参照付き)
- Python (src/python_run/piper/voice.py): PhonemeType.BILINGUAL 分岐に
  Deprecation 注記 + SV/KO が学習済みモデル未対応の理由をコメント化
- C# (src/csharp/PiperPlus.Core/Config/PiperConfig.cs): Espeak フィールドに
  XML doc 追加 (legacy config.json 互換のみ、新規モデルは null とする旨)
- examples/{c-api,dart,godot}/README.md: CI で実行検証されているか否かを
  各 README 冒頭に明示 (c-api はビルドのみ検証、dart/godot は未検証)
- CONTRIBUTING.md: "Package Versioning Policy" セクション新規追加
  (8 パッケージそれぞれの独立バージョン管理ポリシーとタグ命名規則を表形式で明文化)

実装ロジックには変更なし (コメント・docstring・README のみ)。

* docs: Copilot レビュー指摘 16 件 + 追加発見をすべて対応

Copilot pull-request reviewer が PR #368 に付けた 16 件のレビューコメントと、
それを契機にした再監査で見つかった整合性問題を一括解消。リリース直前の
一貫性確認に過ぎないので、いずれもドキュメント・コメントレベルの調整のみ。

Copilot 指摘 (16件):
- 多言語 README 11 ファイル (README.md/EN/DE/ES/FR/HI/KO/PT/RU/SV/ZH): bullets が
  「7 ランタイム」と書きながら列挙は 6 つだったのを「6 ランタイム」に統一。
  日本語版/英語版は libpiper_plus を C++ にまとめる旨を補足
- docker/python-inference/inference.py: モジュール docstring が定義されていない
  `POST /api/phoneme-timing` を載せ、`/synthesize` を POST と書いていたのを修正
  (該当エンドポイントは src/python_run/piper/http_server.py 側であることも明記)
- src/python/piper_train/__main__.py:255-260: `--language-balanced-sampling` が
  `num_speakers > 1` も必要 (single-speaker は SpeakerBalancedBatchSampler を
  バイパス) という条件を help に追記
- docker/README.md:19: Go Dockerfile 行の base image を `golang:1.22` から
  実際の `golang:1.26` に修正
- src/go/README.md:380-: `docker buildx build` の例に `--load` (single-arch) と
  `--push` (multi-arch) の両パターンを示し、ローカル実行不可だった例を解消
- src/go/README.md:298 / 406: 見出し「## HTTP API / HTTPエンドポイント」を
  「## HTTP API」に変更してアンカーを `#http-api` に統一、リンク
  `[HTTP API](#http-api--http-api)` の broken anchor を修正
- src/csharp/PiperPlus.Core/README.md:34: `new DotNetG2PEngine()` は
  PiperPlus.Cli の `internal sealed class` で外部から呼べないため、
  IJapaneseG2PEngine を持ち込む必要がある旨を明記したサンプルに置換
@ayutaz ayutaz mentioned this pull request May 4, 2026
2 tasks
ayutaz added a commit that referenced this pull request May 4, 2026
* chore(release): v1.12.0 — MB-iSTFT 統一 + Voice Cloning/SSML/短テキスト品質改善

- VERSION を 1.11.0 → 1.12.0 に更新
- CHANGELOG.md に v1.12.0 の全変更点を整理 (34コミット分)

## v1.12.0 ハイライト

### Breaking
- Decoder を MB-iSTFT-VITS2 に統一 (HiFi-GAN Generator 削除)、CPU 推論 2.21x 高速化 (#320)

### New Features
- 全7ランタイムで短テキスト合成品質改善 Strategy A/B/C (#337)
- Voice Cloning (5ランタイム) + SSML (4ランタイム) + Wyoming Docker + iOS/Android CI (#331)
- Python ランタイム phoneme timing + ストリーミング文単位分割 (#349, #367)
- HTTP server を Flask → FastAPI 移行 + StreamingResponse 対応 (#361)
- 汎用 Colab ファインチューニングノートブック (#324)

### Refactor / Removed
- HTS voice 依存を完全除去 (#342)
- Unity UPM 削除 (#341)

### Chore
- .NET 全プロジェクトを net10.0 LTS に移行 (#374)
- GitHub Actions runner を ubuntu-24.04、Docker base を Debian trixie (#373)
- EOL ランタイム (Node 18, Python 3.8) を更新 (#370)

* chore(release): バージョンファイル整合性 + リリースワークフロー動的バージョン化

- src/python/piper_train/VERSION: 1.11.0 → 1.12.0
- src/python/pyproject.toml (piper-train): version 1.11.0 → 1.12.0
- uv.lock 再生成 (piper-train v1.12.0 反映)
- CHANGELOG L94: Flask → FastAPI (HTTP server 移行と整合)
- dev-create-release.yml: C#/Rust/npm のリリースノート install コマンドを各 manifest から動的取得に変更 (従来 0.1.0 ハードコード)

* chore(packages): C#/Rust/npm パッケージのバージョンを v1.12.0 機能反映に合わせて bump

v1.12.0 の Voice Cloning / SSML / 短テキスト品質改善 / Phoneme Timing は全ランタイムに影響するため、独立管理パッケージも MINOR を上げる。

- C# `PiperPlus.Core` / `PiperPlus.Cli`: 0.2.0 → 0.3.0
- Rust workspace (`piper-plus`, `piper-plus-cli`, `piper-plus-g2p` 等): 0.3.0 → 0.4.0
- 内部 path+version 依存も 0.3.0 → 0.4.0 に同期
- Cargo.lock 再生成
- npm `piper-plus` (openjtalk-web): 0.5.0 → 0.6.0
- npm `@piper-plus/g2p`: 0.3.0 → 0.4.0
- npm `piper-plus` の `@piper-plus/g2p` 依存も `^0.4.0` に更新

* fix(catalog): モデルカタログ size_bytes と説明を最新 HuggingFace アセットに同期

各言語実装 (cpp / C# / Go / Python / Rust) のモデルカタログで size_bytes と description が異なる値を持っていた問題を解消。HuggingFace Tree API で実ファイルサイズを取得して全実装で統一。

- tsukuyomi-chan-6lang-fp16.onnx: 39,652,717 B (HF 実サイズ)
- css10-ja-6lang-fp16.onnx: 39,652,717 B (HF 実サイズ)
- C# VoiceCatalog: tsukuyomi の size_bytes 77594624 (誤値、WavLM 旧モデル) → 39652717 に修正、描述 "WavLM discriminator (300 epochs)" → MB-iSTFT 版に更新
- Go voice_catalog: tsukuyomi の placeholder filename を実ファイル名 `tsukuyomi-chan-6lang-fp16.onnx` に修正、css10 の RepoID 誤り (piper-plus-base 指定) を `piper-plus-css10-ja-6lang` に修正
- config.json サイズも HF 実サイズ (6279 B / 5912 B) に統一
- md5_digest は空のまま (verification はスキップ動作で対応済み)

* docs: 多言語 README と各種ドキュメントを v1.12.0 内容に追従

ユーザー向け文書から廃止/古い情報を一掃。

### 多言語 README (11ファイル)
- 9言語版 (DE/ES/FR/HI/KO/PT/RU/SV/ZH) で `--mb-istft` フラグ言及を除去 (v1.12.0 で常時有効)
- 8言語版で Windows セットアップから espeak-ng / ESPEAK_DATA_PATH を削除し OpenJTalk 自動 DL 説明に統一 (espeak-ng は元から不使用)
- 11言語全 README の .NET TFM `net8.0/net9.0` → `net10.0` (PR #374 反映)
- 11言語全 README の Rust crate 例 `piper-plus = "0.2.0"` → `"0.3"`

### docs/
- docs/README.md, binary-selection.md, building-from-source.md, troubleshooting.md, windows-setup.md の `.NET 8/9` → `.NET 10`
- docs/guides/training.md: `--stochastic` フラグ例を削除 (デフォルト有効のため)

### その他
- CLAUDE.md: npm version 表記 0.3.1 → 0.5.0、v1.12.0 Breaking changes 注意書き追加
- CONTRIBUTING.md: 例示バージョン v1.11.0 → v1.12.0、npm-v0.3.1 → npm-v0.5.0
- README.npm.md: importmap `piper-plus@0.4.0` → `piper-plus@0.5.0`
- docker/README.md: C++ Dockerfile から espeak-ng 言及を削除 (HTS voice 依存除去 #342)
- src/csharp/PiperPlus.Cli/README.md, src/python_run/README.md: .NET 10 同期
- src/python_run/README_http.md: 「Flask 版からの移行」→「v1.11 以前 (Flask) からの互換性」
- src/python_run/piper/http_server.py: docstring の "Flask-compatible" → "FastAPI compatible"

* docs(readme): Rust crate version 例を 0.3 → 0.4 に修正

11 言語 README で workspace 実バージョン (`0.4.0`) と整合させる。前コミット (2686d43) で `0.2.0 → 0.3` に置換したが、bump コミット (9516bb5) で workspace は `0.4.0` まで上げているため不整合。

* docs(changelog): phonemize() Breaking 格上げ + マイグレーションガイド新設

### CHANGELOG
- `PiperVoice.phonemize()` の戻り値**意味論**変更を Added → Changed (Breaking) セクションに移動。
  - 戻り値型 `list[list[str]]` は v1.11 と同じだが、v1.11 は 1 要素 (whole text) を返していたのに対し v1.12 は文ごとに N 要素返す。
  - `phonemize(text)[0]` で固定アクセスしている呼び出し側は壊れるため Breaking 扱いが妥当。

### docs/migration/v1.11-to-v1.12.md (新規)
ユーザー種別ごとの移行手順を集約:
- 推論のみ利用 (Breaking なし)
- HiFi-GAN ckpt から学習継続中 (再 FT 必要)
- Flask `[http]` extras 利用 (FastAPI 自動切替)
- Unity UPM 利用 (`ayutaz/uPiper` 別 repo)
- `PiperVoice.phonemize()` 直接利用 (戻り値要素数変更)
- バージョン対応表 + トラブルシューティング

* feat(train): HiFi-GAN ckpt resume 検出 + CONTRIBUTING に npm リリース順序追記

### __main__.py: HiFi-GAN ckpt 検出
v1.11.0 以前の HiFi-GAN ckpt を `--resume_from_checkpoint` または
`--resume-from-multispeaker-checkpoint` に渡された際、強制的に RuntimeError
で migration ガイドへ案内する。検出ロジックは:

- state_dict に `model_g.dec.*` がある (= decoder 入りモデル)
- かつ `model_g.dec.subband_conv_post` / `model_g.dec.pqmf` の MB-iSTFT
  マーカーが**ない**

これに合致する ckpt は HiFi-GAN ベースとみなしてエラー。従来の strict=False
フォールバック (info ログだけ吐いて静かに学習継続) では構造不一致のまま
学習が進み、ユーザーが原因に気づきにくかった。

### CONTRIBUTING.md: npm リリース順序
`@piper-plus/g2p` のリリースを先に行ってから `piper-plus` を上げる必要が
あることを Release order セクションに明記。Manual Release ワークフローは
PyPI/NuGet/crates.io のみ自動化されており、npm は `npm-v*` / `g2p-v*`
タグ別経路で動くため、順序を間違うと
`No matching version found for @piper-plus/g2p@^0.4.0` で install 失敗する。

* chore(deps): ONNX Runtime 1.14.x → 1.17.0 統一 (C++ / Android PR CI / Docker)

CVE 残存リスク (GHSA-fp9j-rgxr-w83q 他) のあった C++ ローカルビルドと
Android PR CI を release 配布 (release-shared-lib.yml) と同じ 1.17.0 に揃える。

- cmake/OnnxRuntime.cmake: Linux/macOS download URL を 1.14.1 → 1.17.0
- cmake/find_onnxruntime_windows.cmake: Windows download URL を 1.14.1 → 1.17.0
- docker/cpp-dev/Dockerfile: Linux x64 prebuilt 1.14.1 → 1.17.0
- _build-test-cpp.yml: Linux x64 / macOS arm64 / macOS x86_64 / Windows x64 各
  ダウンロード URL を 1.14.1 → 1.17.0
- android-build.yml (PR CI): ONNXRUNTIME_VERSION 1.14.0 → 1.17.0
- ort-versions.md: Android (PR CI) 行を 1.14.0 → 1.17.0 に表更新

これで release / iOS / Android (release+PR) / C++ build / Docker dev 全てが
1.17.0 に揃う。Issue #372 の Rust ort 2.0.0-rc.12 や Python `>=1.17` (open
range)、C# 1.24.3、Go 1.27.0 はそのまま (別途検討)。

* ci(security): pip-audit / cargo-audit / npm audit + Dependency Review を追加

Dependabot は週次の reactive な検出に依存していたが、PR 時点で proactive に
脆弱性を捕捉するため CVE スキャナを CI に統合。

- dependency-review-action (PR のみ): 新規追加依存の HIGH 以上で fail
- pip-audit: pyproject.toml + src/python_run の OSV データソース照合
- cargo-audit: src/rust ワークスペース、warnings も deny
- npm audit: src/wasm/{openjtalk-web,g2p} の production 依存 HIGH 以上で fail

トリガー:
- pull_request (依存ファイル変更時のみ paths フィルタ)
- push to dev/main
- schedule (weekly Mon 03:00 UTC = 12:00 JST)
- workflow_dispatch (手動)

* ci(release): WebUI Docker 自動配信 + shared-lib Windows ビルド修正

### docker-build.yml: build-webui ジョブ追加
build-wyoming と同じパターンで build-webui ジョブを追加。タグ push 時に
- ghcr.io/<owner>/<repo>/webui (常時)
- DockerHub <USER>/piper-plus-webui (DOCKERHUB_USERNAME/TOKEN 設定時のみ)

の両方に publish される。これで python-inference / python-train / cpp-dev /
cpp-inference / wyoming / webui の 6 イメージが揃って自動更新される。

### release-shared-lib.yml: Windows ビルドの CMake パスエスケープ修正
v1.11.0 で Windows ビルドが「`D:apiper-pluspiper-plus/install/...`」と
化けて失敗していた問題を修正。原因は bash on windows-2022 が
`${{ github.workspace }}` (= `D:\a\piper-plus\piper-plus`) を展開する際、
バックスラッシュをエスケープシーケンスとして消費していたこと。

対応:
- Configure CMake / Build / Verify install layout / Create archive を
  Unix と Windows で別ステップに分離
- Windows 側は `pwsh` + `${env:GITHUB_WORKSPACE}` + 手動で `\` → `/` 置換
- Install ステップは引数でパスを使わないので bash 共通のまま

これで iOS / Android / Linux / macOS / Windows 全 5 ターゲットの shared lib
が release タグで揃って配布される。

* docs(changelog): Copilot レビュー指摘を反映 — Colab notebook と HTS voice の記述を正確化

PR #375 の Copilot Reviewer インラインコメント 2 件への対応。

- L62 Colab notebook: 「任意のカスタムデータセット」→「LJSpeech 形式 (wavs/ + metadata.csv) のカスタムデータセット」
  notebook の実装は LJSpeech レイアウト前提。任意形式が使える誤解を防ぐ。

- L127 HTS voice 削除: 「ピュアな pyopenjtalk-plus パスのみ使用」→
  「Python ランタイムから HTS voice 依存を完全除去 — Python は pyopenjtalk-plus
  パスのみ。C++/Go/Rust/WASM の OpenJTalk バックエンドは引き続き利用」
  PR #342 は Python ランタイム限定の変更で、他言語の OpenJTalk バックエンドは
  そのまま残っている。「ピュアな…パスのみ」表記は他ランタイムユーザーを
  誤解させる。

* fix(lint): except 内の raise に from None を付与 (ruff B904)

HiFi-GAN ckpt 検出ロジック (c873fd4) で追加した raise RuntimeError が
except ブロック内にあったため B904 違反。元の Lightning の RuntimeError は
strict=False フォールバックの起点であり、HiFi-GAN 検出エラーとは無関係なので
from None で抑制する。

* docs(claude): CLAUDE.md を最適化 (966 → 323 行、67% 削減)

v1.12.0 リリース直前の状態に同期しつつ、構造を整理して可読性向上。

### 削減ポイント
- **学習コマンドの重複削除**: 6lang 事前学習コマンドとつくよみちゃん FT コマンドを Template A/B に統合 (3重複 → 1)
- **実装済み機能セクションの圧縮**: 22 機能をカテゴリ別 (Decoder/学習補助/ONNX/Voice Cloning/G2P/ランタイム/サーバー) にグルーピング、各機能を 1-2 行に
- **ファイルパス索引の集約**: 7 言語別の重複表を「Python 学習側 / ランタイム側 / 横断仕様 / 各言語ランタイム」の 4 表に統合
- **アーカイブ圧縮**: バイリンガル v2/v3/v4 詳細をバージョン比較表 + Key learnings に圧縮
- **HuggingFace モデル一覧の更新**: css10-ja-6lang を追加

### 新規/更新内容
- v1.12.0 Breaking changes 注記をヘッダーに昇格、マイグレーションガイドへリンク
- 学習済みモデル一覧を MB-iSTFT 版含めて整理
- ランタイム別パッケージ表で各言語の最新バージョン (1.12.0 / 0.3.0 / 0.4.0 / 0.6.0) を明示
- HiFi-GAN ckpt resume 不可のトラブルシューティング項目追加
- 横断仕様 (`docs/spec/*.toml`) の参照を主要ファイル索引に集約

機能の網羅性は維持。詳細な実装ファイルパスは各機能行に保持し、別途索引と二重管理しない方針に変更。

* fix(ci): CI 失敗 3 件を修正 (build-piper ORT 同期 + audit 設定調整)

PR #375 で発生していた CI 失敗 3 件を解消。

### macOS TTS test (Test Japanese TTS / Test Multilingual TTS on macos-latest)
原因: build-piper.yml は 1.14.1 を /usr/local/lib に置くが、CMake は 1.17.0
を ExternalProject 経由で取得。piper バイナリが rpath
@rpath/libonnxruntime.1.17.0.dylib を期待するが、dist/piper/lib にコピーされた
のは 1.14.1 dylib。結果「unloadable mach-o file type 10」(dSYM 扱い) で fail。

対応: build-piper.yml の ONNX Runtime 全参照を 1.17.0 に同期 (Linux x64 +
macOS arm64、キャッシュキー suffix を v3 に更新)。これで先の C++ ORT 同期コミット
(33c203b) と整合する。

### cargo-audit (Rust)
原因: --deny warnings 指定で unmaintained 警告 (RUSTSEC-2025-0141 bincode、
RUSTSEC-2021-0153 encoding) も fail 扱いに。これらは vulnerabilities ではなく
"unmaintained" 警告なのでリリースをブロックすべきではない。

対応: --deny warnings を削除。cargo audit デフォルト挙動 (実 CVE で exit 1、
unmaintained は warn のみ) に戻す。

### npm audit (src/wasm/g2p)
原因: src/wasm/g2p は package-lock.json をコミットしていないため
"This command requires an existing lockfile" で fail。

対応: audit ステップ前に lockfile を生成 (npm install --package-lock-only
--no-audit --no-fund)。openjtalk-web 側はコミット済 lockfile を利用。

* fix(ci/windows): build-piper の Windows ビルドで実エラーを可視化 + piper.exe 不在を fail 扱い

PR #375 の Windows multilingual ビルドが「Build succeeded」と表示されつつ
piper.exe が生成されず、後続の dist 作成ステップで「piper.exe not found,
creating minimal package」となり、テストが「lib/onnx not loadable」で fail
していた。

原因 (推定):
- `$buildResult = cmake --build ...` で stdout を変数にキャプチャしていたため
  実際の build ログ (linker エラー等) が一切表示されない
- LASTEXITCODE = 0 なのに piper.exe が生成されない場合 (CMake target 不一致や
  link 失敗の隠蔽) を検知する仕組みが無く、`Warning: piper.exe not found,
  creating minimal package` で握り潰されていた

対応:
- cmake --build の出力をキャプチャせず、`--verbose` と `--target piper` を付与
  して直接 stdout/stderr を表示
- build 後に piper.exe の存在を Test-Path で検証し、無ければ Get-ChildItem
  で実際に生成された exe/dll を一覧表示してから exit 1

これで次の CI 実行で根本原因 (linker エラー等) が log に表示される。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants