erkwoo's picture
Update app.py
7d26a50 verified
# app.py
import re
import gradio as gr
from datetime import datetime
import os
from docx import Document # krever python-docx i requirements
# Aksepterer både punktum og komma i desimaldelen
TIMESTAMP_RE = re.compile(r'(\[\d{2}:\d{2}:\d{2}(?:[.,]\d{1,3})?\])')
TMP_DIR = "/tmp/hf_transcript"
os.makedirs(TMP_DIR, exist_ok=True)
def format_transcript(text: str) -> str:
"""Bevarer tidsstempler og slår sammen linjer per tidsstempel."""
if not text:
return ""
text = text.replace('\r\n', '\n').replace('\r', '\n')
parts = TIMESTAMP_RE.split(text)
out_lines = []
i = 0
if parts and not TIMESTAMP_RE.match(parts[0]):
if len(parts) > 1:
parts[1] = parts[0] + parts[1]
i = 1
else:
return re.sub(r'\n+', ' ', text).strip()
while i < len(parts) - 1:
ts = parts[i].strip()
body = parts[i+1]
body = re.sub(r'\n+', ' ', body).strip()
body = re.sub(r' {2,}', ' ', body)
line = f"{ts} {body}".strip()
out_lines.append(line)
i += 2
if i < len(parts):
tail = parts[i].strip()
if tail:
tail = re.sub(r'\n+', ' ', tail).strip()
out_lines.append(tail)
return "\n\n".join(out_lines)
def format_without_timestamps(text: str, sentences_per_paragraph: int = 5) -> str:
"""
Tar tekst uten tidskoder og formaterer den til avsnitt etter hver N setninger.
- splitter på setningsendelser (., !, ?), forsøker å beholde forkortelser rimelig.
- samler setninger i grupper på sentences_per_paragraph og separerer gruppene med et tomt linjeskift.
"""
if not text:
return ""
# Normaliser whitespace og newlines
txt = text.replace('\r\n', '\n').replace('\r', '\n')
txt = re.sub(r'\n+', ' ', txt) # fjern nye linjer internt
txt = re.sub(r'\s+', ' ', txt).strip() # collapse whitespace
# Split på setningsavslutning: behold skilletegn
# Dette splitter på (?<=[.!?]) etterfulgt av ett eller flere mellomrom
raw_sentences = re.split(r'(?<=[.!?])\s+', txt)
# Hvis veldig korte "setninger" eller tomme, filter dem ut
sentences = [s.strip() for s in raw_sentences if s.strip()]
if not sentences:
return txt # fallback
# Gruppér setninger og lag avsnitt
paragraphs = []
for i in range(0, len(sentences), sentences_per_paragraph):
group = sentences[i:i+sentences_per_paragraph]
paragraph = ' '.join(group).strip()
paragraphs.append(paragraph)
return "\n\n".join(paragraphs)
def download_filename(prefix="formatted_transcript"):
now = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
return f"{prefix}_{now}"
def make_txt_file(text: str) -> str:
fname = download_filename() + ".txt"
path = os.path.join(TMP_DIR, fname)
with open(path, "wb") as f:
f.write(text.encode("utf-8"))
return path
def make_docx_file(text: str) -> str:
fname = download_filename() + ".docx"
path = os.path.join(TMP_DIR, fname)
doc = Document()
segments = text.split("\n\n")
for seg in segments:
doc.add_paragraph(seg)
doc.save(path)
return path
def format_and_prepare_files(preferred_text: str) -> tuple:
"""
Lager txt og docx fra gitt tekst (forventet allerede formatert).
Returnerer: (tekst, txt_path, docx_path)
"""
formatted = preferred_text if preferred_text is not None else ""
txt_path = make_txt_file(formatted)
docx_path = make_docx_file(formatted)
return formatted, txt_path, docx_path
def generate_from_preferred(inp_text: str, out_text: str):
"""
Velger utdatafeltets tekst hvis det finnes (prioritet), ellers bruker original input.
Deretter lager filer fra valgt tekst.
"""
preferred = out_text.strip() if out_text and out_text.strip() else inp_text
if not preferred:
return "", None, None
return format_and_prepare_files(preferred)
def clear_input_and_outputs():
return gr.update(value=""), gr.update(value=""), None, None
with gr.Blocks(title="Transkript-formatter (TXT + DOCX)") as demo:
gr.Markdown(
"<b>Transkript-formatering</b><br>"
"Lim inn transkriptet ditt (med tidskoder eller uten).<br>"
"- Bruk <i>Formatér</i> for å slå sammen tekst under tidskoder. <br>"
"- Bruk <i>Uten tidskoder</i> for å formatere tekst uten tidskoder: avsnitt etter hver 5. setning. <br>"
"- Når utdata er i tekstfeltet, kan du trykke <i>Generer .txt og .docx</i> for å laste ned filene basert på utdata."
)
with gr.Row():
inp = gr.Textbox(lines=18, label="Råtekst (lim inn her)", placeholder="Lim inn hele transkriptet her...")
out = gr.Textbox(lines=18, label="Formatert tekst (kopier herfra eller generer filer)")
with gr.Row():
fmt_btn = gr.Button("Formatér (vis i felt)")
no_ts_btn = gr.Button("Uten tidskoder") # <-- ny knapp
gen_btn = gr.Button("Generer .txt og .docx (nedlasting)")
txt_file = gr.File(label="Last ned .txt")
docx_file = gr.File(label="Last ned .docx")
with gr.Row():
copy_btn = gr.Button("Oppdater utdata (klar for kopiering)")
clear_btn = gr.Button("Clear input")
# Normalt format (bevarer tidskoder)
fmt_btn.click(lambda t: format_transcript(t), inputs=inp, outputs=out)
# Uten tidskoder: formaterer tekst ved å gruppere hver 5 setning til ett avsnitt
# (Returnerer oppdatert out-tekst)
def without_timestamps_and_show(text):
return format_without_timestamps(text, sentences_per_paragraph=5)
no_ts_btn.click(without_timestamps_and_show, inputs=inp, outputs=out)
# Generer bruker preferert tekst (out hvis ikke tom, ellers inp)
gen_btn.click(generate_from_preferred, inputs=[inp, out], outputs=[out, txt_file, docx_file])
copy_btn.click(lambda t: t, inputs=out, outputs=out)
clear_btn.click(clear_input_and_outputs, inputs=None, outputs=[inp, out, txt_file, docx_file])
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860)