don0726 commited on
Commit
aecd9fc
Β·
verified Β·
1 Parent(s): ef534e5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +45 -42
app.py CHANGED
@@ -15,16 +15,24 @@ from collections import deque
15
  os.environ["COQUI_TOS_AGREED"] = "1"
16
 
17
  # =========================
18
- # πŸ”₯ LOAD MODEL ONCE
19
  # =========================
20
  device = "cuda" if torch.cuda.is_available() else "cpu"
21
 
22
- print("πŸš€ Loading XTTS model...")
23
- tts = TTS(
24
- model_name="tts_models/multilingual/multi-dataset/xtts_v2",
25
- progress_bar=False
26
- ).to(device)
27
- print("βœ… Model loaded!")
 
 
 
 
 
 
 
 
28
 
29
  # =========================
30
  # πŸ“ OUTPUT DIR
@@ -33,48 +41,41 @@ OUTPUT_DIR = "outputs"
33
  os.makedirs(OUTPUT_DIR, exist_ok=True)
34
 
35
  # =========================
36
- # ⚑ BATCH CONFIG
37
  # =========================
38
- BATCH_SIZE = 5
39
- BATCH_WAIT_TIME = 2 # seconds
40
-
41
  request_queue = deque()
42
 
43
  # =========================
44
- # πŸ”₯ BATCH WORKER
45
  # =========================
46
- async def batch_worker():
47
- print("πŸ”₯ Batch worker started...")
48
-
49
  while True:
50
  if len(request_queue) == 0:
51
  await asyncio.sleep(0.1)
52
  continue
53
 
54
- # Wait to collect batch
55
- await asyncio.sleep(BATCH_WAIT_TIME)
56
-
57
- batch = []
58
- while len(request_queue) > 0 and len(batch) < BATCH_SIZE:
59
- batch.append(request_queue.popleft())
60
-
61
- print(f"⚑ Processing batch of {len(batch)}")
62
-
63
- for item in batch:
64
- text, lang, audio_path, output_path, future = item
65
 
66
- try:
67
- tts.tts_to_file(
68
- text=text,
69
- speaker_wav=audio_path,
70
- language=lang,
71
- file_path=output_path,
72
- split_sentences=True
73
- )
74
- future.set_result(output_path)
75
 
76
- except Exception as e:
77
- future.set_result(str(e))
 
 
 
 
 
 
 
 
 
 
 
78
 
79
 
80
  # =========================
@@ -84,7 +85,10 @@ api = FastAPI()
84
 
85
  @api.on_event("startup")
86
  async def startup_event():
87
- asyncio.create_task(batch_worker())
 
 
 
88
 
89
 
90
  @api.post("/clone-voice/")
@@ -103,6 +107,7 @@ async def clone_voice_api(
103
  loop = asyncio.get_event_loop()
104
  future = loop.create_future()
105
 
 
106
  request_queue.append((text, language, input_path, output_path, future))
107
 
108
  result = await future
@@ -132,7 +137,6 @@ async def clone_voice_ui(audio_path, text, language):
132
  future = loop.create_future()
133
 
134
  request_queue.append((text, language, audio_path, output_path, future))
135
-
136
  result = await future
137
 
138
  if isinstance(result, str) and result.endswith(".wav"):
@@ -141,8 +145,8 @@ async def clone_voice_ui(audio_path, text, language):
141
  return f"❌ {result}", None
142
 
143
 
144
- with gr.Blocks(title="XTTS Voice Cloning (Batching)") as demo:
145
- gr.Markdown("# 🎀 XTTS Voice Cloning (Batch Mode)")
146
 
147
  audio_input = gr.Audio(type="filepath", label="Speaker Audio")
148
  text_input = gr.Textbox(label="Text")
@@ -159,7 +163,6 @@ with gr.Blocks(title="XTTS Voice Cloning (Batching)") as demo:
159
  outputs=[status, output_audio]
160
  )
161
 
162
- # βœ… FIXED QUEUE (no concurrency_count)
163
  demo.queue(max_size=20)
164
 
165
  # =========================
 
15
  os.environ["COQUI_TOS_AGREED"] = "1"
16
 
17
  # =========================
18
+ # πŸ”₯ DEVICE
19
  # =========================
20
  device = "cuda" if torch.cuda.is_available() else "cpu"
21
 
22
+ # =========================
23
+ # πŸ”₯ MULTI-CHANNEL MODEL POOL
24
+ # =========================
25
+ NUM_CHANNELS = 5
26
+ print(f"πŸš€ Loading {NUM_CHANNELS} XTTS channels...")
27
+
28
+ channels = []
29
+ for i in range(NUM_CHANNELS):
30
+ tts_model = TTS(
31
+ model_name="tts_models/multilingual/multi-dataset/xtts_v2",
32
+ progress_bar=False
33
+ ).to(device)
34
+ channels.append({"tts": tts_model, "busy": False})
35
+ print(f"βœ… Channel {i+1} loaded")
36
 
37
  # =========================
38
  # πŸ“ OUTPUT DIR
 
41
  os.makedirs(OUTPUT_DIR, exist_ok=True)
42
 
43
  # =========================
44
+ # πŸ”Ή REQUEST QUEUE
45
  # =========================
 
 
 
46
  request_queue = deque()
47
 
48
  # =========================
49
+ # πŸ”₯ MULTI-CHANNEL WORKER
50
  # =========================
51
+ async def channel_worker(channel):
52
+ """Worker that processes requests assigned to this channel."""
 
53
  while True:
54
  if len(request_queue) == 0:
55
  await asyncio.sleep(0.1)
56
  continue
57
 
58
+ if channel["busy"]:
59
+ await asyncio.sleep(0.05)
60
+ continue
 
 
 
 
 
 
 
 
61
 
62
+ # Pick next request
63
+ text, lang, audio_path, output_path, future = request_queue.popleft()
64
+ channel["busy"] = True
 
 
 
 
 
 
65
 
66
+ try:
67
+ channel["tts"].tts_to_file(
68
+ text=text,
69
+ speaker_wav=audio_path,
70
+ language=lang,
71
+ file_path=output_path,
72
+ split_sentences=True
73
+ )
74
+ future.set_result(output_path)
75
+ except Exception as e:
76
+ future.set_result(str(e))
77
+ finally:
78
+ channel["busy"] = False
79
 
80
 
81
  # =========================
 
85
 
86
  @api.on_event("startup")
87
  async def startup_event():
88
+ # Start a worker for each channel
89
+ for ch in channels:
90
+ asyncio.create_task(channel_worker(ch))
91
+ print(f"πŸ”₯ {NUM_CHANNELS} channel workers started!")
92
 
93
 
94
  @api.post("/clone-voice/")
 
107
  loop = asyncio.get_event_loop()
108
  future = loop.create_future()
109
 
110
+ # Add to request queue
111
  request_queue.append((text, language, input_path, output_path, future))
112
 
113
  result = await future
 
137
  future = loop.create_future()
138
 
139
  request_queue.append((text, language, audio_path, output_path, future))
 
140
  result = await future
141
 
142
  if isinstance(result, str) and result.endswith(".wav"):
 
145
  return f"❌ {result}", None
146
 
147
 
148
+ with gr.Blocks(title="XTTS Voice Cloning (Multi-Channel)") as demo:
149
+ gr.Markdown("# 🎀 XTTS Voice Cloning (Multi-Channel)")
150
 
151
  audio_input = gr.Audio(type="filepath", label="Speaker Audio")
152
  text_input = gr.Textbox(label="Text")
 
163
  outputs=[status, output_audio]
164
  )
165
 
 
166
  demo.queue(max_size=20)
167
 
168
  # =========================