SohomToom commited on
Commit
8fd86b6
·
verified ·
1 Parent(s): e2fd223

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +75 -69
app.py CHANGED
@@ -10,6 +10,11 @@ import zipfile
10
  from io import BytesIO
11
  import re
12
 
 
 
 
 
 
13
  # Voice model
14
  VOICE_MODEL = "tts_models/en/vctk/vits"
15
 
@@ -106,87 +111,88 @@ SPEAKER_METADATA = {
106
  273: { "age": 18, "gender": "F", "accent": "English"}
107
  }
108
 
 
 
 
 
 
 
 
 
 
 
 
109
 
 
 
110
 
111
- # Static list of speakers for dropdown
112
- SPEAKER_CHOICES = [
113
- f"{sid} - {data['gender']} - {data['accent']} (Age {data['age']})"
114
- for sid, data in SPEAKER_METADATA.items()
115
- ]
116
-
117
- # VCTK model (multi-speaker)
118
- MODEL_NAME = "tts_models/en/vctk/vits"
119
- tts = TTS(model_name=MODEL_NAME, progress_bar=False, gpu=False)
120
-
121
- # Extract plain text from docx, ignoring hyperlinks
122
- def extract_text_ignoring_hyperlinks(docx_file):
123
- doc = Document(docx_file.name)
124
- text_blocks = []
125
- for para in doc.paragraphs:
126
- # Remove hyperlinks using regex or by inspecting runs
127
- if para.text.strip():
128
- clean_text = re.sub(r'https?://\S+', '', para.text)
129
- text_blocks.append(clean_text.strip())
130
- return text_blocks
131
-
132
- # Generate sample audio for preview
133
- def generate_sample_audio(sample_text, selected_speaker):
134
- if not sample_text.strip():
135
- raise gr.Error("Sample text cannot be empty.")
136
- sid = selected_speaker.split(" ")[0] # Extract speaker ID
137
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_wav:
138
- tts.tts_to_file(text=sample_text, speaker="p"+sid, file_path=tmp_wav.name)
139
  return tmp_wav.name
140
 
141
- # Main conversion function
142
- def docx_to_zipped_wavs(doc_file, selected_speaker):
143
- sid = selected_speaker.split(" ")[0]
144
- paragraphs = extract_text_ignoring_hyperlinks(doc_file)
145
- audio_files = []
 
 
 
146
  try:
147
- for i, para in enumerate(paragraphs):
148
- if not para:
149
- continue
150
- with tempfile.NamedTemporaryFile(suffix=f"_{i}.wav", delete=False) as tmp_wav:
151
- tts.tts_to_file(text=para, speaker="p"+sid, file_path=tmp_wav.name)
152
- audio_files.append(tmp_wav.name)
 
 
153
  except Exception as e:
154
- print("Connection interrupted, returning partial result.", str(e))
155
-
156
- # Zip the results
157
- zip_buffer = BytesIO()
158
- with zipfile.ZipFile(zip_buffer, "w") as zipf:
159
- for wav_path in audio_files:
160
- zipf.write(wav_path, arcname=os.path.basename(wav_path))
161
- zip_buffer.seek(0)
162
-
163
- # Save the zip temporarily for download
164
- final_zip = tempfile.NamedTemporaryFile(delete=False, suffix=".zip")
165
- final_zip.write(zip_buffer.read())
166
- final_zip.close()
167
- return final_zip.name
168
-
169
- # Gradio UI
170
- with gr.Blocks() as interface:
171
- gr.Markdown("""# Multi-Paragraph Voiceover Generator
172
- Upload a `.docx` file and convert each paragraph to audio. You can also try a short sample first.
173
- """)
174
 
175
- with gr.Row():
176
- #sample_text = gr.Textbox(label="Sample Text (Max 500 chars)", max_lines=4, lines=3, max_length=500)
177
- speaker_dropdown = gr.Dropdown(label="Select Speaker", choices=SPEAKER_CHOICES, value=SPEAKER_CHOICES[0])
 
 
 
 
178
 
179
- # sample_button = gr.Button("Generate Sample Audio")
180
- # sample_audio = gr.Audio(label="Sample Audio", type="filepath")
 
 
 
 
 
 
 
 
 
 
 
181
 
182
  with gr.Row():
183
- docx_input = gr.File(label="Upload .docx File", type="filepath")
184
- convert_button = gr.Button("Generate WAV Zip")
 
185
 
186
- final_output = gr.File(label="Download ZIP of WAVs")
187
 
188
- # sample_button.click(fn=generate_sample_audio, inputs=[sample_text, speaker_dropdown], outputs=sample_audio)
189
- convert_button.click(fn=docx_to_zipped_wavs, inputs=[docx_input, speaker_dropdown], outputs=final_output)
 
 
 
 
 
 
 
190
 
191
  if __name__ == "__main__":
192
- interface.launch()
 
 
 
10
  from io import BytesIO
11
  import re
12
 
13
+ from pydub import AudioSegment
14
+
15
+ final_audio = AudioSegment.empty()
16
+
17
+
18
  # Voice model
19
  VOICE_MODEL = "tts_models/en/vctk/vits"
20
 
 
111
  273: { "age": 18, "gender": "F", "accent": "English"}
112
  }
113
 
114
+ def clean_text(text):
115
+ # Remove hyperlinks
116
+ return re.sub(r'http[s]?://\S+', '', text)
117
+
118
+ def extract_paragraphs_from_docx(docx_file):
119
+ document = Document(docx_file.name)
120
+ paragraphs = [p.text.strip() for p in document.paragraphs if p.text.strip()]
121
+ return [clean_text(p) for p in paragraphs]
122
+
123
+ def list_speaker_choices():
124
+ return [f"{sid} | {meta['gender']} | {meta['accent']}" for sid, meta in speaker_metadata.items()]
125
 
126
+ def get_speaker_id_from_label(label):
127
+ return label.split('|')[0].strip()
128
 
129
+ def generate_sample_audio(sample_text, speaker_label):
130
+ speaker_id = get_speaker_id_from_label(speaker_label)
131
+ model = TTS("tts_models/multilingual/multi-dataset/your_model")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp_wav:
133
+ model.tts_to_file(text=sample_text, speaker="p"+speaker_id, file_path=tmp_wav.name)
134
  return tmp_wav.name
135
 
136
+ def generate_audio(docx_file, speaker_label):
137
+ speaker_id = get_speaker_id_from_label(speaker_label)
138
+ model = TTS("tts_models/multilingual/multi-dataset/your_model")
139
+
140
+ paragraphs = extract_paragraphs_from_docx(docx_file)
141
+ combined_audio = AudioSegment.empty()
142
+ temp_files = []
143
+
144
  try:
145
+ for idx, para in enumerate(paragraphs):
146
+ tmp = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)
147
+ model.tts_to_file(text=para, speaker="p"+speaker_id, file_path=tmp.name)
148
+ audio_chunk = AudioSegment.from_wav(tmp.name)
149
+ combined_audio += audio_chunk
150
+ temp_files.append(tmp.name)
151
+ tmp.close()
152
+
153
  except Exception as e:
154
+ print("Generation interrupted. Saving partial output.", e)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
+ output_dir = tempfile.mkdtemp()
157
+ final_output_path = os.path.join(output_dir, "final_output.wav")
158
+ combined_audio.export(final_output_path, format="wav")
159
+
160
+ zip_path = os.path.join(output_dir, "output.zip")
161
+ with zipfile.ZipFile(zip_path, 'w') as zipf:
162
+ zipf.write(final_output_path, arcname="final_output.wav")
163
 
164
+ for f in temp_files:
165
+ os.remove(f)
166
+
167
+ return zip_path
168
+
169
+ # --- UI ---
170
+ speaker_choices = list_speaker_choices()
171
+
172
+ with gr.Blocks() as demo:
173
+ gr.Markdown("## 📄 TTS Voice Generator with Paragraph-Wise Processing")
174
+
175
+ with gr.Row():
176
+ speaker_dropdown = gr.Dropdown(label="Select Voice", choices=speaker_choices)
177
 
178
  with gr.Row():
179
+ sample_textbox = gr.Textbox(label="Enter Sample Text (Max 500 characters)", max_lines=5, max_chars=500)
180
+ sample_button = gr.Button("Generate Sample")
181
+ clear_button = gr.Button("Clear Sample")
182
 
183
+ sample_audio = gr.Audio(label="Sample Output", type="filepath")
184
 
185
+ sample_button.click(fn=generate_sample_audio, inputs=[sample_textbox, speaker_dropdown], outputs=[sample_audio])
186
+ clear_button.click(fn=lambda: None, inputs=[], outputs=[sample_audio])
187
+
188
+ with gr.Row():
189
+ docx_input = gr.File(label="Upload DOCX File", file_types=[".docx"])
190
+ generate_button = gr.Button("Generate Full Audio")
191
+ download_output = gr.File(label="Download Output Zip")
192
+
193
+ generate_button.click(fn=generate_audio, inputs=[docx_input, speaker_dropdown], outputs=[download_output])
194
 
195
  if __name__ == "__main__":
196
+ demo.launch()
197
+
198
+