|
| 1 | +# Architecture Overview |
| 2 | + |
| 3 | +Bite-Size Notes is a desktop meeting transcriber that captures microphone and system audio simultaneously, runs local Whisper speech-to-text (via faster-whisper), summarizes transcripts with a local LLM (Qwen3-4B via llama-cpp), and displays a live color-coded transcript. Built with PySide6 (Qt) and Python 3.10+. |
| 4 | + |
| 5 | +**Tech stack**: PySide6, sounddevice, pyaudiowpatch (Windows), faster-whisper, llama-cpp-python, huggingface-hub, NumPy. |
| 6 | + |
| 7 | +## Directory Structure |
| 8 | + |
| 9 | +``` |
| 10 | +src/bite_size_notes/ |
| 11 | +├── __init__.py # Package root, declares __version__ |
| 12 | +├── __main__.py # `python -m bite_size_notes` entry point |
| 13 | +├── app.py # main() bootstrap, QApplication, crash handler |
| 14 | +├── assets/ |
| 15 | +│ ├── logo.ico # App icon (runtime & PyInstaller) |
| 16 | +│ └── readme.png # Screenshot for README |
| 17 | +│ |
| 18 | +├── audio/ # Audio capture subsystem |
| 19 | +│ ├── __init__.py |
| 20 | +│ ├── capture.py # AudioCaptureThread, AudioChunk |
| 21 | +│ ├── devices.py # Device enumeration (mic, loopback) |
| 22 | +│ └── mixer.py # mix_audio() utility |
| 23 | +│ |
| 24 | +├── gui/ # Qt user interface |
| 25 | +│ ├── __init__.py |
| 26 | +│ ├── main_window.py # MainWindow, _ModelPreloadThread, _SummarizeThread |
| 27 | +│ ├── transcript_view.py # TranscriptView (center panel) |
| 28 | +│ ├── chat_bubble.py # TranscriptLineWidget, _AutoResizePlainTextEdit |
| 29 | +│ ├── sidebar_panel.py # SidebarPanel, _SessionItemWidget |
| 30 | +│ ├── output_panel.py # OutputPanel (summary display) |
| 31 | +│ ├── notes_panel.py # NotesPanel (floating overlay) |
| 32 | +│ ├── settings_dialog.py # SettingsDialog, model download threads |
| 33 | +│ ├── export_dialog.py # export_transcript(), export_output() |
| 34 | +│ └── themes.py # Dark/Light palettes, stylesheet builder |
| 35 | +│ |
| 36 | +├── models/ # Data models & persistence |
| 37 | +│ ├── __init__.py |
| 38 | +│ ├── transcript.py # TranscriptSegment, TranscriptSession |
| 39 | +│ └── session_store.py # SessionStore (filesystem persistence) |
| 40 | +│ |
| 41 | +├── summarization/ # LLM summarization |
| 42 | +│ ├── __init__.py |
| 43 | +│ └── engine.py # Qwen3-4B GGUF via llama-cpp-python |
| 44 | +│ |
| 45 | +├── transcription/ # Speech-to-text |
| 46 | +│ ├── __init__.py |
| 47 | +│ ├── engine.py # TranscriptionEngine (faster-whisper wrapper) |
| 48 | +│ ├── worker.py # TranscriberWorker (QThread) |
| 49 | +│ └── model_utils.py # Model cache checks & downloads |
| 50 | +│ |
| 51 | +└── utils/ # Shared utilities |
| 52 | + ├── __init__.py |
| 53 | + ├── config.py # AppConfig (QSettings wrapper) |
| 54 | + └── platform.py # is_windows(), is_macos() |
| 55 | +``` |
| 56 | + |
| 57 | +## Module Responsibilities |
| 58 | + |
| 59 | +### `audio/` |
| 60 | + |
| 61 | +Handles all audio input. `AudioCaptureThread` opens two parallel streams — one for the microphone (via sounddevice) and one for system/loopback audio (WASAPI on Windows, BlackHole on macOS). It accumulates audio in per-stream buffers, runs silence detection, and flushes `AudioChunk` dataclass objects into a shared `queue.Queue`. `devices.py` provides device enumeration and auto-detection helpers. `mixer.py` contains a utility for mixing two audio arrays (zero-pad + normalize). |
| 62 | + |
| 63 | +### `transcription/` |
| 64 | + |
| 65 | +Converts audio chunks to text. `TranscriptionEngine` wraps `faster_whisper.WhisperModel` and runs inference with VAD filtering. `TranscriberWorker` is a `QThread` that pulls `AudioChunk` objects from the shared queue, calls the engine, and emits `transcription_ready` Qt signals with speaker label, timestamp, and text. `model_utils.py` provides helpers to check if a Whisper model is cached and to download one. |
| 66 | + |
| 67 | +### `summarization/` |
| 68 | + |
| 69 | +Generates meeting summaries from transcript text. Uses the Qwen3-4B-Q4_K_M GGUF model via `llama-cpp-python`. The module provides `load_summarizer()` to download/load the model and `summarize()` to run inference with a structured system prompt that produces formatted meeting notes. |
| 70 | + |
| 71 | +### `gui/` |
| 72 | + |
| 73 | +All Qt UI code. `MainWindow` orchestrates the application — managing the record/stop lifecycle, connecting signals between audio/transcription threads and the UI, and handling session management. The layout is a horizontal `QSplitter` with three panels: `SidebarPanel` (session list), `TranscriptView` (live transcript with editable chat bubbles), and `OutputPanel` (summary display). `NotesPanel` is a floating overlay for user notes. `SettingsDialog` manages preferences and model downloads. `themes.py` provides dark/light/system theme support. |
| 74 | + |
| 75 | +### `models/` |
| 76 | + |
| 77 | +Data structures and persistence. `TranscriptSegment` represents a single transcribed utterance (text, source, timestamp, speaker). `TranscriptSession` aggregates segments into a session with title, summary, and export methods (text, SRT, Markdown, JSON). `SessionStore` manages reading/writing session JSON files to the OS-specific app data directory. |
| 78 | + |
| 79 | +### `utils/` |
| 80 | + |
| 81 | +Shared configuration and platform detection. `AppConfig` wraps `QSettings` with typed properties for all user preferences (devices, model size, language, theme). `platform.py` provides `is_windows()` and `is_macos()` helpers used throughout the codebase. |
| 82 | + |
| 83 | +## Class Hierarchy |
| 84 | + |
| 85 | +### Audio |
| 86 | + |
| 87 | +| Class | Base | Role | |
| 88 | +|---|---|---| |
| 89 | +| `AudioChunk` | `dataclass` | Data container: `data` (float32 ndarray), `source` ("mic"/"loopback"), `timestamp`, `sample_rate` | |
| 90 | +| `AudioCaptureThread` | `threading.Thread` | Opens mic + loopback streams, silence detection, flushes chunks to queue | |
| 91 | +| `AudioDevice` | `dataclass` | Device descriptor: `index`, `name`, `max_input_channels`, `default_samplerate`, `is_loopback` | |
| 92 | + |
| 93 | +### Transcription |
| 94 | + |
| 95 | +| Class | Base | Role | |
| 96 | +|---|---|---| |
| 97 | +| `TranscriptionEngine` | — | Wraps `faster_whisper.WhisperModel`; `transcribe(audio) -> list[dict]` | |
| 98 | +| `TranscriberWorker` | `QThread` | Pulls chunks from queue, runs engine, emits `transcription_ready` signal | |
| 99 | + |
| 100 | +### Summarization |
| 101 | + |
| 102 | +| Function | Role | |
| 103 | +|---|---| |
| 104 | +| `load_summarizer()` | Downloads/loads Qwen3-4B GGUF, returns `Llama` instance | |
| 105 | +| `summarize(llm, text)` | Runs chat completion, strips think blocks, returns summary string | |
| 106 | +| `is_summarizer_cached()` | Checks HF cache for the GGUF file | |
| 107 | +| `download_summarizer_sync()` | Downloads the GGUF via `hf_hub_download` | |
| 108 | + |
| 109 | +### GUI |
| 110 | + |
| 111 | +| Class | Base | Role | |
| 112 | +|---|---|---| |
| 113 | +| `MainWindow` | `QMainWindow` | Top-level window; orchestrates recording, transcription, summarization, sessions | |
| 114 | +| `TranscriptView` | `QWidget` | Scrollable list of transcript chat bubbles | |
| 115 | +| `TranscriptLineWidget` | `QFrame` | Single transcript entry: timestamp + speaker label + editable text | |
| 116 | +| `_AutoResizePlainTextEdit` | `QPlainTextEdit` | Text edit that auto-sizes to content height | |
| 117 | +| `SidebarPanel` | `QWidget` | Session list with new/rename/delete actions | |
| 118 | +| `_SessionItemWidget` | `QWidget` | Single session row in the sidebar | |
| 119 | +| `OutputPanel` | `QWidget` | Summary display with "Bite Size It" button, copy/export controls | |
| 120 | +| `NotesPanel` | `QFrame` | Floating 300x250 overlay for user notes | |
| 121 | +| `SettingsDialog` | `QDialog` | Preferences: theme, devices, model size, language, summarizer | |
| 122 | +| `_ModelPreloadThread` | `QThread` | Loads `TranscriptionEngine` in background at startup | |
| 123 | +| `_SummarizeThread` | `QThread` | Runs summarization in background | |
| 124 | +| `_ModelDownloadThread` | `QThread` | Downloads Whisper model (from settings dialog) | |
| 125 | +| `_SummarizerDownloadThread` | `QThread` | Downloads GGUF model (from settings dialog) | |
| 126 | + |
| 127 | +### Models |
| 128 | + |
| 129 | +| Class | Base | Role | |
| 130 | +|---|---|---| |
| 131 | +| `TranscriptSegment` | `dataclass` | Single utterance: `text`, `source`, `timestamp`, `speaker_label` | |
| 132 | +| `TranscriptSession` | `dataclass` | Full session: segments list, title, summary, start_time, UUID; export methods | |
| 133 | +| `SessionStore` | — | Filesystem CRUD for session JSON files in app data directory | |
| 134 | + |
| 135 | +### Utils |
| 136 | + |
| 137 | +| Class | Base | Role | |
| 138 | +|---|---|---| |
| 139 | +| `AppConfig` | — | `QSettings` wrapper with typed properties for all user preferences | |
| 140 | + |
| 141 | +--- |
| 142 | + |
| 143 | +See also: [Data Flow](data-flow.md) | [Platform Guide](platform-guide.md) |
0 commit comments