A modern macOS application that combines real-time speech transcription with AI-powered summaries. Built with React (TypeScript) frontend and Python (FastAPI) backend, powered by Deepgram for transcription and Google Gemini for AI insights.
- π€ Real-time Transcription - Live speech-to-text using Deepgram's advanced API
- π Speaker Audio Capture - Transcribe YouTube videos, music, or any system audio using BlackHole
- π€ AI-Powered Summaries - Intelligent meeting summaries using Google Gemini Flash 2.5
- π Smart Insights - Extract action items, key points, and decisions automatically
- π¨ Modern UI - Beautiful, responsive design optimized for macOS
- π Privacy-Focused - No bots in meetings, audio processed securely
- β‘ Real-time Updates - See transcription as you speak with WebSocket connection
- π΅ Multi-Output Audio - Hear audio while transcribing simultaneously
- π Easy Export - Copy transcriptions and summaries to clipboard
Frontend:
- React 18 with TypeScript
- Modern CSS with glassmorphism design
- Lucide React icons
- WebSocket for real-time communication
Backend:
- Python FastAPI
- Deepgram SDK for speech recognition
- Google Generative AI (Gemini)
- WebSocket support
- Pydantic for data validation
Before you begin, ensure you have:
- Python 3.8+ - Download Python
- Node.js 16+ - Download Node.js
- Deepgram API Key - Get free API key
- Google Gemini API Key - Get API key
- BlackHole (Optional) - For transcribing speaker audio (videos, music, etc.) instead of just microphone input
git clone <your-repo-url>
cd ai-note-taker# Install Python dependencies
pip install -r requirements.txt
# Create environment file
cp env.example .env
# Edit .env file with your API keys
# DEEPGRAM_API_KEY=your_deepgram_api_key_here
# GEMINI_API_KEY=your_gemini_api_key_here# Install Node.js dependencies
npm installDeepgram API Key:
- Go to Deepgram Console
- Sign up for a free account (includes $200 credit)
- Create a new project
- Copy your API key
Google Gemini API Key:
- Go to Google AI Studio
- Sign in with your Google account
- Create a new API key
- Copy your API key
Option A: Using the Startup Script (Recommended)
# Terminal 1 - Start Python Backend
./start_backend.sh
# Terminal 2 - Start React Frontend
npm startOption B: Manual Startup
# Terminal 1 - Start Python Backend
cd backend
source venv/bin/activate
uvicorn main:app --host 0.0.0.0 --port 8000
# Terminal 2 - Start React Frontend
npm startExpected Output:
- Backend runs on
http://localhost:8000 - Frontend runs on
http://localhost:3000 - You should see "INFO: Uvicorn running on http://0.0.0.0:8000" for backend
- You should see "webpack compiled successfully" for frontend
Quick Status Check:
# Check if backend is running
curl http://localhost:8000/api/health
# Should return: {"status":"healthy","deepgram_configured":true,"gemini_configured":true}Visual Confirmation:
- Frontend: Open
http://localhost:3000- should show the AI Note Taker interface - Backend: Open
http://localhost:8000- should show API information - Both terminals should show no error messages
- Open
http://localhost:3000in your browser - Click "Start Recording" and allow microphone access
- Start speaking - see real-time transcription
- Click "AI Summary" to get intelligent insights
- Use quick actions for specific extractions
- Copy results or clear to start over
Want to transcribe audio from YouTube videos, music, or any speaker output? Follow this advanced setup to capture system audio instead of just microphone input.
- macOS (BlackHole is macOS-specific)
- Homebrew - Install Homebrew if you don't have it
# Install BlackHole virtual audio driver
brew install blackhole-2ch
# Note: You'll need to restart your Mac after installation
sudo rebootIf you want to both hear audio AND transcribe it simultaneously:
-
Open Audio MIDI Setup:
open -a "Audio MIDI Setup" -
Create Multi-Output Device:
- Click the "+" button β "Create Multi-Output Device"
- Check both boxes:
- β Your speakers (e.g., "Mac mini Speakers")
- β BlackHole 2ch
- Rename it to "Speakers + BlackHole"
Option A: Transcribe Only (No Audio Playback)
# Set both input and output to BlackHole
# Output: All system audio goes to BlackHole (no speakers)
# Input: App captures audio from BlackHoleOption B: Hear + Transcribe Simultaneously
# Set output to Multi-Output Device (speakers + BlackHole)
# Set input to BlackHole 2ch
# Result: You hear audio AND app captures itInstall SwitchAudioSource for easy switching:
brew install switchaudio-osxQuick Commands:
# Check available audio devices
SwitchAudioSource -a
# Set output to BlackHole only (transcribe only, no audio)
SwitchAudioSource -s "BlackHole 2ch"
SwitchAudioSource -t input -s "BlackHole 2ch"
# Set output to Multi-Output (hear + transcribe)
SwitchAudioSource -s "Speakers + BlackHole"
SwitchAudioSource -t input -s "BlackHole 2ch"
# Return to normal (speakers + microphone)
SwitchAudioSource -s "Mac mini Speakers"
SwitchAudioSource -t input -s "External Microphone"- Configure audio routing (using commands above)
- Play a YouTube video with clear speech
- Open your transcription app:
http://localhost:3000 - Click "Start Recording"
- Watch the video's audio get transcribed in real-time! π΅βπ
YouTube Video β System Audio β BlackHole β Your App β Deepgram β Transcription
π₯ π π π± π€ π
BlackHole acts as a "virtual cable" that routes system audio to your transcription app, enabling you to transcribe any audio playing on your computer.
βββββββββββββββββββ WebSocket βββββββββββββββββββ API Calls βββββββββββββββββββ
β React App β ββββββββββββββββΊ β Python Backend β ββββββββββββββββΊ β Deepgram API β
β (Frontend) β β (FastAPI) β β (Speech AI) β
β β β β βββββββββββββββββββ
β β HTTP/REST β β API Calls βββββββββββββββββββ
β β ββββββββββββββββΊ β β ββββββββββββββββΊ β Gemini API β
βββββββββββββββββββ βββββββββββββββββββ β (AI Summary) β
βββββββββββββββββββ
ai-note-taker/
βββ backend/
β βββ main.py # Python FastAPI server
βββ src/
β βββ App.tsx # Main React component
β βββ App.css # Styles for the app
β βββ types.ts # TypeScript type definitions
β βββ index.tsx # React app entry point
β βββ index.css # Global styles
βββ public/
β βββ index.html # HTML template
βββ package.json # Node.js dependencies
βββ requirements.txt # Python dependencies
βββ tsconfig.json # TypeScript configuration
βββ env.example # Environment variables template
βββ README.md # This file
Since you're new to TypeScript, here are the key concepts used in this project:
interface TranscriptionMessage {
type: string; // Required field
text?: string; // Optional field (note the ?)
is_final?: boolean; // Optional boolean
}What this means: Interfaces define the shape of objects. The ? makes properties optional.
const [isRecording, setIsRecording] = useState<boolean>(false);
const [transcription, setTranscription] = useState<string>('');What this means: We tell TypeScript exactly what type of data each state variable holds.
type ConnectionStatus = 'Disconnected' | 'Connected' | 'Connection Error';What this means: A variable can be one of several specific string values.
const websocketRef = useRef<WebSocket | null>(null);What this means: The ref can hold either a WebSocket object OR null.
const connectWebSocket = (): Promise<void> => {
// Returns a Promise that resolves to nothing (void)
};ws://localhost:8000/ws- Real-time transcription
GET /- API informationGET /api/health- Health checkPOST /api/summarize- Generate AI summary
// Generate AI summary
const response = await fetch('http://localhost:8000/api/summarize', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: "Meeting transcript here...",
summary_type: "meeting" // or "action_items" or "key_points"
})
});- Audio Capture: React captures microphone audio using MediaRecorder
- WebSocket Streaming: Audio sent to Python backend via WebSocket
- Deepgram Processing: Backend forwards audio to Deepgram's real-time API
- Live Results: Deepgram returns both interim and final transcriptions
- UI Updates: React displays results in real-time
- Text Processing: Complete transcript sent to backend
- Gemini Analysis: Google's Gemini AI analyzes the content
- Structured Output: AI returns formatted summaries, action items, etc.
- Display: Frontend shows organized insights
- Glassmorphism Design - Modern translucent panels with blur effects
- Real-time Status - Live connection status with animated indicators
- Responsive Layout - Works on desktop and mobile devices
- Copy Functionality - Easy clipboard integration
- Loading States - Visual feedback during AI processing
- Error Handling - Clear error messages and recovery options
1. Backend Server Won't Start or Stops Immediately
Symptoms: Backend starts but immediately exits, or shows "venv/bin/activate: No such file or directory"
Solutions:
# Make sure you're in the right directory
cd /path/to/your/RealtimeVoiceToText
# Use the startup script
chmod +x start_backend.sh
./start_backend.sh
# OR manually activate virtual environment
cd backend
source venv/bin/activate
uvicorn main:app --host 0.0.0.0 --port 80002. "Cannot find module 'react'" Error
npm install3. "API Key not found" Error
- Ensure
.envfile exists inbackend/directory (not root) - Add your actual API keys to
backend/.env - Restart the Python backend
4. Microphone Permission Denied
- Check browser microphone permissions
- On macOS: System Preferences β Security & Privacy β Privacy β Microphone
- Ensure browser has microphone access
5. WebSocket Connection Failed
- Ensure Python backend is running on port 8000
- Check that you see "INFO: Uvicorn running on http://0.0.0.0:8000"
- Try restarting both frontend and backend
- Check firewall settings
6. AI Summary Not Working
- Verify Gemini API key is correct in
backend/.env - Check backend logs for errors
- Ensure you have API quota remaining
7. "It was working before" - Quick Fix
- Backend probably stopped running
- Use
./start_backend.shto restart it - Frontend usually stays running and is fine
6. No Transcription from Speaker Audio
- Verify BlackHole is installed:
SwitchAudioSource -a | grep BlackHole - Check audio routing: Output and Input both use BlackHole
- Restart browser after changing audio settings
- Check browser console (F12) for audio device selection
7. Can't Hear Audio While Transcribing
- Use Multi-Output Device instead of BlackHole only
- Ensure both speakers and BlackHole are checked in Multi-Output Device
- Audio MIDI Setup β Multi-Output Device β Check both boxes
8. Browser Not Using BlackHole
- Clear browser microphone permissions
- Refresh page and manually select "BlackHole 2ch" when prompted
- Chrome: Settings β Privacy β Microphone β Allow localhost:3000
9. BlackHole Not Appearing in Browser
- Restart browser after installing BlackHole
- Restart Mac if BlackHole still not visible
- Check System Preferences β Sound β Input for BlackHole
10. Audio Cutting Out or Poor Quality
- Reduce audio constraints in browser (disable echo cancellation for system audio)
- Check CPU usage - transcription is resource-intensive
- Try lower sample rate in MediaRecorder settings
# Backend development with auto-reload
cd backend && uvicorn main:app --reload
# Frontend development
npm start
# Install new Python package
pip install package_name && pip freeze > requirements.txt
# Install new Node package
npm install package_name- Build React App
npm run build- Package Python Backend
pip install pyinstaller
pyinstaller --onefile backend/main.py- Create macOS App Bundle
- Use tools like
py2apporelectronto create native macOS app - Include both frontend build and backend executable
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Deepgram for excellent speech-to-text API
- Google AI for Gemini AI capabilities
- FastAPI for the modern Python web framework
- React for the powerful frontend library
- Lucide for beautiful icons
If you encounter issues:
- Check the troubleshooting section above
- Look at browser console for error messages
- Check Python backend logs
- Create an issue in this repository
Happy note-taking! π€βπβπ€