Spaces:
Running
Running
drewThomasson
commited on
Commit
•
4a45bb8
1
Parent(s):
a105e1c
Update app.py
Browse files
app.py
CHANGED
@@ -2,12 +2,38 @@ print("starting...")
|
|
2 |
|
3 |
import argparse
|
4 |
|
5 |
-
|
6 |
-
|
7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
args = parser.parse_args()
|
9 |
|
10 |
|
|
|
11 |
import os
|
12 |
import shutil
|
13 |
import subprocess
|
@@ -15,7 +41,6 @@ import re
|
|
15 |
from pydub import AudioSegment
|
16 |
import tempfile
|
17 |
from pydub import AudioSegment
|
18 |
-
import os
|
19 |
import nltk
|
20 |
from nltk.tokenize import sent_tokenize
|
21 |
import sys
|
@@ -162,15 +187,24 @@ def create_m4b_from_chapters(input_dir, ebook_file, output_dir):
|
|
162 |
except Exception as e:
|
163 |
print(f"Error extracting eBook metadata or cover: {e}")
|
164 |
return None
|
165 |
-
|
166 |
-
def combine_wav_files(chapter_files, output_path):
|
167 |
# Initialize an empty audio segment
|
168 |
combined_audio = AudioSegment.empty()
|
169 |
-
|
170 |
-
#
|
171 |
-
for
|
172 |
-
|
173 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
# Export the combined audio to the output file path
|
175 |
combined_audio.export(output_path, format='wav')
|
176 |
print(f"Combined audio saved to {output_path}")
|
@@ -234,7 +268,7 @@ def create_m4b_from_chapters(input_dir, ebook_file, output_dir):
|
|
234 |
|
235 |
|
236 |
|
237 |
-
#this code right here isnt the book grabbing thing but its before to refrence in
|
238 |
import os
|
239 |
import subprocess
|
240 |
import ebooklib
|
@@ -682,78 +716,99 @@ def download_audiobooks():
|
|
682 |
return list_audiobook_files(audiobook_output_path)
|
683 |
|
684 |
|
685 |
-
language_options = [
|
686 |
-
"en", "es", "fr", "de", "it", "pt", "pl", "tr", "ru", "nl", "cs", "ar", "zh-cn", "ja", "hu", "ko"
|
687 |
-
]
|
688 |
-
|
689 |
-
theme = gr.themes.Soft(
|
690 |
-
primary_hue="blue",
|
691 |
-
secondary_hue="blue",
|
692 |
-
neutral_hue="blue",
|
693 |
-
text_size=gr.themes.sizes.text_md,
|
694 |
-
)
|
695 |
-
|
696 |
# Gradio UI setup
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
with gr.Row():
|
709 |
-
with gr.Column(scale=3):
|
710 |
-
ebook_file = gr.File(label="eBook File")
|
711 |
-
target_voice_file = gr.File(label="Target Voice File (Optional)")
|
712 |
-
language = gr.Dropdown(label="Language", choices=language_options, value="en")
|
713 |
-
|
714 |
-
with gr.Column(scale=3):
|
715 |
-
use_custom_model = gr.Checkbox(label="Use Custom Model")
|
716 |
-
custom_model_file = gr.File(label="Custom Model File (Optional)", visible=False)
|
717 |
-
custom_config_file = gr.File(label="Custom Config File (Optional)", visible=False)
|
718 |
-
custom_vocab_file = gr.File(label="Custom Vocab File (Optional)", visible=False)
|
719 |
-
custom_model_url = gr.Textbox(label="Custom Model Zip URL (Optional)", visible=False)
|
720 |
-
|
721 |
-
convert_btn = gr.Button("Convert to Audiobook", variant="primary")
|
722 |
-
output = gr.Textbox(label="Conversion Status")
|
723 |
-
audio_player = gr.Audio(label="Audiobook Player", type="filepath")
|
724 |
-
download_btn = gr.Button("Download Audiobook Files")
|
725 |
-
download_files = gr.File(label="Download Files", interactive=False)
|
726 |
-
|
727 |
-
convert_btn.click(
|
728 |
-
convert_ebook_to_audio,
|
729 |
-
inputs=[ebook_file, target_voice_file, language, use_custom_model, custom_model_file, custom_config_file, custom_vocab_file, custom_model_url],
|
730 |
-
outputs=[output, audio_player]
|
731 |
-
)
|
732 |
-
|
733 |
-
use_custom_model.change(
|
734 |
-
lambda x: [gr.update(visible=x)] * 4,
|
735 |
-
inputs=[use_custom_model],
|
736 |
-
outputs=[custom_model_file, custom_config_file, custom_vocab_file, custom_model_url]
|
737 |
-
)
|
738 |
-
|
739 |
-
download_btn.click(
|
740 |
-
download_audiobooks,
|
741 |
-
outputs=[download_files]
|
742 |
)
|
743 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
744 |
|
|
|
|
|
|
|
|
|
|
|
|
|
745 |
|
|
|
|
|
746 |
|
747 |
-
|
748 |
-
#
|
749 |
-
|
750 |
-
# Get the correct local IP or localhost
|
751 |
-
hostname = socket.gethostname()
|
752 |
-
local_ip = socket.gethostbyname(hostname)
|
753 |
-
|
754 |
-
# Ensure Gradio runs and prints the correct local IP
|
755 |
-
print(f"Running on local URL: http://{local_ip}:7860")
|
756 |
-
print(f"Running on local URL: http://localhost:7860")
|
757 |
-
|
758 |
-
# Your Gradio launch command
|
759 |
-
demo.launch(server_name="0.0.0.0", server_port=7860, share=args.share)
|
|
|
2 |
|
3 |
import argparse
|
4 |
|
5 |
+
language_options = [
|
6 |
+
"en", "es", "fr", "de", "it", "pt", "pl", "tr", "ru", "nl", "cs", "ar", "zh-cn", "ja", "hu", "ko"
|
7 |
+
]
|
8 |
+
|
9 |
+
# Convert the list of languages to a string to display in the help text
|
10 |
+
language_options_str = ", ".join(language_options)
|
11 |
+
|
12 |
+
# Argument parser to handle optional parameters with descriptions
|
13 |
+
parser = argparse.ArgumentParser(
|
14 |
+
description="Convert eBooks to Audiobooks using a Text-to-Speech model. You can either launch the Gradio interface or run the script in headless mode for direct conversion.",
|
15 |
+
epilog="Example: python script.py --headless --ebook path_to_ebook --voice path_to_voice --language en --use_custom_model True --custom_model model.pth --custom_config config.json --custom_vocab vocab.json"
|
16 |
+
)
|
17 |
+
parser.add_argument("--share", type=bool, default=False, help="Set to True to enable a public shareable Gradio link. Defaults to False.")
|
18 |
+
parser.add_argument("--headless", type=bool, default=False, help="Set to True to run in headless mode without the Gradio interface. Defaults to False.")
|
19 |
+
parser.add_argument("--ebook", type=str, help="Path to the ebook file for conversion. Required in headless mode.")
|
20 |
+
parser.add_argument("--voice", type=str, help="Path to the target voice file for TTS. Optional, uses a default voice if not provided.")
|
21 |
+
parser.add_argument("--language", type=str, default="en",
|
22 |
+
help=f"Language for the audiobook conversion. Options: {language_options_str}. Defaults to English (en).")
|
23 |
+
parser.add_argument("--use_custom_model", type=bool, default=False,
|
24 |
+
help="Set to True to use a custom TTS model. Defaults to False. Must be True to use custom models, otherwise you'll get an error.")
|
25 |
+
parser.add_argument("--custom_model", type=str, help="Path to the custom model file (.pth). Required if using a custom model.")
|
26 |
+
parser.add_argument("--custom_config", type=str, help="Path to the custom config file (config.json). Required if using a custom model.")
|
27 |
+
parser.add_argument("--custom_vocab", type=str, help="Path to the custom vocab file (vocab.json). Required if using a custom model.")
|
28 |
+
parser.add_argument("--custom_model_url", type=str,
|
29 |
+
help=("URL to download the custom model as a zip file. Optional, but will be used if provided. "
|
30 |
+
"Examples include David Attenborough's model: "
|
31 |
+
"'https://huggingface.co/drewThomasson/xtts_David_Attenborough_fine_tune/resolve/main/Finished_model_files.zip?download=true'. "
|
32 |
+
"More XTTS fine-tunes can be found on my Hugging Face at 'https://huggingface.co/drewThomasson'."))
|
33 |
args = parser.parse_args()
|
34 |
|
35 |
|
36 |
+
|
37 |
import os
|
38 |
import shutil
|
39 |
import subprocess
|
|
|
41 |
from pydub import AudioSegment
|
42 |
import tempfile
|
43 |
from pydub import AudioSegment
|
|
|
44 |
import nltk
|
45 |
from nltk.tokenize import sent_tokenize
|
46 |
import sys
|
|
|
187 |
except Exception as e:
|
188 |
print(f"Error extracting eBook metadata or cover: {e}")
|
189 |
return None
|
190 |
+
# Combine WAV files into a single file
|
191 |
+
def combine_wav_files(chapter_files, output_path, batch_size=256):
|
192 |
# Initialize an empty audio segment
|
193 |
combined_audio = AudioSegment.empty()
|
194 |
+
|
195 |
+
# Process the chapter files in batches
|
196 |
+
for i in range(0, len(chapter_files), batch_size):
|
197 |
+
batch_files = chapter_files[i:i + batch_size]
|
198 |
+
batch_audio = AudioSegment.empty() # Initialize an empty AudioSegment for the batch
|
199 |
+
|
200 |
+
# Sequentially append each file in the current batch to the batch_audio
|
201 |
+
for chapter_file in batch_files:
|
202 |
+
audio_segment = AudioSegment.from_wav(chapter_file)
|
203 |
+
batch_audio += audio_segment
|
204 |
+
|
205 |
+
# Combine the batch audio with the overall combined_audio
|
206 |
+
combined_audio += batch_audio
|
207 |
+
|
208 |
# Export the combined audio to the output file path
|
209 |
combined_audio.export(output_path, format='wav')
|
210 |
print(f"Combined audio saved to {output_path}")
|
|
|
268 |
|
269 |
|
270 |
|
271 |
+
#this code right here isnt the book grabbing thing but its before to refrence in order to create the sepecial chapter labeled book thing with calibre idk some systems cant seem to get it so just in case but the next bit of code after this is the book grabbing code with booknlp
|
272 |
import os
|
273 |
import subprocess
|
274 |
import ebooklib
|
|
|
716 |
return list_audiobook_files(audiobook_output_path)
|
717 |
|
718 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
719 |
# Gradio UI setup
|
720 |
+
def run_gradio_interface():
|
721 |
+
language_options = [
|
722 |
+
"en", "es", "fr", "de", "it", "pt", "pl", "tr", "ru", "nl", "cs", "ar", "zh-cn", "ja", "hu", "ko"
|
723 |
+
]
|
724 |
+
|
725 |
+
theme = gr.themes.Soft(
|
726 |
+
primary_hue="blue",
|
727 |
+
secondary_hue="blue",
|
728 |
+
neutral_hue="blue",
|
729 |
+
text_size=gr.themes.sizes.text_md,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
730 |
)
|
731 |
|
732 |
+
with gr.Blocks(theme=theme) as demo:
|
733 |
+
gr.Markdown(
|
734 |
+
"""
|
735 |
+
# eBook to Audiobook Converter
|
736 |
+
|
737 |
+
Transform your eBooks into immersive audiobooks with optional custom TTS models.
|
738 |
+
|
739 |
+
This interface is based on [Ebook2AudioBookXTTS](https://github.com/DrewThomasson/ebook2audiobookXTTS).
|
740 |
+
"""
|
741 |
+
)
|
742 |
+
|
743 |
+
with gr.Row():
|
744 |
+
with gr.Column(scale=3):
|
745 |
+
ebook_file = gr.File(label="eBook File")
|
746 |
+
target_voice_file = gr.File(label="Target Voice File (Optional)")
|
747 |
+
language = gr.Dropdown(label="Language", choices=language_options, value="en")
|
748 |
+
|
749 |
+
with gr.Column(scale=3):
|
750 |
+
use_custom_model = gr.Checkbox(label="Use Custom Model")
|
751 |
+
custom_model_file = gr.File(label="Custom Model File (Optional)", visible=False)
|
752 |
+
custom_config_file = gr.File(label="Custom Config File (Optional)", visible=False)
|
753 |
+
custom_vocab_file = gr.File(label="Custom Vocab File (Optional)", visible=False)
|
754 |
+
custom_model_url = gr.Textbox(label="Custom Model Zip URL (Optional)", visible=False)
|
755 |
+
|
756 |
+
convert_btn = gr.Button("Convert to Audiobook", variant="primary")
|
757 |
+
output = gr.Textbox(label="Conversion Status")
|
758 |
+
audio_player = gr.Audio(label="Audiobook Player", type="filepath")
|
759 |
+
download_btn = gr.Button("Download Audiobook Files")
|
760 |
+
download_files = gr.File(label="Download Files", interactive=False)
|
761 |
+
|
762 |
+
convert_btn.click(
|
763 |
+
convert_ebook_to_audio,
|
764 |
+
inputs=[ebook_file, target_voice_file, language, use_custom_model, custom_model_file, custom_config_file, custom_vocab_file, custom_model_url],
|
765 |
+
outputs=[output, audio_player]
|
766 |
+
)
|
767 |
+
|
768 |
+
use_custom_model.change(
|
769 |
+
lambda x: [gr.update(visible=x)] * 4,
|
770 |
+
inputs=[use_custom_model],
|
771 |
+
outputs=[custom_model_file, custom_config_file, custom_vocab_file, custom_model_url]
|
772 |
+
)
|
773 |
+
|
774 |
+
download_btn.click(
|
775 |
+
download_audiobooks,
|
776 |
+
outputs=[download_files]
|
777 |
+
)
|
778 |
+
|
779 |
+
# Get the correct local IP or localhost
|
780 |
+
hostname = socket.gethostname()
|
781 |
+
local_ip = socket.gethostbyname(hostname)
|
782 |
+
|
783 |
+
# Ensure Gradio runs and prints the correct local IP
|
784 |
+
print(f"Running on local URL: http://{local_ip}:7860")
|
785 |
+
print(f"Running on local URL: http://localhost:7860")
|
786 |
+
|
787 |
+
# Launch Gradio app
|
788 |
+
demo.launch(server_name="0.0.0.0", server_port=7860, share=args.share)
|
789 |
+
|
790 |
+
|
791 |
+
|
792 |
+
# Check if running in headless mode
|
793 |
+
if args.headless:
|
794 |
+
if not args.ebook:
|
795 |
+
print("Error: In headless mode, you must specify an ebook file using --ebook.")
|
796 |
+
exit(1)
|
797 |
+
|
798 |
+
ebook_file_path = args.ebook
|
799 |
+
target_voice = args.voice if args.voice else None
|
800 |
+
custom_model = None
|
801 |
|
802 |
+
if args.use_custom_model:
|
803 |
+
custom_model = {
|
804 |
+
'model': args.custom_model,
|
805 |
+
'config': args.custom_config,
|
806 |
+
'vocab': args.custom_vocab
|
807 |
+
}
|
808 |
|
809 |
+
# Example headless execution
|
810 |
+
convert_ebook_to_audio(ebook_file_path, target_voice, args.language, args.use_custom_model, args.custom_model, args.custom_config, args.custom_vocab)
|
811 |
|
812 |
+
else:
|
813 |
+
# Launch Gradio UI
|
814 |
+
run_gradio_interface()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|