hivecorp commited on
Commit
1d3dfb9
ยท
verified ยท
1 Parent(s): a66f077

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -42
app.py CHANGED
@@ -1,16 +1,19 @@
 
 
 
1
  import os
2
  import time
3
- import asyncio
4
- from fastapi import FastAPI
5
- import edge_tts
6
- from fastapi.responses import FileResponse
7
- from pydub import AudioSegment
8
 
9
  app = FastAPI()
10
 
11
- # ๐Ÿ”น Function to split text into manageable chunks
 
 
12
  def split_text(text, max_chunk_size=500):
13
- """Split text into smaller chunks at sentence boundaries."""
14
  sentences = text.replace('เฅค', '.').replace('ุŸ', '?').split('.')
15
  chunks = []
16
  current_chunk = []
@@ -33,64 +36,76 @@ def split_text(text, max_chunk_size=500):
33
 
34
  return chunks
35
 
36
- # ๐Ÿ”น Function to process a single chunk asynchronously
37
  async def process_chunk(text, voice, temp_dir, chunk_index):
38
- """Generate speech for a single chunk and save as MP3."""
39
- tmp_path = os.path.join(temp_dir, f"chunk_{chunk_index}.mp3")
40
- print(f"๐ŸŽค Processing chunk {chunk_index}: {text[:50]}...") # Logging for debugging
41
  communicate = edge_tts.Communicate(text, voice)
42
  await communicate.save(tmp_path)
43
  return tmp_path
44
 
45
- # ๐Ÿ”น Function to merge all chunked MP3 files into a single audio file
46
  async def combine_audio_files(chunk_files, output_path):
47
- """Combine multiple MP3 files into one final MP3."""
48
- combined = AudioSegment.empty()
49
-
50
  for file in chunk_files:
51
- print(f"๐Ÿ”น Adding {file} to final output") # Logging for debugging
52
- combined += AudioSegment.from_mp3(file)
53
 
54
  combined.export(output_path, format="mp3")
55
 
56
- # Remove temporary files
57
  for file in chunk_files:
58
- os.remove(file)
 
 
 
59
 
60
  @app.get("/")
61
  def home():
62
- return {"message": "โœ… EdgeTTS FastAPI is running!"}
 
 
 
 
 
 
 
 
 
 
63
 
64
- # ๐Ÿ”น Main TTS API
65
  @app.get("/tts")
66
- async def tts(text: str, voice: str = "en-US-AriaNeural"):
67
- """Main API function to handle text-to-speech conversion."""
68
- temp_dir = "temp_audio"
69
- os.makedirs(temp_dir, exist_ok=True)
70
 
71
- chunks = split_text(text)
 
 
 
72
 
73
- # If text is short, process directly
74
- if len(chunks) == 1:
75
- print("๐Ÿ“ข Processing without chunking...")
76
- output_file = await process_chunk(text, voice, temp_dir, 0)
77
- return FileResponse(output_file, media_type="audio/mpeg", filename="speech.mp3")
78
 
79
- print(f"๐Ÿš€ Splitting into {len(chunks)} chunks and processing concurrently...")
80
 
81
- # ๐Ÿ”น Concurrently process all chunks
82
- chunk_files = await asyncio.gather(*[
83
- process_chunk(ch, voice, temp_dir, i) for i, ch in enumerate(chunks)
84
- ])
85
 
86
- # ๐Ÿ”น Merge all MP3 files
87
- output_file = "final_output.mp3"
88
- await combine_audio_files(chunk_files, output_file)
89
 
90
- print("โœ… TTS Generation Complete. Sending response...")
91
- return FileResponse(output_file, media_type="audio/mpeg", filename="speech.mp3")
 
 
 
 
 
 
92
 
93
- # ๐Ÿ”น Ensure app starts in Hugging Face Spaces
94
  if __name__ == "__main__":
95
  import uvicorn
96
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
1
+ from fastapi import FastAPI, BackgroundTasks
2
+ import edge_tts
3
+ import asyncio
4
  import os
5
  import time
6
+ from fastapi.responses import FileResponse, JSONResponse
7
+ from typing import List
8
+ import pydub
 
 
9
 
10
  app = FastAPI()
11
 
12
+ # Global dictionary to track active requests
13
+ active_requests = {}
14
+
15
  def split_text(text, max_chunk_size=500):
16
+ """Split text into chunks at sentence boundaries."""
17
  sentences = text.replace('เฅค', '.').replace('ุŸ', '?').split('.')
18
  chunks = []
19
  current_chunk = []
 
36
 
37
  return chunks
38
 
 
39
  async def process_chunk(text, voice, temp_dir, chunk_index):
40
+ """Process a single chunk of text asynchronously."""
41
+ tmp_path = os.path.join(temp_dir, f"chunk_{chunk_index}_{int(time.time())}.mp3")
 
42
  communicate = edge_tts.Communicate(text, voice)
43
  await communicate.save(tmp_path)
44
  return tmp_path
45
 
 
46
  async def combine_audio_files(chunk_files, output_path):
47
+ """Combine multiple MP3 files into one."""
48
+ combined = pydub.AudioSegment.empty()
 
49
  for file in chunk_files:
50
+ audio_segment = pydub.AudioSegment.from_mp3(file)
51
+ combined += audio_segment
52
 
53
  combined.export(output_path, format="mp3")
54
 
55
+ # Cleanup chunk files
56
  for file in chunk_files:
57
+ try:
58
+ os.remove(file)
59
+ except:
60
+ pass
61
 
62
  @app.get("/")
63
  def home():
64
+ return {"message": "EdgeTTS FastAPI is running!"}
65
+
66
+ @app.get("/health")
67
+ def health_check():
68
+ """Check if the API is running and how many requests are active."""
69
+ return {"status": "running", "active_requests": len(active_requests)}
70
+
71
+ @app.get("/status")
72
+ def status():
73
+ """Return the list of active requests being processed."""
74
+ return {"active_requests": list(active_requests.keys())}
75
 
 
76
  @app.get("/tts")
77
+ async def tts(text: str, voice: str = "en-US-JennyNeural", background_tasks: BackgroundTasks = None):
78
+ """Generate speech from text using EdgeTTS with parallel processing."""
79
+ request_id = f"{int(time.time())}_{os.urandom(4).hex()}"
80
+ active_requests[request_id] = "processing"
81
 
82
+ try:
83
+ output_file = f"output_{request_id}.mp3"
84
+ temp_dir = f"temp_{request_id}"
85
+ os.makedirs(temp_dir, exist_ok=True)
86
 
87
+ chunks = split_text(text)
88
+ tasks = [process_chunk(chunk, voice, temp_dir, i) for i, chunk in enumerate(chunks)]
89
+ chunk_files = await asyncio.gather(*tasks)
 
 
90
 
91
+ await combine_audio_files(chunk_files, output_file)
92
 
93
+ background_tasks.add_task(cleanup_request, request_id)
94
+ return FileResponse(output_file, media_type="audio/mpeg", filename="speech.mp3")
 
 
95
 
96
+ except Exception as e:
97
+ del active_requests[request_id]
98
+ return JSONResponse(content={"error": str(e)}, status_code=500)
99
 
100
+ def cleanup_request(request_id):
101
+ """Cleanup function to remove temporary files."""
102
+ del active_requests[request_id]
103
+ temp_dir = f"temp_{request_id}"
104
+ if os.path.exists(temp_dir):
105
+ for file in os.listdir(temp_dir):
106
+ os.remove(os.path.join(temp_dir, file))
107
+ os.rmdir(temp_dir)
108
 
 
109
  if __name__ == "__main__":
110
  import uvicorn
111
  uvicorn.run(app, host="0.0.0.0", port=7860)