aheedsajid commited on
Commit
e19b042
·
verified ·
1 Parent(s): d4d0839

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +30 -108
app.py CHANGED
@@ -10,14 +10,11 @@ import uuid
10
  from dotenv import load_dotenv
11
  import re
12
 
13
-
14
  load_dotenv()
15
 
16
  def sanitize_filename(filename):
17
  """Convert a string to a safe filename by removing special characters and spaces"""
18
-
19
  safe_filename = re.sub(r'[^a-zA-Z0-9_-]', '', filename.replace(' ', '_'))
20
-
21
  return safe_filename.lower()[:50]
22
 
23
  async def get_voices():
@@ -28,7 +25,6 @@ async def get_voices():
28
  if voice["Locale"].startswith(("en-US", "en-GB", "en-AU", "en-CA", "en-IN"))
29
  ]
30
 
31
-
32
  formatted_voices = [
33
  f"{voice['ShortName']} ({voice['Gender']}, {voice['Locale']})"
34
  for voice in english_voices
@@ -44,87 +40,54 @@ async def generate_audio(text, voice, filename):
44
  communicate = edge_tts.Communicate(text, extract_voice_name(voice))
45
  await communicate.save(filename)
46
 
47
- async def create_podcast_versions(data, speaker1_name, speaker2_name, speaker1_voice, speaker2_voice, title):
48
-
49
  session_id = str(uuid.uuid4())
50
  temp_dir = f'temp_{session_id}'
51
-
52
-
53
  safe_title = sanitize_filename(title)
54
 
55
-
56
  if not os.path.exists(temp_dir):
57
  os.makedirs(temp_dir)
58
 
59
  try:
60
-
61
- speaker1_version = AudioSegment.empty()
62
- speaker2_version = AudioSegment.empty()
63
  combined_version = AudioSegment.empty()
64
 
65
-
66
  for i, entry in enumerate(data['conversation']):
67
- if 'speaker1text' in entry:
68
- temp_file = f'{temp_dir}/speaker1_{i}.mp3'
69
- await generate_audio(entry['speaker1text'], speaker1_voice, temp_file)
70
  audio = AudioSegment.from_file(temp_file)
71
-
72
- speaker1_version += audio
73
- speaker2_version += AudioSegment.silent(duration=len(audio))
74
  combined_version += audio
75
  os.remove(temp_file)
76
-
77
- if 'speaker2text' in entry:
78
- temp_file = f'{temp_dir}/speaker2_{i}.mp3'
79
- await generate_audio(entry['speaker2text'], speaker2_voice, temp_file)
80
- audio = AudioSegment.from_file(temp_file)
81
-
82
- speaker2_version += audio
83
- speaker1_version += AudioSegment.silent(duration=len(audio))
84
- combined_version += audio
85
- os.remove(temp_file)
86
-
87
-
88
- speaker1_path = f"{safe_title}_{speaker1_name.lower()}_only.mp3"
89
- speaker2_path = f"{safe_title}_{speaker2_name.lower()}_only.mp3"
90
- combined_path = f"{safe_title}_combined.mp3"
91
 
92
- speaker1_version.export(speaker1_path, format="mp3")
93
- speaker2_version.export(speaker2_path, format="mp3")
94
- combined_version.export(combined_path, format="mp3")
95
 
96
- return speaker1_path, speaker2_path, combined_path, temp_dir
97
 
98
  except Exception as e:
99
  if os.path.exists(temp_dir):
100
  shutil.rmtree(temp_dir)
101
  raise e
102
 
103
- def generate_podcast(title, channel_name, speaker1_name, speaker2_name, speaker1_voice, speaker2_voice):
104
  try:
105
-
106
- if not all([title, channel_name, speaker1_name, speaker2_name, speaker1_voice, speaker2_voice]):
107
  raise ValueError("All fields must be filled out")
108
 
109
-
110
  client = Client(os.getenv('API_URL'))
111
  result = client.predict(
112
  message=f"""{os.getenv('API_MESSAGE')} {{
113
  "title": "{title}",
114
  "channel": "{channel_name}",
115
- "speaker1": "{speaker1_name}",
116
- "speaker2": "{speaker2_name}",
117
  "conversation": [
118
  {{
119
- "speaker1text": ""
120
- }},
121
- {{
122
- "speaker2text": ""
123
  }}
124
  ]
125
  }}
126
 
127
- give 36 sentences for both.
128
  """,
129
  request=os.getenv('API_REQUEST'),
130
  param_3=0.5,
@@ -134,12 +97,9 @@ def generate_podcast(title, channel_name, speaker1_name, speaker2_name, speaker1
134
  api_name="/chat"
135
  )
136
 
137
-
138
  try:
139
-
140
  podcast_data = json.loads(result)
141
  except json.JSONDecodeError:
142
-
143
  json_start = result.find('```') + 3
144
  json_end = result.rfind('```')
145
 
@@ -151,44 +111,28 @@ def generate_podcast(title, channel_name, speaker1_name, speaker2_name, speaker1
151
  else:
152
  raise ValueError("Could not parse JSON from response")
153
 
154
-
155
- speaker1_path, speaker2_path, combined_path, temp_dir = asyncio.run(
156
- create_podcast_versions(
157
  podcast_data,
158
- speaker1_name,
159
- speaker2_name,
160
- speaker1_voice,
161
- speaker2_voice,
162
  title
163
  )
164
  )
165
 
166
-
167
  if os.path.exists(temp_dir):
168
  shutil.rmtree(temp_dir)
169
 
170
- return [
171
- speaker1_path,
172
- speaker2_path,
173
- combined_path,
174
- podcast_data
175
- ]
176
 
177
  except Exception as e:
178
- return [
179
- None,
180
- None,
181
- None,
182
- f"Error: {str(e)}"
183
- ]
184
-
185
 
186
  with gr.Blocks(theme=gr.themes.Soft()) as interface:
187
-
188
  available_voices = asyncio.run(get_voices())
189
 
190
  gr.Markdown("# Easy Podcast")
191
- gr.Markdown("Generate a podcast conversation between two speakers on any topic. Choose voices and customize speaker details to create your perfect podcast.<br>To use elevelabs voices or cloned voices, or to automate the podcast video creation with avatar contact me at aheedsajid@gmail.com<br>Support me USDT (TRC-20) (TAe7hsSVWtMEYz3G5V1UiUdYPQVqm28bKx)")
192
 
193
  with gr.Row():
194
  with gr.Column():
@@ -203,43 +147,25 @@ with gr.Blocks(theme=gr.themes.Soft()) as interface:
203
  value="WeePakistan",
204
  show_label=True
205
  )
 
 
206
  with gr.Column():
207
- speaker1_name = gr.Textbox(
208
- label="First Speaker Name",
209
  placeholder="e.g., John",
210
  value="Andrew",
211
  show_label=True
212
  )
213
- speaker2_name = gr.Textbox(
214
- label="Second Speaker Name",
215
- placeholder="e.g., Sarah",
216
- value="Priya",
217
- show_label=True
218
- )
219
-
220
- with gr.Row():
221
- with gr.Column():
222
- speaker1_voice = gr.Dropdown(
223
  choices=available_voices,
224
  value=next((v for v in available_voices if "Andrew" in v), available_voices[0]),
225
- label="First Speaker Voice",
226
- info="Select voice for the first speaker"
227
- )
228
- with gr.Column():
229
- speaker2_voice = gr.Dropdown(
230
- choices=available_voices,
231
- value=next((v for v in available_voices if "Ava" in v), available_voices[0]),
232
- label="Second Speaker Voice",
233
- info="Select voice for the second speaker"
234
  )
235
 
236
  generate_btn = gr.Button("Generate Podcast", variant="primary")
237
 
238
- with gr.Row():
239
- speaker1_audio = gr.Audio(label="First Speaker Audio")
240
- speaker2_audio = gr.Audio(label="Second Speaker Audio")
241
- combined_audio = gr.Audio(label="Combined Audio")
242
-
243
  conversation_json = gr.JSON(label="Generated Conversation")
244
 
245
  generate_btn.click(
@@ -247,15 +173,11 @@ with gr.Blocks(theme=gr.themes.Soft()) as interface:
247
  inputs=[
248
  title,
249
  channel_name,
250
- speaker1_name,
251
- speaker2_name,
252
- speaker1_voice,
253
- speaker2_voice
254
  ],
255
  outputs=[
256
- speaker1_audio,
257
- speaker2_audio,
258
- combined_audio,
259
  conversation_json
260
  ]
261
  )
 
10
  from dotenv import load_dotenv
11
  import re
12
 
 
13
  load_dotenv()
14
 
15
  def sanitize_filename(filename):
16
  """Convert a string to a safe filename by removing special characters and spaces"""
 
17
  safe_filename = re.sub(r'[^a-zA-Z0-9_-]', '', filename.replace(' ', '_'))
 
18
  return safe_filename.lower()[:50]
19
 
20
  async def get_voices():
 
25
  if voice["Locale"].startswith(("en-US", "en-GB", "en-AU", "en-CA", "en-IN"))
26
  ]
27
 
 
28
  formatted_voices = [
29
  f"{voice['ShortName']} ({voice['Gender']}, {voice['Locale']})"
30
  for voice in english_voices
 
40
  communicate = edge_tts.Communicate(text, extract_voice_name(voice))
41
  await communicate.save(filename)
42
 
43
+ async def create_podcast_version(data, speaker_name, speaker_voice, title):
 
44
  session_id = str(uuid.uuid4())
45
  temp_dir = f'temp_{session_id}'
 
 
46
  safe_title = sanitize_filename(title)
47
 
 
48
  if not os.path.exists(temp_dir):
49
  os.makedirs(temp_dir)
50
 
51
  try:
 
 
 
52
  combined_version = AudioSegment.empty()
53
 
 
54
  for i, entry in enumerate(data['conversation']):
55
+ if 'speakertext' in entry:
56
+ temp_file = f'{temp_dir}/speaker_{i}.mp3'
57
+ await generate_audio(entry['speakertext'], speaker_voice, temp_file)
58
  audio = AudioSegment.from_file(temp_file)
 
 
 
59
  combined_version += audio
60
  os.remove(temp_file)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
+ output_path = f"{safe_title}_{speaker_name.lower()}.mp3"
63
+ combined_version.export(output_path, format="mp3")
 
64
 
65
+ return output_path, temp_dir
66
 
67
  except Exception as e:
68
  if os.path.exists(temp_dir):
69
  shutil.rmtree(temp_dir)
70
  raise e
71
 
72
+ def generate_podcast(title, channel_name, speaker_name, speaker_voice):
73
  try:
74
+ if not all([title, channel_name, speaker_name, speaker_voice]):
 
75
  raise ValueError("All fields must be filled out")
76
 
 
77
  client = Client(os.getenv('API_URL'))
78
  result = client.predict(
79
  message=f"""{os.getenv('API_MESSAGE')} {{
80
  "title": "{title}",
81
  "channel": "{channel_name}",
82
+ "speaker": "{speaker_name}",
 
83
  "conversation": [
84
  {{
85
+ "speakertext": ""
 
 
 
86
  }}
87
  ]
88
  }}
89
 
90
+ give 36 sentences.
91
  """,
92
  request=os.getenv('API_REQUEST'),
93
  param_3=0.5,
 
97
  api_name="/chat"
98
  )
99
 
 
100
  try:
 
101
  podcast_data = json.loads(result)
102
  except json.JSONDecodeError:
 
103
  json_start = result.find('```') + 3
104
  json_end = result.rfind('```')
105
 
 
111
  else:
112
  raise ValueError("Could not parse JSON from response")
113
 
114
+ audio_path, temp_dir = asyncio.run(
115
+ create_podcast_version(
 
116
  podcast_data,
117
+ speaker_name,
118
+ speaker_voice,
 
 
119
  title
120
  )
121
  )
122
 
 
123
  if os.path.exists(temp_dir):
124
  shutil.rmtree(temp_dir)
125
 
126
+ return [audio_path, podcast_data]
 
 
 
 
 
127
 
128
  except Exception as e:
129
+ return [None, f"Error: {str(e)}"]
 
 
 
 
 
 
130
 
131
  with gr.Blocks(theme=gr.themes.Soft()) as interface:
 
132
  available_voices = asyncio.run(get_voices())
133
 
134
  gr.Markdown("# Easy Podcast")
135
+ gr.Markdown("Generate a podcast monologue on any topic. Choose a voice and customize speaker details to create your perfect podcast.<br>To use elevelabs voices or cloned voices, or to automate the podcast video creation with avatar contact me at aheedsajid@gmail.com<br>Support me USDT (TRC-20) (TAe7hsSVWtMEYz3G5V1UiUdYPQVqm28bKx)")
136
 
137
  with gr.Row():
138
  with gr.Column():
 
147
  value="WeePakistan",
148
  show_label=True
149
  )
150
+
151
+ with gr.Row():
152
  with gr.Column():
153
+ speaker_name = gr.Textbox(
154
+ label="Speaker Name",
155
  placeholder="e.g., John",
156
  value="Andrew",
157
  show_label=True
158
  )
159
+ speaker_voice = gr.Dropdown(
 
 
 
 
 
 
 
 
 
160
  choices=available_voices,
161
  value=next((v for v in available_voices if "Andrew" in v), available_voices[0]),
162
+ label="Speaker Voice",
163
+ info="Select voice for the speaker"
 
 
 
 
 
 
 
164
  )
165
 
166
  generate_btn = gr.Button("Generate Podcast", variant="primary")
167
 
168
+ audio_output = gr.Audio(label="Generated Audio")
 
 
 
 
169
  conversation_json = gr.JSON(label="Generated Conversation")
170
 
171
  generate_btn.click(
 
173
  inputs=[
174
  title,
175
  channel_name,
176
+ speaker_name,
177
+ speaker_voice
 
 
178
  ],
179
  outputs=[
180
+ audio_output,
 
 
181
  conversation_json
182
  ]
183
  )