File size: 2,858 Bytes
fdd0daa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from flask import Flask, request, jsonify, send_from_directory, render_template
import edge_tts
import asyncio
import os
import uuid
from rvc_service import convert_voice, init_rvc

app = Flask(__name__)

# Initialize RVC locally if possible
try:
    init_rvc()
except Exception as e:
    print(f"RVC intialization failed: {e}")

# Directory to store generated audio files
AUDIO_DIR = os.path.join(os.path.dirname(__file__), 'audio')
if not os.path.exists(AUDIO_DIR):
    os.makedirs(AUDIO_DIR)

# Dictionary of available free voices
VOICES = {
    # Vietnamese
    'nam_minh_northern_male': 'vi-VN-NamMinhNeural',
    'hoai_my_southern_female': 'vi-VN-HoaiMyNeural',
    # English
    'jenny_us_female': 'en-US-JennyNeural',
    'guy_us_male': 'en-US-GuyNeural'
}

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/en')
def english_index():
    return render_template('en.html')

@app.route('/api/synthesize', methods=['POST'])
def synthesize():
    data = request.json
    if not data or 'text' not in data or 'voice' not in data:
        return jsonify({"error": "Missing text or voice in request"}), 400
    
    text = data['text']
    voice_key = data['voice']
    anime_voice = data.get('anime_voice', 'none') # Can be 'none' or 'mahiru'

    if voice_key not in VOICES:
         return jsonify({"error": "Invalid base voice selected"}), 400
    
    voice_id = VOICES[voice_key]
    
    # Generate a unique filename
    base_filename = f"{uuid.uuid4()}_base.mp3"
    final_filename = f"{uuid.uuid4()}_final.mp3"
    
    base_filepath = os.path.join(AUDIO_DIR, base_filename)
    final_filepath = os.path.join(AUDIO_DIR, final_filename)
    
    # We use asyncio to run the edge-tts generation
    async def _generate_audio():
        communicate = edge_tts.Communicate(text, voice_id)
        await communicate.save(base_filepath)
    
    try:
        # Step 1: Generate Base TTS Audio
        asyncio.run(_generate_audio())
        
        # Step 2: Apply RVC if requested
        if anime_voice == 'mahiru':
            convert_voice(base_filepath, final_filepath)
            # We serve the final (cloned) file
            serve_filename = final_filename
            # Cleanup base if you want, but leaving it is fine for debugging.
        else:
            # If no anime voice, serve the base TTS directly
            serve_filename = base_filename

        return jsonify({
            "success": True, 
            "audio_url": f"/audio/{serve_filename}"
        })
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@app.route('/audio/<filename>')
def serve_audio(filename):
    return send_from_directory(AUDIO_DIR, filename)

if __name__ == '__main__':
    app.run(debug=True, port=5000)