File size: 3,563 Bytes
1d3dfb9
 
 
42fcedf
 
1d3dfb9
 
 
e60c650
 
 
1d3dfb9
 
 
42fcedf
1d3dfb9
42fcedf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1d3dfb9
 
42fcedf
 
 
 
366652b
1d3dfb9
 
42fcedf
1d3dfb9
 
42fcedf
366652b
42fcedf
1d3dfb9
42fcedf
1d3dfb9
 
 
 
e60c650
a66f077
 
1d3dfb9
 
 
 
 
 
 
 
 
 
 
a66f077
e60c650
1d3dfb9
 
 
 
a66f077
1d3dfb9
 
 
 
a66f077
1d3dfb9
 
 
a66f077
1d3dfb9
366652b
1d3dfb9
 
366652b
1d3dfb9
 
 
366652b
1d3dfb9
 
 
 
 
 
 
 
a66f077
 
 
 
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
101
102
103
104
105
106
107
108
109
110
111
112
from fastapi import FastAPI, BackgroundTasks
import edge_tts
import asyncio
import os
import time
from fastapi.responses import FileResponse, JSONResponse
from typing import List
import pydub

app = FastAPI()

# Global dictionary to track active requests
active_requests = {}

def split_text(text, max_chunk_size=500):
    """Split text into chunks at sentence boundaries."""
    sentences = text.replace('।', '.').replace('؟', '?').split('.')
    chunks = []
    current_chunk = []
    current_length = 0

    for sentence in sentences:
        sentence = sentence.strip() + '.'
        sentence_length = len(sentence)

        if current_length + sentence_length > max_chunk_size and current_chunk:
            chunks.append(' '.join(current_chunk))
            current_chunk = []
            current_length = 0

        current_chunk.append(sentence)
        current_length += sentence_length

    if current_chunk:
        chunks.append(' '.join(current_chunk))

    return chunks

async def process_chunk(text, voice, temp_dir, chunk_index):
    """Process a single chunk of text asynchronously."""
    tmp_path = os.path.join(temp_dir, f"chunk_{chunk_index}_{int(time.time())}.mp3")
    communicate = edge_tts.Communicate(text, voice)
    await communicate.save(tmp_path)
    return tmp_path

async def combine_audio_files(chunk_files, output_path):
    """Combine multiple MP3 files into one."""
    combined = pydub.AudioSegment.empty()
    for file in chunk_files:
        audio_segment = pydub.AudioSegment.from_mp3(file)
        combined += audio_segment

    combined.export(output_path, format="mp3")

    # Cleanup chunk files
    for file in chunk_files:
        try:
            os.remove(file)
        except:
            pass

@app.get("/")
def home():
    return {"message": "EdgeTTS FastAPI is running!"}

@app.get("/health")
def health_check():
    """Check if the API is running and how many requests are active."""
    return {"status": "running", "active_requests": len(active_requests)}

@app.get("/status")
def status():
    """Return the list of active requests being processed."""
    return {"active_requests": list(active_requests.keys())}

@app.get("/tts")
async def tts(text: str, voice: str = "en-US-JennyNeural", background_tasks: BackgroundTasks = None):
    """Generate speech from text using EdgeTTS with parallel processing."""
    request_id = f"{int(time.time())}_{os.urandom(4).hex()}"
    active_requests[request_id] = "processing"

    try:
        output_file = f"output_{request_id}.mp3"
        temp_dir = f"temp_{request_id}"
        os.makedirs(temp_dir, exist_ok=True)

        chunks = split_text(text)
        tasks = [process_chunk(chunk, voice, temp_dir, i) for i, chunk in enumerate(chunks)]
        chunk_files = await asyncio.gather(*tasks)

        await combine_audio_files(chunk_files, output_file)

        background_tasks.add_task(cleanup_request, request_id)
        return FileResponse(output_file, media_type="audio/mpeg", filename="speech.mp3")

    except Exception as e:
        del active_requests[request_id]
        return JSONResponse(content={"error": str(e)}, status_code=500)

def cleanup_request(request_id):
    """Cleanup function to remove temporary files."""
    del active_requests[request_id]
    temp_dir = f"temp_{request_id}"
    if os.path.exists(temp_dir):
        for file in os.listdir(temp_dir):
            os.remove(os.path.join(temp_dir, file))
        os.rmdir(temp_dir)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=7860)