mgbam commited on
Commit
d07300c
Β·
verified Β·
1 Parent(s): 527a68e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +210 -16
app.py CHANGED
@@ -14,8 +14,9 @@ from dotenv import load_dotenv
14
  # Load environment variables
15
  load_dotenv()
16
 
17
- # Initialize OpenAI API key
18
  openai.api_key = os.getenv("OPENAI_API_KEY")
 
19
 
20
  # =============================
21
  # ENHANCED AGENT IMPLEMENTATION
@@ -292,12 +293,69 @@ class DesignAgent:
292
  st.error(f"Design generation error: {str(e)}")
293
  return None
294
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  # Initialize agents
296
  topic_agent = TopicAgent()
297
  content_agent = ContentAgent()
298
  slide_agent = SlideAgent()
299
  code_agent = CodeAgent()
300
  design_agent = DesignAgent()
 
301
 
302
  # =====================
303
  # STREAMLIT APPLICATION
@@ -337,6 +395,35 @@ st.markdown("""
337
  border-radius: 10px;
338
  padding: 15px;
339
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  </style>
341
  """, unsafe_allow_html=True)
342
 
@@ -346,33 +433,108 @@ with col1:
346
  st.image("https://cdn-icons-png.flaticon.com/512/1995/1995485.png", width=100)
347
  with col2:
348
  st.title("πŸ€– Workshop in a Box Pro")
349
- st.caption("Generate Premium Corporate AI Training Workshops in Minutes")
 
 
 
 
 
 
 
 
 
 
 
 
350
 
351
  # Sidebar configuration
352
  with st.sidebar:
353
  st.header("βš™οΈ Workshop Configuration")
354
- workshop_topic = st.text_input("Workshop Topic", "Advanced Prompt Engineering")
 
 
 
 
 
 
 
 
 
 
 
 
 
355
  duration = st.slider("Duration (hours)", 1.0, 8.0, 3.0, 0.5)
356
  difficulty = st.selectbox("Difficulty Level",
357
  ["Beginner", "Intermediate", "Advanced", "Expert"])
358
  include_code = st.checkbox("Include Code Labs", True)
359
  include_design = st.checkbox("Generate Visual Designs", True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
 
361
  if st.button("✨ Generate Workshop", type="primary", use_container_width=True):
362
  st.session_state.generating = True
 
363
 
364
  # Generation pipeline
365
- if hasattr(st.session_state, 'generating'):
366
- with st.spinner("πŸš€ Creating your premium workshop materials..."):
367
  start_time = time.time()
368
 
369
  # Agent pipeline
370
- outline = topic_agent.generate_outline(workshop_topic, duration, difficulty)
371
  content = content_agent.generate_content(outline)
372
  slides = slide_agent.generate_slides(content)
373
  code_labs = code_agent.generate_code(content) if include_code else None
374
  design_url = design_agent.generate_design(slides) if include_design else None
375
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
  # Prepare download package
377
  zip_buffer = io.BytesIO()
378
  with zipfile.ZipFile(zip_buffer, "a") as zip_file:
@@ -387,6 +549,9 @@ if hasattr(st.session_state, 'generating'):
387
  zip_file.writestr("slide_design.png", img_data)
388
  except:
389
  pass
 
 
 
390
 
391
  # Store results
392
  st.session_state.outline = outline
@@ -394,20 +559,21 @@ if hasattr(st.session_state, 'generating'):
394
  st.session_state.slides = slides
395
  st.session_state.code_labs = code_labs
396
  st.session_state.design_url = design_url
 
397
  st.session_state.zip_buffer = zip_buffer
398
  st.session_state.gen_time = round(time.time() - start_time, 2)
399
  st.session_state.generated = True
400
  st.session_state.generating = False
401
 
402
  # Results display
403
- if hasattr(st.session_state, 'generated'):
404
- st.success(f"βœ… Premium workshop materials generated in {st.session_state.gen_time} seconds!")
405
 
406
  # Download button
407
  st.download_button(
408
  label="πŸ“₯ Download Workshop Package",
409
  data=st.session_state.zip_buffer.getvalue(),
410
- file_name=f"{workshop_topic.replace(' ', '_')}_workshop.zip",
411
  mime="application/zip",
412
  use_container_width=True
413
  )
@@ -429,15 +595,35 @@ if hasattr(st.session_state, 'generated'):
429
  if st.session_state.design_url:
430
  with st.expander("🎨 Generated Design"):
431
  st.image(st.session_state.design_url, caption="Custom Slide Design")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
432
 
433
  # Sales and booking section
434
  st.divider()
435
  st.subheader("πŸš€ Ready to Deliver This Workshop?")
436
- st.markdown("""
437
- ### Premium Corporate Training Package
438
  - **Live Workshop Delivery**: $10,000 per session
439
  - **On-Demand Course**: $5,000 (unlimited access)
440
  - **Pilot Program**: $1,000 refundable deposit
 
441
 
442
  ✨ **All inclusive**: Customization, materials, and follow-up support
443
  """)
@@ -458,12 +644,20 @@ with st.sidebar:
458
  else:
459
  st.warning("OpenAI API not set - using enhanced mock data")
460
 
461
- st.info("""
 
 
 
 
 
 
 
 
462
  **Premium Features:**
463
- - AI-generated slide designs
 
464
  - Real-world case studies
465
  - Practical code labs
466
- - Professional templates
467
  """)
468
 
469
  # How it works section
@@ -471,10 +665,10 @@ st.divider()
471
  st.subheader("πŸ’‘ How It Works")
472
  st.markdown("""
473
  1. **Configure** your workshop topic and parameters
474
- 2. **Generate** premium training materials in seconds
475
  3. **Customize** the content to your specific needs
476
  4. **Deliver** high-value corporate training at $10K/session
477
  5. **Reuse** the materials for unlimited revenue
478
 
479
- *"Created 3 workshops in 15 minutes and booked $30K in contracts"* - Sarah T., AI Training Consultant
480
  """)
 
14
  # Load environment variables
15
  load_dotenv()
16
 
17
+ # Initialize API keys
18
  openai.api_key = os.getenv("OPENAI_API_KEY")
19
+ ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
20
 
21
  # =============================
22
  # ENHANCED AGENT IMPLEMENTATION
 
293
  st.error(f"Design generation error: {str(e)}")
294
  return None
295
 
296
+ class VoiceoverAgent:
297
+ def __init__(self):
298
+ self.api_key = ELEVENLABS_API_KEY
299
+ self.voice_id = "21m00Tcm4TlvDq8ikWAM" # Default voice ID (Bella)
300
+ self.model = "eleven_monolingual_v1"
301
+
302
+ def generate_voiceover(self, text, voice_id=None):
303
+ if not self.api_key:
304
+ return None
305
+
306
+ try:
307
+ # Use custom voice if provided, otherwise use default
308
+ voice = voice_id if voice_id else self.voice_id
309
+
310
+ url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice}"
311
+ headers = {
312
+ "Accept": "audio/mpeg",
313
+ "Content-Type": "application/json",
314
+ "xi-api-key": self.api_key
315
+ }
316
+ data = {
317
+ "text": text,
318
+ "model_id": self.model,
319
+ "voice_settings": {
320
+ "stability": 0.7,
321
+ "similarity_boost": 0.8,
322
+ "style": 0.5,
323
+ "use_speaker_boost": True
324
+ }
325
+ }
326
+ response = requests.post(url, json=data, headers=headers)
327
+
328
+ if response.status_code == 200:
329
+ return response.content
330
+ else:
331
+ st.error(f"Voiceover API error: {response.status_code} - {response.text}")
332
+ return None
333
+ except Exception as e:
334
+ st.error(f"Voiceover generation error: {str(e)}")
335
+ return None
336
+
337
+ def get_voices(self):
338
+ if not self.api_key:
339
+ return []
340
+
341
+ try:
342
+ url = "https://api.elevenlabs.io/v1/voices"
343
+ headers = {"xi-api-key": self.api_key}
344
+ response = requests.get(url, headers=headers)
345
+
346
+ if response.status_code == 200:
347
+ return response.json().get("voices", [])
348
+ return []
349
+ except:
350
+ return []
351
+
352
  # Initialize agents
353
  topic_agent = TopicAgent()
354
  content_agent = ContentAgent()
355
  slide_agent = SlideAgent()
356
  code_agent = CodeAgent()
357
  design_agent = DesignAgent()
358
+ voiceover_agent = VoiceoverAgent()
359
 
360
  # =====================
361
  # STREAMLIT APPLICATION
 
395
  border-radius: 10px;
396
  padding: 15px;
397
  }
398
+ .audio-player {
399
+ margin: 15px 0;
400
+ border-radius: 10px;
401
+ background: rgba(255,255,255,0.1);
402
+ padding: 15px;
403
+ }
404
+ .voice-option {
405
+ display: flex;
406
+ align-items: center;
407
+ margin: 5px 0;
408
+ padding: 8px;
409
+ border-radius: 8px;
410
+ cursor: pointer;
411
+ transition: background 0.3s;
412
+ }
413
+ .voice-option:hover {
414
+ background: rgba(255,255,255,0.2);
415
+ }
416
+ .voice-option.selected {
417
+ background: rgba(0,180,155,0.3);
418
+ border: 2px solid #00b09b;
419
+ }
420
+ .voice-thumb {
421
+ width: 40px;
422
+ height: 40px;
423
+ border-radius: 50%;
424
+ margin-right: 10px;
425
+ object-fit: cover;
426
+ }
427
  </style>
428
  """, unsafe_allow_html=True)
429
 
 
433
  st.image("https://cdn-icons-png.flaticon.com/512/1995/1995485.png", width=100)
434
  with col2:
435
  st.title("πŸ€– Workshop in a Box Pro")
436
+ st.caption("Generate Premium Corporate AI Training Workshops with Voiceovers")
437
+
438
+ # Initialize session state
439
+ if 'workshop_topic' not in st.session_state:
440
+ st.session_state.workshop_topic = "Advanced Prompt Engineering"
441
+ if 'generated' not in st.session_state:
442
+ st.session_state.generated = False
443
+ if 'generating' not in st.session_state:
444
+ st.session_state.generating = False
445
+ if 'voiceovers' not in st.session_state:
446
+ st.session_state.voiceovers = {}
447
+ if 'selected_voice' not in st.session_state:
448
+ st.session_state.selected_voice = "21m00Tcm4TlvDq8ikWAM" # Default voice ID
449
 
450
  # Sidebar configuration
451
  with st.sidebar:
452
  st.header("βš™οΈ Workshop Configuration")
453
+
454
+ # Workshop topic input with session state
455
+ st.session_state.workshop_topic = st.text_input(
456
+ "Workshop Topic",
457
+ st.session_state.workshop_topic,
458
+ key="topic_input",
459
+ help="Enter the main topic for your workshop"
460
+ )
461
+
462
+ # Validate topic input
463
+ if st.session_state.workshop_topic.strip() == "":
464
+ st.warning("Please enter a workshop topic")
465
+ st.stop()
466
+
467
  duration = st.slider("Duration (hours)", 1.0, 8.0, 3.0, 0.5)
468
  difficulty = st.selectbox("Difficulty Level",
469
  ["Beginner", "Intermediate", "Advanced", "Expert"])
470
  include_code = st.checkbox("Include Code Labs", True)
471
  include_design = st.checkbox("Generate Visual Designs", True)
472
+ include_voiceover = st.checkbox("Generate Voiceovers", True)
473
+
474
+ # Voice selection
475
+ if include_voiceover:
476
+ st.subheader("πŸŽ™οΈ Voice Selection")
477
+
478
+ # Get available voices
479
+ voices = voiceover_agent.get_voices()
480
+
481
+ # If we have voices, let the user select one
482
+ if voices:
483
+ # Create 2 columns for voice selection
484
+ cols = st.columns(2)
485
+ for i, voice in enumerate(voices[:4]): # Show first 4 voices
486
+ with cols[i % 2]:
487
+ # Create a unique key for each voice button
488
+ voice_key = f"voice_{voice['voice_id']}"
489
+
490
+ # Display voice option
491
+ if st.button(
492
+ f"πŸ—£οΈ {voice['name']}",
493
+ key=voice_key,
494
+ use_container_width=True,
495
+ help=f"Select {voice['name']} voice"
496
+ ):
497
+ st.session_state.selected_voice = voice['voice_id']
498
+
499
+ # Show which voice is currently selected
500
+ selected_voice_name = next((v['name'] for v in voices if v['voice_id'] == st.session_state.selected_voice), "Default")
501
+ st.info(f"Selected Voice: **{selected_voice_name}**")
502
+ else:
503
+ st.warning("Couldn't load voices. Using default voice.")
504
 
505
  if st.button("✨ Generate Workshop", type="primary", use_container_width=True):
506
  st.session_state.generating = True
507
+ st.session_state.voiceovers = {} # Reset previous voiceovers
508
 
509
  # Generation pipeline
510
+ if st.session_state.generating:
511
+ with st.spinner(f"πŸš€ Creating your {st.session_state.workshop_topic} workshop..."):
512
  start_time = time.time()
513
 
514
  # Agent pipeline
515
+ outline = topic_agent.generate_outline(st.session_state.workshop_topic, duration, difficulty)
516
  content = content_agent.generate_content(outline)
517
  slides = slide_agent.generate_slides(content)
518
  code_labs = code_agent.generate_code(content) if include_code else None
519
  design_url = design_agent.generate_design(slides) if include_design else None
520
 
521
+ # Generate voiceovers if enabled
522
+ voiceovers = {}
523
+ if include_voiceover and ELEVENLABS_API_KEY:
524
+ for i, module in enumerate(content.get("modules", [])):
525
+ # Create a short intro for each module (limit to 500 characters)
526
+ intro_text = f"Welcome to Module {i+1}: {module['title']}. " + \
527
+ f"In this module, we'll cover: {', '.join(module.get('speaker_notes', []))[:300]}"
528
+
529
+ # Generate voiceover
530
+ audio_data = voiceover_agent.generate_voiceover(
531
+ intro_text,
532
+ st.session_state.selected_voice
533
+ )
534
+
535
+ if audio_data:
536
+ voiceovers[f"module_{i+1}_intro.mp3"] = audio_data
537
+
538
  # Prepare download package
539
  zip_buffer = io.BytesIO()
540
  with zipfile.ZipFile(zip_buffer, "a") as zip_file:
 
549
  zip_file.writestr("slide_design.png", img_data)
550
  except:
551
  pass
552
+ # Add voiceovers to ZIP
553
+ for filename, audio_data in voiceovers.items():
554
+ zip_file.writestr(f"voiceovers/{filename}", audio_data)
555
 
556
  # Store results
557
  st.session_state.outline = outline
 
559
  st.session_state.slides = slides
560
  st.session_state.code_labs = code_labs
561
  st.session_state.design_url = design_url
562
+ st.session_state.voiceovers = voiceovers
563
  st.session_state.zip_buffer = zip_buffer
564
  st.session_state.gen_time = round(time.time() - start_time, 2)
565
  st.session_state.generated = True
566
  st.session_state.generating = False
567
 
568
  # Results display
569
+ if st.session_state.generated:
570
+ st.success(f"βœ… {st.session_state.workshop_topic} workshop generated in {st.session_state.gen_time} seconds!")
571
 
572
  # Download button
573
  st.download_button(
574
  label="πŸ“₯ Download Workshop Package",
575
  data=st.session_state.zip_buffer.getvalue(),
576
+ file_name=f"{st.session_state.workshop_topic.replace(' ', '_')}_workshop.zip",
577
  mime="application/zip",
578
  use_container_width=True
579
  )
 
595
  if st.session_state.design_url:
596
  with st.expander("🎨 Generated Design"):
597
  st.image(st.session_state.design_url, caption="Custom Slide Design")
598
+
599
+ # Voiceover player
600
+ if st.session_state.voiceovers:
601
+ with st.expander("πŸ”Š Voiceover Previews"):
602
+ for i, (filename, audio_bytes) in enumerate(st.session_state.voiceovers.items()):
603
+ module_num = filename.split("_")[1]
604
+ st.subheader(f"Module {module_num} Introduction")
605
+
606
+ # Create an audio player for each voiceover
607
+ st.audio(audio_bytes, format="audio/mp3")
608
+
609
+ # Add download button for individual voiceover
610
+ st.download_button(
611
+ label=f"Download Module {module_num} Voiceover",
612
+ data=audio_bytes,
613
+ file_name=filename,
614
+ mime="audio/mpeg",
615
+ key=f"voiceover_dl_{i}"
616
+ )
617
 
618
  # Sales and booking section
619
  st.divider()
620
  st.subheader("πŸš€ Ready to Deliver This Workshop?")
621
+ st.markdown(f"""
622
+ ### Premium {st.session_state.workshop_topic} Training Package
623
  - **Live Workshop Delivery**: $10,000 per session
624
  - **On-Demand Course**: $5,000 (unlimited access)
625
  - **Pilot Program**: $1,000 refundable deposit
626
+ - **Voiceover Add-on**: $500 per module
627
 
628
  ✨ **All inclusive**: Customization, materials, and follow-up support
629
  """)
 
644
  else:
645
  st.warning("OpenAI API not set - using enhanced mock data")
646
 
647
+ if ELEVENLABS_API_KEY:
648
+ st.success("ElevenLabs API Connected")
649
+ elif st.session_state.get('voiceovers'):
650
+ st.warning("ElevenLabs API not set - using mock voiceovers")
651
+
652
+ st.info(f"""
653
+ **Current Workshop:**
654
+ {st.session_state.workshop_topic}
655
+
656
  **Premium Features:**
657
+ - AI-generated voiceovers
658
+ - Professional slide designs
659
  - Real-world case studies
660
  - Practical code labs
 
661
  """)
662
 
663
  # How it works section
 
665
  st.subheader("πŸ’‘ How It Works")
666
  st.markdown("""
667
  1. **Configure** your workshop topic and parameters
668
+ 2. **Generate** premium training materials with voiceovers
669
  3. **Customize** the content to your specific needs
670
  4. **Deliver** high-value corporate training at $10K/session
671
  5. **Reuse** the materials for unlimited revenue
672
 
673
+ *"The voiceover feature helped me create on-demand courses that sold for $5K each"* - Michael L., AI Consultant
674
  """)