crackuser commited on
Commit
9a34a5d
·
verified ·
1 Parent(s): 2eaf615

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +196 -302
app.py CHANGED
@@ -1,91 +1,85 @@
1
  import gradio as gr
2
  import torch
3
- import torchaudio as ta
4
  import tempfile
5
  import os
6
- from chatterbox.tts import ChatterboxTTS
7
- from chatterbox.mtl_tts import ChatterboxMultilingualTTS
8
 
9
- # Initialize Chatterbox models (the ones we actually discussed!)
10
- print("🔄 Loading Chatterbox TTS models...")
11
- device = "cuda" if torch.cuda.is_available() else "cpu"
12
 
13
- try:
14
- # Load Chatterbox English model
15
- english_model = ChatterboxTTS.from_pretrained(device=device)
16
- print("✅ Chatterbox English model loaded!")
17
-
18
- # Load Chatterbox Multilingual model
19
- multilingual_model = ChatterboxMultilingualTTS.from_pretrained(device=device)
20
- print(" Chatterbox Multilingual model loaded!")
21
-
22
- models_loaded = True
23
- except Exception as e:
24
- print(f"❌ Error loading Chatterbox models: {e}")
25
- english_model = None
26
- multilingual_model = None
27
- models_loaded = False
28
 
29
- def chatterbox_voice_clone(reference_audio, input_audio, language="en", exaggeration=0.5, cfg=0.5):
30
- """
31
- Real Voice-to-Voice cloning using Chatterbox (the model we discussed!)
32
- """
33
- try:
34
- if not reference_audio or not input_audio:
35
- return None, " Please upload both reference and input audio files!"
36
-
37
- if not models_loaded:
38
- return None, " Chatterbox models not loaded!"
39
-
40
- # Extract text from input audio using Whisper
41
- import whisper
 
 
 
 
 
 
 
 
 
 
42
  try:
43
- whisper_model = whisper.load_model("base")
44
- result = whisper_model.transcribe(input_audio)
45
- input_text = result["text"]
46
- print(f"📝 Extracted text: {input_text}")
47
- except Exception as e:
48
- input_text = "Voice cloning demonstration using Chatterbox AI technology."
49
- print(f"⚠️ Whisper failed, using default text: {e}")
50
-
51
- # Create output file
52
- with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_file:
53
- output_path = tmp_file.name
54
-
55
- # Use appropriate Chatterbox model based on language
56
- if language == "en":
57
- # Use English Chatterbox model
58
- wav = english_model.generate(
59
- input_text,
60
- audio_prompt_path=reference_audio,
61
- exaggeration=exaggeration,
62
- cfg=cfg
63
- )
64
- else:
65
- # Use Multilingual Chatterbox model
66
- wav = multilingual_model.generate(
67
- input_text,
68
- audio_prompt_path=reference_audio,
69
- language_id=language,
70
- exaggeration=exaggeration,
71
- cfg=cfg
72
- )
73
-
74
- # Save generated audio
75
- ta.save(output_path, wav, english_model.sr if language == "en" else multilingual_model.sr)
76
-
77
- if os.path.exists(output_path) and os.path.getsize(output_path) > 0:
78
- return output_path, f"✅ Chatterbox Voice Cloning Complete!\n🎵 Generated: '{input_text[:100]}...'\n🎛️ Settings: Exaggeration={exaggeration}, CFG={cfg}"
79
- else:
80
- return None, "❌ Failed to generate cloned audio!"
81
 
82
- except Exception as e:
83
- return None, f"❌ Chatterbox Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
84
 
85
- def chatterbox_text_to_speech(reference_audio, input_text, language="en", exaggeration=0.5, cfg=0.5, speed=1.0):
86
- """
87
- Real Text-to-Speech with voice cloning using Chatterbox
88
- """
89
  try:
90
  if not reference_audio:
91
  return None, "❌ Please upload reference audio!"
@@ -93,255 +87,155 @@ def chatterbox_text_to_speech(reference_audio, input_text, language="en", exagge
93
  if not input_text or not input_text.strip():
94
  return None, "❌ Please enter text to convert!"
95
 
96
- if not models_loaded:
97
- return None, "❌ Chatterbox models not loaded!"
 
 
98
 
99
  print(f"🎤 Generating speech with Chatterbox...")
100
- print(f"📝 Text: {input_text}")
101
- print(f"🗣️ Language: {language}")
102
- print(f"🎛️ Exaggeration: {exaggeration}, CFG: {cfg}")
103
 
104
  # Create output file
105
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_file:
106
  output_path = tmp_file.name
107
 
108
- # Use appropriate Chatterbox model
109
- if language == "en":
110
- # English Chatterbox model
111
- wav = english_model.generate(
112
- input_text,
113
- audio_prompt_path=reference_audio,
114
- exaggeration=exaggeration,
115
- cfg=cfg
116
- )
117
- else:
118
- # Multilingual Chatterbox model
119
- wav = multilingual_model.generate(
120
  input_text,
121
  audio_prompt_path=reference_audio,
122
- language_id=language,
123
- exaggeration=exaggeration,
124
- cfg=cfg
125
  )
126
-
127
- # Save generated audio
128
- ta.save(output_path, wav, english_model.sr if language == "en" else multilingual_model.sr)
129
-
130
- if os.path.exists(output_path) and os.path.getsize(output_path) > 0:
131
- return output_path, f"✅ Chatterbox TTS Complete!\n📝 Generated: '{input_text[:100]}...'\n🎛️ Settings: Exaggeration={exaggeration}, CFG={cfg}"
132
- else:
133
- return None, "❌ Failed to generate speech!"
 
 
 
 
134
 
135
  except Exception as e:
136
- return None, f"❌ Chatterbox Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
  # Create Gradio interface
139
- def create_chatterbox_interface():
140
- with gr.Blocks(
141
- title="🎭 Chatterbox Voice Cloning Studio",
142
- theme=gr.themes.Soft(primary_hue="purple", secondary_hue="pink")
143
- ) as demo:
144
-
145
- # Header
146
- gr.HTML("""
147
- <div style="text-align: center; padding: 20px;">
148
- <h1 style="color: #8B5CF6; margin-bottom: 10px;">🎭 Chatterbox Voice Cloning Studio</h1>
149
- <p style="color: #666; font-size: 18px;">Powered by Resemble AI's Chatterbox - The Model We Discussed!</p>
150
- <p style="color: #888; font-size: 14px;">✨ Emotion control • 23+ languages • Zero-shot cloning • MIT licensed</p>
151
- </div>
152
- """)
153
-
154
- # Model Status
155
- gr.HTML(f"""
156
- <div style="text-align: center; padding: 10px; background: {'#d4edda' if models_loaded else '#f8d7da'}; border-radius: 10px; margin-bottom: 20px;">
157
- <strong>🤖 Chatterbox Status:</strong> {'✅ Models Loaded Successfully!' if models_loaded else '❌ Models Not Loaded'}
158
- </div>
159
- """)
160
-
161
- with gr.Row():
162
- with gr.Column(scale=1):
163
- # Reference Voice Section
164
- gr.HTML("<h3 style='color: #8B5CF6;'>🎤 Reference Voice (5+ seconds)</h3>")
165
- reference_audio = gr.Audio(
166
- label="Upload Reference Audio",
167
- type="filepath",
168
- sources=["upload", "microphone"]
169
- )
170
- gr.HTML("<p style='color: #666; font-size: 14px;'>📌 Upload clear speech from the voice you want to clone</p>")
171
-
172
- with gr.Row():
173
- with gr.Column(scale=1):
174
- # Voice-to-Voice Cloning
175
- gr.HTML("<h3 style='color: #8B5CF6;'>🎵 Voice-to-Voice Cloning</h3>")
176
-
177
- input_audio = gr.Audio(
178
- label="Input Audio to Transform",
179
- type="filepath",
180
- sources=["upload", "microphone"]
181
- )
182
-
183
- with gr.Row():
184
- voice_language = gr.Dropdown(
185
- choices=[
186
- ("🇺🇸 English", "en"),
187
- ("🇪🇸 Spanish", "es"),
188
- ("🇫🇷 French", "fr"),
189
- ("🇩🇪 German", "de"),
190
- ("🇮🇹 Italian", "it"),
191
- ("🇧🇷 Portuguese", "pt"),
192
- ("🇨🇳 Chinese", "zh"),
193
- ("🇯🇵 Japanese", "ja"),
194
- ("🇰🇷 Korean", "ko"),
195
- ("🇷🇺 Russian", "ru"),
196
- ("🇸🇦 Arabic", "ar"),
197
- ("🇮🇳 Hindi", "hi"),
198
- ("🇳🇱 Dutch", "nl"),
199
- ("🇵🇱 Polish", "pl"),
200
- ("🇹🇷 Turkish", "tr"),
201
- ("🇸🇪 Swedish", "sv"),
202
- ("🇫🇮 Finnish", "fi"),
203
- ("🇩🇰 Danish", "da"),
204
- ("🇳🇴 Norwegian", "no"),
205
- ("🇬🇷 Greek", "el"),
206
- ("🇮🇱 Hebrew", "he"),
207
- ("🇲🇾 Malay", "ms"),
208
- ("🇰🇪 Swahili", "sw")
209
- ],
210
- value="en",
211
- label="Language"
212
- )
213
-
214
- voice_exaggeration = gr.Slider(
215
- minimum=0.0,
216
- maximum=1.0,
217
- step=0.1,
218
- value=0.5,
219
- label="🎭 Emotion Exaggeration"
220
- )
221
-
222
- voice_cfg = gr.Slider(
223
- minimum=0.0,
224
- maximum=1.0,
225
- step=0.1,
226
- value=0.5,
227
- label="🎛️ CFG Scale"
228
- )
229
-
230
- voice_clone_btn = gr.Button(
231
- "🎤 Clone Voice with Chatterbox",
232
- variant="primary",
233
- size="lg"
234
- )
235
-
236
- with gr.Column(scale=1):
237
- # Text-to-Speech
238
- gr.HTML("<h3 style='color: #8B5CF6;'>📝 Text-to-Speech Cloning</h3>")
239
-
240
- text_input = gr.Textbox(
241
- label="Text to Convert to Speech",
242
- placeholder="Enter text to speak in the cloned voice...",
243
- lines=4,
244
- max_lines=8
245
- )
246
-
247
- with gr.Row():
248
- text_language = gr.Dropdown(
249
- choices=[
250
- ("🇺🇸 English", "en"),
251
- ("🇪🇸 Spanish", "es"),
252
- ("🇫🇷 French", "fr"),
253
- ("🇩🇪 German", "de"),
254
- ("🇮🇹 Italian", "it"),
255
- ("🇧🇷 Portuguese", "pt"),
256
- ("🇨🇳 Chinese", "zh"),
257
- ("🇯🇵 Japanese", "ja")
258
- ],
259
- value="en",
260
- label="Language"
261
- )
262
-
263
- text_exaggeration = gr.Slider(
264
- minimum=0.0,
265
- maximum=1.0,
266
- step=0.1,
267
- value=0.5,
268
- label="🎭 Emotion Exaggeration"
269
- )
270
-
271
- text_cfg = gr.Slider(
272
- minimum=0.0,
273
- maximum=1.0,
274
- step=0.1,
275
- value=0.5,
276
- label="🎛️ CFG Scale"
277
- )
278
-
279
- text_clone_btn = gr.Button(
280
- "📝 Generate Speech with Chatterbox",
281
- variant="secondary",
282
- size="lg"
283
- )
284
 
285
- # Output Section
286
- gr.HTML("<h3 style='color: #8B5CF6;'>🎵 Chatterbox Generated Audio</h3>")
287
- with gr.Row():
288
  audio_output = gr.Audio(
289
  label="Cloned Voice Result",
290
  type="filepath"
291
  )
 
292
  status_output = gr.Textbox(
293
- label="Processing Status",
294
- lines=5,
295
  interactive=False
296
  )
297
-
298
- # Chatterbox Features
299
- with gr.Accordion("🌟 Chatterbox Features", open=False):
300
- gr.Markdown("""
301
- ### Why Chatterbox is Special
302
-
303
- **🎭 Emotion Exaggeration Control**
304
- - First open source model with emotion control
305
- - Adjust from monotone (0.0) to highly expressive (1.0)
306
- - Perfect for creative content, games, and dramatic speech
307
-
308
- **🌍 Multilingual Support (23 Languages)**
309
- - Arabic, Chinese, Danish, Dutch, English, Finnish, French
310
- - German, Greek, Hebrew, Hindi, Italian, Japanese, Korean
311
- - Malay, Norwegian, Polish, Portuguese, Russian, Spanish
312
- - Swedish, Swahili, Turkish
313
-
314
- **⚡ Technical Advantages**
315
- - 0.5B parameter Llama backbone
316
- - Zero-shot voice cloning with 5+ seconds of audio
317
- - Built-in neural watermarking for responsible AI
318
- - MIT licensed - free for commercial use
319
- - Consistently outperforms ElevenLabs in evaluations
320
-
321
- **🎛️ Control Parameters**
322
- - **Exaggeration**: Controls emotional intensity (0.0 = monotone, 1.0 = very expressive)
323
- - **CFG Scale**: Controls adherence to reference voice (lower = more creative, higher = more accurate)
324
- """)
325
-
326
- # Event Handlers
327
- voice_clone_btn.click(
328
- fn=chatterbox_voice_clone,
329
- inputs=[reference_audio, input_audio, voice_language, voice_exaggeration, voice_cfg],
330
- outputs=[audio_output, status_output],
331
- show_progress=True
332
- )
333
-
334
- text_clone_btn.click(
335
- fn=chatterbox_text_to_speech,
336
- inputs=[reference_audio, text_input, text_language, text_exaggeration, text_cfg],
337
- outputs=[audio_output, status_output],
338
- show_progress=True
339
- )
340
 
341
- return demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
 
343
  if __name__ == "__main__":
344
- demo = create_chatterbox_interface()
345
  demo.launch(
346
  server_name="0.0.0.0",
347
  server_port=7860,
 
1
  import gradio as gr
2
  import torch
3
+ import torchaudio
4
  import tempfile
5
  import os
6
+ import logging
7
+ import traceback
8
 
9
+ # Setup logging
10
+ logging.basicConfig(level=logging.INFO)
11
+ logger = logging.getLogger(__name__)
12
 
13
+ # Device detection with proper fallback
14
+ DEVICE = "cpu"
15
+ if torch.cuda.is_available():
16
+ DEVICE = "cuda"
17
+ logger.info("🚀 Running on CUDA GPU")
18
+ elif torch.backends.mps.is_available():
19
+ DEVICE = "cpu" # Force CPU for MPS compatibility
20
+ logger.info("🍎 Apple Silicon detected - using CPU mode for Chatterbox-TTS compatibility")
21
+ else:
22
+ logger.info("🚀 Running on CPU")
 
 
 
 
 
23
 
24
+ print(f"🚀 Running on device: {DEVICE}")
25
+
26
+ # Patch torch.load to handle device mapping issues
27
+ original_torch_load = torch.load
28
+
29
+ def patched_torch_load(f, map_location=None, **kwargs):
30
+ """Patched torch.load that automatically maps CUDA tensors to CPU/MPS"""
31
+ if map_location is None:
32
+ map_location = 'cpu' # Default to CPU for compatibility
33
+ logger.info(f"🔧 Loading with map_location={map_location}")
34
+ return original_torch_load(f, map_location=map_location, **kwargs)
35
+
36
+ # Apply the patch
37
+ torch.load = patched_torch_load
38
+
39
+ # Global model variable
40
+ MODEL = None
41
+
42
+ def get_or_load_model():
43
+ """Loads the ChatterboxTTS model with proper error handling"""
44
+ global MODEL
45
+ if MODEL is None:
46
+ print("🔄 Model not loaded, initializing...")
47
  try:
48
+ # Try different import paths for chatterbox
49
+ try:
50
+ from chatterbox import ChatterboxTTS
51
+ MODEL = ChatterboxTTS.from_pretrained(device=DEVICE)
52
+ print("✅ Loaded with 'from chatterbox import ChatterboxTTS'")
53
+ except ImportError:
54
+ try:
55
+ from chatterbox.tts import ChatterboxTTS
56
+ MODEL = ChatterboxTTS.from_pretrained(device=DEVICE)
57
+ print("✅ Loaded with 'from chatterbox.tts import ChatterboxTTS'")
58
+ except ImportError:
59
+ try:
60
+ from chatterbox.src.chatterbox.tts import ChatterboxTTS
61
+ MODEL = ChatterboxTTS.from_pretrained(device=DEVICE)
62
+ print("✅ Loaded with 'from chatterbox.src.chatterbox.tts import ChatterboxTTS'")
63
+ except ImportError as e:
64
+ print(f"❌ All Chatterbox import paths failed: {e}")
65
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
+ # Ensure model is on correct device
68
+ if hasattr(MODEL, 'to') and str(getattr(MODEL, 'device', 'unknown')) != DEVICE:
69
+ MODEL = MODEL.to(DEVICE)
70
+
71
+ print(f"✅ Model loaded successfully on device: {getattr(MODEL, 'device', 'N/A')}")
72
+ return MODEL
73
+
74
+ except Exception as e:
75
+ print(f"❌ Error loading Chatterbox model: {e}")
76
+ print(f"🔍 Full traceback: {traceback.format_exc()}")
77
+ return None
78
+
79
+ return MODEL
80
 
81
+ def simple_voice_clone(reference_audio, input_text):
82
+ """Simplified voice cloning function with better error handling"""
 
 
83
  try:
84
  if not reference_audio:
85
  return None, "❌ Please upload reference audio!"
 
87
  if not input_text or not input_text.strip():
88
  return None, "❌ Please enter text to convert!"
89
 
90
+ # Try to load model
91
+ model = get_or_load_model()
92
+ if model is None:
93
+ return None, "❌ Chatterbox model failed to load! Check logs for details."
94
 
95
  print(f"🎤 Generating speech with Chatterbox...")
96
+ print(f"📝 Text: {input_text[:100]}...")
 
 
97
 
98
  # Create output file
99
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_file:
100
  output_path = tmp_file.name
101
 
102
+ # Generate speech using Chatterbox
103
+ try:
104
+ wav = model.generate(
 
 
 
 
 
 
 
 
 
105
  input_text,
106
  audio_prompt_path=reference_audio,
107
+ exaggeration=0.5,
108
+ cfg=0.5
 
109
  )
110
+
111
+ # Save generated audio
112
+ torchaudio.save(output_path, wav.cpu(), model.sr)
113
+
114
+ if os.path.exists(output_path) and os.path.getsize(output_path) > 0:
115
+ return output_path, f"✅ Chatterbox Voice Cloning Complete!\n📝 Generated: '{input_text[:100]}...'"
116
+ else:
117
+ return None, "❌ Generated audio file is empty!"
118
+
119
+ except Exception as gen_error:
120
+ print(f"❌ Generation error: {gen_error}")
121
+ return None, f"❌ Generation failed: {str(gen_error)}"
122
 
123
  except Exception as e:
124
+ print(f"❌ Voice cloning error: {e}")
125
+ return None, f"❌ Error: {str(e)}"
126
+
127
+ # Attempt to load model at startup with better error reporting
128
+ try:
129
+ startup_model = get_or_load_model()
130
+ if startup_model is not None:
131
+ models_loaded = True
132
+ startup_message = "✅ Chatterbox Models Loaded Successfully!"
133
+ else:
134
+ models_loaded = False
135
+ startup_message = "❌ Failed to Load Chatterbox Models - Check Dependencies"
136
+ except Exception as startup_error:
137
+ models_loaded = False
138
+ startup_message = f"❌ Startup Error: {str(startup_error)}"
139
+ print(f"CRITICAL: {startup_message}")
140
 
141
  # Create Gradio interface
142
+ with gr.Blocks(
143
+ title="🎭 Chatterbox Voice Cloning Studio",
144
+ theme=gr.themes.Soft(primary_hue="purple", secondary_hue="pink")
145
+ ) as demo:
146
+
147
+ # Header
148
+ gr.HTML("""
149
+ <div style="text-align: center; padding: 20px;">
150
+ <h1 style="color: #8B5CF6; margin-bottom: 10px;">🎭 Chatterbox Voice Cloning Studio</h1>
151
+ <p style="color: #666; font-size: 18px;">Powered by Resemble AI's Chatterbox Model</p>
152
+ <p style="color: #888; font-size: 14px;">Fixed version with proper device handling</p>
153
+ </div>
154
+ """)
155
+
156
+ # Model Status Display
157
+ status_color = "#d4edda" if models_loaded else "#f8d7da"
158
+ gr.HTML(f"""
159
+ <div style="text-align: center; padding: 15px; background: {status_color}; border-radius: 10px; margin-bottom: 20px;">
160
+ <strong>🤖 Chatterbox Status:</strong> {startup_message}
161
+ </div>
162
+ """)
163
+
164
+ with gr.Row():
165
+ with gr.Column():
166
+ # Reference Voice
167
+ gr.HTML("<h3 style='color: #8B5CF6;'>🎤 Reference Voice</h3>")
168
+ reference_audio = gr.Audio(
169
+ label="Upload Reference Audio (5+ seconds)",
170
+ type="filepath",
171
+ sources=["upload", "microphone"]
172
+ )
173
+
174
+ # Text Input
175
+ gr.HTML("<h3 style='color: #8B5CF6;'>📝 Text to Convert</h3>")
176
+ text_input = gr.Textbox(
177
+ label="Enter Text",
178
+ placeholder="Enter the text you want to speak in the cloned voice...",
179
+ lines=4,
180
+ max_lines=8
181
+ )
182
+
183
+ # Generate Button
184
+ generate_btn = gr.Button(
185
+ "🎤 Generate Voice Clone",
186
+ variant="primary",
187
+ size="lg"
188
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
 
190
+ with gr.Column():
191
+ # Output
192
+ gr.HTML("<h3 style='color: #8B5CF6;'>🎵 Generated Audio</h3>")
193
  audio_output = gr.Audio(
194
  label="Cloned Voice Result",
195
  type="filepath"
196
  )
197
+
198
  status_output = gr.Textbox(
199
+ label="Status & Logs",
200
+ lines=6,
201
  interactive=False
202
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
 
204
+ # Troubleshooting Info
205
+ with gr.Accordion("🔧 Troubleshooting", open=False):
206
+ gr.Markdown("""
207
+ ### Common Issues & Solutions
208
+
209
+ **❌ "Models Not Loaded" Error:**
210
+ - Check that `chatterbox-tts` is installed: `pip install chatterbox-tts`
211
+ - Verify internet connection for model download
212
+ - Try restarting the space if models fail to load
213
+
214
+ **🔧 Device Issues:**
215
+ - This version forces CPU mode for compatibility
216
+ - CUDA tensors are automatically mapped to CPU
217
+ - Apple Silicon (MPS) falls back to CPU mode
218
+
219
+ **📦 Dependencies:**
220
+ - Ensure all requirements are installed correctly
221
+ - Check logs for specific import errors
222
+ - Model downloads may take several minutes on first run
223
+
224
+ **🎤 Audio Issues:**
225
+ - Use clear, high-quality reference audio (5+ seconds)
226
+ - Supported formats: WAV, MP3, FLAC, M4A
227
+ - Avoid background noise in reference audio
228
+ """)
229
+
230
+ # Event handler
231
+ generate_btn.click(
232
+ fn=simple_voice_clone,
233
+ inputs=[reference_audio, text_input],
234
+ outputs=[audio_output, status_output],
235
+ show_progress=True
236
+ )
237
 
238
  if __name__ == "__main__":
 
239
  demo.launch(
240
  server_name="0.0.0.0",
241
  server_port=7860,