2026-07-02 18:51:23 +08:00
|
|
|
from flask import Blueprint, request, jsonify, session
|
2026-06-30 21:00:20 +08:00
|
|
|
import base64
|
|
|
|
|
import os
|
|
|
|
|
from app.services.minimax_service import synthesize_minimax
|
|
|
|
|
from app.services.cosyvoice_service import synthesize_cosyvoice
|
2026-07-02 21:11:23 +08:00
|
|
|
from app.services.doubao_service import synthesize_doubao
|
2026-07-02 23:29:15 +08:00
|
|
|
from app.services.fish_audio_service import synthesize_fish_audio
|
2026-07-02 18:51:23 +08:00
|
|
|
from app.routes.auth import login_required
|
|
|
|
|
from app.db import get_db
|
2026-06-30 21:00:20 +08:00
|
|
|
|
|
|
|
|
bp = Blueprint('tts', __name__, url_prefix='/api')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@bp.route('/synthesize', methods=['POST'])
|
2026-07-02 18:51:23 +08:00
|
|
|
@login_required
|
2026-06-30 21:00:20 +08:00
|
|
|
def synthesize():
|
|
|
|
|
data = request.get_json()
|
2026-07-02 18:51:23 +08:00
|
|
|
|
2026-06-30 21:00:20 +08:00
|
|
|
if not data or 'text' not in data:
|
|
|
|
|
return jsonify({'error': '缺少text参数'}), 400
|
2026-07-02 18:51:23 +08:00
|
|
|
|
2026-06-30 21:00:20 +08:00
|
|
|
text = data.get('text')
|
|
|
|
|
engine = data.get('engine', 'minimax')
|
|
|
|
|
speed = data.get('speed', 1.0)
|
|
|
|
|
pitch = data.get('pitch', 0)
|
|
|
|
|
volume = data.get('volume', 1.0)
|
2026-07-02 18:51:23 +08:00
|
|
|
instruction = data.get('instruction')
|
|
|
|
|
emotion = data.get('emotion', 'neutral')
|
|
|
|
|
|
2026-06-30 21:00:20 +08:00
|
|
|
if not text.strip():
|
|
|
|
|
return jsonify({'error': '文本不能为空'}), 400
|
2026-07-02 18:51:23 +08:00
|
|
|
|
2026-06-30 23:47:23 +08:00
|
|
|
if len(text) > 2000:
|
|
|
|
|
return jsonify({'error': '文本不能超过2000字'}), 400
|
2026-07-02 18:51:23 +08:00
|
|
|
|
2026-06-30 21:00:20 +08:00
|
|
|
try:
|
|
|
|
|
if engine == 'cosyvoice':
|
|
|
|
|
audio_data = synthesize_cosyvoice(
|
2026-07-02 18:51:23 +08:00
|
|
|
text=text, speed=speed, pitch=pitch,
|
|
|
|
|
volume=volume, instruction=instruction
|
2026-06-30 21:00:20 +08:00
|
|
|
)
|
2026-07-02 21:11:23 +08:00
|
|
|
elif engine == 'doubao':
|
|
|
|
|
audio_data = synthesize_doubao(
|
|
|
|
|
text=text, speed=speed, pitch=pitch,
|
2026-07-02 23:29:15 +08:00
|
|
|
volume=volume, emotion=emotion
|
|
|
|
|
)
|
|
|
|
|
elif engine == 'fish_audio':
|
|
|
|
|
audio_data = synthesize_fish_audio(
|
|
|
|
|
text=text, speed=speed, pitch=pitch,
|
2026-07-02 21:11:23 +08:00
|
|
|
volume=volume, emotion=emotion
|
|
|
|
|
)
|
2026-06-30 21:00:20 +08:00
|
|
|
else:
|
|
|
|
|
audio_data = synthesize_minimax(
|
2026-07-02 18:51:23 +08:00
|
|
|
text=text, speed=speed, pitch=pitch,
|
|
|
|
|
volume=volume, emotion=emotion
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# 记录使用日志
|
|
|
|
|
try:
|
|
|
|
|
conn = get_db()
|
|
|
|
|
conn.execute(
|
|
|
|
|
'''INSERT INTO usage_logs
|
|
|
|
|
(user_id, username, display_name, text_content, text_length, engine, emotion)
|
|
|
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)''',
|
|
|
|
|
(session['user_id'], session['username'], session['display_name'],
|
|
|
|
|
text, len(text), engine, emotion)
|
2026-06-30 21:00:20 +08:00
|
|
|
)
|
2026-07-02 18:51:23 +08:00
|
|
|
conn.commit()
|
|
|
|
|
conn.close()
|
|
|
|
|
except Exception:
|
|
|
|
|
pass # 日志写入失败不影响正常合成
|
|
|
|
|
|
2026-06-30 21:00:20 +08:00
|
|
|
return jsonify({
|
|
|
|
|
'success': True,
|
|
|
|
|
'audio': base64.b64encode(audio_data).decode('utf-8')
|
|
|
|
|
})
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 500
|