Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
DISCORD_BOT_TOKEN=your_bot_token_here
OPENAI_API_KEY=your_openai_api_key_here
21 changes: 17 additions & 4 deletions bot/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from meeting_state import MeetingStateManager, MeetingStatus
from audio_recorder import AudioRecordingManager

from summarizer import process_meeting_recordings, generate_structured_summary
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
Expand Down Expand Up @@ -322,10 +322,23 @@ async def end_meeting(interaction: discord.Interaction):
)

if recording_info:
response += f"👥 Recorded {recording_info['user_count']} user(s)\n"
response += f"📁 Saved to: `{recording_info['output_dir']}`"
response += f"Recorded {recording_info['user_count']} user(s)\n"
response += f"Saved to: `{recording_info['output_dir']}`"

await interaction.followup.send(response)

if recording_info and recording_info.get("user_count", 0) > 0:
await interaction.followup.send("⏳ Transcribing audio and generating summary...")
try:
transcript = process_meeting_recordings(recording_info["output_dir"])
if transcript:
summary = generate_structured_summary(transcript)
await interaction.followup.send(f"📝 **Meeting Summary**\n\n{summary}")
else:
await interaction.followup.send("⚠️ No audio was captured to summarize.")
except Exception as e:
logger.error(f"Error generating summary: {e}")
await interaction.followup.send("⚠️ Could not generate summary. Check logs for details.")

logger.info(
f"Meeting ended: {ended_session.meeting_id} in guild {guild_id}, "
Expand Down
79 changes: 79 additions & 0 deletions bot/summarizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import os
import openai

client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"))


def transcribe_audio(audio_path: str) -> str:
"""Transcribes a .wav audio file to text using OpenAI Whisper."""
with open(audio_path, "rb") as audio_file:
response = client.audio.transcriptions.create(
model="whisper-1",
file=audio_file
)
return response.text


def generate_structured_summary(transcript: str) -> str:
"""Takes a plain-text transcript and returns a structured AI summary."""
if not transcript or not transcript.strip():
return "⚠️ No transcript content to summarize."

prompt = """
You are an AI assistant that creates structured meeting summaries.

Given the raw transcript below, produce a summary with exactly these three sections:

## 🗝️ Key Topics Discussed
- List the main subjects and themes covered.

## ✅ Decisions Made
- List any concrete decisions or agreements reached.

## 📋 Action Items / Follow-ups
- List tasks to be completed, with owner and deadline if mentioned.

If a section has nothing to report, write: "None identified."

Keep it concise and professional. Do not add any extra sections.

---
Transcript:
{transcript}
""".format(transcript=transcript.strip())

response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": prompt}],
temperature=0.3,
max_tokens=800
)

return response.choices[0].message.content.strip()


def process_meeting_recordings(output_dir: str) -> str:
"""
Finds all .wav files in the meeting directory,
transcribes each one, and combines into a single transcript.
"""
from pathlib import Path

wav_files = list(Path(output_dir).glob("*.wav"))

if not wav_files:
return ""

full_transcript = []

for wav_file in wav_files:
# Use filename as speaker label (e.g. user_123456_John)
speaker = wav_file.stem.split("_")[-1]
try:
text = transcribe_audio(str(wav_file))
if text.strip():
full_transcript.append(f"{speaker}: {text.strip()}")
except Exception as e:
full_transcript.append(f"[Could not transcribe {wav_file.name}: {e}]")

return "\n".join(full_transcript)
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
discord.py[voice]>=2.3.0
PyNaCl>=1.5.0
python-dotenv>=1.0.0
openai>=1.0.0