Spaces:
Running
on
Zero
Running
on
Zero
File size: 13,849 Bytes
1adf592 537d90c 517d583 4206a0e 1adf592 4206a0e 1adf592 4206a0e 1adf592 517d583 da9fcb8 517d583 1adf592 517d583 4206a0e 517d583 4206a0e 517d583 4206a0e 517d583 4206a0e 517d583 1adf592 f10608a 1adf592 4206a0e 1adf592 4206a0e 1adf592 517d583 1adf592 4206a0e 517d583 1adf592 4206a0e 1adf592 4206a0e 1adf592 517d583 4206a0e 1adf592 517d583 4206a0e 1adf592 517d583 dfd02f5 4206a0e 537d90c fe5aaf9 1adf592 537d90c fe5aaf9 1adf592 dfd02f5 1adf592 dfd02f5 1adf592 4206a0e 1adf592 da9fcb8 4206a0e 1adf592 f10608a da9fcb8 1adf592 da9fcb8 517d583 1adf592 517d583 1adf592 4206a0e 1adf592 da9fcb8 1adf592 da9fcb8 1adf592 517d583 da9fcb8 517d583 1adf592 517d583 1adf592 4206a0e 1adf592 da9fcb8 1adf592 da9fcb8 517d583 1adf592 517d583 1adf592 4206a0e 1adf592 da9fcb8 1adf592 da9fcb8 1adf592 da9fcb8 1adf592 537d90c 1adf592 da9fcb8 1adf592 da9fcb8 1adf592 517d583 da9fcb8 517d583 4206a0e 1adf592 da9fcb8 1adf592 da9fcb8 1adf592 da9fcb8 1adf592 da9fcb8 1adf592 da9fcb8 1adf592 da9fcb8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
import os
import gradio as gr
import torch
import numpy as np
import soundfile as sf
from outetts import Interface, ModelConfig, GenerationConfig, Backend, Models, GenerationType, SamplerConfig # SamplerConfigをインポート
import spaces # spacesライブラリをインポート
import uuid # 一時ファイル名生成用
# モデル設定
MODEL_PATH = "OuteAI/OuteTTS-1.0-0.6B"
# ディレクトリの作成
os.makedirs("samples", exist_ok=True)
os.makedirs("outputs", exist_ok=True)
os.makedirs("speakers", exist_ok=True)
os.makedirs("temp_speakers", exist_ok=True) # 一時スピーカープロファイル保存用
# GPUワーカープロセス内で使用されるグローバル変数
# これらの変数は、各GPUワーカープロセスごとに独立して存在します。
_gpu_interface = None
# インターフェースの初期化 (GPUワーカープロセス内で実行される)
@spaces.GPU # GPUリソースを必要とすることを明示的に指定
def _initialize_model_in_gpu_worker():
global _gpu_interface
if _gpu_interface is None:
if torch.cuda.is_available():
print("CUDA is available. OuteTTS will attempt to use GPU.")
else:
print("CUDA is not available. OuteTTS will run on CPU.")
_gpu_interface = Interface(
ModelConfig.auto_config(
model=Models.VERSION_1_0_SIZE_0_6B,
backend=Backend.HF, # Hugging Face Transformersバックエンド
)
)
print("OuteTTS model initialized successfully in GPU worker.")
# この関数はモデルオブジェクトを返しません。
# 代わりに、GPUワーカープロセス内のグローバル変数 _gpu_interface を設定します。
# 各Gradio関数から呼び出されるモデルロードヘルパー
def _get_gpu_interface():
# _initialize_model_in_gpu_worker() を呼び出すことで、
# モデルがGPUワーカープロセス内でロードされることを保証します。
_initialize_model_in_gpu_worker()
return _gpu_interface
# スピーカープロファイルの作成 (GPUワーカープロセス内で実行される)
@spaces.GPU
def create_speaker_profile_gpu(audio_file):
if audio_file is None:
return None, None, gr.update(value="エラー: 音声ファイルが選択されていません。", interactive=True), None # パスもNoneに
audio_file_path = audio_file.name # GradioのFileコンポーネントはname属性でパスを提供
interface = _get_gpu_interface()
try:
speaker = interface.create_speaker(audio_file_path)
speaker_name = os.path.basename(audio_file_path)
# 一時ファイルにスピーカープロファイルを保存
temp_speaker_filename = f"temp_speaker_{uuid.uuid4()}.json"
temp_speaker_path = os.path.join("temp_speakers", temp_speaker_filename)
interface.save_speaker(speaker, temp_speaker_path)
decoded_path = f"speakers/decoded_{speaker_name}.wav"
interface.decode_and_save_speaker(speaker=speaker, path=decoded_path)
status_message = f"スピーカープロファイル '{speaker_name}' を作成しました。"
return temp_speaker_path, decoded_path, gr.update(value=status_message, interactive=True), temp_speaker_path
except Exception as e:
error_message = f"エラー: スピーカープロファイルの作成に失敗しました: {str(e)}"
print(error_message)
return None, None, gr.update(value=error_message, interactive=True), None
# デフォルトスピーカーのロード (GPUワーカープロセス内で実行される)
@spaces.GPU
def load_default_speaker_gpu(language, gender, style):
interface = _get_gpu_interface()
speaker_id = f"{language}-{gender}-1-{style}"
try:
# Python実装では "EN-FEMALE-1-NEUTRAL" のみがデフォルトで利用可能
# UIで選択肢を限定しているため、このチェックは主に安全のため
if speaker_id != "EN-FEMALE-1-NEUTRAL":
error_message = f"エラー: スピーカー {speaker_id} はデフォルトでは利用できません。利用可能なのは 'EN-FEMALE-1-NEUTRAL' のみです。"
print(error_message)
return error_message, None
speaker = interface.load_default_speaker(speaker_id)
# ロードしたデフォルトスピーカーを一時ファイルに保存
temp_speaker_filename = f"temp_default_speaker_{uuid.uuid4()}.json"
temp_speaker_path = os.path.join("temp_speakers", temp_speaker_filename)
interface.save_speaker(speaker, temp_speaker_path)
status_message = f"デフォルトスピーカー {speaker_id} をロードしました"
return status_message, temp_speaker_path
except Exception as e:
error_message = f"エラー: {str(e)}"
print(error_message)
return error_message, None
# 保存されたスピーカーのロード (GPUワーカープロセス内で実行される)
@spaces.GPU
def load_saved_speaker_gpu(speaker_path):
if not speaker_path:
return "スピーカーファイルを選択してください", None
interface = _get_gpu_interface()
try:
speaker = interface.load_speaker(speaker_path)
# ロードしたスピーカーを一時ファイルに保存 (念のため)
temp_speaker_filename = f"temp_saved_speaker_{uuid.uuid4()}.json"
temp_speaker_path = os.path.join("temp_speakers", temp_speaker_filename)
interface.save_speaker(speaker, temp_speaker_path)
status_message = f"スピーカー {os.path.basename(speaker_path)} をロードしました"
return status_message, temp_speaker_path
except Exception as e:
error_message = f"エラー: {str(e)}"
print(error_message)
return error_message, None
# 音声生成 (GPUワーカープロセス内で実行される)
@spaces.GPU
def generate_speech_gpu(text, temperature, repetition_penalty, top_k, top_p, min_p, current_speaker_path):
if not text:
return "テキストを入力してください", None
if current_speaker_path is None:
return "スピーカープロファイルをロードしてください", None
interface = _get_gpu_interface()
try:
# パスからスピーカーをロード
speaker = interface.load_speaker(current_speaker_path)
# SamplerConfigを生成
sampler_config = SamplerConfig(
temperature=temperature,
repetition_penalty=repetition_penalty,
top_k=top_k,
top_p=top_p,
min_p=min_p
# mirostat_eta, mirostat_tau はUIにないので含めない
)
# GenerationConfigの引数をOuteTTSがサポートするものに限定
# repetition_range は GenerationConfig の直接の引数ではないため削除
output = interface.generate(
GenerationConfig(
text=text,
speaker=speaker,
sampler_config=sampler_config, # SamplerConfigオブジェクトを渡す
# repetition_range=64, # ドキュメントに記載がない、またはSamplerConfig内にある可能性
)
)
output_path = f"outputs/output_{hash(text)}.wav"
output.save(output_path)
return "音声生成が完了しました", output_path
except Exception as e:
error_message = f"エラー: {str(e)}"
print(error_message)
return error_message, None
# Gradio UI
def create_ui():
with gr.Blocks(title="OuteTTS 音声生成デモ") as demo:
gr.Markdown("# OuteTTS-1.0-0.6B 音声生成デモ")
gr.Markdown("このデモでは、OuteTTS-1.0-0.6Bモデルを使用して、テキストから音声を生成します。音声クローニング機能も利用できます。")
# 現在のスピーカープロファイルのパスを保持する隠しStateコンポーネント
current_speaker_path_state = gr.State(value=None)
with gr.Tab("デフォルトスピーカー"):
with gr.Row():
# Python実装では "EN-FEMALE-1-NEUTRAL" のみがデフォルトで利用可能
language = gr.Dropdown(choices=["EN"], value="EN", label="言語")
gender = gr.Dropdown(choices=["FEMALE"], value="FEMALE", label="性別")
style = gr.Dropdown(choices=["NEUTRAL"], value="NEUTRAL", label="スタイル")
load_default_btn = gr.Button("デフォルトスピーカーをロード")
default_speaker_status = gr.Textbox(label="ステータス")
# GPU対応関数を呼び出す
load_default_btn.click(
fn=load_default_speaker_gpu,
inputs=[language, gender, style],
outputs=[default_speaker_status, current_speaker_path_state] # 隠しStateも更新
)
with gr.Tab("音声クローニング"):
gr.Markdown("### 音声ファイルからスピーカープロファイルを作成")
audio_file = gr.File(label="音声ファイル(5〜10秒の明瞭な音声を推奨)")
create_speaker_btn = gr.Button("スピーカープロファイルを作成")
with gr.Row():
speaker_path_output = gr.Textbox(label="保存されたスピーカープロファイルのパス")
decoded_audio = gr.Audio(label="再構成された音声(品質確認用)")
# スピーカー作成時のステータス表示用
create_speaker_status = gr.Textbox(label="スピーカー作成ステータス")
# GPU対応関数を呼び出す
create_speaker_btn.click(
fn=create_speaker_profile_gpu,
inputs=[audio_file],
outputs=[speaker_path_output, decoded_audio, create_speaker_status, current_speaker_path_state] # 隠しStateも更新
)
gr.Markdown("### 保存されたスピーカープロファイルをロード")
saved_speaker_path = gr.Textbox(label="スピーカープロファイルのパス")
load_saved_btn = gr.Button("保存されたスピーカーをロード")
saved_speaker_status = gr.Textbox(label="ステータス")
# GPU対応関数を呼び出す
load_saved_btn.click(
fn=load_saved_speaker_gpu,
inputs=[saved_speaker_path],
outputs=[saved_speaker_status, current_speaker_path_state] # 隠しStateも更新
)
gr.Markdown("## テキストから音声を生成")
with gr.Row():
with gr.Column():
text_input = gr.Textbox(label="テキスト", lines=5, placeholder="ここにテキストを入力してください...")
with gr.Accordion("詳細設定", open=False):
# これらのスライダーはGradio UIに残しますが、
# GenerationConfigには渡しません。
# outettsのドキュメントでサポートされているか確認し、
# 必要であればGenerationConfigに含めてください。
temperature = gr.Slider(minimum=0.1, maximum=1.0, value=0.4, step=0.05, label="Temperature")
repetition_penalty = gr.Slider(minimum=1.0, maximum=1.5, value=1.1, step=0.05, label="Repetition Penalty")
top_k = gr.Slider(minimum=1, maximum=100, value=40, step=1, label="Top-k")
top_p = gr.Slider(minimum=0.1, maximum=1.0, value=0.9, step=0.05, label="Top-p")
min_p = gr.Slider(minimum=0.01, maximum=0.2, value=0.05, step=0.01, label="Min-p")
generate_btn = gr.Button("音声を生成")
with gr.Column():
status_output = gr.Textbox(label="ステータス")
audio_output = gr.Audio(label="生成された音声")
# GPU対応関数を呼び出す
generate_btn.click(
fn=generate_speech_gpu,
inputs=[text_input, temperature, repetition_penalty, top_k, top_p, min_p, current_speaker_path_state], # 隠しStateをinputsに追加
outputs=[status_output, audio_output]
)
gr.Markdown("## サンプル")
with gr.Accordion("使用例", open=True):
gr.Markdown("""
### 使用例:
1. 「デフォルトスピーカー」タブで言語・性別・スタイルを選択し、「デフォルトスピーカーをロード」をクリックします。
2. または「音声クローニング」タブで音声ファイルをアップロードし、「スピーカープロファイルを作成」をクリックします。
3. テキスト入力欄にテキストを入力します。
4. 「音声を生成」ボタンをクリックします。
5. 生成された音声が表示されます。
### 注意事項:
- 音声クローニングには、5〜10秒の明瞭な音声を使用することをお勧めします。
- 日本語と英語の両方に対応していますが、最良の結果を得るには、使用する言語に合ったスピーカープロファイルを作成してください。
- 生成される音声の品質は、スピーカープロファイルの品質に大きく依存します。
""")
return demo
# アプリケーションの起動
demo = create_ui()
demo.launch()
|