File size: 4,198 Bytes
abd39d3 | 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 | """Real CT2 translation + Piper CUDA session and short synthesis smoke check."""
import argparse
import io
import json
import sys
import time
import wave
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--model', default='HachimiMT-60-QT')
parser.add_argument('--voice', default='ngochuyennew')
parser.add_argument('--tts-engine',choices=['piper','vieneu'],default='piper')
args = parser.parse_args()
from translation.core.ct2_safe_import import import_ctranslate2
ct2 = import_ctranslate2()
import importlib.metadata
import ctypes
for package in ('onnxruntime-gpu', 'nvidia-cudnn-cu12', 'ctranslate2', 'piper-tts'):
try:
print(f'{package}={importlib.metadata.version(package)}', flush=True)
except importlib.metadata.PackageNotFoundError:
print(f'{package}=not-installed', flush=True)
try:
cudnn = ctypes.CDLL('libcudnn.so.9')
cudnn.cudnnGetVersion.restype = ctypes.c_size_t
print(f'loaded_cudnn_version={cudnn.cudnnGetVersion()}', flush=True)
except OSError as exc:
print(f'cuDNN load check: {exc}', flush=True)
if ct2.get_cuda_device_count() < 1:
raise RuntimeError('CT2 không thấy GPU. Chọn runtime T4 và kiểm tra nvidia-smi.')
from translation.engines import LocalEngine
engine = LocalEngine(args.model, backend='ct2')
engine.load()
output = engine.translate_raw(['你好世界。'], beam_size=2)
device = engine.translator.device if engine.translator is not None else engine.model.device
if device != 'cuda':
raise RuntimeError(f'CT2 đang chạy {device}, không phải CUDA')
# Release translation model before checking voice to keep smoke-test simple.
del engine
if args.tts_engine=='vieneu':
import tempfile,os
import soundfile as sf
from audio.vieneu_service import synthesize_to_wav,get_runtime,runtime_status
os.environ['VIENEU_DEVICE']='cuda';before=time.perf_counter()
with tempfile.TemporaryDirectory() as work:
path=Path(work)/'smoke.wav'
synthesize_to_wav('Xin chào, kiểm tra giọng đọc trên GPU.',args.voice,path)
samples,rate=sf.read(path)
if get_runtime().backend!='pytorch' or len(samples)==0 or rate!=48000:
raise RuntimeError('VieNeu GPU không trả về WAV 48 kHz hợp lệ.')
print(json.dumps({'ct2_device':device,'translation_sample':output,'tts':runtime_status(),'audio_seconds':len(samples)/rate,'synthesis_seconds':time.perf_counter()-before},ensure_ascii=False))
return
from audio.audio_service import get_voice, tts_runtime_status
from tts.synthesis import synthesize_wav
voice = get_voice(args.voice)
providers = voice.session.get_providers()
if 'CUDAExecutionProvider' not in providers:
raise RuntimeError(f'Piper session không dùng CUDA: {providers}')
# Separate WAVs because Piper sets WAV parameters on each synthesis call.
before = time.perf_counter()
durations = []
for text in ('Xin chào, kiểm tra giọng đọc trên GPU.',
('người lữ hành bước qua khu rừng và nhìn về phía chân trời ' * 20).strip()):
buffer = io.BytesIO()
with wave.open(buffer, 'wb') as wav:
synthesize_wav(voice, text, wav)
with wave.open(io.BytesIO(buffer.getvalue()), 'rb') as wav:
durations.append(wav.getnframes() / wav.getframerate())
duration = sum(durations)
if 'CUDAExecutionProvider' not in voice.session.get_providers():
raise RuntimeError('Piper rơi về CPU sau inference')
print(json.dumps({'ct2_device': device, 'translation_sample': output,
'tts': tts_runtime_status(), 'audio_seconds': duration,
'synthesis_seconds': round(time.perf_counter() - before, 3)},
ensure_ascii=False, indent=2))
if any(value <= 0 for value in durations):
raise RuntimeError('Piper trả về audio rỗng')
if __name__ == '__main__':
main()
|