Use verbose_json diarization, add JSON+TXT email feature
This commit is contained in:
+180
-21
@@ -7,13 +7,16 @@ Runs the Web GUI that:
|
||||
- Sends audio to LocalAI for transcription + diarization
|
||||
- Optionally sends transcript to a second LLM for summarization
|
||||
- Returns transcript (and summary) in the browser
|
||||
- Optionally emails transcript files (TXT + JSON)
|
||||
|
||||
This is the default entrypoint when running in Docker.
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
import tempfile
|
||||
from datetime import datetime
|
||||
|
||||
import gradio as gr
|
||||
|
||||
@@ -70,10 +73,23 @@ def create_app():
|
||||
)
|
||||
|
||||
# Helper: run transcription via LocalAI API
|
||||
def run_transcribe(audio_path, task, language, num_speakers):
|
||||
def run_transcribe(
|
||||
audio_path,
|
||||
task,
|
||||
language,
|
||||
num_speakers,
|
||||
send_email_flag,
|
||||
email_to,
|
||||
email_cc,
|
||||
email_subject,
|
||||
):
|
||||
if not audio_path:
|
||||
raise ValueError("No audio file provided.")
|
||||
|
||||
email_status = ""
|
||||
attachments = []
|
||||
|
||||
# Ensure we use rich export mode (for JSON with diarization)
|
||||
try:
|
||||
if task == "transcript_and_summarize":
|
||||
result = scraibe.transcript_and_summarize(
|
||||
@@ -81,11 +97,14 @@ def create_app():
|
||||
language=language or None,
|
||||
num_speakers=int(num_speakers) if num_speakers else None,
|
||||
verbose=True,
|
||||
for_export=True,
|
||||
)
|
||||
transcript_text = result.get("transcript", "")
|
||||
summary_text = result.get("summary", "")
|
||||
segments = result.get("segments", [])
|
||||
raw_result = result.get("raw_result")
|
||||
|
||||
# Save as .md
|
||||
# Save as .md (transcript + summary)
|
||||
md_path = tempfile.mktemp(suffix=".md")
|
||||
with open(md_path, "w", encoding="utf-8") as f:
|
||||
f.write("# Transcript\n\n")
|
||||
@@ -93,32 +112,74 @@ def create_app():
|
||||
f.write("\n\n# Summary\n\n")
|
||||
f.write(summary_text)
|
||||
|
||||
return (
|
||||
transcript_text,
|
||||
summary_text,
|
||||
md_path,
|
||||
"Transcription and summarization completed.",
|
||||
)
|
||||
# Save as .txt (plain transcript)
|
||||
txt_path = tempfile.mktemp(suffix=".txt")
|
||||
with open(txt_path, "w", encoding="utf-8") as f:
|
||||
f.write(transcript_text)
|
||||
|
||||
# Save as .json (diarization + transcript + summary)
|
||||
json_data = {
|
||||
"task": "transcript_and_summarize",
|
||||
"transcript": transcript_text,
|
||||
"summary": summary_text,
|
||||
"segments": segments,
|
||||
"metadata": {
|
||||
"timestamp": datetime.utcnow().isoformat()
|
||||
},
|
||||
}
|
||||
if raw_result is not None:
|
||||
json_data["raw_result"] = raw_result
|
||||
|
||||
json_path = tempfile.mktemp(suffix=".json")
|
||||
with open(json_path, "w", encoding="utf-8") as f:
|
||||
json.dump(json_data, f, indent=2, ensure_ascii=False)
|
||||
|
||||
# Prepare attachments for email
|
||||
if send_email_flag:
|
||||
attachments = [txt_path, json_path]
|
||||
|
||||
status_msg = "Transcription and summarization completed."
|
||||
|
||||
else:
|
||||
# Default: transcribe only
|
||||
text = scraibe.transcribe(
|
||||
# transcribe only (with diarization)
|
||||
result = scraibe.transcribe(
|
||||
audio_file=audio_path,
|
||||
language=language or None,
|
||||
num_speakers=int(num_speakers) if num_speakers else None,
|
||||
verbose=True,
|
||||
for_export=True,
|
||||
)
|
||||
transcript_text = result.get("transcript", "")
|
||||
segments = result.get("segments", [])
|
||||
raw_result = result.get("raw_result")
|
||||
|
||||
# Save as .txt
|
||||
# Save as .txt (plain transcript)
|
||||
txt_path = tempfile.mktemp(suffix=".txt")
|
||||
with open(txt_path, "w", encoding="utf-8") as f:
|
||||
f.write(text)
|
||||
f.write(transcript_text)
|
||||
|
||||
# Save as .json (diarization + transcript)
|
||||
json_data = {
|
||||
"task": "transcribe",
|
||||
"transcript": transcript_text,
|
||||
"segments": segments,
|
||||
"metadata": {
|
||||
"timestamp": datetime.utcnow().isoformat()
|
||||
},
|
||||
}
|
||||
if raw_result is not None:
|
||||
json_data["raw_result"] = raw_result
|
||||
|
||||
json_path = tempfile.mktemp(suffix=".json")
|
||||
with open(json_path, "w", encoding="utf-8") as f:
|
||||
json.dump(json_data, f, indent=2, ensure_ascii=False)
|
||||
|
||||
# Prepare attachments for email
|
||||
if send_email_flag:
|
||||
attachments = [txt_path, json_path]
|
||||
|
||||
status_msg = "Transcription completed."
|
||||
|
||||
return (
|
||||
text,
|
||||
"",
|
||||
txt_path,
|
||||
"Transcription completed.",
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Error during transcription: %s", e)
|
||||
return (
|
||||
@@ -126,8 +187,56 @@ def create_app():
|
||||
"",
|
||||
None,
|
||||
f"Error: {e}",
|
||||
"",
|
||||
)
|
||||
|
||||
# Handle email after successful transcription
|
||||
if send_email_flag and attachments:
|
||||
try:
|
||||
from .email_sender import send_email, EmailError
|
||||
except ImportError:
|
||||
email_status = "Email feature unavailable (email_sender not found)."
|
||||
else:
|
||||
to = (email_to or "").strip()
|
||||
cc = (email_cc or "").strip()
|
||||
subject = (email_subject or "").strip()
|
||||
|
||||
if not to:
|
||||
email_status = "Email not sent: 'To' address is empty."
|
||||
else:
|
||||
if not subject:
|
||||
subject = f"ScrAIbe Transcript - {datetime.utcnow().strftime('%Y-%m-%d %H:%M UTC')}"
|
||||
|
||||
body = (
|
||||
"Please find the transcription files attached.\n"
|
||||
"This message was generated by ScrAIbe.\n"
|
||||
)
|
||||
|
||||
try:
|
||||
send_email(
|
||||
to=to,
|
||||
cc=cc or None,
|
||||
subject=subject,
|
||||
body=body,
|
||||
attachments=attachments,
|
||||
)
|
||||
email_status = "Transcript files sent via email."
|
||||
except EmailError as e:
|
||||
email_status = f"Email failed: {e}"
|
||||
except Exception as e:
|
||||
email_status = f"Email failed: {e}"
|
||||
|
||||
# Use md_path for file_output in transcript_and_summarize, else txt_path
|
||||
file_path = md_path if task == "transcript_and_summarize" else txt_path
|
||||
|
||||
return (
|
||||
transcript_text,
|
||||
summary_text if task == "transcript_and_summarize" else "",
|
||||
file_path,
|
||||
status_msg,
|
||||
email_status,
|
||||
)
|
||||
|
||||
# Load header/footer HTML if present
|
||||
header_path = layout_cfg.get("header", "/app/src/misc/header.html")
|
||||
footer_path = layout_cfg.get("footer", "/app/src/misc/footer.html")
|
||||
@@ -180,6 +289,31 @@ def create_app():
|
||||
precision=0,
|
||||
)
|
||||
|
||||
# Email options
|
||||
send_email_checkbox = gr.Checkbox(
|
||||
label="Send transcript files via email"
|
||||
)
|
||||
|
||||
with gr.Group(visible=False) as email_group:
|
||||
email_to = gr.Textbox(
|
||||
label="To (comma-separated)",
|
||||
placeholder="e.g. name@example.com",
|
||||
)
|
||||
email_cc = gr.Textbox(
|
||||
label="CC (optional, comma-separated)",
|
||||
placeholder="e.g. manager@example.com",
|
||||
)
|
||||
email_subject = gr.Textbox(
|
||||
label="Subject (optional)",
|
||||
placeholder="Default: ScrAIbe Transcript - <date>",
|
||||
)
|
||||
|
||||
send_email_checkbox.change(
|
||||
fn=lambda v: gr.update(visible=v),
|
||||
inputs=[send_email_checkbox],
|
||||
outputs=[email_group],
|
||||
)
|
||||
|
||||
transcribe_btn = gr.Button("Start", variant="primary")
|
||||
|
||||
with gr.Column(scale=3):
|
||||
@@ -201,6 +335,11 @@ def create_app():
|
||||
label="Status",
|
||||
interactive=False,
|
||||
)
|
||||
email_status_text = gr.Textbox(
|
||||
label="Email status",
|
||||
interactive=False,
|
||||
visible=True,
|
||||
)
|
||||
|
||||
# Footer
|
||||
if footer_html:
|
||||
@@ -218,20 +357,34 @@ def create_app():
|
||||
outputs=[summary_text],
|
||||
)
|
||||
|
||||
def on_transcribe(audio, task, language, num_speakers):
|
||||
def on_transcribe(
|
||||
audio,
|
||||
task,
|
||||
language,
|
||||
num_speakers,
|
||||
send_email_flag,
|
||||
email_to_val,
|
||||
email_cc_val,
|
||||
email_subject_val,
|
||||
):
|
||||
if not audio:
|
||||
return (
|
||||
"",
|
||||
"",
|
||||
None,
|
||||
"Please upload or record audio.",
|
||||
"",
|
||||
)
|
||||
|
||||
transcript, summary, file_path, msg = run_transcribe(
|
||||
transcript, summary, file_path, status_msg, email_status = run_transcribe(
|
||||
audio_path=audio,
|
||||
task=task,
|
||||
language=language,
|
||||
num_speakers=num_speakers,
|
||||
send_email_flag=bool(send_email_flag),
|
||||
email_to=email_to_val,
|
||||
email_cc=email_cc_val,
|
||||
email_subject=email_subject_val,
|
||||
)
|
||||
|
||||
show_summary = bool(summary)
|
||||
@@ -239,7 +392,8 @@ def create_app():
|
||||
transcript,
|
||||
summary,
|
||||
file_path if file_path else None,
|
||||
msg,
|
||||
status_msg,
|
||||
email_status,
|
||||
)
|
||||
|
||||
transcribe_btn.click(
|
||||
@@ -249,12 +403,17 @@ def create_app():
|
||||
task_choice,
|
||||
language_input,
|
||||
num_speakers_input,
|
||||
send_email_checkbox,
|
||||
email_to,
|
||||
email_cc,
|
||||
email_subject,
|
||||
],
|
||||
outputs=[
|
||||
output_text,
|
||||
summary_text,
|
||||
file_output,
|
||||
status_text,
|
||||
email_status_text,
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user