Nihal2000 commited on
Commit
c414a99
Β·
verified Β·
1 Parent(s): 3577769

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +132 -21
app.py CHANGED
@@ -980,9 +980,8 @@ voice_conversation_state = {
980
  # return f"❌ Error: {str(e)}"
981
 
982
  def generate_podcast_ui(doc_ids, style, duration, voice1, voice2):
983
- """UI wrapper for podcast generation"""
984
  try:
985
- # Add detailed logging
986
  logger.info(f"generate_podcast_ui called with:")
987
  logger.info(f" doc_ids: {doc_ids} (type: {type(doc_ids)})")
988
  logger.info(f" style: {style}")
@@ -990,22 +989,18 @@ def generate_podcast_ui(doc_ids, style, duration, voice1, voice2):
990
  logger.info(f" voice1: {voice1}")
991
  logger.info(f" voice2: {voice2}")
992
 
993
- # Handle various input formats
994
  if doc_ids is None:
995
  logger.warning("doc_ids is None")
996
  return ("⚠️ Please select at least one document", None, "No documents selected", "")
997
 
998
- # Convert to list if needed
999
  if isinstance(doc_ids, str):
1000
  logger.info(f"Converting string doc_id to list: {doc_ids}")
1001
  doc_ids = [doc_ids]
1002
 
1003
- # Check if empty
1004
  if not doc_ids or len(doc_ids) == 0:
1005
  logger.warning(f"doc_ids is empty or has length 0: {doc_ids}")
1006
  return ("⚠️ Please select at least one document", None, "No documents selected", "")
1007
 
1008
- # Filter out None or empty string values
1009
  doc_ids = [doc_id for doc_id in doc_ids if doc_id and doc_id.strip()]
1010
 
1011
  if not doc_ids:
@@ -1094,6 +1089,105 @@ def load_dashboard_stats():
1094
  logger.error(f"Error loading dashboard stats: {str(e)}")
1095
  return (0, 0, 0.0, [], "❌ Error", "❌ Error", "❌ Error")
1096
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1097
  def create_gradio_interface():
1098
  custom_theme = gr.themes.Soft(
1099
  primary_hue=gr.themes.colors.indigo,
@@ -1530,40 +1624,34 @@ def create_gradio_interface():
1530
  gr.Markdown("""
1531
  # πŸŽ™οΈ AI Podcast Studio
1532
  ## Transform Documents into Engaging Audio
1533
-
1534
  Convert your documents into professional podcast conversations with AI-generated voices.
1535
-
1536
  ### How It Works:
1537
  1. **Select Documents** - Choose 1-5 documents from your library
1538
  2. **Choose Style** - Pick conversation style (casual, educational, etc.)
1539
  3. **Set Duration** - Select podcast length (5-30 minutes)
1540
  4. **Select Voices** - Pick two AI hosts from available voices
1541
  5. **Generate** - AI creates natural dialogue discussing your content
1542
-
1543
  ### Powered By:
1544
  - 🎡 **ElevenLabs AI** - Ultra-realistic voice synthesis
1545
  - πŸ€– **LLM** - Intelligent content analysis and script generation
1546
  - πŸ“š **RAG** - Context-aware information retrieval
1547
-
1548
  ---
1549
  """)
1550
-
1551
  with gr.Row():
1552
  with gr.Column(scale=2):
1553
  # Configuration Panel
1554
  with gr.Group():
1555
  gr.Markdown("#### πŸ“š Select Content")
1556
 
1557
- # IMPORTANT: CheckboxGroup that stores document IDs
1558
  podcast_doc_selector = gr.CheckboxGroup(
1559
- choices=get_document_choices(), # List of (label, value) tuples
1560
  label="Documents to Include",
1561
  info="Choose 1-5 documents for best results",
1562
  interactive=True,
1563
- value=[] # Start with empty selection
1564
  )
1565
 
1566
- # Debug display (optional - remove in production)
1567
  gr.Markdown("*Selected document IDs will be used for podcast generation*")
1568
 
1569
  with gr.Accordion("🎨 Podcast Settings", open=True):
@@ -1616,26 +1704,25 @@ def create_gradio_interface():
1616
  )
1617
 
1618
  with gr.Column(scale=3):
1619
- # Output Panel
1620
  with gr.Group():
1621
- gr.Markdown("#### 🎡 Generated Podcast")
1622
 
1623
  podcast_audio_player = gr.Audio(
1624
- label="podcast_audio_player",
1625
  type="filepath",
1626
  interactive=False,
1627
  autoplay=True,
1628
- container=False
1629
  show_label=False
1630
  )
1631
- gr.DownloadButton("πŸ’Ύ Download MP3", value=podcast_audio_player)
1632
 
1633
  with gr.Accordion("πŸ“ Transcript", open=False):
1634
  podcast_transcript_display = gr.Markdown(
1635
  value="*Transcript will appear after generation...*"
1636
  )
1637
 
1638
- # Event handler - Connect the button to the function
 
 
1639
  generate_podcast_btn.click(
1640
  fn=generate_podcast_ui,
1641
  inputs=[
@@ -1651,6 +1738,30 @@ def create_gradio_interface():
1651
  podcast_transcript_display,
1652
  podcast_id_display
1653
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1654
  )
1655
 
1656
  with gr.Tab("❓ Ask Questions"):
 
980
  # return f"❌ Error: {str(e)}"
981
 
982
  def generate_podcast_ui(doc_ids, style, duration, voice1, voice2):
983
+ """UI wrapper for podcast generation (EXISTING FUNCTION - keep as is)"""
984
  try:
 
985
  logger.info(f"generate_podcast_ui called with:")
986
  logger.info(f" doc_ids: {doc_ids} (type: {type(doc_ids)})")
987
  logger.info(f" style: {style}")
 
989
  logger.info(f" voice1: {voice1}")
990
  logger.info(f" voice2: {voice2}")
991
 
 
992
  if doc_ids is None:
993
  logger.warning("doc_ids is None")
994
  return ("⚠️ Please select at least one document", None, "No documents selected", "")
995
 
 
996
  if isinstance(doc_ids, str):
997
  logger.info(f"Converting string doc_id to list: {doc_ids}")
998
  doc_ids = [doc_ids]
999
 
 
1000
  if not doc_ids or len(doc_ids) == 0:
1001
  logger.warning(f"doc_ids is empty or has length 0: {doc_ids}")
1002
  return ("⚠️ Please select at least one document", None, "No documents selected", "")
1003
 
 
1004
  doc_ids = [doc_id for doc_id in doc_ids if doc_id and doc_id.strip()]
1005
 
1006
  if not doc_ids:
 
1089
  logger.error(f"Error loading dashboard stats: {str(e)}")
1090
  return (0, 0, 0.0, [], "❌ Error", "❌ Error", "❌ Error")
1091
 
1092
+ # ADD THESE HELPER FUNCTIONS BEFORE create_gradio_interface():
1093
+ def load_podcast_library_ui():
1094
+ """Load and display podcast library with audio players"""
1095
+ try:
1096
+ result = mcp_server.list_podcasts_sync(limit=50)
1097
+
1098
+ if not result.get("success"):
1099
+ return (
1100
+ gr.Column(visible=False),
1101
+ f"❌ Failed to load podcasts: {result.get('error', 'Unknown error')}"
1102
+ )
1103
+
1104
+ podcasts = result.get("podcasts", [])
1105
+
1106
+ if not podcasts:
1107
+ return (
1108
+ gr.Column(visible=False),
1109
+ "πŸ“­ No podcasts generated yet. Create your first podcast above!"
1110
+ )
1111
+
1112
+ # Build the library UI dynamically
1113
+ with gr.Column(visible=True) as library_col:
1114
+ for idx, podcast in enumerate(podcasts, 1):
1115
+ with gr.Group():
1116
+ with gr.Row():
1117
+ # Column 1: Podcast Info (40%)
1118
+ with gr.Column(scale=2):
1119
+ gr.Markdown(f"### πŸŽ™οΈ Podcast #{idx}")
1120
+
1121
+ # Extract document names from metadata
1122
+ doc_names = []
1123
+ doc_ids = [] # Initialize here to avoid reference error
1124
+
1125
+ if podcast.get("metadata"):
1126
+ doc_ids = podcast["metadata"].get("document_ids", [])
1127
+ # Get document names
1128
+ for doc_id in doc_ids:
1129
+ try:
1130
+ doc = mcp_server.run_async(
1131
+ mcp_server.document_store.get_document(doc_id)
1132
+ )
1133
+ if doc:
1134
+ doc_names.append(doc.filename)
1135
+ except Exception as e:
1136
+ logger.warning(f"Could not fetch document {doc_id}: {e}")
1137
+ doc_names.append(f"Doc {doc_id[:8]}...")
1138
+
1139
+ # Display document names
1140
+ if doc_names:
1141
+ gr.Markdown(f"**πŸ“„ Documents:** {', '.join(doc_names)}")
1142
+ else:
1143
+ doc_count = len(doc_ids) if doc_ids else 'N/A'
1144
+ gr.Markdown(f"**πŸ“„ Documents:** {doc_count} document(s)")
1145
+
1146
+ # Podcast metadata
1147
+ style = podcast.get("metadata", {}).get("style", "Unknown")
1148
+ duration = podcast.get("metadata", {}).get("duration_minutes", "N/A")
1149
+ created = podcast.get("created_at", "Unknown")[:19] if podcast.get("created_at") else "Unknown"
1150
+
1151
+ gr.Markdown(
1152
+ f"**🎨 Style:** {style.title()} \n"
1153
+ f"**⏱️ Duration:** ~{duration} min \n"
1154
+ f"**πŸ“… Created:** {created} \n"
1155
+ f"**πŸ†” ID:** `{podcast['id'][:16]}...`"
1156
+ )
1157
+
1158
+ # Column 2: Audio Player (60%)
1159
+ with gr.Column(scale=3):
1160
+ audio_file = podcast.get("audio_file")
1161
+
1162
+ if audio_file and os.path.exists(audio_file):
1163
+ gr.Audio(
1164
+ value=audio_file,
1165
+ type="filepath",
1166
+ interactive=False,
1167
+ show_label=False,
1168
+ show_download_button=True,
1169
+ waveform_options={"show_controls": True}
1170
+ )
1171
+ else:
1172
+ gr.Markdown("⚠️ *Audio file not found*")
1173
+ if audio_file:
1174
+ gr.Markdown(f"*Expected path: {audio_file}*")
1175
+
1176
+ # Optional: Show transcript in accordion
1177
+ with gr.Accordion(f"πŸ“ View Transcript", open=False):
1178
+ transcript = podcast.get("transcript", "Transcript not available")
1179
+ gr.Markdown(transcript)
1180
+
1181
+ status_msg = f"βœ… Loaded {len(podcasts)} podcast{'s' if len(podcasts) != 1 else ''}"
1182
+ return library_col, status_msg
1183
+
1184
+ except Exception as e:
1185
+ logger.error(f"Error loading podcast library: {str(e)}", exc_info=True)
1186
+ return (
1187
+ gr.Column(visible=False),
1188
+ f"❌ Error loading library: {str(e)}"
1189
+ )
1190
+
1191
  def create_gradio_interface():
1192
  custom_theme = gr.themes.Soft(
1193
  primary_hue=gr.themes.colors.indigo,
 
1624
  gr.Markdown("""
1625
  # πŸŽ™οΈ AI Podcast Studio
1626
  ## Transform Documents into Engaging Audio
 
1627
  Convert your documents into professional podcast conversations with AI-generated voices.
 
1628
  ### How It Works:
1629
  1. **Select Documents** - Choose 1-5 documents from your library
1630
  2. **Choose Style** - Pick conversation style (casual, educational, etc.)
1631
  3. **Set Duration** - Select podcast length (5-30 minutes)
1632
  4. **Select Voices** - Pick two AI hosts from available voices
1633
  5. **Generate** - AI creates natural dialogue discussing your content
 
1634
  ### Powered By:
1635
  - 🎡 **ElevenLabs AI** - Ultra-realistic voice synthesis
1636
  - πŸ€– **LLM** - Intelligent content analysis and script generation
1637
  - πŸ“š **RAG** - Context-aware information retrieval
 
1638
  ---
1639
  """)
1640
+
1641
  with gr.Row():
1642
  with gr.Column(scale=2):
1643
  # Configuration Panel
1644
  with gr.Group():
1645
  gr.Markdown("#### πŸ“š Select Content")
1646
 
 
1647
  podcast_doc_selector = gr.CheckboxGroup(
1648
+ choices=get_document_choices(),
1649
  label="Documents to Include",
1650
  info="Choose 1-5 documents for best results",
1651
  interactive=True,
1652
+ value=[]
1653
  )
1654
 
 
1655
  gr.Markdown("*Selected document IDs will be used for podcast generation*")
1656
 
1657
  with gr.Accordion("🎨 Podcast Settings", open=True):
 
1704
  )
1705
 
1706
  with gr.Column(scale=3):
1707
+ # Output Panel - Latest Generated
1708
  with gr.Group():
1709
+ gr.Markdown("#### 🎡 Latest Generated Podcast")
1710
 
1711
  podcast_audio_player = gr.Audio(
 
1712
  type="filepath",
1713
  interactive=False,
1714
  autoplay=True,
 
1715
  show_label=False
1716
  )
 
1717
 
1718
  with gr.Accordion("πŸ“ Transcript", open=False):
1719
  podcast_transcript_display = gr.Markdown(
1720
  value="*Transcript will appear after generation...*"
1721
  )
1722
 
1723
+ podcast_library_container = gr.Column()
1724
+
1725
+ # Event handler for generate button
1726
  generate_podcast_btn.click(
1727
  fn=generate_podcast_ui,
1728
  inputs=[
 
1738
  podcast_transcript_display,
1739
  podcast_id_display
1740
  ]
1741
+ ).then(
1742
+ # Auto-refresh library after generation
1743
+ fn=load_podcast_library_ui,
1744
+ outputs=[podcast_library_container, podcast_library_status]
1745
+ )
1746
+
1747
+ # NEW SECTION: Podcast Library (at tab level, same as first gr.Row())
1748
+ gr.Markdown("---")
1749
+ gr.Markdown("### πŸ“š Podcast Library")
1750
+ gr.Markdown("Browse and play all your generated podcasts")
1751
+
1752
+ with gr.Row():
1753
+ refresh_podcast_library_btn = gr.Button("πŸ”„ Refresh Library", variant="secondary")
1754
+ podcast_library_status = gr.Textbox(
1755
+ label="Library Status",
1756
+ value="Click 'Refresh Library' to load podcasts",
1757
+ interactive=False,
1758
+ scale=3
1759
+ )
1760
+
1761
+ # Event handler for refresh button
1762
+ refresh_podcast_library_btn.click(
1763
+ fn=load_podcast_library_ui,
1764
+ outputs=[podcast_library_container, podcast_library_status]
1765
  )
1766
 
1767
  with gr.Tab("❓ Ask Questions"):