meeting-noter 0.5.1__tar.gz → 0.6.1__tar.gz
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.
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/PKG-INFO +8 -12
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/README.md +4 -9
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/pyproject.toml +4 -6
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/audio/encoder.py +58 -51
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/transcription/engine.py +27 -1
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter.egg-info/PKG-INFO +8 -12
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter.egg-info/requires.txt +3 -2
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/setup.cfg +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/__init__.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/__main__.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/audio/__init__.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/audio/capture.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/audio/system_audio.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/cli.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/config.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/daemon.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/gui/__init__.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/gui/__main__.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/gui/app.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/gui/main_window.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/gui/meetings_tab.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/gui/recording_tab.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/gui/settings_tab.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/install/__init__.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/install/macos.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/meeting_detector.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/menubar.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/mic_monitor.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/output/__init__.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/output/writer.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/resources/__init__.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/resources/icon.icns +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/resources/icon.png +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/resources/icon_128.png +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/resources/icon_16.png +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/resources/icon_256.png +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/resources/icon_32.png +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/resources/icon_512.png +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/resources/icon_64.png +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter/transcription/__init__.py +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter.egg-info/SOURCES.txt +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter.egg-info/dependency_links.txt +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter.egg-info/entry_points.txt +0 -0
- {meeting_noter-0.5.1 → meeting_noter-0.6.1}/src/meeting_noter.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meeting-noter
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: Offline meeting transcription for macOS with automatic meeting detection
|
|
5
5
|
Author: Victor
|
|
6
6
|
License: MIT
|
|
@@ -28,14 +28,15 @@ Requires-Dist: numpy>=1.24
|
|
|
28
28
|
Requires-Dist: faster-whisper>=1.0.0
|
|
29
29
|
Requires-Dist: rumps>=0.4.0
|
|
30
30
|
Requires-Dist: PyQt6>=6.5.0
|
|
31
|
+
Requires-Dist: imageio-ffmpeg>=0.4.9
|
|
31
32
|
Requires-Dist: pyobjc-framework-Cocoa>=9.0; sys_platform == "darwin"
|
|
32
33
|
Requires-Dist: pyobjc-framework-Quartz>=9.0; sys_platform == "darwin"
|
|
33
34
|
Requires-Dist: pyobjc-framework-ScreenCaptureKit>=9.0; sys_platform == "darwin"
|
|
34
35
|
Requires-Dist: pyobjc-framework-AVFoundation>=9.0; sys_platform == "darwin"
|
|
35
36
|
Requires-Dist: pyobjc-framework-CoreMedia>=9.0; sys_platform == "darwin"
|
|
36
37
|
Requires-Dist: pyobjc-framework-libdispatch>=9.0; sys_platform == "darwin"
|
|
37
|
-
Provides-Extra:
|
|
38
|
-
Requires-Dist:
|
|
38
|
+
Provides-Extra: offline
|
|
39
|
+
Requires-Dist: meeting-noter-models>=0.1.0; extra == "offline"
|
|
39
40
|
Provides-Extra: dev
|
|
40
41
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
41
42
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
@@ -59,11 +60,7 @@ Offline meeting transcription tool for macOS. Captures both your voice and meeti
|
|
|
59
60
|
## Installation
|
|
60
61
|
|
|
61
62
|
```bash
|
|
62
|
-
|
|
63
|
-
brew install ffmpeg lame pkg-config python@3.12
|
|
64
|
-
|
|
65
|
-
# Install meeting-noter (use Python 3.12 for best compatibility)
|
|
66
|
-
pipx install meeting-noter --python /opt/homebrew/bin/python3.12
|
|
63
|
+
pipx install meeting-noter
|
|
67
64
|
```
|
|
68
65
|
|
|
69
66
|
Or with pip:
|
|
@@ -71,6 +68,8 @@ Or with pip:
|
|
|
71
68
|
pip install meeting-noter
|
|
72
69
|
```
|
|
73
70
|
|
|
71
|
+
No system dependencies required - ffmpeg is bundled automatically.
|
|
72
|
+
|
|
74
73
|
## Quick Start
|
|
75
74
|
|
|
76
75
|
**Menu Bar App** (recommended):
|
|
@@ -208,10 +207,7 @@ Config file: `~/.config/meeting-noter/config.json`
|
|
|
208
207
|
## Requirements
|
|
209
208
|
|
|
210
209
|
- macOS 12.3+ (for ScreenCaptureKit)
|
|
211
|
-
- Python 3.9+
|
|
212
|
-
- FFmpeg (`brew install ffmpeg`) - required for audio processing
|
|
213
|
-
- LAME (`brew install lame`) - required for MP3 encoding
|
|
214
|
-
- pkg-config (`brew install pkg-config`) - required for building dependencies
|
|
210
|
+
- Python 3.9+
|
|
215
211
|
|
|
216
212
|
## License
|
|
217
213
|
|
|
@@ -14,11 +14,7 @@ Offline meeting transcription tool for macOS. Captures both your voice and meeti
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
|
|
18
|
-
brew install ffmpeg lame pkg-config python@3.12
|
|
19
|
-
|
|
20
|
-
# Install meeting-noter (use Python 3.12 for best compatibility)
|
|
21
|
-
pipx install meeting-noter --python /opt/homebrew/bin/python3.12
|
|
17
|
+
pipx install meeting-noter
|
|
22
18
|
```
|
|
23
19
|
|
|
24
20
|
Or with pip:
|
|
@@ -26,6 +22,8 @@ Or with pip:
|
|
|
26
22
|
pip install meeting-noter
|
|
27
23
|
```
|
|
28
24
|
|
|
25
|
+
No system dependencies required - ffmpeg is bundled automatically.
|
|
26
|
+
|
|
29
27
|
## Quick Start
|
|
30
28
|
|
|
31
29
|
**Menu Bar App** (recommended):
|
|
@@ -163,10 +161,7 @@ Config file: `~/.config/meeting-noter/config.json`
|
|
|
163
161
|
## Requirements
|
|
164
162
|
|
|
165
163
|
- macOS 12.3+ (for ScreenCaptureKit)
|
|
166
|
-
- Python 3.9+
|
|
167
|
-
- FFmpeg (`brew install ffmpeg`) - required for audio processing
|
|
168
|
-
- LAME (`brew install lame`) - required for MP3 encoding
|
|
169
|
-
- pkg-config (`brew install pkg-config`) - required for building dependencies
|
|
164
|
+
- Python 3.9+
|
|
170
165
|
|
|
171
166
|
## License
|
|
172
167
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "meeting-noter"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.6.1"
|
|
8
8
|
description = "Offline meeting transcription for macOS with automatic meeting detection"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -35,6 +35,7 @@ dependencies = [
|
|
|
35
35
|
"faster-whisper>=1.0.0",
|
|
36
36
|
"rumps>=0.4.0",
|
|
37
37
|
"PyQt6>=6.5.0",
|
|
38
|
+
"imageio-ffmpeg>=0.4.9", # Bundles ffmpeg binary for MP3 encoding
|
|
38
39
|
"pyobjc-framework-Cocoa>=9.0; sys_platform == 'darwin'",
|
|
39
40
|
"pyobjc-framework-Quartz>=9.0; sys_platform == 'darwin'",
|
|
40
41
|
"pyobjc-framework-ScreenCaptureKit>=9.0; sys_platform == 'darwin'",
|
|
@@ -43,12 +44,9 @@ dependencies = [
|
|
|
43
44
|
"pyobjc-framework-libdispatch>=9.0; sys_platform == 'darwin'",
|
|
44
45
|
]
|
|
45
46
|
|
|
46
|
-
# lameenc requires LAME to be installed (brew install lame)
|
|
47
|
-
# It will be installed automatically if LAME is present
|
|
48
|
-
|
|
49
47
|
[project.optional-dependencies]
|
|
50
|
-
|
|
51
|
-
"
|
|
48
|
+
offline = [
|
|
49
|
+
"meeting-noter-models>=0.1.0",
|
|
52
50
|
]
|
|
53
51
|
dev = [
|
|
54
52
|
"pytest>=7.0",
|
|
@@ -1,37 +1,21 @@
|
|
|
1
|
-
"""MP3 encoding for audio recordings."""
|
|
1
|
+
"""MP3 encoding for audio recordings using ffmpeg."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import re
|
|
6
|
-
import
|
|
6
|
+
import subprocess
|
|
7
7
|
import numpy as np
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from datetime import datetime
|
|
10
10
|
from typing import Optional, Tuple
|
|
11
11
|
|
|
12
|
-
#
|
|
12
|
+
# Get bundled ffmpeg binary path
|
|
13
13
|
try:
|
|
14
|
-
import
|
|
15
|
-
|
|
14
|
+
import imageio_ffmpeg
|
|
15
|
+
FFMPEG_PATH = imageio_ffmpeg.get_ffmpeg_exe()
|
|
16
16
|
except ImportError:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def _check_lameenc():
|
|
22
|
-
"""Check if lameenc is available, raise helpful error if not."""
|
|
23
|
-
if not LAMEENC_AVAILABLE:
|
|
24
|
-
print("\n" + "=" * 60, file=sys.stderr)
|
|
25
|
-
print("ERROR: MP3 encoding requires the 'lame' library", file=sys.stderr)
|
|
26
|
-
print("=" * 60, file=sys.stderr)
|
|
27
|
-
print("\nTo fix this, run:", file=sys.stderr)
|
|
28
|
-
print("\n brew install lame", file=sys.stderr)
|
|
29
|
-
print("\nThen reinstall meeting-noter:", file=sys.stderr)
|
|
30
|
-
print("\n pip install --force-reinstall meeting-noter", file=sys.stderr)
|
|
31
|
-
print("\n" + "=" * 60 + "\n", file=sys.stderr)
|
|
32
|
-
raise ImportError(
|
|
33
|
-
"lameenc not available. Install LAME first: brew install lame"
|
|
34
|
-
)
|
|
17
|
+
# Fallback to system ffmpeg
|
|
18
|
+
FFMPEG_PATH = "ffmpeg"
|
|
35
19
|
|
|
36
20
|
|
|
37
21
|
def _sanitize_filename(name: str, max_length: int = 50) -> str:
|
|
@@ -62,24 +46,42 @@ def _is_timestamp_name(name: str) -> bool:
|
|
|
62
46
|
|
|
63
47
|
|
|
64
48
|
class MP3Encoder:
|
|
65
|
-
"""Encodes audio data to MP3 format."""
|
|
49
|
+
"""Encodes audio data to MP3 format using ffmpeg."""
|
|
66
50
|
|
|
67
51
|
def __init__(
|
|
68
52
|
self,
|
|
53
|
+
output_path: Path,
|
|
69
54
|
sample_rate: int = 16000,
|
|
70
55
|
channels: int = 1,
|
|
71
56
|
bitrate: int = 128,
|
|
72
|
-
quality: int = 2,
|
|
73
57
|
):
|
|
74
|
-
|
|
58
|
+
self.output_path = output_path
|
|
75
59
|
self.sample_rate = sample_rate
|
|
76
60
|
self.channels = channels
|
|
77
|
-
self.
|
|
78
|
-
self.
|
|
79
|
-
self.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
61
|
+
self.bitrate = bitrate
|
|
62
|
+
self._process: Optional[subprocess.Popen] = None
|
|
63
|
+
self._start_ffmpeg()
|
|
64
|
+
|
|
65
|
+
def _start_ffmpeg(self):
|
|
66
|
+
"""Start ffmpeg process for encoding."""
|
|
67
|
+
cmd = [
|
|
68
|
+
FFMPEG_PATH,
|
|
69
|
+
"-y", # Overwrite output
|
|
70
|
+
"-f", "s16le", # Input format: signed 16-bit little-endian PCM
|
|
71
|
+
"-ar", str(self.sample_rate), # Sample rate
|
|
72
|
+
"-ac", str(self.channels), # Channels
|
|
73
|
+
"-i", "pipe:0", # Read from stdin
|
|
74
|
+
"-codec:a", "libmp3lame", # MP3 encoder
|
|
75
|
+
"-b:a", f"{self.bitrate}k", # Bitrate
|
|
76
|
+
"-f", "mp3", # Output format
|
|
77
|
+
str(self.output_path),
|
|
78
|
+
]
|
|
79
|
+
self._process = subprocess.Popen(
|
|
80
|
+
cmd,
|
|
81
|
+
stdin=subprocess.PIPE,
|
|
82
|
+
stdout=subprocess.DEVNULL,
|
|
83
|
+
stderr=subprocess.DEVNULL,
|
|
84
|
+
)
|
|
83
85
|
|
|
84
86
|
def encode_chunk(self, audio: np.ndarray) -> bytes:
|
|
85
87
|
"""Encode a chunk of audio data.
|
|
@@ -88,16 +90,29 @@ class MP3Encoder:
|
|
|
88
90
|
audio: Float32 audio data, values between -1 and 1
|
|
89
91
|
|
|
90
92
|
Returns:
|
|
91
|
-
|
|
93
|
+
Empty bytes (ffmpeg writes directly to file)
|
|
92
94
|
"""
|
|
95
|
+
if self._process is None or self._process.stdin is None:
|
|
96
|
+
return b""
|
|
97
|
+
|
|
93
98
|
# Convert float32 to int16
|
|
94
99
|
int_data = (audio * 32767).astype(np.int16)
|
|
95
|
-
|
|
96
|
-
|
|
100
|
+
try:
|
|
101
|
+
self._process.stdin.write(int_data.tobytes())
|
|
102
|
+
except BrokenPipeError:
|
|
103
|
+
pass
|
|
104
|
+
return b"" # ffmpeg writes to file, not returning data
|
|
97
105
|
|
|
98
106
|
def finalize(self) -> bytes:
|
|
99
|
-
"""Finalize encoding
|
|
100
|
-
|
|
107
|
+
"""Finalize encoding."""
|
|
108
|
+
if self._process is not None and self._process.stdin is not None:
|
|
109
|
+
try:
|
|
110
|
+
self._process.stdin.close()
|
|
111
|
+
except Exception:
|
|
112
|
+
pass
|
|
113
|
+
self._process.wait()
|
|
114
|
+
self._process = None
|
|
115
|
+
return b""
|
|
101
116
|
|
|
102
117
|
|
|
103
118
|
class RecordingSession:
|
|
@@ -115,7 +130,6 @@ class RecordingSession:
|
|
|
115
130
|
self.channels = channels
|
|
116
131
|
self.meeting_name = meeting_name
|
|
117
132
|
self.encoder: Optional[MP3Encoder] = None
|
|
118
|
-
self.file_handle = None
|
|
119
133
|
self.filepath: Optional[Path] = None
|
|
120
134
|
self.start_time: Optional[datetime] = None
|
|
121
135
|
self.total_samples = 0
|
|
@@ -139,22 +153,20 @@ class RecordingSession:
|
|
|
139
153
|
self.filepath = self.output_dir / filename
|
|
140
154
|
|
|
141
155
|
self.encoder = MP3Encoder(
|
|
156
|
+
output_path=self.filepath,
|
|
142
157
|
sample_rate=self.sample_rate,
|
|
143
158
|
channels=self.channels,
|
|
144
159
|
)
|
|
145
|
-
self.file_handle = open(self.filepath, "wb")
|
|
146
160
|
self.total_samples = 0
|
|
147
161
|
|
|
148
162
|
return self.filepath
|
|
149
163
|
|
|
150
164
|
def write(self, audio: np.ndarray):
|
|
151
165
|
"""Write audio data to the recording."""
|
|
152
|
-
if self.encoder is None
|
|
166
|
+
if self.encoder is None:
|
|
153
167
|
raise RuntimeError("Recording session not started")
|
|
154
168
|
|
|
155
|
-
|
|
156
|
-
if mp3_data:
|
|
157
|
-
self.file_handle.write(mp3_data)
|
|
169
|
+
self.encoder.encode_chunk(audio)
|
|
158
170
|
self.total_samples += len(audio)
|
|
159
171
|
|
|
160
172
|
def stop(self) -> Tuple[Optional[Path], float]:
|
|
@@ -166,13 +178,9 @@ class RecordingSession:
|
|
|
166
178
|
duration = 0.0
|
|
167
179
|
filepath = self.filepath
|
|
168
180
|
|
|
169
|
-
if self.encoder
|
|
170
|
-
#
|
|
171
|
-
|
|
172
|
-
if final_data:
|
|
173
|
-
self.file_handle.write(final_data)
|
|
174
|
-
self.file_handle.close()
|
|
175
|
-
|
|
181
|
+
if self.encoder:
|
|
182
|
+
# Finalize encoding
|
|
183
|
+
self.encoder.finalize()
|
|
176
184
|
duration = self.total_samples / self.sample_rate
|
|
177
185
|
|
|
178
186
|
# Delete if too short (less than 5 seconds)
|
|
@@ -181,7 +189,6 @@ class RecordingSession:
|
|
|
181
189
|
filepath = None
|
|
182
190
|
|
|
183
191
|
self.encoder = None
|
|
184
|
-
self.file_handle = None
|
|
185
192
|
self.filepath = None
|
|
186
193
|
self.start_time = None
|
|
187
194
|
self.total_samples = 0
|
|
@@ -8,13 +8,39 @@ from datetime import datetime
|
|
|
8
8
|
from typing import Optional
|
|
9
9
|
|
|
10
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
|
+
|
|
11
23
|
def get_model(model_size: str = "tiny.en"):
|
|
12
24
|
"""Load the Whisper model.
|
|
13
25
|
|
|
14
|
-
|
|
26
|
+
Priority:
|
|
27
|
+
1. Bundled model from meeting-noter-models package (offline)
|
|
28
|
+
2. Download from Hugging Face Hub (cached after first download)
|
|
15
29
|
"""
|
|
16
30
|
from faster_whisper import WhisperModel
|
|
17
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
|
|
18
44
|
click.echo(f"Loading model '{model_size}'...")
|
|
19
45
|
|
|
20
46
|
# Use INT8 for CPU efficiency
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meeting-noter
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: Offline meeting transcription for macOS with automatic meeting detection
|
|
5
5
|
Author: Victor
|
|
6
6
|
License: MIT
|
|
@@ -28,14 +28,15 @@ Requires-Dist: numpy>=1.24
|
|
|
28
28
|
Requires-Dist: faster-whisper>=1.0.0
|
|
29
29
|
Requires-Dist: rumps>=0.4.0
|
|
30
30
|
Requires-Dist: PyQt6>=6.5.0
|
|
31
|
+
Requires-Dist: imageio-ffmpeg>=0.4.9
|
|
31
32
|
Requires-Dist: pyobjc-framework-Cocoa>=9.0; sys_platform == "darwin"
|
|
32
33
|
Requires-Dist: pyobjc-framework-Quartz>=9.0; sys_platform == "darwin"
|
|
33
34
|
Requires-Dist: pyobjc-framework-ScreenCaptureKit>=9.0; sys_platform == "darwin"
|
|
34
35
|
Requires-Dist: pyobjc-framework-AVFoundation>=9.0; sys_platform == "darwin"
|
|
35
36
|
Requires-Dist: pyobjc-framework-CoreMedia>=9.0; sys_platform == "darwin"
|
|
36
37
|
Requires-Dist: pyobjc-framework-libdispatch>=9.0; sys_platform == "darwin"
|
|
37
|
-
Provides-Extra:
|
|
38
|
-
Requires-Dist:
|
|
38
|
+
Provides-Extra: offline
|
|
39
|
+
Requires-Dist: meeting-noter-models>=0.1.0; extra == "offline"
|
|
39
40
|
Provides-Extra: dev
|
|
40
41
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
41
42
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
@@ -59,11 +60,7 @@ Offline meeting transcription tool for macOS. Captures both your voice and meeti
|
|
|
59
60
|
## Installation
|
|
60
61
|
|
|
61
62
|
```bash
|
|
62
|
-
|
|
63
|
-
brew install ffmpeg lame pkg-config python@3.12
|
|
64
|
-
|
|
65
|
-
# Install meeting-noter (use Python 3.12 for best compatibility)
|
|
66
|
-
pipx install meeting-noter --python /opt/homebrew/bin/python3.12
|
|
63
|
+
pipx install meeting-noter
|
|
67
64
|
```
|
|
68
65
|
|
|
69
66
|
Or with pip:
|
|
@@ -71,6 +68,8 @@ Or with pip:
|
|
|
71
68
|
pip install meeting-noter
|
|
72
69
|
```
|
|
73
70
|
|
|
71
|
+
No system dependencies required - ffmpeg is bundled automatically.
|
|
72
|
+
|
|
74
73
|
## Quick Start
|
|
75
74
|
|
|
76
75
|
**Menu Bar App** (recommended):
|
|
@@ -208,10 +207,7 @@ Config file: `~/.config/meeting-noter/config.json`
|
|
|
208
207
|
## Requirements
|
|
209
208
|
|
|
210
209
|
- macOS 12.3+ (for ScreenCaptureKit)
|
|
211
|
-
- Python 3.9+
|
|
212
|
-
- FFmpeg (`brew install ffmpeg`) - required for audio processing
|
|
213
|
-
- LAME (`brew install lame`) - required for MP3 encoding
|
|
214
|
-
- pkg-config (`brew install pkg-config`) - required for building dependencies
|
|
210
|
+
- Python 3.9+
|
|
215
211
|
|
|
216
212
|
## License
|
|
217
213
|
|
|
@@ -4,6 +4,7 @@ numpy>=1.24
|
|
|
4
4
|
faster-whisper>=1.0.0
|
|
5
5
|
rumps>=0.4.0
|
|
6
6
|
PyQt6>=6.5.0
|
|
7
|
+
imageio-ffmpeg>=0.4.9
|
|
7
8
|
|
|
8
9
|
[:sys_platform == "darwin"]
|
|
9
10
|
pyobjc-framework-Cocoa>=9.0
|
|
@@ -20,5 +21,5 @@ black
|
|
|
20
21
|
ruff
|
|
21
22
|
mypy
|
|
22
23
|
|
|
23
|
-
[
|
|
24
|
-
|
|
24
|
+
[offline]
|
|
25
|
+
meeting-noter-models>=0.1.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|