259 lines
7.9 KiB
Python
259 lines
7.9 KiB
Python
"""
|
||
语音测试相关路由
|
||
"""
|
||
import os
|
||
import json
|
||
import tempfile
|
||
from flask import Blueprint, request, jsonify, render_template, current_app
|
||
from flask_login import login_required, current_user
|
||
from app.services.cosyvoice_service import cosyvoice_service
|
||
from werkzeug.utils import secure_filename
|
||
import logging
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
voice_test_bp = Blueprint('voice_test', __name__)
|
||
|
||
@voice_test_bp.route('/voice-test')
|
||
@login_required
|
||
def voice_test_page():
|
||
"""语音测试页面"""
|
||
return render_template('voice_test/index.html')
|
||
|
||
@voice_test_bp.route('/api/voice-test/connection', methods=['POST'])
|
||
@login_required
|
||
def test_connection():
|
||
"""测试CosyVoice服务连接"""
|
||
try:
|
||
result = cosyvoice_service.test_connection()
|
||
return jsonify(result)
|
||
except Exception as e:
|
||
logger.error(f"连接测试失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"message": f"测试失败: {str(e)}"
|
||
})
|
||
|
||
@voice_test_bp.route('/api/voice-test/voices', methods=['GET'])
|
||
@login_required
|
||
def get_voices():
|
||
"""获取可用音色列表"""
|
||
try:
|
||
voices = cosyvoice_service.get_available_voices()
|
||
return jsonify({
|
||
"success": True,
|
||
"voices": voices
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"获取音色列表失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"message": f"获取失败: {str(e)}"
|
||
})
|
||
|
||
@voice_test_bp.route('/api/voice-test/generate/preset', methods=['POST'])
|
||
@login_required
|
||
def generate_with_preset_voice():
|
||
"""使用预训练音色生成语音"""
|
||
try:
|
||
data = request.get_json()
|
||
text = data.get('text', '')
|
||
voice = data.get('voice', '中文女')
|
||
seed = data.get('seed', 42)
|
||
speed = data.get('speed', 1.0)
|
||
|
||
if not text:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "请输入要合成的文本"
|
||
})
|
||
|
||
# 生成语音
|
||
stream_audio, full_audio = cosyvoice_service.generate_speech_with_preset_voice(
|
||
text=text,
|
||
voice=voice,
|
||
seed=seed,
|
||
speed=speed
|
||
)
|
||
|
||
if full_audio:
|
||
return jsonify({
|
||
"success": True,
|
||
"message": "语音生成成功",
|
||
"audio_url": full_audio,
|
||
"stream_audio_url": stream_audio
|
||
})
|
||
else:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "语音生成失败"
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"预训练音色生成失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"message": f"生成失败: {str(e)}"
|
||
})
|
||
|
||
@voice_test_bp.route('/api/voice-test/generate/natural', methods=['POST'])
|
||
@login_required
|
||
def generate_with_natural_control():
|
||
"""使用自然语言控制生成语音"""
|
||
try:
|
||
data = request.get_json()
|
||
text = data.get('text', '')
|
||
instruction = data.get('instruction', '请用温柔甜美的女声朗读')
|
||
seed = data.get('seed', 42)
|
||
|
||
if not text:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "请输入要合成的文本"
|
||
})
|
||
|
||
# 生成语音
|
||
stream_audio, full_audio = cosyvoice_service.generate_speech_with_natural_control(
|
||
text=text,
|
||
instruction=instruction,
|
||
seed=seed
|
||
)
|
||
|
||
if full_audio:
|
||
return jsonify({
|
||
"success": True,
|
||
"message": "语音生成成功",
|
||
"audio_url": full_audio,
|
||
"stream_audio_url": stream_audio
|
||
})
|
||
else:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "语音生成失败"
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"自然语言控制生成失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"message": f"生成失败: {str(e)}"
|
||
})
|
||
|
||
@voice_test_bp.route('/api/voice-test/upload-audio', methods=['POST'])
|
||
@login_required
|
||
def upload_audio():
|
||
"""上传音频文件用于语音克隆"""
|
||
try:
|
||
if 'audio' not in request.files:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "请选择音频文件"
|
||
})
|
||
|
||
file = request.files['audio']
|
||
if file.filename == '':
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "请选择音频文件"
|
||
})
|
||
|
||
# 检查文件类型
|
||
allowed_extensions = {'wav', 'mp3', 'm4a', 'flac'}
|
||
if not ('.' in file.filename and
|
||
file.filename.rsplit('.', 1)[1].lower() in allowed_extensions):
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "不支持的音频格式,请使用WAV、MP3、M4A或FLAC格式"
|
||
})
|
||
|
||
# 保存文件到临时目录
|
||
filename = secure_filename(file.filename)
|
||
temp_dir = tempfile.gettempdir()
|
||
file_path = os.path.join(temp_dir, f"voice_clone_{current_user.id}_{filename}")
|
||
file.save(file_path)
|
||
|
||
# 尝试识别音频内容
|
||
recognized_text = cosyvoice_service.recognize_audio(file_path)
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"message": "音频上传成功",
|
||
"file_path": file_path,
|
||
"recognized_text": recognized_text
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"音频上传失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"message": f"上传失败: {str(e)}"
|
||
})
|
||
|
||
@voice_test_bp.route('/api/voice-test/generate/clone', methods=['POST'])
|
||
@login_required
|
||
def generate_with_voice_cloning():
|
||
"""使用语音克隆生成语音"""
|
||
try:
|
||
data = request.get_json()
|
||
text = data.get('text', '')
|
||
reference_audio_path = data.get('reference_audio_path', '')
|
||
reference_text = data.get('reference_text', '')
|
||
seed = data.get('seed', 42)
|
||
|
||
if not text:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "请输入要合成的文本"
|
||
})
|
||
|
||
if not reference_audio_path or not os.path.exists(reference_audio_path):
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "请先上传参考音频"
|
||
})
|
||
|
||
# 生成语音
|
||
stream_audio, full_audio = cosyvoice_service.generate_speech_with_voice_cloning(
|
||
text=text,
|
||
reference_audio_path=reference_audio_path,
|
||
reference_text=reference_text,
|
||
seed=seed
|
||
)
|
||
|
||
if full_audio:
|
||
return jsonify({
|
||
"success": True,
|
||
"message": "语音克隆成功",
|
||
"audio_url": full_audio,
|
||
"stream_audio_url": stream_audio
|
||
})
|
||
else:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "语音克隆失败"
|
||
})
|
||
|
||
except Exception as e:
|
||
logger.error(f"语音克隆失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"message": f"克隆失败: {str(e)}"
|
||
})
|
||
|
||
@voice_test_bp.route('/api/voice-test/random-seed', methods=['GET'])
|
||
@login_required
|
||
def get_random_seed():
|
||
"""获取随机种子"""
|
||
try:
|
||
seed = cosyvoice_service.generate_random_seed()
|
||
return jsonify({
|
||
"success": True,
|
||
"seed": seed
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"获取随机种子失败: {str(e)}")
|
||
return jsonify({
|
||
"success": False,
|
||
"message": f"获取失败: {str(e)}"
|
||
})
|