Skip to content

Commit

Permalink
style_id引数やAPIをspeakerに戻す (VOICEVOX#1016)
Browse files Browse the repository at this point in the history
* style_id引数やAPIをspeakerに戻す

* READMEの戻し忘れ
  • Loading branch information
Hiroshiba authored Jan 20, 2024
1 parent 4fe753d commit 9e1b0f0
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 430 deletions.
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,21 @@ echo -n "こんにちは、音声合成の世界へようこそ" >text.txt

curl -s \
-X POST \
"127.0.0.1:50021/audio_query?style_id=1"\
"127.0.0.1:50021/audio_query?speaker=1"\
--get --data-urlencode [email protected] \
> query.json

curl -s \
-H "Content-Type: application/json" \
-X POST \
-d @query.json \
"127.0.0.1:50021/synthesis?style_id=1" \
"127.0.0.1:50021/synthesis?speaker=1" \
> audio.wav
```

生成される音声はサンプリングレートが 24000Hz と少し特殊なため、音声プレーヤーによっては再生できない場合があります。

`style_id` に指定する値は `/speakers` エンドポイントで得られます
`speaker` に指定する値は `/speakers` エンドポイントで得られる `style_id` です。互換性のために `speaker` という名前になっています

### 読み方を AquesTalk 風記法で取得・修正

Expand Down Expand Up @@ -99,7 +99,7 @@ echo -n "ディープラーニングは万能薬ではありません" >text.txt

curl -s \
-X POST \
"127.0.0.1:50021/audio_query?style_id=1" \
"127.0.0.1:50021/audio_query?speaker=1" \
--get --data-urlencode [email protected] \
> query.json

Expand All @@ -111,7 +111,7 @@ cat query.json | grep -o -E "\"kana\":\".*\""
echo -n "ディイプラ'アニングワ/バンノ'オヤクデワ/アリマセ'ン" > kana.txt
curl -s \
-X POST \
"127.0.0.1:50021/accent_phrases?style_id=1&is_kana=true" \
"127.0.0.1:50021/accent_phrases?speaker=1&is_kana=true" \
--get --data-urlencode [email protected] \
> newphrases.json

Expand All @@ -122,7 +122,7 @@ curl -s \
-H "Content-Type: application/json" \
-X POST \
-d @newquery.json \
"127.0.0.1:50021/synthesis?style_id=1" \
"127.0.0.1:50021/synthesis?speaker=1" \
> audio.wav
```

Expand Down Expand Up @@ -238,7 +238,7 @@ curl -s \
-H "Content-Type: application/json" \
-X POST \
-d @query.json \
"127.0.0.1:50021/synthesis?style_id=$style_id" \
"127.0.0.1:50021/synthesis?speaker=$style_id" \
> audio.wav
```

Expand All @@ -255,7 +255,7 @@ echo -n "モーフィングを利用することで、2種類の声を混ぜ

curl -s \
-X POST \
"127.0.0.1:50021/audio_query?style_id=0"\
"127.0.0.1:50021/audio_query?speaker=8"\
--get --data-urlencode [email protected] \
> query.json

Expand All @@ -264,7 +264,7 @@ curl -s \
-H "Content-Type: application/json" \
-X POST \
-d @query.json \
"127.0.0.1:50021/synthesis?style_id=0" \
"127.0.0.1:50021/synthesis?speaker=8" \
> audio.wav

export MORPH_RATE=0.5
Expand All @@ -274,17 +274,17 @@ curl -s \
-H "Content-Type: application/json" \
-X POST \
-d @query.json \
"127.0.0.1:50021/synthesis_morphing?base_style_id=0&target_style_id=1&morph_rate=$MORPH_RATE" \
"127.0.0.1:50021/synthesis_morphing?base_speaker=8&target_speaker=10&morph_rate=$MORPH_RATE" \
> audio.wav

export MORPH_RATE=0.9

# query、base_style_id、target_style_idが同じ場合はキャッシュが使用されるため比較的高速に生成される
# query、base_speaker、target_speakerが同じ場合はキャッシュが使用されるため比較的高速に生成される
curl -s \
-H "Content-Type: application/json" \
-X POST \
-d @query.json \
"127.0.0.1:50021/synthesis_morphing?base_style_id=0&target_style_id=1&morph_rate=$MORPH_RATE" \
"127.0.0.1:50021/synthesis_morphing?base_speaker=8&target_speaker=10&morph_rate=$MORPH_RATE" \
> audio.wav
```

Expand Down
2 changes: 2 additions & 0 deletions docs/VOICEVOX音声合成エンジンとの連携.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
- バージョンが上がっても、`/audio_query`で返ってくる値をそのまま`/synthesis`に POST すれば音声合成できるようにする予定です
- `AudioQuery`のパラメータは増えますが、なるべくデフォルト値で以前と変わらない音声が生成されるようにします
- バージョン 0.7 から音声スタイルが実装されました。スタイルの情報は`/speakers`から取得できます
- スタイルの情報にある`style_id``speaker`に指定することで、今まで通り音声合成ができます
- style_id の指定先が speaker なのは互換性のためです
136 changes: 19 additions & 117 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@
import re
import sys
import traceback
import warnings
import zipfile
from collections.abc import Awaitable, Callable
from functools import lru_cache
from io import BytesIO, TextIOWrapper
from pathlib import Path
from tempfile import NamedTemporaryFile, TemporaryFile
from typing import Annotated, Any, Optional, TypeVar
from typing import Annotated, Any, Optional

import soundfile
import uvicorn
Expand Down Expand Up @@ -94,24 +93,6 @@
)
from voicevox_engine.utility.run_utility import decide_boolean_from_env

# NOTE: Python 3.12以降で[S: StyleId | list[StyleId]]に置き換えられる
S = TypeVar("S", StyleId, list[StyleId])


def get_style_id_from_deprecated(style_id: S | None, deprecated_speaker: S | None) -> S:
"""
style_idとspeaker両方ともNoneかNoneでないかをチェックし、
どちらか片方しかNoneが存在しなければstyle_idを返す
"""
if deprecated_speaker is not None and style_id is None:
warnings.warn("speakerは非推奨です。style_idを利用してください。", stacklevel=1)
return deprecated_speaker
elif style_id is not None and deprecated_speaker is None:
return style_id
raise HTTPException(
status_code=400, detail="speakerとstyle_idが両方とも存在しないか、両方とも存在しています。"
)


def b64encode_str(s):
return base64.b64encode(s).decode("utf-8")
Expand Down Expand Up @@ -290,16 +271,12 @@ def get_core(core_version: Optional[str]) -> CoreAdapter:
)
def audio_query(
text: str,
style_id: StyleId | None = None,
speaker: StyleId | None = Query(default=None, deprecated=True), # noqa: B008
style_id: StyleId = Query(alias="speaker"), # noqa: B008
core_version: str | None = None,
) -> AudioQuery:
"""
音声合成用のクエリの初期値を得ます。ここで得られたクエリはそのまま音声合成に利用できます。各値の意味は`Schemas`を参照してください。
"""
style_id = get_style_id_from_deprecated(
style_id=style_id, deprecated_speaker=speaker
)
engine = get_engine(core_version)
core = get_core(core_version)
accent_phrases = engine.create_accent_phrases(text, style_id)
Expand Down Expand Up @@ -371,8 +348,7 @@ def audio_query_from_preset(
)
def accent_phrases(
text: str,
style_id: StyleId | None = None,
speaker: StyleId | None = Query(default=None, deprecated=True), # noqa: B008
style_id: StyleId = Query(alias="speaker"), # noqa: B008
is_kana: bool = False,
core_version: str | None = None,
) -> list[AccentPhrase]:
Expand All @@ -385,9 +361,6 @@ def accent_phrases(
* アクセント位置を`'`で指定する。全てのアクセント句にはアクセント位置を1つ指定する必要がある。
* アクセント句末に`?`(全角)を入れることにより疑問文の発音ができる。
"""
style_id = get_style_id_from_deprecated(
style_id=style_id, deprecated_speaker=speaker
)
engine = get_engine(core_version)
if is_kana:
try:
Expand All @@ -407,13 +380,9 @@ def accent_phrases(
)
def mora_data(
accent_phrases: list[AccentPhrase],
style_id: StyleId | None = None,
speaker: StyleId | None = Query(default=None, deprecated=True), # noqa: B008
style_id: StyleId = Query(alias="speaker"), # noqa: B008
core_version: str | None = None,
) -> list[AccentPhrase]:
style_id = get_style_id_from_deprecated(
style_id=style_id, deprecated_speaker=speaker
)
engine = get_engine(core_version)
return engine.update_length_and_pitch(accent_phrases, style_id)

Expand All @@ -425,13 +394,9 @@ def mora_data(
)
def mora_length(
accent_phrases: list[AccentPhrase],
style_id: StyleId | None = None,
speaker: StyleId | None = Query(default=None, deprecated=True), # noqa: B008
style_id: StyleId = Query(alias="speaker"), # noqa: B008
core_version: str | None = None,
) -> list[AccentPhrase]:
style_id = get_style_id_from_deprecated(
style_id=style_id, deprecated_speaker=speaker
)
engine = get_engine(core_version)
return engine.update_length(accent_phrases, style_id)

Expand All @@ -443,13 +408,9 @@ def mora_length(
)
def mora_pitch(
accent_phrases: list[AccentPhrase],
style_id: StyleId | None = None,
speaker: StyleId | None = Query(default=None, deprecated=True), # noqa: B008
style_id: StyleId = Query(alias="speaker"), # noqa: B008
core_version: str | None = None,
) -> list[AccentPhrase]:
style_id = get_style_id_from_deprecated(
style_id=style_id, deprecated_speaker=speaker
)
engine = get_engine(core_version)
return engine.update_pitch(accent_phrases, style_id)

Expand All @@ -468,17 +429,13 @@ def mora_pitch(
)
def synthesis(
query: AudioQuery,
style_id: StyleId | None = None,
speaker: StyleId | None = Query(default=None, deprecated=True), # noqa: B008
style_id: StyleId = Query(alias="speaker"), # noqa: B008
enable_interrogative_upspeak: bool = Query( # noqa: B008
default=True,
description="疑問系のテキストが与えられたら語尾を自動調整する",
),
core_version: str | None = None,
) -> FileResponse:
style_id = get_style_id_from_deprecated(
style_id=style_id, deprecated_speaker=speaker
)
engine = get_engine(core_version)
wave = engine.synthesize_wave(
query, style_id, enable_interrogative_upspeak=enable_interrogative_upspeak
Expand Down Expand Up @@ -511,13 +468,9 @@ def synthesis(
def cancellable_synthesis(
query: AudioQuery,
request: Request,
style_id: StyleId | None = None,
speaker: StyleId | None = Query(default=None, deprecated=True), # noqa: B008
style_id: StyleId = Query(alias="speaker"), # noqa: B008
core_version: str | None = None,
) -> FileResponse:
style_id = get_style_id_from_deprecated(
style_id=style_id, deprecated_speaker=speaker
)
if cancellable_engine is None:
raise HTTPException(
status_code=404,
Expand Down Expand Up @@ -552,13 +505,9 @@ def cancellable_synthesis(
)
def multi_synthesis(
queries: list[AudioQuery],
style_id: StyleId | None = None,
speaker: StyleId | None = Query(default=None, deprecated=True), # noqa: B008
style_id: StyleId = Query(alias="speaker"), # noqa: B008
core_version: str | None = None,
) -> FileResponse:
style_id = get_style_id_from_deprecated(
style_id=style_id, deprecated_speaker=speaker
)
engine = get_engine(core_version)
sampling_rate = queries[0].outputSamplingRate

Expand Down Expand Up @@ -634,27 +583,15 @@ def morphable_targets(
)
def _synthesis_morphing(
query: AudioQuery,
base_style_id: StyleId | None = None,
base_speaker: (StyleId | None) = Query( # noqa: B008
default=None, deprecated=True
),
target_style_id: StyleId | None = None,
target_speaker: (StyleId | None) = Query( # noqa: B008
default=None, deprecated=True
),
base_style_id: StyleId = Query(alias="base_speaker"), # noqa: B008
target_style_id: StyleId = Query(alias="target_speaker"), # noqa: B008
morph_rate: float = Query(..., ge=0.0, le=1.0), # noqa: B008
core_version: str | None = None,
) -> FileResponse:
"""
指定された2種類のスタイルで音声を合成、指定した割合でモーフィングした音声を得ます。
モーフィングの割合は`morph_rate`で指定でき、0.0でベースのスタイル、1.0でターゲットのスタイルに近づきます。
"""
base_style_id = get_style_id_from_deprecated(
style_id=base_style_id, deprecated_speaker=base_speaker
)
target_style_id = get_style_id_from_deprecated(
style_id=target_style_id, deprecated_speaker=target_speaker
)
engine = get_engine(core_version)
core = get_core(core_version)

Expand Down Expand Up @@ -1028,68 +965,33 @@ def uninstall_library(library_uuid: str) -> Response:
library_manager.uninstall_library(library_uuid)
return Response(status_code=204)

@app.post("/initialize_style_id", status_code=204, tags=["その他"])
def initialize_style_id(
style_id: StyleId,
@app.post("/initialize_speaker", status_code=204, tags=["その他"])
def initialize_speaker(
style_id: StyleId = Query(alias="speaker"), # noqa: B008
skip_reinit: bool = Query( # noqa: B008
default=False, description="既に初期化済みのスタイルの再初期化をスキップするかどうか"
),
core_version: str | None = None,
) -> Response:
"""
指定されたstyle_idのスタイルを初期化します
指定されたスタイルを初期化します
実行しなくても他のAPIは使用できますが、初回実行時に時間がかかることがあります。
"""
core = get_core(core_version)
core.initialize_style_id_synthesis(style_id, skip_reinit=skip_reinit)
return Response(status_code=204)

@app.get("/is_initialized_style_id", response_model=bool, tags=["その他"])
def is_initialized_style_id(
style_id: StyleId,
@app.get("/is_initialized_speaker", response_model=bool, tags=["その他"])
def is_initialized_speaker(
style_id: StyleId = Query(alias="speaker"), # noqa: B008
core_version: str | None = None,
) -> bool:
"""
指定されたstyle_idのスタイルが初期化されているかどうかを返します
指定されたスタイルが初期化されているかどうかを返します
"""
core = get_core(core_version)
return core.is_initialized_style_id_synthesis(style_id)

@app.post("/initialize_speaker", status_code=204, tags=["その他"], deprecated=True)
def initialize_speaker(
speaker: StyleId,
skip_reinit: bool = Query( # noqa: B008
default=False, description="既に初期化済みの話者の再初期化をスキップするかどうか"
),
core_version: str | None = None,
) -> Response:
"""
こちらのAPIは非推奨です。`initialize_style_id`を利用してください。
"""
warnings.warn(
"使用しているAPI(/initialize_speaker)は非推奨です。/initialized_style_idを利用してください。",
stacklevel=1,
)
return initialize_style_id(
speaker, skip_reinit=skip_reinit, core_version=core_version
)

@app.get(
"/is_initialized_speaker", response_model=bool, tags=["その他"], deprecated=True
)
def is_initialized_speaker(
speaker: StyleId,
core_version: str | None = None,
) -> bool:
"""
こちらのAPIは非推奨です。`is_initialize_style_id`を利用してください。
"""
warnings.warn(
"使用しているAPI(/is_initialize_speaker)は非推奨です。/is_initialized_style_idを利用してください。",
stacklevel=1,
)
return is_initialized_style_id(speaker, core_version=core_version)

@app.get("/user_dict", response_model=dict[str, UserDictWord], tags=["ユーザー辞書"])
def get_user_dict_words() -> dict[str, UserDictWord]:
"""
Expand Down
Loading

0 comments on commit 9e1b0f0

Please sign in to comment.