Spaces:
Sleeping
Sleeping
File size: 4,814 Bytes
a41f928 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | import gradio as gr
from faster_whisper import WhisperModel
from docx import Document
import tempfile
import os
# Load model once at startup (cached after first run)
print("Loading Whisper model...")
model = WhisperModel("medium", compute_type="int8")
print("Model ready!")
def build_paragraphs(segments, pause_threshold=1.5):
"""
Group Whisper segments into paragraphs.
A new paragraph starts whenever the gap between the end of one segment
and the start of the next exceeds `pause_threshold` seconds.
"""
paragraphs = []
current_sentences = []
prev_end = None
for seg in segments:
if prev_end is not None and (seg.start - prev_end) >= pause_threshold:
# Long pause → flush current paragraph
if current_sentences:
paragraphs.append(" ".join(current_sentences).strip())
current_sentences = []
current_sentences.append(seg.text.strip())
prev_end = seg.end
# Flush remaining
if current_sentences:
paragraphs.append(" ".join(current_sentences).strip())
return paragraphs
def transcribe_audio(audio_file, output_format):
"""Transcribe an uploaded audio file and return a downloadable file + preview text."""
if audio_file is None:
return None, "⚠️ Please upload an audio file."
# Transcribe — consume iterator once
segments, _ = model.transcribe(audio_file)
paragraphs = build_paragraphs(list(segments))
base_name = os.path.splitext(os.path.basename(audio_file))[0]
if output_format == "Word (.docx)":
# ── Build Word document ───────────────────────────────────────────────
doc = Document()
doc.add_heading("Lecture Transcript", level=1)
for para in paragraphs:
doc.add_paragraph(para)
tmp = tempfile.NamedTemporaryFile(
delete=False,
suffix=".docx",
prefix=f"{base_name}_transcript_",
)
tmp.close()
doc.save(tmp.name)
preview = "\n\n".join(paragraphs)
return tmp.name, preview
else:
# ── Plain text ────────────────────────────────────────────────────────
full_text = "\n\n".join(paragraphs)
tmp = tempfile.NamedTemporaryFile(
delete=False,
suffix=".txt",
prefix=f"{base_name}_transcript_",
mode="w",
encoding="utf-8",
)
tmp.write(full_text)
tmp.close()
return tmp.name, full_text
# ── Gradio UI ─────────────────────────────────────────────────────────────────
with gr.Blocks(title="🎙️ Lecture Transcriber") as demo:
gr.HTML("""
<div style="text-align:center; margin-bottom: 4px;"><h1>🎙️ Lecture Transcriber</h1></div>
<div style="text-align:center; color:#888; margin-bottom:24px; font-size:0.95em;">
Upload an <b>.mp3</b> or <b>.m4a</b> audio file and get a formatted transcript instantly.
</div>
""")
with gr.Row():
with gr.Column(scale=1):
audio_input = gr.Audio(
label="Upload Audio File",
type="filepath",
sources=["upload"],
)
format_radio = gr.Radio(
choices=["Plain Text (.txt)", "Word (.docx)"],
value="Plain Text (.txt)",
label="Output Format",
)
transcribe_btn = gr.Button("✨ Transcribe", variant="primary", size="lg")
with gr.Column(scale=1):
text_output = gr.Textbox(
label="Transcript Preview",
placeholder="Your transcript will appear here, split into paragraphs by natural pauses...",
lines=16,
)
file_output = gr.File(label="⬇️ Download Transcript")
transcribe_btn.click(
fn=transcribe_audio,
inputs=[audio_input, format_radio],
outputs=[file_output, text_output],
show_progress="full",
)
gr.HTML("""
<div style="text-align:center; margin-top:16px; color:#aaa; font-size:0.85em;">
Powered by <a href="https://github.com/SYSTRAN/faster-whisper" target="_blank">faster-whisper</a>
· Paragraphs split by natural pauses · Runs 100% locally, no data stored.
</div>
""")
demo.launch(
theme=gr.themes.Soft(primary_hue="violet"),
css="""
footer { display: none !important; }
""",
)
|