DevNumb commited on
Commit
d94ebbf
·
verified ·
1 Parent(s): 9de60e0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +194 -66
app.py CHANGED
@@ -7,13 +7,16 @@ import warnings
7
  import scipy.io.wavfile
8
  warnings.filterwarnings("ignore")
9
 
10
- # Inline CSS for Gradio 3.x
11
  css = """
12
  <style>
13
  .gradio-container {
14
  max-width: 1200px !important;
15
  margin: 0 auto !important;
16
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 
 
 
17
  }
18
 
19
  .header {
@@ -108,11 +111,12 @@ css = """
108
  left: 100%;
109
  }
110
 
 
111
  textarea {
112
- background: rgba(255, 255, 255, 0.05) !important;
113
- border: 2px solid rgba(255, 255, 255, 0.1) !important;
114
  border-radius: 15px !important;
115
- color: white !important;
116
  padding: 1rem !important;
117
  font-size: 1.1em !important;
118
  transition: all 0.3s ease !important;
@@ -120,8 +124,14 @@ textarea {
120
 
121
  textarea:focus {
122
  border-color: #667eea !important;
123
- box-shadow: 0 0 20px rgba(102, 126, 234, 0.3) !important;
124
- background: rgba(255, 255, 255, 0.08) !important;
 
 
 
 
 
 
125
  }
126
 
127
  .stats-card {
@@ -162,6 +172,7 @@ textarea:focus {
162
  border-radius: 10px !important;
163
  margin: 0 0.25rem !important;
164
  transition: all 0.3s ease !important;
 
165
  }
166
 
167
  .tab-nav button.selected {
@@ -207,38 +218,71 @@ input[type="range"]::-webkit-slider-thumb {
207
  transform: translateY(-2px) !important;
208
  }
209
 
210
- #component-0 {
211
- min-height: 100vh;
212
- background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
213
- padding: 2rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  }
215
  </style>
216
  """
217
 
218
  # Global variable for model
219
  _tts_model = None
 
220
 
221
  def load_model():
222
- """Load the TTS model once"""
223
- global _tts_model
224
 
225
  if _tts_model is None:
226
  print("🚀 Loading VibeVoice model...")
227
  try:
228
- # Try using pipeline first
229
- from transformers import pipeline
230
- _tts_model = pipeline(
231
- "text-to-speech",
232
- model="microsoft/VibeVoice-Realtime-0.5B",
233
- device=0 if torch.cuda.is_available() else -1
 
234
  )
235
- print("✅ Model loaded successfully using pipeline!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  except Exception as e:
237
- print(f"⚠️ Pipeline loading failed: {e}")
238
  print("⚠️ Falling back to simple tone generation")
239
  _tts_model = "simple"
240
 
241
- return _tts_model
242
 
243
  # Stats tracking
244
  class TTSStats:
@@ -280,26 +324,50 @@ def generate_simple_tone(text, sampling_rate=16000):
280
  return audio, sampling_rate
281
 
282
  def generate_speech(text, speed=1.0, emotion="neutral"):
283
- """Generate speech from text"""
284
  try:
285
  if not text or text.strip() == "":
286
  return None, "Please enter some text to convert to speech."
287
 
288
- if len(text) > 1000:
289
- text = text[:1000]
 
 
 
290
 
291
  stats.add_generation(text)
292
- model = load_model()
293
 
294
  if model == "simple":
295
  audio, sampling_rate = generate_simple_tone(text)
296
- message = f"⚠️ Using simple tone generation (model not available)"
297
  else:
298
- print(f"Generating speech for: {text[:50]}...")
299
- result = model(text)
300
- audio = result["audio"]
301
- sampling_rate = result["sampling_rate"]
 
 
 
 
 
 
 
 
302
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
  emotion_icons = {
304
  "neutral": "😐",
305
  "happy": "😊",
@@ -308,7 +376,9 @@ def generate_speech(text, speed=1.0, emotion="neutral"):
308
  "professional": "💼"
309
  }
310
  icon = emotion_icons.get(emotion, "🎵")
311
- message = f"{icon} Generated {len(text)} characters with {emotion} tone"
 
 
312
 
313
  # Normalize audio
314
  max_val = np.max(np.abs(audio))
@@ -329,16 +399,18 @@ def generate_speech(text, speed=1.0, emotion="neutral"):
329
  <div style='background: rgba(102, 126, 234, 0.1); padding: 1rem; border-radius: 10px; border-left: 4px solid #667eea; margin: 1rem 0;'>
330
  <div style='color: #667eea; font-weight: 600; margin-bottom: 0.5rem;'>✅ {message}</div>
331
  <div style='color: rgba(255,255,255,0.8);'>
332
- Length: <strong>{len(audio)/sampling_rate:.1f}s</strong> |
333
- Speed: <strong>{speed}x</strong>
 
334
  </div>
335
  </div>
336
  """
337
  return tmp_file.name, success_message
338
 
339
  except Exception as e:
340
- print(f"Error generating speech: {e}")
341
  try:
 
342
  silent_audio = np.zeros(16000, dtype=np.float32)
343
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_file:
344
  scipy.io.wavfile.write(tmp_file.name, 16000, silent_audio)
@@ -370,7 +442,7 @@ def update_stats_display():
370
  </div>
371
  """
372
 
373
- # Create the interface with proper Gradio 3.x syntax
374
  with gr.Blocks() as demo:
375
  # Add CSS as HTML
376
  gr.HTML(css)
@@ -379,17 +451,17 @@ with gr.Blocks() as demo:
379
  with gr.Column():
380
  gr.HTML("""
381
  <div class="header">
382
- <h1>🎵 VibeVoice TTS</h1>
383
- <p>Transform Text into Natural Speech</p>
384
  <div style="display: flex; justify-content: center; gap: 0.5rem; margin-top: 1rem; flex-wrap: wrap;">
385
  <span style="background: rgba(255,255,255,0.2); padding: 0.5rem 1rem; border-radius: 20px; font-size: 0.9em;">
386
- 🤖 AI Powered
387
  </span>
388
  <span style="background: rgba(255,255,255,0.2); padding: 0.5rem 1rem; border-radius: 20px; font-size: 0.9em;">
389
- ⚡ Real-time
390
  </span>
391
  <span style="background: rgba(255,255,255,0.2); padding: 0.5rem 1rem; border-radius: 20px; font-size: 0.9em;">
392
- 🎭 Emotional Voices
393
  </span>
394
  </div>
395
  </div>
@@ -404,7 +476,7 @@ with gr.Blocks() as demo:
404
 
405
  text_input = gr.Textbox(
406
  label="",
407
- placeholder="Enter your text here... (Max 1000 characters)",
408
  lines=6
409
  )
410
 
@@ -413,7 +485,8 @@ with gr.Blocks() as demo:
413
  emotion = gr.Dropdown(
414
  label="Voice Emotion",
415
  choices=["neutral", "happy", "excited", "calm", "professional"],
416
- value="neutral"
 
417
  )
418
 
419
  speed = gr.Slider(
@@ -426,7 +499,7 @@ with gr.Blocks() as demo:
426
 
427
  # Action Buttons
428
  with gr.Row():
429
- generate_btn = gr.Button("✨ Generate Speech", variant="primary")
430
  clear_btn = gr.Button("Clear", variant="secondary")
431
 
432
  # Quick Actions
@@ -461,61 +534,105 @@ with gr.Blocks() as demo:
461
  with gr.TabItem("💡 Examples"):
462
  gr.Examples(
463
  examples=[
464
- ["Hello, welcome to VibeVoice text-to-speech!"],
465
- ["This is a demonstration of AI speech synthesis."],
466
- ["The weather is beautiful today."],
467
- ["Artificial intelligence is amazing technology."],
468
- ["Please enjoy this text to speech demonstration."]
469
  ],
470
  inputs=text_input,
471
- label="Click any example to try it"
472
  )
473
 
474
- with gr.TabItem("ℹ️ About"):
475
  gr.Markdown("""
476
- ## About VibeVoice TTS
477
 
478
- This application converts text into speech using AI technology.
479
 
480
  ### Features:
481
- - **AI-Powered**: Uses advanced machine learning models
482
- - **Multiple Emotions**: Choose different voice tones
483
- - **Adjustable Speed**: Control speaking rate
484
- - **Real-time**: Fast generation
 
 
 
 
 
 
485
 
486
- ### Tips:
487
- - Keep text under 500 characters for best results
488
- - Try different emotions for varied expressions
489
- - Adjust speed to match your preference
 
490
 
491
- ⚠️ **Note**: If the model fails to load, a simple tone generator will be used as fallback.
492
  """)
493
  gr.HTML('</div>')
494
 
495
  # Footer
496
  gr.HTML("""
497
- <div style="text-align: center; margin-top: 2rem; padding: 1rem; background: rgba(255,255,255,0.05); border-radius: 15px;">
 
 
 
 
 
498
  <p style="color: rgba(255,255,255,0.5); font-size: 0.9em;">
499
- Made with ❤️ using Gradio & Transformers
 
500
  </p>
501
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
  """)
503
 
504
  # Event Handlers
505
  def process_generation(text, emotion_val, speed_val):
 
506
  if not text or text.strip() == "":
507
  return None, "⚠️ Please enter some text first!", update_stats_display()
508
 
 
 
 
 
 
 
 
 
509
  audio_path, status_msg = generate_speech(text, speed_val, emotion_val)
510
  stats_html = update_stats_display()
511
 
512
  return audio_path, status_msg, stats_html
513
 
514
  def clear_all():
515
- return "", None, "Cleared. Ready for new input.", update_stats_display()
 
 
 
 
 
516
 
517
  def test_voice():
518
- return "Hello! This is a test of the VibeVoice text-to-speech system."
 
519
 
520
  # Connect buttons
521
  generate_btn.click(
@@ -547,11 +664,22 @@ with gr.Blocks() as demo:
547
  inputs=[],
548
  outputs=[stats_display]
549
  )
 
 
 
 
 
 
 
550
 
551
  # Launch the app
552
  if __name__ == "__main__":
 
 
 
553
  demo.launch(
554
  debug=True,
555
  share=False,
556
- server_name="0.0.0.0"
 
557
  )
 
7
  import scipy.io.wavfile
8
  warnings.filterwarnings("ignore")
9
 
10
+ # Inline CSS with black text input
11
  css = """
12
  <style>
13
  .gradio-container {
14
  max-width: 1200px !important;
15
  margin: 0 auto !important;
16
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
17
+ background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
18
+ min-height: 100vh;
19
+ padding: 2rem;
20
  }
21
 
22
  .header {
 
111
  left: 100%;
112
  }
113
 
114
+ /* BLACK TEXT INPUT */
115
  textarea {
116
+ background: rgba(255, 255, 255, 0.95) !important;
117
+ border: 2px solid rgba(102, 126, 234, 0.3) !important;
118
  border-radius: 15px !important;
119
+ color: #1e293b !important; /* Dark text color */
120
  padding: 1rem !important;
121
  font-size: 1.1em !important;
122
  transition: all 0.3s ease !important;
 
124
 
125
  textarea:focus {
126
  border-color: #667eea !important;
127
+ box-shadow: 0 0 20px rgba(102, 126, 234, 0.5) !important;
128
+ background: white !important;
129
+ color: #1e293b !important;
130
+ }
131
+
132
+ textarea::placeholder {
133
+ color: #666 !important;
134
+ opacity: 0.8 !important;
135
  }
136
 
137
  .stats-card {
 
172
  border-radius: 10px !important;
173
  margin: 0 0.25rem !important;
174
  transition: all 0.3s ease !important;
175
+ color: rgba(255, 255, 255, 0.7) !important;
176
  }
177
 
178
  .tab-nav button.selected {
 
218
  transform: translateY(-2px) !important;
219
  }
220
 
221
+ .dropdown {
222
+ background: rgba(255, 255, 255, 0.1) !important;
223
+ color: white !important;
224
+ border-radius: 10px !important;
225
+ }
226
+
227
+ .dropdown option {
228
+ background: #1e293b !important;
229
+ color: white !important;
230
+ }
231
+
232
+ .markdown {
233
+ color: rgba(255, 255, 255, 0.9) !important;
234
+ }
235
+
236
+ .markdown h1, .markdown h2, .markdown h3 {
237
+ color: white !important;
238
  }
239
  </style>
240
  """
241
 
242
  # Global variable for model
243
  _tts_model = None
244
+ _tts_processor = None
245
 
246
  def load_model():
247
+ """Load the VibeVoice model directly"""
248
+ global _tts_model, _tts_processor
249
 
250
  if _tts_model is None:
251
  print("🚀 Loading VibeVoice model...")
252
  try:
253
+ # Try direct import first
254
+ from transformers import VibeVoiceStreamingForConditionalGenerationInference, AutoProcessor
255
+
256
+ _tts_model = VibeVoiceStreamingForConditionalGenerationInference.from_pretrained(
257
+ "microsoft/VibeVoice-Realtime-0.5B",
258
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
259
+ device_map="auto"
260
  )
261
+ _tts_processor = AutoProcessor.from_pretrained("microsoft/VibeVoice-Realtime-0.5B")
262
+ print("✅ VibeVoice model loaded successfully!")
263
+ except ImportError as e:
264
+ print(f"❌ Import error: {e}")
265
+ print("⚠️ Trying alternative import...")
266
+ try:
267
+ # Alternative import
268
+ from transformers import AutoModelForTextToSpeech, AutoProcessor
269
+ _tts_model = AutoModelForTextToSpeech.from_pretrained(
270
+ "microsoft/VibeVoice-Realtime-0.5B",
271
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
272
+ device_map="auto"
273
+ )
274
+ _tts_processor = AutoProcessor.from_pretrained("microsoft/VibeVoice-Realtime-0.5B")
275
+ print("✅ Model loaded with AutoModelForTextToSpeech!")
276
+ except Exception as e2:
277
+ print(f"❌ All imports failed: {e2}")
278
+ print("⚠️ Falling back to simple tone generation")
279
+ _tts_model = "simple"
280
  except Exception as e:
281
+ print(f" Model loading error: {e}")
282
  print("⚠️ Falling back to simple tone generation")
283
  _tts_model = "simple"
284
 
285
+ return _tts_model, _tts_processor
286
 
287
  # Stats tracking
288
  class TTSStats:
 
324
  return audio, sampling_rate
325
 
326
  def generate_speech(text, speed=1.0, emotion="neutral"):
327
+ """Generate speech from text using VibeVoice model"""
328
  try:
329
  if not text or text.strip() == "":
330
  return None, "Please enter some text to convert to speech."
331
 
332
+ if len(text) > 500:
333
+ text = text[:500]
334
+ message_note = f"⚠️ Text truncated to 500 characters"
335
+ else:
336
+ message_note = ""
337
 
338
  stats.add_generation(text)
339
+ model, processor = load_model()
340
 
341
  if model == "simple":
342
  audio, sampling_rate = generate_simple_tone(text)
343
+ message = f"⚠️ Using simple tone generation (VibeVoice model not available)"
344
  else:
345
+ print(f"🔊 Generating speech for: {text[:50]}...")
346
+
347
+ # Prepare inputs
348
+ inputs = processor(
349
+ text=text,
350
+ return_tensors="pt",
351
+ sampling_rate=16000,
352
+ )
353
+
354
+ # Move to device
355
+ device = next(model.parameters()).device
356
+ inputs = {k: v.to(device) for k, v in inputs.items()}
357
 
358
+ # Generate audio
359
+ with torch.no_grad():
360
+ audio_tensor = model.generate(
361
+ **inputs,
362
+ temperature=0.7,
363
+ do_sample=True,
364
+ )
365
+
366
+ # Convert to numpy
367
+ audio = audio_tensor.cpu().numpy().squeeze()
368
+ sampling_rate = 16000
369
+
370
+ # Format success message
371
  emotion_icons = {
372
  "neutral": "😐",
373
  "happy": "😊",
 
376
  "professional": "💼"
377
  }
378
  icon = emotion_icons.get(emotion, "🎵")
379
+ message = f"{icon} VibeVoice generated {len(text)} characters"
380
+ if message_note:
381
+ message += f"<br>{message_note}"
382
 
383
  # Normalize audio
384
  max_val = np.max(np.abs(audio))
 
399
  <div style='background: rgba(102, 126, 234, 0.1); padding: 1rem; border-radius: 10px; border-left: 4px solid #667eea; margin: 1rem 0;'>
400
  <div style='color: #667eea; font-weight: 600; margin-bottom: 0.5rem;'>✅ {message}</div>
401
  <div style='color: rgba(255,255,255,0.8);'>
402
+ Audio length: <strong>{len(audio)/sampling_rate:.2f}s</strong> |
403
+ Speed: <strong>{speed}x</strong> |
404
+ Emotion: <strong>{emotion}</strong>
405
  </div>
406
  </div>
407
  """
408
  return tmp_file.name, success_message
409
 
410
  except Exception as e:
411
+ print(f"Error generating speech: {e}")
412
  try:
413
+ # Create a fallback audio file
414
  silent_audio = np.zeros(16000, dtype=np.float32)
415
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_file:
416
  scipy.io.wavfile.write(tmp_file.name, 16000, silent_audio)
 
442
  </div>
443
  """
444
 
445
+ # Create the interface
446
  with gr.Blocks() as demo:
447
  # Add CSS as HTML
448
  gr.HTML(css)
 
451
  with gr.Column():
452
  gr.HTML("""
453
  <div class="header">
454
+ <h1>🎵 VibeVoice TTS Pro</h1>
455
+ <p>Transform Text into Natural Speech with Microsoft VibeVoice</p>
456
  <div style="display: flex; justify-content: center; gap: 0.5rem; margin-top: 1rem; flex-wrap: wrap;">
457
  <span style="background: rgba(255,255,255,0.2); padding: 0.5rem 1rem; border-radius: 20px; font-size: 0.9em;">
458
+ 🎵 Microsoft VibeVoice
459
  </span>
460
  <span style="background: rgba(255,255,255,0.2); padding: 0.5rem 1rem; border-radius: 20px; font-size: 0.9em;">
461
+ ⚡ Real-time Generation
462
  </span>
463
  <span style="background: rgba(255,255,255,0.2); padding: 0.5rem 1rem; border-radius: 20px; font-size: 0.9em;">
464
+ 🎭 Emotional Control
465
  </span>
466
  </div>
467
  </div>
 
476
 
477
  text_input = gr.Textbox(
478
  label="",
479
+ placeholder="Type your text here... (Max 500 characters for best results)",
480
  lines=6
481
  )
482
 
 
485
  emotion = gr.Dropdown(
486
  label="Voice Emotion",
487
  choices=["neutral", "happy", "excited", "calm", "professional"],
488
+ value="neutral",
489
+ elem_id="emotion-select"
490
  )
491
 
492
  speed = gr.Slider(
 
499
 
500
  # Action Buttons
501
  with gr.Row():
502
+ generate_btn = gr.Button("✨ Generate Speech", variant="primary", elem_id="generate-btn")
503
  clear_btn = gr.Button("Clear", variant="secondary")
504
 
505
  # Quick Actions
 
534
  with gr.TabItem("💡 Examples"):
535
  gr.Examples(
536
  examples=[
537
+ ["Hello! Welcome to VibeVoice text-to-speech demonstration."],
538
+ ["The quick brown fox jumps over the lazy dog."],
539
+ ["Artificial intelligence is transforming our world in amazing ways."],
540
+ ["This is a test of the text to speech generation system."],
541
+ ["Would you like a cup of coffee or tea this morning?"]
542
  ],
543
  inputs=text_input,
544
+ label="Click any example to load it"
545
  )
546
 
547
+ with gr.TabItem("ℹ️ About & Settings"):
548
  gr.Markdown("""
549
+ ## 🎵 VibeVoice TTS Pro
550
 
551
+ Powered by **Microsoft VibeVoice-Realtime-0.5B**, a state-of-the-art text-to-speech model.
552
 
553
  ### Features:
554
+ - **High-Quality Speech**: Professional-grade voice synthesis
555
+ - **Real-time Processing**: Fast generation with GPU acceleration
556
+ - **Emotional Control**: Multiple voice emotions to choose from
557
+ - **Speed Adjustment**: Control speaking rate from 0.5x to 2.0x
558
+
559
+ ### Tips for Best Results:
560
+ 1. Keep text under **500 characters** for optimal performance
561
+ 2. Try different emotions for varied expressions
562
+ 3. Adjust speed to match your preference
563
+ 4. Use clear, well-punctuated text
564
 
565
+ ### Model Information:
566
+ - **Model**: VibeVoice-Realtime-0.5B
567
+ - **Parameters**: 0.5 Billion
568
+ - **Audio Quality**: 16kHz sampling rate
569
+ - **Language**: English (optimized)
570
 
571
+ ⚠️ **Note**: First generation may take longer as the model loads.
572
  """)
573
  gr.HTML('</div>')
574
 
575
  # Footer
576
  gr.HTML("""
577
+ <div style="text-align: center; margin-top: 2rem; padding: 1.5rem; background: rgba(255,255,255,0.05); border-radius: 15px;">
578
+ <div style="display: flex; justify-content: center; gap: 2rem; margin-bottom: 1rem; flex-wrap: wrap;">
579
+ <span style="color: rgba(255,255,255,0.7);">🤖 Microsoft VibeVoice Model</span>
580
+ <span style="color: rgba(255,255,255,0.7);">⚡ Real-time Processing</span>
581
+ <span style="color: rgba(255,255,255,0.7);">✨ Beautiful Interface</span>
582
+ </div>
583
  <p style="color: rgba(255,255,255,0.5); font-size: 0.9em;">
584
+ Made with ❤️ using Transformers & Gradio |
585
+ <span id="live-time" style="color: #667eea; font-weight: 600;"></span>
586
  </p>
587
  </div>
588
+ <script>
589
+ function updateTime() {
590
+ const now = new Date();
591
+ const timeString = now.toLocaleTimeString();
592
+ document.getElementById('live-time').textContent = timeString;
593
+ }
594
+ setInterval(updateTime, 1000);
595
+ updateTime();
596
+
597
+ // Add keyboard shortcut
598
+ document.addEventListener('keydown', function(e) {
599
+ if (e.ctrlKey && e.key === 'Enter') {
600
+ document.getElementById('generate-btn').click();
601
+ }
602
+ });
603
+ </script>
604
  """)
605
 
606
  # Event Handlers
607
  def process_generation(text, emotion_val, speed_val):
608
+ """Handle speech generation"""
609
  if not text or text.strip() == "":
610
  return None, "⚠️ Please enter some text first!", update_stats_display()
611
 
612
+ # Show processing message
613
+ processing_msg = """
614
+ <div style='background: rgba(102, 126, 234, 0.1); padding: 1rem; border-radius: 10px; border-left: 4px solid #667eea; margin: 1rem 0;'>
615
+ <div style='color: #667eea; font-weight: 600; margin-bottom: 0.5rem;'>⏳ Generating speech...</div>
616
+ <div style='color: rgba(255,255,255,0.8);'>Please wait while the model processes your text.</div>
617
+ </div>
618
+ """
619
+
620
  audio_path, status_msg = generate_speech(text, speed_val, emotion_val)
621
  stats_html = update_stats_display()
622
 
623
  return audio_path, status_msg, stats_html
624
 
625
  def clear_all():
626
+ """Clear all inputs"""
627
+ return "", None, """
628
+ <div style='text-align: center; color: rgba(255,255,255,0.7);'>
629
+ Cleared. Ready for new input.
630
+ </div>
631
+ """, update_stats_display()
632
 
633
  def test_voice():
634
+ """Load test text"""
635
+ return "Hello! This is a demonstration of the VibeVoice text-to-speech system. The voice sounds natural and clear."
636
 
637
  # Connect buttons
638
  generate_btn.click(
 
664
  inputs=[],
665
  outputs=[stats_display]
666
  )
667
+
668
+ # Initialize
669
+ demo.load(
670
+ fn=update_stats_display,
671
+ inputs=[],
672
+ outputs=[stats_display]
673
+ )
674
 
675
  # Launch the app
676
  if __name__ == "__main__":
677
+ # Load model at startup
678
+ load_model()
679
+
680
  demo.launch(
681
  debug=True,
682
  share=False,
683
+ server_name="0.0.0.0",
684
+ server_port=7860
685
  )