DEV Community

Chappie
Chappie

Posted on

Build Your Own AI-Powered Meeting Notes System This Weekend

Build Your Own AI-Powered Meeting Notes System This Weekend

Turn hours of manual note-taking into an automated workflow with Python, Whisper, and Claude


We've all been there: you finish a meeting, realize you should have taken better notes, and spend the next 20 minutes trying to reconstruct what was discussed from fragmented memories and a few bullet points.

This weekend, let's fix that permanently. We're going to build an AI-powered meeting notes system that:

  1. Transcribes audio recordings using OpenAI's Whisper
  2. Generates structured summaries with action items using Claude
  3. Saves everything to Markdown files for your second brain

Total time: 2-3 hours. Difficulty: Beginner-friendly.

What You'll Need

  • Python 3.9+
  • An Anthropic API key (for Claude)
  • Basic terminal knowledge
  • Audio files of meetings (or a microphone to record new ones)

Project Structure

meeting-notes/
├── transcribe.py
├── summarize.py
├── main.py
├── recordings/
├── transcripts/
└── summaries/
Enter fullscreen mode Exit fullscreen mode

Step 1: Set Up the Environment

mkdir meeting-notes && cd meeting-notes
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

pip install openai-whisper anthropic python-dotenv
Enter fullscreen mode Exit fullscreen mode

Create a .env file:

ANTHROPIC_API_KEY=your-key-here
Enter fullscreen mode Exit fullscreen mode

Step 2: Build the Transcription Module

Whisper runs locally, so your audio never leaves your machine. Create transcribe.py:

import whisper
from pathlib import Path

def transcribe_audio(audio_path: str, model_size: str = "base") -> str:
    """
    Transcribe audio file using Whisper.
    Model sizes: tiny, base, small, medium, large
    Larger = more accurate but slower
    """
    model = whisper.load_model(model_size)
    result = model.transcribe(audio_path)
    return result["text"]

def save_transcript(text: str, output_path: str) -> None:
    """Save transcript to file."""
    Path(output_path).parent.mkdir(parents=True, exist_ok=True)
    with open(output_path, "w") as f:
        f.write(text)

if __name__ == "__main__":
    # Quick test
    import sys
    if len(sys.argv) > 1:
        text = transcribe_audio(sys.argv[1])
        print(text[:500] + "..." if len(text) > 500 else text)
Enter fullscreen mode Exit fullscreen mode

Pro tip: Start with base model for speed during development. Switch to medium or large for production quality.

Step 3: Build the AI Summary Module

Now the magic happens. Create summarize.py:

import anthropic
from dotenv import load_dotenv

load_dotenv()

SUMMARY_PROMPT = """You are an expert meeting analyst. Given a transcript, create a structured summary with:

## Meeting Summary
A 2-3 sentence overview of what was discussed.

## Key Points
- Bullet points of main topics covered

## Decisions Made
- Any decisions that were finalized

## Action Items
- [ ] Task description (@owner if mentioned) - deadline if specified

## Questions/Open Items
- Unresolved questions or items needing follow-up

Be concise but thorough. Extract every actionable item mentioned.

TRANSCRIPT:
{transcript}
"""

def summarize_transcript(transcript: str) -> str:
    """Generate structured meeting notes from transcript."""
    client = anthropic.Anthropic()

    message = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=2000,
        messages=[
            {
                "role": "user",
                "content": SUMMARY_PROMPT.format(transcript=transcript)
            }
        ]
    )

    return message.content[0].text

def save_summary(summary: str, output_path: str, metadata: dict = None) -> None:
    """Save summary with optional YAML frontmatter."""
    from pathlib import Path
    from datetime import datetime

    Path(output_path).parent.mkdir(parents=True, exist_ok=True)

    frontmatter = f"""---
date: {datetime.now().strftime('%Y-%m-%d')}
type: meeting-notes
"""
    if metadata:
        for key, value in metadata.items():
            frontmatter += f"{key}: {value}\n"
    frontmatter += "---\n\n"

    with open(output_path, "w") as f:
        f.write(frontmatter + summary)
Enter fullscreen mode Exit fullscreen mode

Step 4: Wire It All Together

Create main.py:

#!/usr/bin/env python3
"""
AI Meeting Notes Generator
Usage: python main.py path/to/recording.mp3
"""

import sys
from pathlib import Path
from datetime import datetime

from transcribe import transcribe_audio, save_transcript
from summarize import summarize_transcript, save_summary

def process_meeting(audio_path: str, title: str = None) -> str:
    """Full pipeline: audio -> transcript -> summary."""

    audio_path = Path(audio_path)
    timestamp = datetime.now().strftime("%Y-%m-%d_%H%M")
    title = title or audio_path.stem

    print(f"Processing: {audio_path.name}")

    # Step 1: Transcribe
    print("Transcribing audio (this may take a few minutes)...")
    transcript = transcribe_audio(str(audio_path), model_size="base")

    transcript_path = f"transcripts/{timestamp}_{title}.txt"
    save_transcript(transcript, transcript_path)
    print(f"Transcript saved: {transcript_path}")

    # Step 2: Summarize
    print("Generating AI summary...")
    summary = summarize_transcript(transcript)

    summary_path = f"summaries/{timestamp}_{title}.md"
    save_summary(summary, summary_path, {"title": title})
    print(f"Summary saved: {summary_path}")

    return summary_path

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python main.py <audio_file> [title]")
        sys.exit(1)

    audio_file = sys.argv[1]
    title = sys.argv[2] if len(sys.argv) > 2 else None

    output = process_meeting(audio_file, title)
    print(f"\nDone! Open {output} to see your notes.")
Enter fullscreen mode Exit fullscreen mode

Step 5: Take It Further

Here are upgrades for next weekend:

Add a Watchdog: Automatically process new recordings:

from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

class RecordingHandler(FileSystemEventHandler):
    def on_created(self, event):
        if event.src_path.endswith(('.mp3', '.m4a', '.wav')):
            process_meeting(event.src_path)
Enter fullscreen mode Exit fullscreen mode

Build a Simple Web UI: Use Streamlit for drag-and-drop uploads:

import streamlit as st

uploaded_file = st.file_uploader("Drop your meeting recording")
if uploaded_file:
    # Process and display summary in real-time
Enter fullscreen mode Exit fullscreen mode

Send to Your Task Manager: Auto-create Todoist/Linear tasks from action items using their APIs.

The Real Value

This project isn't just about transcription—tools like Otter.ai already do that. The value is in ownership and customization:

  • Your audio stays local (Whisper runs on your machine)
  • Summaries are formatted YOUR way
  • Everything saves to Markdown for Obsidian/Notion/whatever
  • You can tune the prompt for your meeting style
  • No monthly subscription

I've been running this for three months. My action item capture rate went from ~60% to nearly 100%. More importantly, I actually attend meetings now instead of frantically scribbling notes.

Key Takeaways

  1. Local-first AI is practical now. Whisper runs fine on a decent laptop.
  2. Chain simple tools for powerful workflows. Transcription + LLM + file system = complete solution.
  3. Own your data. Build systems that work with your existing tools, not proprietary silos.

The code above is a starting point. Fork it, break it, make it yours. That's the whole point of weekend projects.


Got a weekend project you've built? Drop it in the comments—I'd love to see what you're automating.

Top comments (0)