pratyyush commited on
Commit
392a11b
·
verified ·
1 Parent(s): 9c64538

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -25
app.py CHANGED
@@ -6,7 +6,7 @@ import os
6
  import uuid
7
  from pydub import AudioSegment
8
 
9
- # Fetch available voices (filtering for English by default)
10
  async def get_voices():
11
  voices = await edge_tts.VoicesManager.create()
12
  voice_list = voices.find(Language="en")
@@ -17,62 +17,80 @@ def extract_text(pdf_file):
17
  doc = fitz.open(pdf_file.name)
18
  return "".join([page.get_text() for page in doc])
19
 
20
- # Main conversion logic
21
- async def convert_pdf_to_long_audio(pdf_file, voice_short_name):
 
 
 
 
22
  text = extract_text(pdf_file)
 
23
  if not text.strip():
24
  return "No text found in PDF.", None
25
 
26
- # Chunking text to avoid timeout (approx 2000 chars per chunk)
27
- chunks = [text[i:i+2000] for i in range(0, len(text), 2000)]
28
- combined_audio = AudioSegment.empty()
 
29
 
30
- # Create a temporary directory for chunks
31
  session_id = str(uuid.uuid4())
32
  os.makedirs(session_id, exist_ok=True)
33
 
 
34
  for i, chunk in enumerate(chunks):
 
 
 
35
  chunk_path = os.path.join(session_id, f"chunk_{i}.mp3")
36
  communicate = edge_tts.Communicate(chunk, voice_short_name)
37
  await communicate.save(chunk_path)
38
 
39
- # Load and append to the master file
40
  segment = AudioSegment.from_mp3(chunk_path)
41
  combined_audio += segment
42
 
43
- final_path = f"output_{session_id}.mp3"
 
44
  combined_audio.export(final_path, format="mp3")
45
 
46
- # Cleanup chunks
47
  for f in os.listdir(session_id):
48
  os.remove(os.path.join(session_id, f))
49
  os.rmdir(session_id)
50
 
 
51
  return text[:2000] + "...", final_path
52
 
53
  # Gradio Wrapper
54
- def process(pdf, voice_name):
55
- # Map friendly name back to short name
56
  voice_id = voice_dict[voice_name]
57
- return asyncio.run(convert_pdf_to_long_audio(pdf, voice_id))
58
 
59
  # Initialize voice list
60
  voice_dict = asyncio.run(get_voices())
61
 
62
- with gr.Blocks() as demo:
63
- gr.Markdown("# 📚 PDF to Long-Form AI Audiobook")
64
- gr.Markdown("Upload a PDF and choose a voice. This tool supports long files by processing text in chunks.")
 
65
 
66
  with gr.Row():
67
- pdf_input = gr.File(label="Upload PDF", file_types=[".pdf"])
68
- voice_input = gr.Dropdown(choices=list(voice_dict.keys()), label="Select AI Voice", value=list(voice_dict.keys())[0])
69
-
70
- btn = gr.Button("Convert to Speech")
71
-
72
- with gr.Row():
73
- text_preview = gr.Textbox(label="Text Preview (First 2000 chars)")
74
- audio_output = gr.Audio(label="Full Audiobook File")
 
 
 
 
75
 
 
76
  btn.click(process, inputs=[pdf_input, voice_input], outputs=[text_preview, audio_output])
77
 
78
- demo.launch()
 
 
6
  import uuid
7
  from pydub import AudioSegment
8
 
9
+ # Fetch available voices
10
  async def get_voices():
11
  voices = await edge_tts.VoicesManager.create()
12
  voice_list = voices.find(Language="en")
 
17
  doc = fitz.open(pdf_file.name)
18
  return "".join([page.get_text() for page in doc])
19
 
20
+ # Main conversion logic with Progress Tracker
21
+ async def convert_pdf_to_long_audio(pdf_file, voice_short_name, progress=gr.Progress()):
22
+ if pdf_file is None:
23
+ return "Please upload a file.", None
24
+
25
+ progress(0, desc="Reading PDF...")
26
  text = extract_text(pdf_file)
27
+
28
  if not text.strip():
29
  return "No text found in PDF.", None
30
 
31
+ # Chunking: ~2500 characters is a safe bet for Edge-TTS stability
32
+ chunk_size = 2500
33
+ chunks = [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]
34
+ total_chunks = len(chunks)
35
 
36
+ combined_audio = AudioSegment.empty()
37
  session_id = str(uuid.uuid4())
38
  os.makedirs(session_id, exist_ok=True)
39
 
40
+ # Iterating through chunks with progress updates
41
  for i, chunk in enumerate(chunks):
42
+ # Update progress bar: (current_index / total_count)
43
+ progress((i / total_chunks), desc=f"Converting chunk {i+1} of {total_chunks} to voice...")
44
+
45
  chunk_path = os.path.join(session_id, f"chunk_{i}.mp3")
46
  communicate = edge_tts.Communicate(chunk, voice_short_name)
47
  await communicate.save(chunk_path)
48
 
49
+ # Load and append
50
  segment = AudioSegment.from_mp3(chunk_path)
51
  combined_audio += segment
52
 
53
+ progress(0.95, desc="Merging all audio parts into final file...")
54
+ final_path = f"audiobook_{session_id}.mp3"
55
  combined_audio.export(final_path, format="mp3")
56
 
57
+ # Cleanup
58
  for f in os.listdir(session_id):
59
  os.remove(os.path.join(session_id, f))
60
  os.rmdir(session_id)
61
 
62
+ progress(1.0, desc="Done!")
63
  return text[:2000] + "...", final_path
64
 
65
  # Gradio Wrapper
66
+ def process(pdf, voice_name, progress=gr.Progress()):
 
67
  voice_id = voice_dict[voice_name]
68
+ return asyncio.run(convert_pdf_to_long_audio(pdf, voice_id, progress))
69
 
70
  # Initialize voice list
71
  voice_dict = asyncio.run(get_voices())
72
 
73
+ # Building the Interface
74
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
75
+ gr.Markdown("# 🎧 Infinite PDF Audiobook Generator")
76
+ gr.Markdown("Upload your PDF and wait for the AI to narrate it. **Progress is tracked below the button.**")
77
 
78
  with gr.Row():
79
+ with gr.Column():
80
+ pdf_input = gr.File(label="Upload PDF", file_types=[".pdf"])
81
+ voice_input = gr.Dropdown(
82
+ choices=list(voice_dict.keys()),
83
+ label="Select AI Voice",
84
+ value="Microsoft Guy Online (Natural) - en-US-GuyNeural"
85
+ )
86
+ btn = gr.Button("Start Audio Conversion", variant="primary")
87
+
88
+ with gr.Column():
89
+ text_preview = gr.Textbox(label="Text Preview", lines=5)
90
+ audio_output = gr.Audio(label="Final Audiobook (Download here)")
91
 
92
+ # The magic happens here: passing the progress bar to the function
93
  btn.click(process, inputs=[pdf_input, voice_input], outputs=[text_preview, audio_output])
94
 
95
+ if __name__ == "__main__":
96
+ demo.launch()