Spaces:
Sleeping
Sleeping
import streamlit as st | |
import whisper | |
import torch | |
from transformers import pipeline | |
import spacy | |
from summa import keywords | |
import datetime | |
import os | |
from pydub import AudioSegment | |
import concurrent.futures | |
def load_models(): | |
device = "cuda" if torch.cuda.is_available() else "cpu" | |
whisper_model = whisper.load_model("small").to(device) # Using 'small' for faster speed | |
summarizer = pipeline("summarization", model="facebook/bart-large-cnn") | |
nlp = spacy.load("en_core_web_sm") | |
return whisper_model, summarizer, nlp, device | |
def split_audio(file_path, chunk_length_ms=60000): # 60 seconds per chunk | |
audio = AudioSegment.from_file(file_path) | |
chunks = [audio[i : i + chunk_length_ms] for i in range(0, len(audio), chunk_length_ms)] | |
return chunks | |
def transcribe_chunk(whisper_model, chunk_path, device): | |
options = {"fp16": False} if device == "cpu" else {"fp16": True} | |
return whisper_model.transcribe(chunk_path, **options)["text"] | |
def extract_action_items(text, nlp): | |
doc = nlp(text) | |
actions = [] | |
for sent in doc.sents: | |
for token in sent: | |
if token.dep_ == "ROOT" and token.pos_ == "VERB": | |
action = { | |
"text": sent.text, | |
"responsible": [], | |
"deadline": [] | |
} | |
for ent in sent.ents: | |
if ent.label_ == "PERSON": | |
action["responsible"].append(ent.text) | |
elif ent.label_ == "DATE": | |
action["deadline"].append(ent.text) | |
actions.append(action) | |
break | |
return actions | |
def main(): | |
st.title("π€ Smart AI Meeting Assistant") | |
whisper_model, summarizer, nlp, device = load_models() | |
audio_file = st.file_uploader("Upload meeting audio", type=["wav", "mp3", "m4a", "ogg", "flac"]) | |
if audio_file is not None: | |
file_path = f"uploaded_audio_{datetime.datetime.now().timestamp()}.wav" | |
with open(file_path, "wb") as f: | |
f.write(audio_file.getbuffer()) | |
st.subheader("Meeting Transcription") | |
with st.spinner("Transcribing audio..."): | |
chunks = split_audio(file_path) | |
chunk_paths = [] | |
for i, chunk in enumerate(chunks): | |
chunk_path = f"chunk_{i}.wav" | |
chunk.export(chunk_path, format="wav") | |
chunk_paths.append(chunk_path) | |
with concurrent.futures.ThreadPoolExecutor() as executor: | |
transcripts = list(executor.map(lambda cp: transcribe_chunk(whisper_model, cp, device), chunk_paths)) | |
transcript = " ".join(transcripts) | |
st.write(transcript) | |
os.remove(file_path) | |
st.subheader("Meeting Summary") | |
with st.spinner("Generating summary..."): | |
truncated_text = transcript[:1024] | |
summary = summarizer(truncated_text, max_length=150, min_length=50)[0]['summary_text'] | |
st.write(summary) | |
st.subheader("π Action Items") | |
actions = extract_action_items(transcript, nlp) | |
if not actions: | |
st.write("No action items detected") | |
else: | |
for i, action in enumerate(actions, 1): | |
responsible = ", ".join(action["responsible"]) or "Unassigned" | |
deadline = ", ".join(action["deadline"]) or "No deadline" | |
st.markdown(f""" | |
**Action {i}** | |
- Task: {action["text"]} | |
- Responsible: {responsible} | |
- Deadline: {deadline} | |
""") | |
st.subheader("π Key Terms") | |
key_phrases_result = keywords.keywords(transcript) or "" | |
key_phrases = [kp.strip() for kp in key_phrases_result.split("\n") if kp.strip()] | |
st.write(", ".join(key_phrases) if key_phrases else "No key terms extracted") | |
if __name__ == "__main__": | |
main() | |