saq1b commited on
Commit
8786c21
·
verified ·
1 Parent(s): f0aa276

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +185 -319
app.py CHANGED
@@ -1,23 +1,28 @@
1
  import gradio as gr
 
2
  from pydub import AudioSegment
3
- import google.generativeai as genai
4
- from google.generativeai.types import HarmCategory, HarmBlockThreshold
5
  import json
6
  import uuid
7
  import io
8
  import edge_tts
9
  import asyncio
10
- import aiofiles
11
- import pypdf
12
  import os
13
  import time
14
- from typing import List, Dict, Tuple
 
 
 
 
 
 
15
 
16
  class PodcastGenerator:
17
  def __init__(self):
18
  pass
19
 
20
- async def generate_script(self, prompt: str, language: str, api_key: str) -> Dict:
21
  example = """
22
  {
23
  "topic": "AGI",
@@ -29,187 +34,11 @@ class PodcastGenerator:
29
  {
30
  "speaker": 1,
31
  "line": "Yeah, it's definitely having a moment, isn't it?"
32
- },
33
- {
34
- "speaker": 2,
35
- "line": "It is and for good reason, right? I mean, you've been digging into this stuff, listening to the podcasts and everything. What really stood out to you? What got you hooked?"
36
- },
37
- {
38
- "speaker": 1,
39
- "line": "Honestly, it's the sheer scale of what AGI could do. We're talking about potentially reshaping well everything."
40
- },
41
- {
42
- "speaker": 2,
43
- "line": "No kidding, but let's be real. Sometimes it feels like every other headline is either hyping AGI up as this technological utopia or painting it as our inevitable robot overlords."
44
- },
45
- {
46
- "speaker": 1,
47
- "line": "It's easy to get lost in the noise, for sure."
48
- },
49
- {
50
- "speaker": 2,
51
- "line": "Exactly. So how about we try to cut through some of that, shall we?"
52
- },
53
- {
54
- "speaker": 1,
55
- "line": "Sounds like a plan."
56
- },
57
- {
58
- "speaker": 2,
59
- "line": "Okay, so first things first, AGI, what is it really? And I don't just mean some dictionary definition, we're talking about something way bigger than just a super smart computer, right?"
60
- },
61
- {
62
- "speaker": 1,
63
- "line": "Right, it's not just about more processing power or better algorithms, it's about a fundamental shift in how we think about intelligence itself."
64
- },
65
- {
66
- "speaker": 2,
67
- "line": "So like, instead of programming a machine for a specific task, we're talking about creating something that can learn and adapt like we do."
68
- },
69
- {
70
- "speaker": 1,
71
- "line": "Exactly, think of it this way: Right now, we've got AI that can beat a grandmaster at chess but ask that same AI to, say, write a poem or compose a symphony. No chance."
72
- },
73
- {
74
- "speaker": 2,
75
- "line": "Okay, I see. So, AGI is about bridging that gap, creating something that can move between those different realms of knowledge seamlessly."
76
- },
77
- {
78
- "speaker": 1,
79
- "line": "Precisely. It's about replicating that uniquely human ability to learn something new and apply that knowledge in completely different contexts and that's a tall order, let me tell you."
80
- },
81
- {
82
- "speaker": 2,
83
- "line": "I bet. I mean, think about how much we still don't even understand about our own brains."
84
- },
85
- {
86
- "speaker": 1,
87
- "line": "That's exactly it. We're essentially trying to reverse-engineer something we don't fully comprehend."
88
- },
89
- {
90
- "speaker": 2,
91
- "line": "And how are researchers even approaching that? What are some of the big ideas out there?"
92
- },
93
- {
94
- "speaker": 1,
95
- "line": "Well, there are a few different schools of thought. One is this idea of neuromorphic computing where they're literally trying to build computer chips that mimic the structure and function of the human brain."
96
- },
97
- {
98
- "speaker": 2,
99
- "line": "Wow, so like actually replicating the physical architecture of the brain. That's wild."
100
- },
101
- {
102
- "speaker": 1,
103
- "line": "It's pretty mind-blowing stuff and then you've got folks working on something called whole brain emulation."
104
- },
105
- {
106
- "speaker": 2,
107
- "line": "Okay, and what's that all about?"
108
- },
109
- {
110
- "speaker": 1,
111
- "line": "The basic idea there is to create a complete digital copy of a human brain down to the last neuron and synapse and run it on a sufficiently powerful computer simulation."
112
- },
113
- {
114
- "speaker": 2,
115
- "line": "Hold on, a digital copy of an entire brain, that sounds like something straight out of science fiction."
116
- },
117
- {
118
- "speaker": 1,
119
- "line": "It does, doesn't it? But it gives you an idea of the kind of ambition we're talking about here and the truth is we're still a long way off from truly achieving AGI, no matter which approach you look at."
120
- },
121
- {
122
- "speaker": 2,
123
- "line": "That makes sense but it's still exciting to think about the possibilities, even if they're a ways off."
124
- },
125
- {
126
- "speaker": 1,
127
- "line": "Absolutely and those possibilities are what really get people fired up about AGI, right? Yeah."
128
- },
129
- {
130
- "speaker": 2,
131
- "line": "For sure. In fact, I remember you mentioning something in that podcast about AGI's potential to revolutionize scientific research. Something about supercharging breakthroughs."
132
- },
133
- {
134
- "speaker": 1,
135
- "line": "Oh, absolutely. Imagine an AI that doesn't just crunch numbers but actually understands scientific data the way a human researcher does. We're talking about potential breakthroughs in everything from medicine and healthcare to material science and climate change."
136
- },
137
- {
138
- "speaker": 2,
139
- "line": "It's like giving scientists this incredibly powerful new tool to tackle some of the biggest challenges we face."
140
- },
141
- {
142
- "speaker": 1,
143
- "line": "Exactly, it could be a total game changer."
144
- },
145
- {
146
- "speaker": 2,
147
- "line": "Okay, but let's be real, every coin has two sides. What about the potential downsides of AGI? Because it can't all be sunshine and roses, right?"
148
- },
149
- {
150
- "speaker": 1,
151
- "line": "Right, there are definitely valid concerns. Probably the biggest one is the impact on the job market. As AGI gets more sophisticated, there's a real chance it could automate a lot of jobs that are currently done by humans."
152
- },
153
- {
154
- "speaker": 2,
155
- "line": "So we're not just talking about robots taking over factories but potentially things like, what, legal work, analysis, even creative fields?"
156
- },
157
- {
158
- "speaker": 1,
159
- "line": "Potentially, yes. And that raises a whole host of questions about what happens to those workers, how we retrain them, how we ensure that the benefits of AGI are shared equitably."
160
- },
161
- {
162
- "speaker": 2,
163
- "line": "Right, because it's not just about the technology itself, but how we choose to integrate it into society."
164
- },
165
- {
166
- "speaker": 1,
167
- "line": "Absolutely. We need to be having these conversations now about ethics, about regulation, about how to make sure AGI is developed and deployed responsibly."
168
- },
169
- {
170
- "speaker": 2,
171
- "line": "So it's less about preventing some kind of sci-fi robot apocalypse and more about making sure we're steering this technology in the right direction from the get-go."
172
- },
173
- {
174
- "speaker": 1,
175
- "line": "Exactly, AGI has the potential to be incredibly beneficial, but it's not going to magically solve all our problems. It's on us to make sure we're using it for good."
176
- },
177
- {
178
- "speaker": 2,
179
- "line": "It's like you said earlier, it's about shaping the future of intelligence."
180
- },
181
- {
182
- "speaker": 1,
183
- "line": "I like that. It really is."
184
- },
185
- {
186
- "speaker": 2,
187
- "line": "And honestly, that's a responsibility that extends beyond just the researchers and the policymakers."
188
- },
189
- {
190
- "speaker": 1,
191
- "line": "100%"
192
- },
193
- {
194
- "speaker": 2,
195
- "line": "So to everyone listening out there I'll leave you with this. As AGI continues to develop, what role do you want to play in shaping its future?"
196
- },
197
- {
198
- "speaker": 1,
199
- "line": "That's a question worth pondering."
200
- },
201
- {
202
- "speaker": 2,
203
- "line": "It certainly is and on that note, we'll wrap up this deep dive. Thanks for listening, everyone."
204
- },
205
- {
206
- "speaker": 1,
207
- "line": "Peace."
208
  }
 
209
  ]
210
  }
211
  """
212
-
213
  if language == "Auto Detect":
214
  language_instruction = "- The podcast MUST be in the same language as the user input."
215
  else:
@@ -229,33 +58,33 @@ Follow this example structure:
229
  """
230
  user_prompt = f"Please generate a podcast script based on the following user input:\n{prompt}"
231
 
232
- messages = [
233
- {"role": "user", "parts": [user_prompt]}
234
- ]
235
-
236
- genai.configure(api_key=api_key)
 
 
 
 
 
 
237
 
238
- generation_config = {
239
- "temperature": 1,
240
- "max_output_tokens": 8192,
241
- "response_mime_type": "application/json",
 
242
  }
243
 
244
- model = genai.GenerativeModel(
245
- model_name="gemini-2.0-flash",
246
- generation_config=generation_config,
247
- safety_settings={
248
- HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,
249
- HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,
250
- HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE,
251
- HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE
252
- },
253
- system_instruction=system_prompt
254
- )
255
-
256
  try:
257
- response = await model.generate_content_async(messages)
 
 
 
 
258
  except Exception as e:
 
259
  if "API key not valid" in str(e):
260
  raise gr.Error("Invalid API key. Please provide a valid Gemini API key.")
261
  elif "rate limit" in str(e).lower():
@@ -263,149 +92,186 @@ Follow this example structure:
263
  else:
264
  raise gr.Error(f"Failed to generate podcast script: {e}")
265
 
266
- print(f"Generated podcast script:\n{response.text}")
267
-
268
- return json.loads(response.text)
 
 
 
 
 
269
 
270
  async def tts_generate(self, text: str, speaker: int, speaker1: str, speaker2: str) -> str:
271
  voice = speaker1 if speaker == 1 else speaker2
272
- speech = edge_tts.Communicate(text, voice)
 
 
 
 
273
 
274
  temp_filename = f"temp_{uuid.uuid4()}.wav"
275
  try:
276
  await speech.save(temp_filename)
277
  return temp_filename
278
  except Exception as e:
 
279
  if os.path.exists(temp_filename):
280
  os.remove(temp_filename)
281
- raise e
282
 
283
- async def combine_audio_files(self, audio_files: List[str]) -> str:
284
- combined_audio = AudioSegment.empty()
285
- for audio_file in audio_files:
286
- combined_audio += AudioSegment.from_file(audio_file)
287
- os.remove(audio_file) # Clean up temporary files
288
-
289
- output_filename = f"output_{uuid.uuid4()}.wav"
290
- combined_audio.export(output_filename, format="wav")
291
- return output_filename
292
-
293
- async def generate_podcast(self, input_text: str, language: str, speaker1: str, speaker2: str, api_key: str) -> str:
294
- gr.Info("Generating podcast script...")
295
- start_time = time.time()
296
- podcast_json = await self.generate_script(input_text, language, api_key)
297
- end_time = time.time()
298
- gr.Info(f"Successfully generated podcast script in {(end_time - start_time):.2f} seconds!")
299
-
300
- gr.Info("Generating podcast audio files...")
301
- start_time = time.time()
302
- audio_files = await asyncio.gather(*[self.tts_generate(item['line'], item['speaker'], speaker1, speaker2) for item in podcast_json['podcast']])
303
- end_time = time.time()
304
- gr.Info(f"Successfully generated podcast audio files in {(end_time - start_time):.2f} seconds!")
305
 
306
- combined_audio = await self.combine_audio_files(audio_files)
307
- return combined_audio
308
-
309
- class TextExtractor:
310
- @staticmethod
311
- async def extract_from_pdf(file_path: str) -> str:
312
- async with aiofiles.open(file_path, 'rb') as file:
313
- content = await file.read()
314
- pdf_reader = pypdf.PdfReader(io.BytesIO(content))
315
- return "\n\n".join(page.extract_text() for page in pdf_reader.pages if page.extract_text())
316
 
317
- @staticmethod
318
- async def extract_from_txt(file_path: str) -> str:
319
- async with aiofiles.open(file_path, 'r') as file:
320
- return await file.read()
 
 
 
 
 
 
 
 
321
 
322
- @classmethod
323
- async def extract_text(cls, file_path: str) -> str:
324
- _, file_extension = os.path.splitext(file_path)
325
- if file_extension.lower() == '.pdf':
326
- return await cls.extract_from_pdf(file_path)
327
- elif file_extension.lower() == '.txt':
328
- return await cls.extract_from_txt(file_path)
329
- else:
330
- raise gr.Error(f"Unsupported file type: {file_extension}")
331
 
332
  async def process_input(input_text: str, input_file, language: str, speaker1: str, speaker2: str, api_key: str = "") -> str:
333
- gr.Info("Starting podcast generation...")
334
- start_time = time.time()
335
-
336
- voice_names = {
337
- "Andrew - English (United States)": "en-US-AndrewMultilingualNeural",
338
- "Ava - English (United States)": "en-US-AvaMultilingualNeural",
339
- "Brian - English (United States)": "en-US-BrianMultilingualNeural",
340
- "Emma - English (United States)": "en-US-EmmaMultilingualNeural",
341
- "Florian - German (Germany)": "de-DE-FlorianMultilingualNeural",
342
- "Seraphina - German (Germany)": "de-DE-SeraphinaMultilingualNeural",
343
- "Remy - French (France)": "fr-FR-RemyMultilingualNeural",
344
- "Vivienne - French (France)": "fr-FR-VivienneMultilingualNeural"
345
- }
346
 
347
- speaker1 = voice_names[speaker1]
348
- speaker2 = voice_names[speaker2]
 
 
 
 
 
 
 
 
349
 
350
- if input_file:
351
- input_text = await TextExtractor.extract_text(input_file.name)
352
 
353
- if not api_key:
354
- api_key = os.getenv("GENAI_API_KEY")
 
 
 
 
 
 
 
 
 
 
 
 
 
355
 
356
- podcast_generator = PodcastGenerator()
357
- podcast = await podcast_generator.generate_podcast(input_text, language, speaker1, speaker2, api_key)
 
 
358
 
359
- end_time = time.time()
360
- gr.Info(f"Successfully generated podcast in {(end_time - start_time):.2f} seconds!")
361
 
362
- return podcast
 
 
 
 
 
363
 
364
- # Define Gradio interface
365
  iface = gr.Interface(
366
  fn=process_input,
367
  inputs=[
368
  gr.Textbox(label="Input Text"),
369
  gr.File(label="Or Upload a PDF or TXT file"),
370
- gr.Dropdown(label="Language", choices=[
371
- "Auto Detect",
372
- "Afrikaans", "Albanian", "Amharic", "Arabic", "Armenian", "Azerbaijani",
373
- "Bahasa Indonesian", "Bangla", "Basque", "Bengali", "Bosnian", "Bulgarian",
374
- "Burmese", "Catalan", "Chinese Cantonese", "Chinese Mandarin",
375
- "Chinese Taiwanese", "Croatian", "Czech", "Danish", "Dutch", "English",
376
- "Estonian", "Filipino", "Finnish", "French", "Galician", "Georgian",
377
- "German", "Greek", "Hebrew", "Hindi", "Hungarian", "Icelandic", "Irish",
378
- "Italian", "Japanese", "Javanese", "Kannada", "Kazakh", "Khmer", "Korean",
379
- "Lao", "Latvian", "Lithuanian", "Macedonian", "Malay", "Malayalam",
380
- "Maltese", "Mongolian", "Nepali", "Norwegian Bokmål", "Pashto", "Persian",
381
- "Polish", "Portuguese", "Romanian", "Russian", "Serbian", "Sinhala",
382
- "Slovak", "Slovene", "Somali", "Spanish", "Sundanese", "Swahili",
383
- "Swedish", "Tamil", "Telugu", "Thai", "Turkish", "Ukrainian", "Urdu",
384
- "Uzbek", "Vietnamese", "Welsh", "Zulu"
385
- ],
386
- value="Auto Detect"),
387
- gr.Dropdown(label="Speaker 1 Voice", choices=[
388
- "Andrew - English (United States)",
389
- "Ava - English (United States)",
390
- "Brian - English (United States)",
391
- "Emma - English (United States)",
392
- "Florian - German (Germany)",
393
- "Seraphina - German (Germany)",
394
- "Remy - French (France)",
395
- "Vivienne - French (France)"
396
- ],
397
- value="Andrew - English (United States)"),
398
- gr.Dropdown(label="Speaker 2 Voice", choices=[
399
- "Andrew - English (United States)",
400
- "Ava - English (United States)",
401
- "Brian - English (United States)",
402
- "Emma - English (United States)",
403
- "Florian - German (Germany)",
404
- "Seraphina - German (Germany)",
405
- "Remy - French (France)",
406
- "Vivienne - French (France)"
407
- ],
408
- value="Ava - English (United States)"),
 
 
 
 
 
 
 
 
 
409
  gr.Textbox(label="Your Gemini API Key (Optional) - In case you are getting rate limited"),
410
  ],
411
  outputs=[
 
1
  import gradio as gr
2
+ import logging
3
  from pydub import AudioSegment
4
+ from google import genai # Using the new Gemini API client
5
+ from google.genai import types # For inline file parts
6
  import json
7
  import uuid
8
  import io
9
  import edge_tts
10
  import asyncio
 
 
11
  import os
12
  import time
13
+ import aiofiles
14
+
15
+ # Set up logging
16
+ logging.basicConfig(level=logging.INFO)
17
+
18
+ # Maximum file size allowed: 20 MB
19
+ MAX_FILE_SIZE = 20 * 1024 * 1024
20
 
21
  class PodcastGenerator:
22
  def __init__(self):
23
  pass
24
 
25
+ async def generate_script(self, prompt: str, language: str, api_key: str, file_data=None, file_mime_type=None) -> dict:
26
  example = """
27
  {
28
  "topic": "AGI",
 
34
  {
35
  "speaker": 1,
36
  "line": "Yeah, it's definitely having a moment, isn't it?"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  }
38
+ // ... (rest of the example)
39
  ]
40
  }
41
  """
 
42
  if language == "Auto Detect":
43
  language_instruction = "- The podcast MUST be in the same language as the user input."
44
  else:
 
58
  """
59
  user_prompt = f"Please generate a podcast script based on the following user input:\n{prompt}"
60
 
61
+ # Initialize the Gemini API client with the provided API key.
62
+ client = genai.Client(api_key=api_key)
63
+ contents = []
64
+ if file_data is not None:
65
+ try:
66
+ # Use inline file data directly without uploading.
67
+ contents.append(types.Part.from_bytes(data=file_data, mime_type=file_mime_type))
68
+ except Exception as e:
69
+ logging.error("Error preparing file part: %s", e)
70
+ raise gr.Error(f"Error processing file data: {e}")
71
+ contents.append(user_prompt)
72
 
73
+ config = {
74
+ "system_instruction": system_prompt,
75
+ "temperature": 1,
76
+ "max_output_tokens": 8192,
77
+ "response_mime_type": "application/json",
78
  }
79
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  try:
81
+ response = await client.aio.models.generate_content(
82
+ model="gemini-2.0-flash",
83
+ contents=contents,
84
+ config=config
85
+ )
86
  except Exception as e:
87
+ logging.error("API call failed: %s", e)
88
  if "API key not valid" in str(e):
89
  raise gr.Error("Invalid API key. Please provide a valid Gemini API key.")
90
  elif "rate limit" in str(e).lower():
 
92
  else:
93
  raise gr.Error(f"Failed to generate podcast script: {e}")
94
 
95
+ try:
96
+ result = json.loads(response.text)
97
+ except json.JSONDecodeError as e:
98
+ logging.error("JSON parsing failed: %s", e)
99
+ raise gr.Error(f"Response is not valid JSON: {e}")
100
+
101
+ logging.info("Successfully generated script: %s", result)
102
+ return result
103
 
104
  async def tts_generate(self, text: str, speaker: int, speaker1: str, speaker2: str) -> str:
105
  voice = speaker1 if speaker == 1 else speaker2
106
+ try:
107
+ speech = edge_tts.Communicate(text, voice)
108
+ except Exception as e:
109
+ logging.error("TTS initialization failed: %s", e)
110
+ raise gr.Error(f"Text-to-Speech initialization error: {e}")
111
 
112
  temp_filename = f"temp_{uuid.uuid4()}.wav"
113
  try:
114
  await speech.save(temp_filename)
115
  return temp_filename
116
  except Exception as e:
117
+ logging.error("TTS generation failed: %s", e)
118
  if os.path.exists(temp_filename):
119
  os.remove(temp_filename)
120
+ raise gr.Error(f"Failed to generate speech for text: {e}")
121
 
122
+ async def combine_audio_files(self, audio_files: list) -> str:
123
+ try:
124
+ combined_audio = AudioSegment.empty()
125
+ for audio_file in audio_files:
126
+ try:
127
+ combined_audio += AudioSegment.from_file(audio_file)
128
+ except Exception as inner_e:
129
+ logging.error("Error processing audio file %s: %s", audio_file, inner_e)
130
+ raise gr.Error(f"Error processing audio file: {inner_e}")
131
+ finally:
132
+ if os.path.exists(audio_file):
133
+ os.remove(audio_file) # Clean up temporary file
134
+ output_filename = f"output_{uuid.uuid4()}.wav"
135
+ combined_audio.export(output_filename, format="wav")
136
+ return output_filename
137
+ except Exception as e:
138
+ logging.error("Failed to combine audio files: %s", e)
139
+ raise gr.Error(f"Failed to combine audio files: {e}")
 
 
 
 
140
 
141
+ async def generate_podcast(self, input_text: str, language: str, speaker1: str, speaker2: str, api_key: str, file_data=None, file_mime_type=None) -> str:
142
+ try:
143
+ gr.Info("Generating podcast script...")
144
+ start_time = time.time()
145
+ podcast_json = await self.generate_script(input_text, language, api_key, file_data, file_mime_type)
146
+ end_time = time.time()
147
+ gr.Info(f"Successfully generated podcast script in {(end_time - start_time):.2f} seconds!")
148
+ except Exception as e:
149
+ logging.error("Script generation error: %s", e)
150
+ raise gr.Error(f"Error generating podcast script: {e}")
151
 
152
+ try:
153
+ gr.Info("Generating podcast audio files...")
154
+ start_time = time.time()
155
+ audio_files = await asyncio.gather(*[
156
+ self.tts_generate(item['line'], item['speaker'], speaker1, speaker2)
157
+ for item in podcast_json.get('podcast', [])
158
+ ])
159
+ end_time = time.time()
160
+ gr.Info(f"Successfully generated podcast audio files in {(end_time - start_time):.2f} seconds!")
161
+ except Exception as e:
162
+ logging.error("TTS generation error: %s", e)
163
+ raise gr.Error(f"Error generating audio files: {e}")
164
 
165
+ try:
166
+ combined_audio = await self.combine_audio_files(audio_files)
167
+ return combined_audio
168
+ except Exception as e:
169
+ logging.error("Audio combining error: %s", e)
170
+ raise gr.Error(f"Error combining audio files: {e}")
 
 
 
171
 
172
  async def process_input(input_text: str, input_file, language: str, speaker1: str, speaker2: str, api_key: str = "") -> str:
173
+ try:
174
+ gr.Info("Starting podcast generation...")
175
+ start_time = time.time()
 
 
 
 
 
 
 
 
 
 
176
 
177
+ voice_names = {
178
+ "Andrew - English (United States)": "en-US-AndrewMultilingualNeural",
179
+ "Ava - English (United States)": "en-US-AvaMultilingualNeural",
180
+ "Brian - English (United States)": "en-US-BrianMultilingualNeural",
181
+ "Emma - English (United States)": "en-US-EmmaMultilingualNeural",
182
+ "Florian - German (Germany)": "de-DE-FlorianMultilingualNeural",
183
+ "Seraphina - German (Germany)": "de-DE-SeraphinaMultilingualNeural",
184
+ "Remy - French (France)": "fr-FR-RemyMultilingualNeural",
185
+ "Vivienne - French (France)": "fr-FR-VivienneMultilingualNeural"
186
+ }
187
 
188
+ speaker1 = voice_names.get(speaker1, speaker1)
189
+ speaker2 = voice_names.get(speaker2, speaker2)
190
 
191
+ file_data = None
192
+ file_mime_type = None
193
+ if input_file:
194
+ ext = os.path.splitext(input_file.name)[1].lower()
195
+ if ext not in ['.pdf', '.txt']:
196
+ raise gr.Error("Unsupported file type. Only PDF and TXT files are allowed.")
197
+ try:
198
+ async with aiofiles.open(input_file.name, 'rb') as f:
199
+ file_data = await f.read()
200
+ except Exception as e:
201
+ logging.error("Error reading file: %s", e)
202
+ raise gr.Error(f"Error reading file: {e}")
203
+ if len(file_data) > MAX_FILE_SIZE:
204
+ raise gr.Error("File size exceeds 20MB limit.")
205
+ file_mime_type = 'application/pdf' if ext == '.pdf' else 'text/plain'
206
 
207
+ if not api_key:
208
+ api_key = os.getenv("GENAI_API_KEY")
209
+ if not api_key:
210
+ raise gr.Error("No API key provided and none found in the environment.")
211
 
212
+ podcast_generator = PodcastGenerator()
213
+ podcast = await podcast_generator.generate_podcast(input_text, language, speaker1, speaker2, api_key, file_data, file_mime_type)
214
 
215
+ end_time = time.time()
216
+ gr.Info(f"Successfully generated podcast in {(end_time - start_time):.2f} seconds!")
217
+ return podcast
218
+ except Exception as e:
219
+ logging.error("Process input error: %s", e)
220
+ raise gr.Error(f"Error in processing input: {e}")
221
 
 
222
  iface = gr.Interface(
223
  fn=process_input,
224
  inputs=[
225
  gr.Textbox(label="Input Text"),
226
  gr.File(label="Or Upload a PDF or TXT file"),
227
+ gr.Dropdown(
228
+ label="Language",
229
+ choices=[
230
+ "Auto Detect",
231
+ "Afrikaans", "Albanian", "Amharic", "Arabic", "Armenian", "Azerbaijani",
232
+ "Bahasa Indonesian", "Bangla", "Basque", "Bengali", "Bosnian", "Bulgarian",
233
+ "Burmese", "Catalan", "Chinese Cantonese", "Chinese Mandarin",
234
+ "Chinese Taiwanese", "Croatian", "Czech", "Danish", "Dutch", "English",
235
+ "Estonian", "Filipino", "Finnish", "French", "Galician", "Georgian",
236
+ "German", "Greek", "Hebrew", "Hindi", "Hungarian", "Icelandic", "Irish",
237
+ "Italian", "Japanese", "Javanese", "Kannada", "Kazakh", "Khmer", "Korean",
238
+ "Lao", "Latvian", "Lithuanian", "Macedonian", "Malay", "Malayalam",
239
+ "Maltese", "Mongolian", "Nepali", "Norwegian Bokmål", "Pashto", "Persian",
240
+ "Polish", "Portuguese", "Romanian", "Russian", "Serbian", "Sinhala",
241
+ "Slovak", "Slovene", "Somali", "Spanish", "Sundanese", "Swahili",
242
+ "Swedish", "Tamil", "Telugu", "Thai", "Turkish", "Ukrainian", "Urdu",
243
+ "Uzbek", "Vietnamese", "Welsh", "Zulu"
244
+ ],
245
+ value="Auto Detect"
246
+ ),
247
+ gr.Dropdown(
248
+ label="Speaker 1 Voice",
249
+ choices=[
250
+ "Andrew - English (United States)",
251
+ "Ava - English (United States)",
252
+ "Brian - English (United States)",
253
+ "Emma - English (United States)",
254
+ "Florian - German (Germany)",
255
+ "Seraphina - German (Germany)",
256
+ "Remy - French (France)",
257
+ "Vivienne - French (France)"
258
+ ],
259
+ value="Andrew - English (United States)"
260
+ ),
261
+ gr.Dropdown(
262
+ label="Speaker 2 Voice",
263
+ choices=[
264
+ "Andrew - English (United States)",
265
+ "Ava - English (United States)",
266
+ "Brian - English (United States)",
267
+ "Emma - English (United States)",
268
+ "Florian - German (Germany)",
269
+ "Seraphina - German (Germany)",
270
+ "Remy - French (France)",
271
+ "Vivienne - French (France)"
272
+ ],
273
+ value="Ava - English (United States)"
274
+ ),
275
  gr.Textbox(label="Your Gemini API Key (Optional) - In case you are getting rate limited"),
276
  ],
277
  outputs=[