File size: 2,935 Bytes
92d5846
 
 
 
33c2569
92d5846
 
33c2569
 
92d5846
33c2569
 
 
68876da
 
 
 
92d5846
33c2569
 
 
 
 
 
92d5846
33c2569
 
 
92d5846
33c2569
 
 
 
92d5846
33c2569
 
92d5846
33c2569
92d5846
33c2569
 
 
 
 
92d5846
33c2569
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92d5846
 
33c2569
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
93
94
95
96
97
98
99
100
import time
import requests
import pathlib
from io import BytesIO
from flask import Flask, request, jsonify, send_file
from concurrent.futures import ThreadPoolExecutor, as_completed

# Flask App Setup
app = Flask(__name__)

# ElevenLabs API Configuration
ELEVENLABS_API_URL = "https://api.elevenlabs.io/v1/text-to-speech"
HEADERS = {"User-Agent": "TTSApp"}
# Change cache directory to a writable location
CACHE_DIR = pathlib.Path("/tmp/audio_cache")
CACHE_DIR.mkdir(parents=True, exist_ok=True)


# Available Voices
ALL_VOICES = {
    "Brian": "nPczCjzI2devNBz1zQrb",
    "Alice": "Xb7hH8MSUJpSbSDYk0k2",
    "Will": "bIHbv24MWmeRgasZH58o",
}

# Split text into sentences (Basic)
def split_sentences(text):
    return text.split(". ")

# Generate TTS
def generate_audio(text, voice):
    if voice not in ALL_VOICES:
        return {"error": f"Invalid voice '{voice}'"}

    filename = CACHE_DIR / f"{int(time.time())}.mp3"
    sentences = split_sentences(text)

    def fetch_audio(sentence, part_number):
        try:
            response = requests.post(
                f"{ELEVENLABS_API_URL}/{ALL_VOICES[voice]}",
                headers=HEADERS,
                json={"text": sentence, "model_id": "eleven_multilingual_v2"},
                timeout=20
            )
            response.raise_for_status()
            return part_number, response.content
        except requests.RequestException:
            return part_number, None

    audio_chunks = {}
    with ThreadPoolExecutor() as executor:
        futures = {executor.submit(fetch_audio, sentence.strip(), i): i for i, sentence in enumerate(sentences)}

        for future in as_completed(futures):
            part_number, audio_data = future.result()
            if audio_data:
                audio_chunks[part_number] = audio_data

    combined_audio = BytesIO()
    for part_number in sorted(audio_chunks.keys()):
        combined_audio.write(audio_chunks[part_number])

    with open(filename, "wb") as f:
        f.write(combined_audio.getvalue())

    return filename.as_posix()

# Flask Routes
@app.route("/")
def home():
    return '''
    <h1>Text-to-Speech API</h1>
    <form action="/tts" method="post">
        <label>Text:</label>
        <input type="text" name="text" required>
        <label>Voice:</label>
        <select name="voice">
            <option value="Brian">Brian</option>
            <option value="Alice">Alice</option>
            <option value="Will">Will</option>
        </select>
        <button type="submit">Generate</button>
    </form>
    '''

@app.route("/tts", methods=["POST"])
def tts():
    text = request.form.get("text")
    voice = request.form.get("voice", "Brian")

    if not text:
        return jsonify({"error": "Text is required!"})

    audio_file = generate_audio(text, voice)
    return send_file(audio_file, as_attachment=True)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=5000)