meeting-noter 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of meeting-noter might be problematic. Click here for more details.

Files changed (39) hide show
  1. meeting_noter/__init__.py +3 -0
  2. meeting_noter/__main__.py +6 -0
  3. meeting_noter/audio/__init__.py +1 -0
  4. meeting_noter/audio/capture.py +209 -0
  5. meeting_noter/audio/encoder.py +208 -0
  6. meeting_noter/audio/system_audio.py +363 -0
  7. meeting_noter/cli.py +837 -0
  8. meeting_noter/config.py +197 -0
  9. meeting_noter/daemon.py +519 -0
  10. meeting_noter/gui/__init__.py +5 -0
  11. meeting_noter/gui/__main__.py +6 -0
  12. meeting_noter/gui/app.py +53 -0
  13. meeting_noter/gui/main_window.py +50 -0
  14. meeting_noter/gui/meetings_tab.py +348 -0
  15. meeting_noter/gui/recording_tab.py +358 -0
  16. meeting_noter/gui/settings_tab.py +249 -0
  17. meeting_noter/install/__init__.py +1 -0
  18. meeting_noter/install/macos.py +102 -0
  19. meeting_noter/meeting_detector.py +333 -0
  20. meeting_noter/menubar.py +411 -0
  21. meeting_noter/mic_monitor.py +456 -0
  22. meeting_noter/output/__init__.py +1 -0
  23. meeting_noter/output/writer.py +96 -0
  24. meeting_noter/resources/__init__.py +1 -0
  25. meeting_noter/resources/icon.icns +0 -0
  26. meeting_noter/resources/icon.png +0 -0
  27. meeting_noter/resources/icon_128.png +0 -0
  28. meeting_noter/resources/icon_16.png +0 -0
  29. meeting_noter/resources/icon_256.png +0 -0
  30. meeting_noter/resources/icon_32.png +0 -0
  31. meeting_noter/resources/icon_512.png +0 -0
  32. meeting_noter/resources/icon_64.png +0 -0
  33. meeting_noter/transcription/__init__.py +1 -0
  34. meeting_noter/transcription/engine.py +234 -0
  35. meeting_noter-0.7.0.dist-info/METADATA +224 -0
  36. meeting_noter-0.7.0.dist-info/RECORD +39 -0
  37. meeting_noter-0.7.0.dist-info/WHEEL +5 -0
  38. meeting_noter-0.7.0.dist-info/entry_points.txt +2 -0
  39. meeting_noter-0.7.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,234 @@
1
+ """Transcription engine using faster-whisper."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import click
6
+ from pathlib import Path
7
+ from datetime import datetime
8
+ from typing import Optional
9
+
10
+
11
+ def _get_bundled_model_path() -> Optional[Path]:
12
+ """Check if bundled model is available via meeting-noter-models package."""
13
+ try:
14
+ from meeting_noter_models import get_model_path, MODEL_NAME
15
+ model_path = get_model_path()
16
+ if model_path.exists() and (model_path / "model.bin").exists():
17
+ return model_path
18
+ except ImportError:
19
+ pass
20
+ return None
21
+
22
+
23
+ def get_model(model_size: str = "tiny.en"):
24
+ """Load the Whisper model.
25
+
26
+ Priority:
27
+ 1. Bundled model from meeting-noter-models package (offline)
28
+ 2. Download from Hugging Face Hub (cached after first download)
29
+ """
30
+ from faster_whisper import WhisperModel
31
+
32
+ # Check for bundled model first (for offline use)
33
+ bundled_path = _get_bundled_model_path()
34
+ if bundled_path and model_size == "tiny.en":
35
+ click.echo(f"Loading bundled model '{model_size}'...")
36
+ model = WhisperModel(
37
+ str(bundled_path),
38
+ device="cpu",
39
+ compute_type="int8",
40
+ )
41
+ return model
42
+
43
+ # Fall back to Hugging Face download
44
+ click.echo(f"Loading model '{model_size}'...")
45
+
46
+ # Use INT8 for CPU efficiency
47
+ model = WhisperModel(
48
+ model_size,
49
+ device="cpu",
50
+ compute_type="int8",
51
+ )
52
+
53
+ return model
54
+
55
+
56
+ def format_timestamp(seconds: float) -> str:
57
+ """Format seconds as [HH:MM:SS] or [MM:SS]."""
58
+ hours = int(seconds // 3600)
59
+ minutes = int((seconds % 3600) // 60)
60
+ secs = int(seconds % 60)
61
+
62
+ if hours > 0:
63
+ return f"[{hours:02d}:{minutes:02d}:{secs:02d}]"
64
+ return f"[{minutes:02d}:{secs:02d}]"
65
+
66
+
67
+ def transcribe_audio(audio_path: Path, model_size: str = "tiny.en") -> str:
68
+ """Transcribe an audio file.
69
+
70
+ Args:
71
+ audio_path: Path to MP3 or WAV file
72
+ model_size: Whisper model to use
73
+
74
+ Returns:
75
+ Formatted transcript string
76
+ """
77
+ model = get_model(model_size)
78
+
79
+ click.echo(f"Transcribing {audio_path.name}...")
80
+
81
+ segments, info = model.transcribe(
82
+ str(audio_path),
83
+ beam_size=5,
84
+ vad_filter=True, # Voice Activity Detection
85
+ vad_parameters=dict(
86
+ min_silence_duration_ms=500,
87
+ ),
88
+ )
89
+
90
+ # Build transcript
91
+ lines = []
92
+ lines.append("Meeting Transcription")
93
+ lines.append(f"File: {audio_path.name}")
94
+ lines.append(f"Transcribed: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
95
+ lines.append(f"Language: {info.language} (probability: {info.language_probability:.2f})")
96
+ lines.append(f"Duration: {info.duration:.1f} seconds")
97
+ lines.append("-" * 40)
98
+ lines.append("")
99
+
100
+ for segment in segments:
101
+ timestamp = format_timestamp(segment.start)
102
+ text = segment.text.strip()
103
+ if text:
104
+ lines.append(f"{timestamp} {text}")
105
+
106
+ return "\n".join(lines)
107
+
108
+
109
+ def transcribe_file(
110
+ file: Optional[str],
111
+ output_dir: Path,
112
+ model_size: str = "tiny.en",
113
+ transcripts_dir: Optional[Path] = None,
114
+ ):
115
+ """Transcribe a recording file.
116
+
117
+ If no file specified, transcribes the most recent recording.
118
+ Saves transcript to transcripts_dir (defaults to same as audio file).
119
+ """
120
+ # Find the file to transcribe
121
+ if file:
122
+ audio_path = Path(file)
123
+ if not audio_path.exists():
124
+ # Try in output dir
125
+ audio_path = output_dir / file
126
+ if not audio_path.exists():
127
+ click.echo(click.style(f"File not found: {file}", fg="red"))
128
+ return
129
+ else:
130
+ # Find most recent recording
131
+ mp3_files = sorted(output_dir.glob("*.mp3"), key=lambda p: p.stat().st_mtime)
132
+ if not mp3_files:
133
+ click.echo(click.style(
134
+ f"No recordings found in {output_dir}",
135
+ fg="yellow"
136
+ ))
137
+ return
138
+ audio_path = mp3_files[-1]
139
+ click.echo(f"Using most recent recording: {audio_path.name}")
140
+
141
+ # Determine transcript path
142
+ if transcripts_dir:
143
+ transcripts_dir.mkdir(parents=True, exist_ok=True)
144
+ transcript_path = transcripts_dir / audio_path.with_suffix(".txt").name
145
+ else:
146
+ transcript_path = audio_path.with_suffix(".txt")
147
+ if transcript_path.exists():
148
+ click.echo(click.style(
149
+ f"Transcript already exists: {transcript_path.name}",
150
+ fg="yellow"
151
+ ))
152
+ if not click.confirm("Overwrite?"):
153
+ return
154
+
155
+ # Transcribe
156
+ try:
157
+ transcript = transcribe_audio(audio_path, model_size)
158
+
159
+ # Save transcript
160
+ transcript_path.write_text(transcript)
161
+ click.echo(click.style(
162
+ f"\nTranscript saved: {transcript_path}",
163
+ fg="green"
164
+ ))
165
+
166
+ # Show preview
167
+ click.echo("\n--- Preview ---")
168
+ lines = transcript.split("\n")
169
+ preview_lines = lines[:15]
170
+ for line in preview_lines:
171
+ click.echo(line)
172
+ if len(lines) > 15:
173
+ click.echo(f"... ({len(lines) - 15} more lines)")
174
+
175
+ except Exception as e:
176
+ click.echo(click.style(f"Transcription failed: {e}", fg="red"))
177
+ raise
178
+
179
+
180
+ def transcribe_live(output_dir: Path, model_size: str = "tiny.en"):
181
+ """Real-time transcription of ongoing recording.
182
+
183
+ Note: This is more CPU intensive and may have latency.
184
+ """
185
+ click.echo(click.style(
186
+ "Live transcription is experimental and CPU-intensive.",
187
+ fg="yellow"
188
+ ))
189
+
190
+ # Find active recording (most recent, still being written)
191
+ mp3_files = sorted(output_dir.glob("*.mp3"), key=lambda p: p.stat().st_mtime)
192
+ if not mp3_files:
193
+ click.echo("No recordings found. Is the daemon running?")
194
+ return
195
+
196
+ latest = mp3_files[-1]
197
+ click.echo(f"Monitoring: {latest.name}")
198
+ click.echo("Press Ctrl+C to stop.\n")
199
+
200
+ model = get_model(model_size)
201
+ last_position = 0
202
+
203
+ try:
204
+ import time
205
+ while True:
206
+ # Check file size
207
+ current_size = latest.stat().st_size
208
+ if current_size > last_position:
209
+ # New data available - transcribe the whole file
210
+ # (faster-whisper doesn't support streaming well)
211
+ try:
212
+ segments, info = model.transcribe(
213
+ str(latest),
214
+ beam_size=3, # Faster for live
215
+ vad_filter=True,
216
+ )
217
+
218
+ # Print new segments
219
+ for segment in segments:
220
+ if segment.end > last_position / 1000: # Rough estimate
221
+ timestamp = format_timestamp(segment.start)
222
+ text = segment.text.strip()
223
+ if text:
224
+ click.echo(f"{timestamp} {text}")
225
+
226
+ last_position = current_size
227
+ except Exception as e:
228
+ # File might be locked, retry
229
+ pass
230
+
231
+ time.sleep(5) # Check every 5 seconds
232
+
233
+ except KeyboardInterrupt:
234
+ click.echo("\nStopped live transcription.")
@@ -0,0 +1,224 @@
1
+ Metadata-Version: 2.4
2
+ Name: meeting-noter
3
+ Version: 0.7.0
4
+ Summary: Offline meeting transcription for macOS with automatic meeting detection
5
+ Author: Victor
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/tech4vision/meeting-noter
8
+ Project-URL: Repository, https://github.com/tech4vision/meeting-noter
9
+ Project-URL: Issues, https://github.com/tech4vision/meeting-noter/issues
10
+ Keywords: meeting,transcription,whisper,offline,speech-to-text,audio
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ Requires-Dist: click>=8.0
26
+ Requires-Dist: sounddevice>=0.4.6
27
+ Requires-Dist: numpy>=1.24
28
+ Requires-Dist: faster-whisper>=1.0.0
29
+ Requires-Dist: rumps>=0.4.0
30
+ Requires-Dist: PyQt6>=6.5.0
31
+ Requires-Dist: imageio-ffmpeg>=0.4.9
32
+ Requires-Dist: pyobjc-framework-Cocoa>=9.0; sys_platform == "darwin"
33
+ Requires-Dist: pyobjc-framework-Quartz>=9.0; sys_platform == "darwin"
34
+ Requires-Dist: pyobjc-framework-ScreenCaptureKit>=9.0; sys_platform == "darwin"
35
+ Requires-Dist: pyobjc-framework-AVFoundation>=9.0; sys_platform == "darwin"
36
+ Requires-Dist: pyobjc-framework-CoreMedia>=9.0; sys_platform == "darwin"
37
+ Requires-Dist: pyobjc-framework-libdispatch>=9.0; sys_platform == "darwin"
38
+ Provides-Extra: offline
39
+ Requires-Dist: meeting-noter-models>=0.1.0; extra == "offline"
40
+ Provides-Extra: dev
41
+ Requires-Dist: pytest>=7.0; extra == "dev"
42
+ Requires-Dist: pytest-cov; extra == "dev"
43
+ Requires-Dist: black; extra == "dev"
44
+ Requires-Dist: ruff; extra == "dev"
45
+ Requires-Dist: mypy; extra == "dev"
46
+
47
+ # Meeting Noter
48
+
49
+ Offline meeting transcription tool for macOS. Captures both your voice and meeting participants' audio, saves to MP3, and transcribes locally using Whisper.
50
+
51
+ ## Features
52
+
53
+ - **No setup required** - Just install and run
54
+ - **Captures both sides** - Your mic + system audio (meeting participants)
55
+ - **Offline transcription** - Uses Whisper locally, no API calls
56
+ - **Auto-detection** - Detects active meetings (Zoom, Teams, Meet, Slack)
57
+ - **Multiple interfaces** - Menu bar app, desktop GUI, or CLI
58
+ - **Auto-segmentation** - One file per meeting (detects silence)
59
+
60
+ ## Installation
61
+
62
+ ```bash
63
+ pipx install meeting-noter
64
+ ```
65
+
66
+ **For corporate/offline environments** (bundles Whisper model, no download needed):
67
+ ```bash
68
+ pipx install "meeting-noter[offline]"
69
+ ```
70
+
71
+ ### Upgrading
72
+
73
+ ```bash
74
+ # Standard
75
+ pipx upgrade meeting-noter
76
+
77
+ # With offline model
78
+ pipx reinstall "meeting-noter[offline]"
79
+ ```
80
+
81
+ No system dependencies required - ffmpeg is bundled automatically.
82
+
83
+ ## Quick Start
84
+
85
+ **Menu Bar App** (recommended):
86
+ ```bash
87
+ meeting-noter menubar
88
+ ```
89
+
90
+ **Desktop GUI**:
91
+ ```bash
92
+ meeting-noter gui
93
+ ```
94
+
95
+ **CLI Recording**:
96
+ ```bash
97
+ meeting-noter start "Weekly Standup"
98
+ ```
99
+
100
+ The app will request microphone and Screen Recording permissions on first use.
101
+
102
+ ## Usage
103
+
104
+ ### Recording
105
+ - The menu bar app auto-detects meetings and prompts to record
106
+ - Or manually start recording via the GUI/CLI
107
+ - Press Ctrl+C (CLI) or click Stop to end recording
108
+
109
+ ### Transcription
110
+ Recordings are auto-transcribed by default. Or manually:
111
+
112
+ ```bash
113
+ # Transcribe the most recent recording
114
+ meeting-noter transcribe
115
+
116
+ # Transcribe a specific file
117
+ meeting-noter transcribe recording.mp3
118
+
119
+ # List all recordings
120
+ meeting-noter list
121
+ ```
122
+
123
+ ## Commands
124
+
125
+ | Command | Description |
126
+ |---------|-------------|
127
+ | `meeting-noter` | Launch desktop GUI |
128
+ | `meeting-noter menubar` | Launch menu bar app |
129
+ | `meeting-noter gui` | Launch desktop GUI |
130
+ | `meeting-noter start [name]` | Interactive CLI recording |
131
+ | `meeting-noter list` | List recent recordings |
132
+ | `meeting-noter transcribe` | Transcribe a recording |
133
+ | `meeting-noter devices` | List audio devices |
134
+ | `meeting-noter status` | Check daemon status |
135
+
136
+ ## Options
137
+
138
+ ### `start`
139
+ - First argument: Meeting name (optional, auto-generates timestamp if omitted)
140
+
141
+ ### `transcribe`
142
+ - `-m, --model`: Whisper model size (tiny.en, base.en, small.en, medium.en, large-v3)
143
+ - `-o, --output-dir`: Directory with recordings
144
+
145
+ ### `list`
146
+ - `-n, --limit`: Number of recordings to show
147
+ - `-o, --output-dir`: Directory with recordings
148
+
149
+ ## How It Works
150
+
151
+ ```
152
+ ┌─────────────────────────────────────┐
153
+ │ Your Meeting App │
154
+ │ (Zoom/Teams/Meet/Slack) │
155
+ └──────────────────┬──────────────────┘
156
+
157
+ ┌─────────────┴─────────────┐
158
+ ▼ ▼
159
+ ┌─────────┐ ┌─────────────┐
160
+ │ Mic │ │ System Audio│
161
+ │(default)│ │(ScreenCaptureKit)
162
+ └────┬────┘ └──────┬──────┘
163
+ │ │
164
+ └───────────┬───────────────┘
165
+
166
+ ┌─────────────┐
167
+ │Meeting Noter│
168
+ │ (capture) │
169
+ └──────┬──────┘
170
+
171
+
172
+ ~/meetings/2024-01-15_Weekly_Standup.mp3
173
+
174
+ ▼ (auto or on-demand)
175
+ ┌─────────────┐
176
+ │ Whisper │ (local)
177
+ └──────┬──────┘
178
+
179
+
180
+ ~/meetings/2024-01-15_Weekly_Standup.txt
181
+ ```
182
+
183
+ ## Permissions
184
+
185
+ On first use, macOS will ask for:
186
+
187
+ 1. **Microphone** - For capturing your voice
188
+ 2. **Screen Recording** - For capturing system audio (meeting participants)
189
+
190
+ Grant these in System Settings > Privacy & Security.
191
+
192
+ ## Configuration
193
+
194
+ Config file: `~/.config/meeting-noter/config.json`
195
+
196
+ ```json
197
+ {
198
+ "recordings_dir": "~/meetings",
199
+ "transcripts_dir": "~/meetings",
200
+ "whisper_model": "tiny.en",
201
+ "auto_transcribe": true,
202
+ "silence_timeout": 5,
203
+ "capture_system_audio": true
204
+ }
205
+ ```
206
+
207
+ ## Whisper Models
208
+
209
+ | Model | Size | Speed | Accuracy |
210
+ |-------|------|-------|----------|
211
+ | `tiny.en` | ~75MB | Fastest | Good |
212
+ | `base.en` | ~150MB | Fast | Better |
213
+ | `small.en` | ~500MB | Medium | High |
214
+ | `medium.en` | ~1.5GB | Slow | Very High |
215
+ | `large-v3` | ~3GB | Slowest | Best |
216
+
217
+ ## Requirements
218
+
219
+ - macOS 12.3+ (for ScreenCaptureKit)
220
+ - Python 3.9+
221
+
222
+ ## License
223
+
224
+ MIT
@@ -0,0 +1,39 @@
1
+ meeting_noter/__init__.py,sha256=bLOErRC3sfnQ4a4RyZUzUljZEikXy7zOiYYUz5GytPg,103
2
+ meeting_noter/__main__.py,sha256=6sSOqH1o3jvgvkVzsVKmF6-xVGcUAbNVQkRl2CrygdE,120
3
+ meeting_noter/cli.py,sha256=OAlLc7CEgov3akDo89I0JUMl9wCXs81x3QO2mBcqLvE,27769
4
+ meeting_noter/config.py,sha256=41LFBNp5o0IojYS5Hf0FJVIr7GNn7B5O1TJDE8SQkkk,5977
5
+ meeting_noter/daemon.py,sha256=BYMc-sAz8zo9ZFMRr_Th8iw_l7rc71ldEf1mwsJJgaw,16502
6
+ meeting_noter/meeting_detector.py,sha256=St0qoMkvUERP4BaxnXO1M6fZDJpWqBf9In7z2SgWcWg,10564
7
+ meeting_noter/menubar.py,sha256=Gn6p8y5jA_HCWf1T3ademxH-vndpONHkf9vUlKs6XEo,14379
8
+ meeting_noter/mic_monitor.py,sha256=zgcNypn29gWTyslalu5-JFseG47DVHEtcHCGiEUugAs,16021
9
+ meeting_noter/audio/__init__.py,sha256=O7PU8CxHSHxMeHbc9Jdwt9kePLQzsPh81GQU7VHCtBY,44
10
+ meeting_noter/audio/capture.py,sha256=fDrT5oXfva8vdFlht9cv60NviKbksw2QeJ8eOtI19uE,6469
11
+ meeting_noter/audio/encoder.py,sha256=6UgEYLFACSQEIx2nhH1Qq-cBh3qPJziMGkrm39k6Nz8,6401
12
+ meeting_noter/audio/system_audio.py,sha256=jbHGjNCerI19weXap0a90Ik17lVTCT1hCEgRKYke-p8,13016
13
+ meeting_noter/gui/__init__.py,sha256=z5GxxaeXyjqyEa9ox0dQxuL5u_BART0bi7cI6rfntEI,103
14
+ meeting_noter/gui/__main__.py,sha256=A2HWdYod0bTgjQQIi21O7XpmgxLH36e_X0aygEUZLls,146
15
+ meeting_noter/gui/app.py,sha256=COUAWu_dR5HriNYxbE86CVGS1eGYqyteH2oUFN_YtYQ,1370
16
+ meeting_noter/gui/main_window.py,sha256=vSvNO86CHMgJf9Pem8AOdrqKyTV9ITp3W4nCoqIuAmI,1667
17
+ meeting_noter/gui/meetings_tab.py,sha256=pqXqMv5YvCj8H6yR_TF3SMzsIDMAxyLe2otbENbM2SY,12315
18
+ meeting_noter/gui/recording_tab.py,sha256=UlrPkUiOmkGgOKqVrfAVp4EyiY5sq86W49Y-YAhYexY,12521
19
+ meeting_noter/gui/settings_tab.py,sha256=NUQVKDdSpyNp_MVxPLw2dB93wxaD5VeBKiDtGS4CyoU,8446
20
+ meeting_noter/install/__init__.py,sha256=SX5vLFMrV8aBDEGW18jhaqBqJqnRXaeo0Ct7QVGDgvE,38
21
+ meeting_noter/install/macos.py,sha256=dO-86zbNKRtt0l4D8naVn7kFWjzI8TufWLWE3FRLHQ8,3400
22
+ meeting_noter/output/__init__.py,sha256=F7xPlOrqweZcPbZtDrhved1stBI59vnWnLYfGwdu6oY,31
23
+ meeting_noter/output/writer.py,sha256=zO8y6FAFUAp0EEtALY-M5e2Ja5P-hgV38JjcKW7c-bA,3017
24
+ meeting_noter/resources/__init__.py,sha256=yzHNxgypkuVDFZWv6xZjUygOVB_Equ9NNX_HGRvN7VM,43
25
+ meeting_noter/resources/icon.icns,sha256=zMWqXCq7pI5acS0tbekFgFDvLt66EKUBP5-5IgztwPM,35146
26
+ meeting_noter/resources/icon.png,sha256=nK0hM6CPMor_xXRFYURpm0muA2O7yzotyydUQx-ukyg,2390
27
+ meeting_noter/resources/icon_128.png,sha256=Wg27dIpFfMzv15HG6eQpSqg72jrbGBcqLkGjOfAptO4,1169
28
+ meeting_noter/resources/icon_16.png,sha256=GONIIZCP9FUMb_MWZWMz1_iWxsPCPOwW_XcrPF7W8KY,215
29
+ meeting_noter/resources/icon_256.png,sha256=nK0hM6CPMor_xXRFYURpm0muA2O7yzotyydUQx-ukyg,2390
30
+ meeting_noter/resources/icon_32.png,sha256=Bw6hJXqkd-d1OfDpFv2om7Stex7daedxnpXt32xR8Sg,344
31
+ meeting_noter/resources/icon_512.png,sha256=o7X3ngYcppcIAAk9AcfPx94MUmrsPRp0qBTpb9SzfX8,5369
32
+ meeting_noter/resources/icon_64.png,sha256=TqG7Awx3kK8YdiX1e_z1odZonosZyQI2trlkNZCzUoI,607
33
+ meeting_noter/transcription/__init__.py,sha256=7GY9diP06DzFyoli41wddbrPv5bVDzH35bmnWlIJev4,29
34
+ meeting_noter/transcription/engine.py,sha256=G9NcSS6Q-UhW7PlQ0E85hQXn6BWao64nIvyw4NR2yxI,7208
35
+ meeting_noter-0.7.0.dist-info/METADATA,sha256=8V-ZO5eL8tFm3PauQU9dCZVw0ZbkyCWl6xklfcH3a-c,6952
36
+ meeting_noter-0.7.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
37
+ meeting_noter-0.7.0.dist-info/entry_points.txt,sha256=rKNhzjSF5-e3bLRr8LVe22FeiwcacXabCvNpoEXfu4I,56
38
+ meeting_noter-0.7.0.dist-info/top_level.txt,sha256=9Tuq04_0SXM0OXOHVbOHkHkB5tG3fqkrMrfzCMpbLpY,14
39
+ meeting_noter-0.7.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ meeting-noter = meeting_noter.cli:cli
@@ -0,0 +1 @@
1
+ meeting_noter