Spaces:
Build error
Build error
File size: 4,249 Bytes
afe7b73 aabf5cc afe7b73 aabf5cc afe7b73 aabf5cc afe7b73 aabf5cc afe7b73 aabf5cc afe7b73 abd5180 a585f08 aabf5cc a585f08 afe7b73 abd5180 aabf5cc abd5180 316d507 abd5180 afe7b73 316d507 aabf5cc afe7b73 | 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 | from faster_whisper import WhisperModel
import os
import requests
import json
from langchain.tools import tool
from typing import TypedDict
from langgraph.graph import StateGraph
import gradio as gr
from pydub import AudioSegment
import tempfile
MISTRAL_API_KEY = os.getenv("MISTRAL_API_KEY")
MODEL = "mistral-large-latest"
class State(TypedDict):
file_path: str
transcript: str
summary_json: dict
final_output: str
def convert_to_wav(input_path: str) -> str:
if input_path.lower().endswith(".wav"):
return input_path # No conversion needed
else:
audio = AudioSegment.from_file(input_path)
temp_wav_file = tempfile.NamedTemporaryFile(delete=False, suffix=".wav")
audio.export(temp_wav_file.name, format="wav")
return temp_wav_file.name
def transcribe_audio(state: State) -> State:
model = WhisperModel("base", compute_type="float32")
segments, _ = model.transcribe(state["file_path"], beam_size=5, language="en")
transcript = " ".join(segment.text.strip() for segment in segments)
return {**state, "transcript": transcript}
def summarize_transcript(state: State) -> State:
prompt = f"""
You are an AI assistant summarizing meeting transcripts.
Extract the following:
1. Attendees (Names only, if possible)
2. Key Discussion Points (bullet format)
3. Action Items (with owner and deadline, if mentioned)
4. Decisions Made (if any)
Respond in this format:
{{
"attendees": [...],
"key_points": [...],
"action_items": [...],
"decisions": [...]
}}
Transcript:
\"\"\"{state['transcript']}\"\"\"
"""
res = requests.post(
"https://api.mistral.ai/v1/chat/completions",
headers={
"Authorization": f"Bearer {MISTRAL_API_KEY}",
"Content-Type": "application/json"
},
json={
"model": MODEL,
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.3
}
)
content = res.json()['choices'][0]['message']['content']
return {**state, "summary_json": eval(content)}
def format_output(state: State) -> State:
summary = state["summary_json"]
formatted = "π Attendees:\n" + "\n".join(f"- {name}" for name in summary["attendees"]) + "\n\n"
formatted += "π¬ Key Points:\n" + "\n".join(f"- {pt}" for pt in summary["key_points"]) + "\n\n"
formatted += "β
Action Items:\n" + "\n".join(f"- {item}" for item in summary["action_items"]) + "\n\n"
formatted += "π Decisions:\n" + "\n".join(f"- {d}" for d in summary["decisions"])
return {**state, "final_output": formatted}
# Graph setup
builder = StateGraph(State)
builder.add_node("transcribe_audio", transcribe_audio)
builder.add_node("summarize_transcript", summarize_transcript)
builder.add_node("format_output", format_output)
builder.set_entry_point("transcribe_audio")
builder.add_edge("transcribe_audio", "summarize_transcript")
builder.add_edge("summarize_transcript", "format_output")
graph = builder.compile()
def process_meeting(file):
print(f"Received file: {file}")
wav_path = convert_to_wav(file)
state = {"file_path": wav_path}
print(f"State initialized: {state}")
try:
final_state = graph.invoke(state)
print(f"Final State: {final_state}")
return final_state["final_output"]
except Exception as e:
print(f"Error: {e}")
return str(e)
with gr.Blocks() as demo:
gr.Markdown("### π€ MeetRecap - AI-Powered Meeting Summarizer")
gr.Markdown("""
Upload your audio file (e.g., `.wav`, `.mp3`, `.m4a`) or record it. You'll receive a structured meeting summary including Attendees, Key Points, Action Items, and Decisions.
""")
with gr.Row():
with gr.Column():
audio_input = gr.Audio(type="filepath", label="ποΈ Upload or Record Audio")
submit_btn = gr.Button("π Summarize")
clear_btn = gr.Button("π§Ή Clear")
with gr.Column():
summary_output = gr.Textbox(label="π Meeting Summary", lines=20, max_lines=40)
submit_btn.click(fn=process_meeting, inputs=audio_input, outputs=summary_output)
clear_btn.click(lambda: (None, ""), outputs=[audio_input, summary_output])
demo.launch(share=True) |