上传文件至 /
ow
This commit is contained in:
parent
9001ae19d6
commit
f37f7d6ab5
250
gpt_sovits_api.py
Normal file
250
gpt_sovits_api.py
Normal file
@ -0,0 +1,250 @@
|
||||
'''
|
||||
GPT-SoVITS API - Direct call interface
|
||||
'''
|
||||
import os
|
||||
import sys
|
||||
import random
|
||||
import torch
|
||||
import numpy as np
|
||||
|
||||
now_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.append(now_dir)
|
||||
sys.path.append(os.path.dirname(now_dir))
|
||||
|
||||
from TTS_infer_pack.TTS import TTS, TTS_Config
|
||||
|
||||
class GPTSoVITSAPI:
|
||||
def __init__(self, version="v2ProPlus", device=None, is_half=None):
|
||||
"""
|
||||
Initialize GPT-SoVITS API (same as WebUI)
|
||||
|
||||
Args:
|
||||
version: Model version, options: v1, v2, v3, v4, v2Pro, v2ProPlus
|
||||
device: Running device, e.g. "cuda" or "cpu"
|
||||
is_half: Whether to use half precision
|
||||
"""
|
||||
self.version = version
|
||||
|
||||
# Set device (same as WebUI)
|
||||
if device is not None:
|
||||
self.device = torch.device(device)
|
||||
else:
|
||||
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
||||
|
||||
# Set half precision (same as WebUI)
|
||||
if is_half is not None:
|
||||
self.is_half = is_half
|
||||
else:
|
||||
self.is_half = torch.cuda.is_available()
|
||||
|
||||
# Initialize TTS exactly like WebUI
|
||||
self._init_tts()
|
||||
|
||||
print(f"GPT-SoVITS API initialized")
|
||||
# print(f" Version: {self.version}")
|
||||
# print(f" Device: {self.device}")
|
||||
# print(f" Half precision: {self.is_half}")
|
||||
# print(f" GPT model: {self.tts.configs.t2s_weights_path}")
|
||||
# print(f" SoVITS model: {self.tts.configs.vits_weights_path}")
|
||||
|
||||
def _init_tts(self):
|
||||
"""Initialize TTS pipeline exactly like WebUI"""
|
||||
# Use config file (same as WebUI)
|
||||
self.tts_config = TTS_Config(os.path.join(now_dir, "configs/tts_infer.yaml"))
|
||||
self.tts_config.device = self.device
|
||||
self.tts_config.is_half = self.is_half
|
||||
self.tts_config.update_version(self.version)
|
||||
|
||||
# Create TTS instance
|
||||
self.tts = TTS(self.tts_config)
|
||||
|
||||
def generate(
|
||||
self,
|
||||
ref_wav_path,
|
||||
prompt_text,
|
||||
text,
|
||||
prompt_language="all_zh",
|
||||
text_language="all_zh",
|
||||
top_k=15,
|
||||
top_p=1,
|
||||
temperature=1,
|
||||
text_split_method="cut1",
|
||||
batch_size=20,
|
||||
speed_factor=1.0,
|
||||
split_bucket=True,
|
||||
seed=-1,
|
||||
keep_random=True,
|
||||
parallel_infer=True,
|
||||
repetition_penalty=1.35,
|
||||
sample_steps=32,
|
||||
super_sampling=False,
|
||||
output_path=None,
|
||||
**kwargs
|
||||
):
|
||||
"""
|
||||
Generate speech from text (same parameters as WebUI)
|
||||
|
||||
Args:
|
||||
ref_wav_path: Path to reference audio file
|
||||
prompt_text: Reference text (should match reference audio)
|
||||
text: Target text to synthesize
|
||||
prompt_language: Language of prompt text, options: all_zh, zh, ja, en
|
||||
text_language: Language of target text, options: all_zh, zh, ja, en
|
||||
top_k: Top-K sampling parameter
|
||||
top_p: Top-P sampling parameter
|
||||
temperature: Temperature for sampling
|
||||
text_split_method: Text split method, options: cut1, cut2, cut3
|
||||
batch_size: Batch size for inference
|
||||
speed_factor: Speed factor (1.0 = normal)
|
||||
split_bucket: Whether to use bucket splitting
|
||||
seed: Random seed (-1 = random, or specific seed value)
|
||||
keep_random: Whether to keep random (True) or use fixed seed (False)
|
||||
parallel_infer: Whether to use parallel inference
|
||||
repetition_penalty: Repetition penalty
|
||||
sample_steps: Number of sampling steps
|
||||
super_sampling: Whether to use super sampling
|
||||
output_path: Optional output file path to save audio (e.g., "output.wav")
|
||||
|
||||
Returns:
|
||||
(sample_rate, audio_array) tuple, or (None, None) on failure
|
||||
"""
|
||||
# Handle seed (same logic as WebUI)
|
||||
seed = -1 if keep_random else seed
|
||||
actual_seed = seed if seed not in [-1, "", None] else random.randint(0, 2**32 - 1)
|
||||
|
||||
# Build inputs exactly like WebUI
|
||||
inputs = {
|
||||
"text": text,
|
||||
"text_lang": text_language,
|
||||
"ref_audio_path": ref_wav_path,
|
||||
"aux_ref_audio_paths": [],
|
||||
"prompt_text": prompt_text,
|
||||
"prompt_lang": prompt_language,
|
||||
"top_k": top_k,
|
||||
"top_p": top_p,
|
||||
"temperature": temperature,
|
||||
"text_split_method": text_split_method,
|
||||
"batch_size": batch_size,
|
||||
"speed_factor": float(speed_factor),
|
||||
"split_bucket": split_bucket,
|
||||
"return_fragment": False,
|
||||
"fragment_interval": 0.3,
|
||||
"seed": actual_seed,
|
||||
"parallel_infer": parallel_infer,
|
||||
"repetition_penalty": repetition_penalty,
|
||||
"sample_steps": sample_steps,
|
||||
"super_sampling": super_sampling,
|
||||
}
|
||||
|
||||
# # Print parameters for debugging
|
||||
# print("=" * 60)
|
||||
# print("【API 推理参数】")
|
||||
# print(f" version: {self.version}")
|
||||
# print(f" text: {text[:50]}..." if len(text) > 50 else f" text: {text}")
|
||||
# print(f" text_lang: {text_language}")
|
||||
# print(f" ref_audio_path: {ref_wav_path}")
|
||||
# print(f" prompt_text: {prompt_text[:50]}..." if len(prompt_text) > 50 else f" prompt_text: {prompt_text}")
|
||||
# print(f" prompt_lang: {prompt_language}")
|
||||
# print(f" top_k: {top_k}")
|
||||
# print(f" top_p: {top_p}")
|
||||
# print(f" temperature: {temperature}")
|
||||
# print(f" text_split_method: {text_split_method}")
|
||||
# print(f" batch_size: {batch_size}")
|
||||
# print(f" speed_factor: {speed_factor}")
|
||||
# print(f" split_bucket: {split_bucket}")
|
||||
# print(f" seed: {actual_seed}")
|
||||
# print(f" keep_random: {keep_random}")
|
||||
# print(f" parallel_infer: {parallel_infer}")
|
||||
# print(f" repetition_penalty: {repetition_penalty}")
|
||||
# print(f" sample_steps: {sample_steps}")
|
||||
# print(f" super_sampling: {super_sampling}")
|
||||
# print("=" * 60)
|
||||
|
||||
# Run inference (same as WebUI)
|
||||
result = None
|
||||
for item in self.tts.run(inputs):
|
||||
result = item
|
||||
|
||||
if result is not None:
|
||||
# TTS.run() returns (sr, audio_array) tuple
|
||||
if isinstance(result, tuple) and len(result) >= 2:
|
||||
sr = result[0]
|
||||
audio_data = result[1]
|
||||
|
||||
if isinstance(audio_data, np.ndarray):
|
||||
# Save audio if output_path is provided
|
||||
if output_path is not None:
|
||||
try:
|
||||
import soundfile as sf
|
||||
sf.write(output_path, audio_data, sr)
|
||||
print(f"Audio saved to: {output_path}")
|
||||
except Exception as e:
|
||||
print(f"Error saving audio: {e}")
|
||||
|
||||
return sr, audio_data
|
||||
else:
|
||||
print(f"Warning: audio_data is {type(audio_data)}, not numpy array")
|
||||
return None, None
|
||||
else:
|
||||
print(f"Warning: result is {type(result)}, not a tuple")
|
||||
return None, None
|
||||
|
||||
return None, None
|
||||
|
||||
def save_audio(self, audio_array, sample_rate, output_path):
|
||||
"""
|
||||
Save audio array to file
|
||||
|
||||
Args:
|
||||
audio_array: numpy array of audio data
|
||||
sample_rate: Sample rate
|
||||
output_path: Output file path
|
||||
|
||||
Returns:
|
||||
output_path if successful, None otherwise
|
||||
"""
|
||||
try:
|
||||
import soundfile as sf
|
||||
sf.write(output_path, audio_array, sample_rate)
|
||||
print(f"Audio saved to: {output_path}")
|
||||
return output_path
|
||||
except Exception as e:
|
||||
print(f"Error saving audio: {e}")
|
||||
return None
|
||||
|
||||
|
||||
# Command line interface
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="GPT-SoVITS API")
|
||||
parser.add_argument("--ref_wav", required=True, help="Path to reference audio")
|
||||
parser.add_argument("--prompt_text", required=True, help="Reference text")
|
||||
parser.add_argument("--text", required=True, help="Target text to synthesize")
|
||||
parser.add_argument("--prompt_lang", default="all_zh", help="Prompt language")
|
||||
parser.add_argument("--text_lang", default="all_zh", help="Text language")
|
||||
parser.add_argument("--output", default="output.wav", help="Output file path")
|
||||
parser.add_argument("--version", default="v2ProPlus", help="Model version")
|
||||
parser.add_argument("--seed", type=int, default=819407889, help="Random seed")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Initialize API
|
||||
api = GPTSoVITSAPI(version=args.version)
|
||||
|
||||
# Generate audio
|
||||
sr, audio = api.generate(
|
||||
ref_wav_path=args.ref_wav,
|
||||
prompt_text=args.prompt_text,
|
||||
text=args.text,
|
||||
prompt_language=args.prompt_lang,
|
||||
text_language=args.text_lang,
|
||||
seed=args.seed
|
||||
)
|
||||
|
||||
# Save output
|
||||
if sr is not None and audio is not None:
|
||||
api.save_audio(audio, sr, args.output)
|
||||
print(f"\n✓ Successfully generated audio: {args.output}")
|
||||
else:
|
||||
print("\n✗ Failed to generate audio")
|
||||
19
sovits.py
Normal file
19
sovits.py
Normal file
@ -0,0 +1,19 @@
|
||||
import os
|
||||
import sys
|
||||
import random
|
||||
# Change to project directory這個是針對C#的環境
|
||||
os.chdir(r"F:\GPT-SoVITS\GPT-SoVITS-v2pro-20250604")
|
||||
sys.path.insert(0, os.getcwd())
|
||||
|
||||
now_dir = os.getcwd()
|
||||
sys.path.append(now_dir)
|
||||
sys.path.append("%s/GPT_SoVITS" % (now_dir))
|
||||
|
||||
print(f"Current directory: {now_dir}")
|
||||
print(f"Python path: {sys.executable}")
|
||||
|
||||
from gpt_sovits_api import GPTSoVITSAPI
|
||||
|
||||
print("\nInitializing GPT-SoVITS API...")
|
||||
api = GPTSoVITSAPI(version="v2ProPlus")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user