siddhartharyaai commited on
Commit
b4016db
·
verified ·
1 Parent(s): 424917e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +143 -127
app.py CHANGED
@@ -1,214 +1,230 @@
1
- # app.py
2
-
3
  import streamlit as st
 
 
 
 
 
 
4
  from utils import (
5
  generate_script,
6
- generate_audio_mp3, # Updated import
7
  truncate_text,
8
  extract_text_from_url,
9
  transcribe_youtube_video,
10
  research_topic
11
  )
12
- from prompts import SYSTEM_PROMPT # Ensure this module exists
13
- import pypdf
14
- from pydub import AudioSegment
15
- import tempfile
16
- import os
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  def generate_podcast(file, url, video_url, research_topic_input, tone, length):
19
- print("[LOG] generate_podcast called")
20
-
21
- # Check that only one input source is used
22
  sources = [bool(file), bool(url), bool(video_url), bool(research_topic_input)]
23
  if sum(sources) > 1:
24
- print("[ERROR] Multiple input sources provided.")
25
- return None, "Please provide either a PDF file, a URL, a YouTube link, or a Research topic - not multiple."
26
  if not any(sources):
27
- print("[ERROR] No input source provided.")
28
  return None, "Please provide at least one source."
29
 
30
  text = ""
31
  if file:
32
  try:
33
- print("[LOG] Reading PDF file:", file.name)
34
  if not file.name.lower().endswith('.pdf'):
35
- print("[ERROR] Uploaded file is not a PDF.")
36
  return None, "Please upload a PDF file."
37
  reader = pypdf.PdfReader(file.name)
38
  text = " ".join(page.extract_text() for page in reader.pages if page.extract_text())
39
- print("[LOG] PDF text extraction successful.")
40
  except Exception as e:
41
- print("[ERROR] Error reading PDF file:", e)
42
- return None, f"Error reading PDF file: {str(e)}"
43
  elif url:
44
  try:
45
- print("[LOG] Using URL input")
46
  text = extract_text_from_url(url)
47
  if not text:
48
- print("[ERROR] Failed to extract text from URL.")
49
- return None, "Failed to extract text from the provided URL."
50
  except Exception as e:
51
- print("[ERROR] Error extracting text from URL:", e)
52
  return None, f"Error extracting text from URL: {str(e)}"
53
  elif video_url:
54
  try:
55
- print("[LOG] Using YouTube video input")
56
  text = transcribe_youtube_video(video_url)
57
  if not text:
58
- print("[ERROR] Failed to transcribe YouTube video.")
59
- return None, "Failed to transcribe the provided YouTube video."
60
  except Exception as e:
61
- print("[ERROR] Error transcribing YouTube video:", e)
62
  return None, f"Error transcribing YouTube video: {str(e)}"
63
  elif research_topic_input:
64
  try:
65
- print("[LOG] Researching topic:", research_topic_input)
66
  text = research_topic(research_topic_input)
67
  if not text:
68
- print("[ERROR] No information found for the topic.")
69
- return None, f"Sorry, I couldn't find recent information on '{research_topic_input}'."
70
  except Exception as e:
71
- print("[ERROR] Error researching topic:", e)
72
  return None, f"Error researching topic: {str(e)}"
73
- else:
74
- print("[ERROR] No valid input source detected.")
75
- return None, "Please provide a PDF file, URL, YouTube link, or Research topic."
76
 
77
  try:
78
  text = truncate_text(text)
79
  script = generate_script(SYSTEM_PROMPT, text, tone, length)
80
  except Exception as e:
81
- print("[ERROR] Error generating script:", e)
82
  return None, f"Error generating script: {str(e)}"
83
 
84
  audio_segments = []
85
  transcript = ""
 
86
 
87
  try:
88
- print("[LOG] Generating audio segments...")
89
- # Define crossfade duration in milliseconds
90
- crossfade_duration = 50 # 50ms crossfade for smooth transitions
91
-
92
- for i, item in enumerate(script.dialogue):
93
- try:
94
- audio_file = generate_audio_mp3(item.text, item.speaker) # Updated function call
95
- line_audio = AudioSegment.from_file(audio_file, format="mp3") # Changed format to mp3
96
- audio_segments.append(line_audio)
97
- transcript += f"**{item.speaker}**: {item.text}\n\n"
98
- os.remove(audio_file)
99
- except Exception as e:
100
- print(f"[ERROR] Error generating audio for dialogue item {i+1}: {e}")
101
- continue
102
 
103
  if not audio_segments:
104
- print("[ERROR] No audio segments were generated.")
105
- return None, "No audio segments were generated."
106
 
107
- print("[LOG] Combining audio segments with crossfades...")
108
- # Initialize combined audio with the first segment
109
  combined = audio_segments[0]
110
-
111
- # Append remaining segments with crossfade
112
  for seg in audio_segments[1:]:
113
  combined = combined.append(seg, crossfade=crossfade_duration)
114
 
115
- with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_audio: # Changed suffix to mp3
116
- combined.export(temp_audio.name, format="mp3") # Changed format to mp3
117
- print("[LOG] Podcast generated:", temp_audio.name)
118
- return temp_audio.name, transcript
119
 
120
  except Exception as e:
121
- print("[ERROR] Error generating audio:", e)
122
  return None, f"Error generating audio: {str(e)}"
123
 
124
  def main():
125
- # Set Streamlit page config
126
- st.set_page_config(
127
- page_title="MyPod - AI based Podcast Generator",
128
- layout="centered"
129
- )
130
 
131
  st.title("🎙 MyPod - AI-based Podcast Generator")
132
- st.markdown(
133
- """
134
- <style>
135
- .main {
136
- background-color: #f9f9f9;
137
- }
138
- .block-container {
139
- padding: 2rem;
140
- border-radius: 10px;
141
- background-color: #ffffff;
142
- box-shadow: 0 0 10px rgba(0,0,0,0.1);
143
- }
144
- </style>
145
- """,
146
- unsafe_allow_html=True
147
- )
148
-
149
- st.markdown(
150
- "Welcome to **MyPod**, your go-to AI-powered podcast generator! 🎉\n\n"
151
- "MyPod transforms your documents, webpages, YouTube videos, or research topics into a more human-sounding, conversational podcast.\n"
152
- "Select a tone and a duration range. The script will be on-topic, concise, and respect your chosen length.\n\n"
153
- "### How to use:\n"
154
- "1. **Provide one source:** PDF, URL, YouTube link (Requires User Auth - Work in Progress), or a Topic to Research.\n"
155
- "2. **Choose the tone and the target duration.**\n"
156
- "3. **Click 'Generate Podcast'** to produce your podcast.\n\n"
157
- "**Research a Topic:** Please be as detailed as possible in your topic statement. If it's too niche or specific, "
158
- "you might not get the desired outcome. We'll fetch information from Wikipedia and RSS feeds (BBC, CNN, Associated Press, "
159
- "NDTV, Times of India, The Hindu, Economic Times, Google News) or the LLM knowledge base to get recent info about the topic.\n\n"
160
- "**Token Limit:** Up to ~2,048 tokens are supported. Long inputs may be truncated.\n"
161
- "**Note:** YouTube transcription uses Whisper on CPU and may take longer for very long videos.\n\n"
162
- "⏳**Please be patient while your podcast is being generated.** This process involves content analysis, script creation, "
163
- "and high-quality audio synthesis, which may take a few minutes.\n\n"
164
- "🔥 **Ready to create your personalized podcast?** Give it a try now and let the magic happen! 🔥"
165
- )
166
-
167
- st.write("---")
168
-
169
- # Create 2 columns for inputs
170
- col1, col2 = st.columns(2)
171
 
 
 
172
  with col1:
173
- file = st.file_uploader("Upload PDF (Only .pdf)", type=["pdf"])
174
  url = st.text_input("Or Enter URL")
175
- video_url = st.text_input("Or Enter YouTube Link (Requires User Auth - Work in Progress)")
176
-
177
  with col2:
178
  research_topic_input = st.text_input("Or Research a Topic")
179
- tone = st.radio(
180
- "Tone",
181
- ["Humorous", "Formal", "Casual", "Youthful"],
182
- index=2
183
- )
184
- length = st.radio(
185
- "Length",
186
- ["1-3 Mins", "3-5 Mins", "5-10 Mins", "10-20 Mins"],
187
- index=0
188
- )
189
 
190
- st.write("")
191
  generate_button = st.button("Generate Podcast")
192
 
193
  if generate_button:
194
- # Run the generate_podcast function
195
- with st.spinner("Generating your podcast, please wait..."):
196
- podcast_file, transcript = generate_podcast(
197
- file, url, video_url, research_topic_input, tone, length
198
- )
199
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  if podcast_file is None:
 
 
201
  st.error(transcript)
 
202
  else:
 
 
 
203
  st.success("Podcast generated successfully!")
204
  audio_file = open(podcast_file, 'rb')
205
  audio_bytes = audio_file.read()
206
  audio_file.close()
207
-
208
  st.audio(audio_bytes, format='audio/mp3')
209
- st.markdown(transcript)
210
 
211
- # Clean up the temp file
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  os.remove(podcast_file)
213
 
214
  if __name__ == "__main__":
 
 
 
1
  import streamlit as st
2
+ import time
3
+ import re
4
+ import os
5
+ import tempfile
6
+ import pypdf
7
+ from pydub import AudioSegment
8
  from utils import (
9
  generate_script,
10
+ generate_audio_mp3,
11
  truncate_text,
12
  extract_text_from_url,
13
  transcribe_youtube_video,
14
  research_topic
15
  )
16
+ from prompts import SYSTEM_PROMPT
17
+
18
+ def parse_user_edited_transcript(edited_text: str):
19
+ pattern = r"\*\*(Jane|John)\*\*:\s*(.+)"
20
+ matches = re.findall(pattern, edited_text)
21
+ if not matches:
22
+ # If the user completely changed the format, just treat it as "Jane"
23
+ return [("Jane", edited_text)]
24
+ return matches
25
+
26
+ def regenerate_audio_from_dialogue(dialogue_items):
27
+ audio_segments = []
28
+ transcript = ""
29
+ crossfade_duration = 50 # ms
30
+
31
+ for speaker, line_text in dialogue_items:
32
+ audio_file = generate_audio_mp3(line_text, speaker)
33
+ seg = AudioSegment.from_file(audio_file, format="mp3")
34
+ audio_segments.append(seg)
35
+ transcript += f"**{speaker}**: {line_text}\n\n"
36
+ os.remove(audio_file)
37
+
38
+ if not audio_segments:
39
+ return None, "No audio segments were generated."
40
+
41
+ combined = audio_segments[0]
42
+ for seg in audio_segments[1:]:
43
+ combined = combined.append(seg, crossfade=crossfade_duration)
44
+
45
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_audio:
46
+ combined.export(temp_audio.name, format="mp3")
47
+ final_mp3_path = temp_audio.name
48
+
49
+ return final_mp3_path, transcript
50
 
51
  def generate_podcast(file, url, video_url, research_topic_input, tone, length):
 
 
 
52
  sources = [bool(file), bool(url), bool(video_url), bool(research_topic_input)]
53
  if sum(sources) > 1:
54
+ return None, "Provide only one input (PDF, URL, YouTube, or Research topic)."
 
55
  if not any(sources):
 
56
  return None, "Please provide at least one source."
57
 
58
  text = ""
59
  if file:
60
  try:
 
61
  if not file.name.lower().endswith('.pdf'):
 
62
  return None, "Please upload a PDF file."
63
  reader = pypdf.PdfReader(file.name)
64
  text = " ".join(page.extract_text() for page in reader.pages if page.extract_text())
 
65
  except Exception as e:
66
+ return None, f"Error reading PDF: {str(e)}"
 
67
  elif url:
68
  try:
 
69
  text = extract_text_from_url(url)
70
  if not text:
71
+ return None, "Failed to extract text from URL."
 
72
  except Exception as e:
 
73
  return None, f"Error extracting text from URL: {str(e)}"
74
  elif video_url:
75
  try:
 
76
  text = transcribe_youtube_video(video_url)
77
  if not text:
78
+ return None, "Failed to transcribe YouTube video."
 
79
  except Exception as e:
 
80
  return None, f"Error transcribing YouTube video: {str(e)}"
81
  elif research_topic_input:
82
  try:
 
83
  text = research_topic(research_topic_input)
84
  if not text:
85
+ return None, f"Sorry, no information found on '{research_topic_input}'."
 
86
  except Exception as e:
 
87
  return None, f"Error researching topic: {str(e)}"
 
 
 
88
 
89
  try:
90
  text = truncate_text(text)
91
  script = generate_script(SYSTEM_PROMPT, text, tone, length)
92
  except Exception as e:
 
93
  return None, f"Error generating script: {str(e)}"
94
 
95
  audio_segments = []
96
  transcript = ""
97
+ crossfade_duration = 50 # ms
98
 
99
  try:
100
+ for item in script.dialogue:
101
+ audio_file = generate_audio_mp3(item.text, item.speaker)
102
+ seg = AudioSegment.from_file(audio_file, format="mp3")
103
+ audio_segments.append(seg)
104
+ transcript += f"**{item.speaker}**: {item.text}\n\n"
105
+ os.remove(audio_file)
 
 
 
 
 
 
 
 
106
 
107
  if not audio_segments:
108
+ return None, "No audio segments generated."
 
109
 
 
 
110
  combined = audio_segments[0]
 
 
111
  for seg in audio_segments[1:]:
112
  combined = combined.append(seg, crossfade=crossfade_duration)
113
 
114
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_audio:
115
+ combined.export(temp_audio.name, format="mp3")
116
+ final_mp3_path = temp_audio.name
117
+ return final_mp3_path, transcript
118
 
119
  except Exception as e:
 
120
  return None, f"Error generating audio: {str(e)}"
121
 
122
  def main():
123
+ st.set_page_config(page_title="MyPod - AI-based Podcast Generator", layout="centered")
 
 
 
 
124
 
125
  st.title("🎙 MyPod - AI-based Podcast Generator")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
+ # Standard input UI
128
+ col1, col2 = st.columns(2)
129
  with col1:
130
+ file = st.file_uploader("Upload PDF (.pdf only)", type=["pdf"])
131
  url = st.text_input("Or Enter URL")
132
+ video_url = st.text_input("Or Enter YouTube Link")
 
133
  with col2:
134
  research_topic_input = st.text_input("Or Research a Topic")
135
+ tone = st.radio("Tone", ["Humorous", "Formal", "Casual", "Youthful"], index=2)
136
+ length = st.radio("Length", ["1-3 Mins", "3-5 Mins", "5-10 Mins", "10-20 Mins"], index=0)
 
 
 
 
 
 
 
 
137
 
 
138
  generate_button = st.button("Generate Podcast")
139
 
140
  if generate_button:
141
+ # Show a custom progress bar & messages
142
+ progress_bar = st.progress(0)
143
+ progress_text = st.empty()
144
+
145
+ # We don't have real-time progress from TTS, so we'll do a pseudo countdown:
146
+ # Step 1: Start
147
+ progress_text.write("Alright, let's get started...")
148
+ progress_bar.progress(10)
149
+ time.sleep(1.5)
150
+
151
+ # Step 2: Some cheeky text
152
+ progress_text.write("Working on the magic. Hang tight!")
153
+ progress_bar.progress(40)
154
+ time.sleep(1.5)
155
+
156
+ # Step 3: Almost there
157
+ progress_text.write("Almost done. Adding a dash of awesomeness...")
158
+ progress_bar.progress(70)
159
+ time.sleep(1.5)
160
+
161
+ # Step 4: Actually generate
162
+ podcast_file, transcript = generate_podcast(
163
+ file, url, video_url, research_topic_input, tone, length
164
+ )
165
+ time.sleep(1.5)
166
+
167
  if podcast_file is None:
168
+ # Reset progress to 0 if error
169
+ progress_bar.progress(100)
170
  st.error(transcript)
171
+ return
172
  else:
173
+ progress_bar.progress(100)
174
+ progress_text.write("Done!")
175
+
176
  st.success("Podcast generated successfully!")
177
  audio_file = open(podcast_file, 'rb')
178
  audio_bytes = audio_file.read()
179
  audio_file.close()
 
180
  st.audio(audio_bytes, format='audio/mp3')
 
181
 
182
+ # Show transcript in an editable box
183
+ st.markdown("### Generated Transcript (Editable)")
184
+ edited_text = st.text_area(
185
+ "Feel free to tweak lines, fix errors, or reword anything.",
186
+ value=transcript,
187
+ height=300
188
+ )
189
+
190
+ if st.button("Regenerate Audio From Edited Text"):
191
+ # Another pseudo progress bar for regeneration
192
+ regen_bar = st.progress(0)
193
+ regen_text = st.empty()
194
+
195
+ regen_text.write("Let's do this revision!")
196
+ regen_bar.progress(25)
197
+ time.sleep(1.0)
198
+
199
+ regen_text.write("Cooking up fresh audio...")
200
+ regen_bar.progress(60)
201
+ time.sleep(1.0)
202
+
203
+ # Parse and regenerate
204
+ dialogue_items = parse_user_edited_transcript(edited_text)
205
+ new_audio_path, new_transcript = regenerate_audio_from_dialogue(dialogue_items)
206
+
207
+ regen_bar.progress(90)
208
+ time.sleep(1.0)
209
+
210
+ if new_audio_path is None:
211
+ regen_bar.progress(100)
212
+ st.error(new_transcript)
213
+ else:
214
+ regen_bar.progress(100)
215
+ regen_text.write("All set!")
216
+ st.success("Regenerated audio below:")
217
+
218
+ new_audio_file = open(new_audio_path, 'rb')
219
+ new_audio_bytes = new_audio_file.read()
220
+ new_audio_file.close()
221
+ st.audio(new_audio_bytes, format='audio/mp3')
222
+ st.markdown(new_transcript)
223
+
224
+ # Clean up
225
+ os.remove(new_audio_path)
226
+
227
+ # Clean up the original file
228
  os.remove(podcast_file)
229
 
230
  if __name__ == "__main__":