echoai-helper 1.2.0__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.
- echoai_helper-1.2.0/LICENSE +21 -0
- echoai_helper-1.2.0/PKG-INFO +306 -0
- echoai_helper-1.2.0/README.md +271 -0
- echoai_helper-1.2.0/echoai_helper.egg-info/PKG-INFO +306 -0
- echoai_helper-1.2.0/echoai_helper.egg-info/SOURCES.txt +84 -0
- echoai_helper-1.2.0/echoai_helper.egg-info/dependency_links.txt +1 -0
- echoai_helper-1.2.0/echoai_helper.egg-info/entry_points.txt +2 -0
- echoai_helper-1.2.0/echoai_helper.egg-info/requires.txt +27 -0
- echoai_helper-1.2.0/echoai_helper.egg-info/top_level.txt +2 -0
- echoai_helper-1.2.0/pyproject.toml +72 -0
- echoai_helper-1.2.0/scripts/__init__.py +0 -0
- echoai_helper-1.2.0/scripts/calibrate_vad.py +183 -0
- echoai_helper-1.2.0/scripts/check_audio.py +317 -0
- echoai_helper-1.2.0/scripts/install_launcher.py +54 -0
- echoai_helper-1.2.0/scripts/setup_audio.py +65 -0
- echoai_helper-1.2.0/setup.cfg +4 -0
- echoai_helper-1.2.0/src/AudioRecorder.py +62 -0
- echoai_helper-1.2.0/src/AudioTranscriber.py +532 -0
- echoai_helper-1.2.0/src/GPTResponder.py +293 -0
- echoai_helper-1.2.0/src/ResponseManager.py +374 -0
- echoai_helper-1.2.0/src/SettingsManager.py +147 -0
- echoai_helper-1.2.0/src/TemplateManager.py +186 -0
- echoai_helper-1.2.0/src/TranscriberModels.py +158 -0
- echoai_helper-1.2.0/src/TranscriptUI.py +499 -0
- echoai_helper-1.2.0/src/app.py +1053 -0
- echoai_helper-1.2.0/src/asr/asr_factory.py +44 -0
- echoai_helper-1.2.0/src/asr/asr_interface.py +33 -0
- echoai_helper-1.2.0/src/asr/asr_with_vad.py +266 -0
- echoai_helper-1.2.0/src/asr/azure_asr.py +76 -0
- echoai_helper-1.2.0/src/asr/diarization.py +255 -0
- echoai_helper-1.2.0/src/asr/faster_whisper_asr.py +44 -0
- echoai_helper-1.2.0/src/asr/fun_asr.py +119 -0
- echoai_helper-1.2.0/src/asr/hypothesis.py +164 -0
- echoai_helper-1.2.0/src/asr/models/silero_vad.onnx +0 -0
- echoai_helper-1.2.0/src/asr/openai_whisper_asr.py +35 -0
- echoai_helper-1.2.0/src/asr/segmenter.py +301 -0
- echoai_helper-1.2.0/src/asr/vad.py +55 -0
- echoai_helper-1.2.0/src/asr/whisper_cpp_asr.py +42 -0
- echoai_helper-1.2.0/src/audio/__init__.py +43 -0
- echoai_helper-1.2.0/src/audio/backend.py +109 -0
- echoai_helper-1.2.0/src/audio/coreaudio.py +286 -0
- echoai_helper-1.2.0/src/audio/macos.py +168 -0
- echoai_helper-1.2.0/src/audio/setup_macos.py +402 -0
- echoai_helper-1.2.0/src/audio/windows.py +111 -0
- echoai_helper-1.2.0/src/cli.py +178 -0
- echoai_helper-1.2.0/src/conf.yaml +120 -0
- echoai_helper-1.2.0/src/config.py +312 -0
- echoai_helper-1.2.0/src/custom_speech_recognition/__init__.py +1565 -0
- echoai_helper-1.2.0/src/custom_speech_recognition/__main__.py +24 -0
- echoai_helper-1.2.0/src/custom_speech_recognition/audio.py +318 -0
- echoai_helper-1.2.0/src/custom_speech_recognition/exceptions.py +22 -0
- echoai_helper-1.2.0/src/export_dialog.py +357 -0
- echoai_helper-1.2.0/src/export_markdown.py +175 -0
- echoai_helper-1.2.0/src/launcher_macos.py +171 -0
- echoai_helper-1.2.0/src/llm/__init__.py +4 -0
- echoai_helper-1.2.0/src/llm/cli_provider.py +189 -0
- echoai_helper-1.2.0/src/llm/litellm_provider.py +146 -0
- echoai_helper-1.2.0/src/llm/llm_provider.py +42 -0
- echoai_helper-1.2.0/src/llm/openai_provider.py +85 -0
- echoai_helper-1.2.0/src/llm/provider_factory.py +96 -0
- echoai_helper-1.2.0/src/polish.py +242 -0
- echoai_helper-1.2.0/src/profiles.py +106 -0
- echoai_helper-1.2.0/src/prompts.py +95 -0
- echoai_helper-1.2.0/src/resources/config/settings.json +13 -0
- echoai_helper-1.2.0/src/resources/prompt/Interview Analysis.md +96 -0
- echoai_helper-1.2.0/src/resources/prompt/Meeting Analysis.md +235 -0
- echoai_helper-1.2.0/src/resources/prompt/case_detail/inbound_cs.txt +26 -0
- echoai_helper-1.2.0/src/resources/prompt/case_detail/none.txt +3 -0
- echoai_helper-1.2.0/src/resources/prompt/knowledge/none.txt +2 -0
- echoai_helper-1.2.0/src/resources/prompt/system_role/inbound_cs.py +31 -0
- echoai_helper-1.2.0/src/resources/prompt/system_role/phone_interview.py +32 -0
- echoai_helper-1.2.0/src/session.py +303 -0
- echoai_helper-1.2.0/tests/test_audio_backend.py +90 -0
- echoai_helper-1.2.0/tests/test_audio_setup.py +270 -0
- echoai_helper-1.2.0/tests/test_config.py +75 -0
- echoai_helper-1.2.0/tests/test_diarization.py +282 -0
- echoai_helper-1.2.0/tests/test_export_dialog.py +128 -0
- echoai_helper-1.2.0/tests/test_export_markdown.py +137 -0
- echoai_helper-1.2.0/tests/test_hypothesis.py +210 -0
- echoai_helper-1.2.0/tests/test_launcher.py +111 -0
- echoai_helper-1.2.0/tests/test_polish.py +256 -0
- echoai_helper-1.2.0/tests/test_prompts.py +155 -0
- echoai_helper-1.2.0/tests/test_responder.py +196 -0
- echoai_helper-1.2.0/tests/test_segmenter.py +344 -0
- echoai_helper-1.2.0/tests/test_session.py +220 -0
- echoai_helper-1.2.0/tests/test_transcriber.py +284 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Cola Kang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: echoai-helper
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: Real-time meeting transcription and interview assistance, on-device
|
|
5
|
+
Author: colakang
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/colakang/echoai_helper
|
|
8
|
+
Project-URL: Issues, https://github.com/colakang/echoai_helper/issues
|
|
9
|
+
Keywords: transcription,asr,meeting-notes,diarization,funasr
|
|
10
|
+
Requires-Python: <3.13,>=3.12
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: sounddevice; sys_platform != "win32"
|
|
14
|
+
Requires-Dist: PyAudioWPatch; sys_platform == "win32"
|
|
15
|
+
Requires-Dist: numpy<2
|
|
16
|
+
Requires-Dist: scipy
|
|
17
|
+
Requires-Dist: torch
|
|
18
|
+
Requires-Dist: torchaudio
|
|
19
|
+
Requires-Dist: funasr
|
|
20
|
+
Requires-Dist: modelscope
|
|
21
|
+
Requires-Dist: huggingface_hub
|
|
22
|
+
Requires-Dist: loguru
|
|
23
|
+
Requires-Dist: onnxruntime
|
|
24
|
+
Requires-Dist: soundfile
|
|
25
|
+
Requires-Dist: openai
|
|
26
|
+
Requires-Dist: customtkinter==5.1.3
|
|
27
|
+
Requires-Dist: python-dotenv
|
|
28
|
+
Requires-Dist: pyyaml
|
|
29
|
+
Requires-Dist: pytz
|
|
30
|
+
Provides-Extra: litellm
|
|
31
|
+
Requires-Dist: litellm; extra == "litellm"
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# ๐๏ธ EchoAI Helper
|
|
37
|
+
|
|
38
|
+
[](https://github.com/colakang/echoai_helper/stargazers)
|
|
39
|
+
[](LICENSE)
|
|
40
|
+
[](https://python.org)
|
|
41
|
+
[](#-install)
|
|
42
|
+
[](#windows)
|
|
43
|
+
|
|
44
|
+
Real-time meeting transcription and interview assistance, running on your own
|
|
45
|
+
machine. It records both sides of a conversation โ your microphone and whatever
|
|
46
|
+
the meeting app is playing โ transcribes them as they happen, labels who is
|
|
47
|
+
speaking, and exports readable notes.
|
|
48
|
+
|
|
49
|
+
Speech recognition is local. Audio never leaves the machine unless you ask a
|
|
50
|
+
language model to clean up the finished transcript.
|
|
51
|
+
|
|
52
|
+
<p>
|
|
53
|
+
<a href="https://www.producthunt.com/posts/echoai-interview-copilot?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-echoai-interview-copilot" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=601490&theme=light" alt="EchoAI Interview Copilot  - Real-time conversation with LLM responses | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
<p align="center">
|
|
57
|
+
<img width="800" alt="EchoAI Helper Interface" src="https://github.com/colakang/echoai_helper/raw/main/docs/images/ui.png">
|
|
58
|
+
</p>
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## โจ What it does
|
|
63
|
+
|
|
64
|
+
- **Local speech recognition** โ FunASR / SenseVoice, on-device, GPU-accelerated
|
|
65
|
+
where one is available (Metal on Apple Silicon, CUDA on Windows)
|
|
66
|
+
- **Automatic language detection** โ Mandarin, Cantonese, English, Japanese and
|
|
67
|
+
Korean, switching per utterance, including mid-sentence code-switching
|
|
68
|
+
- **Both sides of the call** โ your microphone and the far end, on separate tracks
|
|
69
|
+
- **Speaker labelling** โ voices on the far-end track are told apart, with the
|
|
70
|
+
number of people configurable when you know it
|
|
71
|
+
- **Pause-based segmentation** โ sentences are cut where people actually pause,
|
|
72
|
+
not on a fixed timer, so the model sees whole utterances
|
|
73
|
+
- **Crash-safe recording** โ every settled sentence is written to disk as it is
|
|
74
|
+
produced; a crash costs the last line, not the meeting
|
|
75
|
+
- **LLM cleanup on export** โ an optional pass that fixes mis-heard words using
|
|
76
|
+
the surrounding conversation, through an API key or through a coding-agent CLI
|
|
77
|
+
on a subscription you already pay for
|
|
78
|
+
- **Markdown and JSON export** โ Markdown to read, JSON as a complete record
|
|
79
|
+
- **Live reply suggestions** โ for interviews, where a prompt is wanted while the
|
|
80
|
+
other person is still talking
|
|
81
|
+
|
|
82
|
+
## ๐ก Two modes
|
|
83
|
+
|
|
84
|
+
| | Meeting notes | Live interview |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| Text appears | at each pause | as you speak (~0.6s) |
|
|
87
|
+
| Model calls | one per sentence | roughly three times as many |
|
|
88
|
+
| Best for | an accurate record | a prompt you can act on |
|
|
89
|
+
|
|
90
|
+
Switch in the app; the several settings that differ move together.
|
|
91
|
+
|
|
92
|
+
## ๐ฌ Demo
|
|
93
|
+
|
|
94
|
+
https://github.com/user-attachments/assets/0d627e4a-960b-4628-8bbc-8d892f02cfd1
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## โก Install
|
|
99
|
+
|
|
100
|
+
### macOS
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
uv tool install echoai-helper # uv brings its own Python 3.12
|
|
104
|
+
echoai-helper setup # audio routing โ one password prompt
|
|
105
|
+
echoai-helper install-launcher # adds an icon to Launchpad
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Launch from Launchpad, or run `echoai-helper`.
|
|
109
|
+
|
|
110
|
+
`setup` installs a virtual audio device and builds the Multi-Output that lets
|
|
111
|
+
you hear a meeting while it is being recorded. macOS asks for a password once,
|
|
112
|
+
because that installs an audio driver โ nothing else needs a privilege, and
|
|
113
|
+
Audio MIDI Setup is not involved.
|
|
114
|
+
|
|
115
|
+
The app takes the audio output while it runs and gives it back silently when it
|
|
116
|
+
quits, including after a crash. `echoai-helper setup --restore` does it by hand;
|
|
117
|
+
`--status` shows what routing is in place.
|
|
118
|
+
|
|
119
|
+
<details>
|
|
120
|
+
<summary>Prefer Homebrew?</summary>
|
|
121
|
+
|
|
122
|
+
A formula is in [`packaging/`](packaging/echoai-helper.rb) for a tap. Homebrew
|
|
123
|
+
can declare the virtual audio device as a dependency, which removes the one step
|
|
124
|
+
that needs a password.
|
|
125
|
+
</details>
|
|
126
|
+
|
|
127
|
+
### Windows
|
|
128
|
+
|
|
129
|
+
```powershell
|
|
130
|
+
uv tool install echoai-helper
|
|
131
|
+
echoai-helper
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
No audio setup step: Windows exposes WASAPI loopback directly, so the far end of
|
|
135
|
+
a call is capturable without a virtual device. The macOS-only commands (`setup`,
|
|
136
|
+
`install-launcher`) report that there is nothing to do. See
|
|
137
|
+
[known limitations](#-known-limitations) โ this path has not been re-tested since
|
|
138
|
+
the segmentation rework.
|
|
139
|
+
|
|
140
|
+
### First run
|
|
141
|
+
|
|
142
|
+
Speech models (~1.5GB) download on first launch. Nothing else is needed.
|
|
143
|
+
|
|
144
|
+
<details>
|
|
145
|
+
<summary>Why Python 3.12 specifically</summary>
|
|
146
|
+
|
|
147
|
+
Not caution. The vendored `src/custom_speech_recognition` imports `aifc` and
|
|
148
|
+
`audioop` at module level, and **both were removed from the standard library in
|
|
149
|
+
Python 3.13**. `uv` installs a suitable interpreter itself, and its 3.12 build
|
|
150
|
+
ships tkinter, so there is no separate Tk step.
|
|
151
|
+
</details>
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## ๐ฏ Using it
|
|
156
|
+
|
|
157
|
+
1. Open the app. If audio routing is not in place, it offers to finish it.
|
|
158
|
+
2. Pick a mode, and set the number of people if you know it.
|
|
159
|
+
3. Hold your meeting. Nothing needs touching.
|
|
160
|
+
4. **Export** โ one dialog covers format, cleanup, which model to clean with,
|
|
161
|
+
and merging over-split speakers.
|
|
162
|
+
|
|
163
|
+
Cleanup runs in the background with a progress bar and an estimate, and can be
|
|
164
|
+
stopped: whatever finished is kept.
|
|
165
|
+
|
|
166
|
+
### Choosing a cleanup backend
|
|
167
|
+
|
|
168
|
+
| | Cost | Speed (measured) |
|
|
169
|
+
|---|---|---|
|
|
170
|
+
| **API** (`conf.yaml`) | per token | 5โ8s per batch of lines |
|
|
171
|
+
| **Claude CLI** | included in a subscription | 20โ50s per batch |
|
|
172
|
+
|
|
173
|
+
Both are offered at export, and the dialog turns the per-batch figure into an
|
|
174
|
+
estimate for the transcript in hand. The live reply suggestions always use the
|
|
175
|
+
configured API โ a CLI takes seconds per answer, which is too late to be useful
|
|
176
|
+
while someone is still talking.
|
|
177
|
+
|
|
178
|
+
### Past recordings
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
echoai-helper sessions # list them
|
|
182
|
+
echoai-helper sessions --export 0 # export one again
|
|
183
|
+
echoai-helper sessions --delete 0
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Re-exporting is the point: a different format, another pass of cleanup, a
|
|
187
|
+
different number of speakers, without re-recording anything. An unfinished
|
|
188
|
+
session from the last 12 hours is offered on the next launch.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## โ๏ธ Configuration
|
|
193
|
+
|
|
194
|
+
Model settings live in `conf.yaml`; everything else is in the app. Installed
|
|
195
|
+
from a wheel the shipped copy sits inside the package, so make yourself an
|
|
196
|
+
editable one:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
echoai-helper config # writes conf.yaml where you can reach it, and prints the path
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
That copy overrides the defaults. You will not usually need it โ both values
|
|
203
|
+
below already ship as `auto`.
|
|
204
|
+
|
|
205
|
+
```yaml
|
|
206
|
+
FunASR:
|
|
207
|
+
model_name: "iic/SenseVoiceSmall"
|
|
208
|
+
device: "auto" # cuda, then mps, then cpu
|
|
209
|
+
language: "auto" # zh, en, yue, ja, ko
|
|
210
|
+
|
|
211
|
+
LLM:
|
|
212
|
+
provider: "openai" # openai | litellm | cli
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Both `auto` values are load-bearing rather than lazy defaults:
|
|
216
|
+
|
|
217
|
+
- **`device: "auto"`** โ measured on an M4, dual-track real-time factor is 2.04
|
|
218
|
+
on cpu (falling behind twice over) against 0.35 on Metal. Landing on cpu by
|
|
219
|
+
accident means transcription that cannot keep up. Naming a device explicitly is
|
|
220
|
+
also wrong on every machine that does not have it, and this file travels.
|
|
221
|
+
- **`language: "auto"`** โ pinning a language does not bias the model, it forces
|
|
222
|
+
the syllables onto words of that language. A Cantonese call transcribed with
|
|
223
|
+
`language: "en"` comes back as fluent nonsense.
|
|
224
|
+
|
|
225
|
+
An OpenAI key goes in `.env` (see `.env.example`), or in a file called `.llm`
|
|
226
|
+
holding nothing else. Both are gitignored.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## ๐ Troubleshooting
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
echoai-helper check-audio # what is being captured, and from where
|
|
234
|
+
echoai-helper setup --status # what routing is in place
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Nothing from the far end (macOS).** The meeting app has its own audio settings
|
|
238
|
+
and remembers them. Set its speaker to `EchoAI Meeting`.
|
|
239
|
+
|
|
240
|
+
**Nothing from the microphone over Bluetooth.** A Bluetooth headset can only send
|
|
241
|
+
its microphone to one device. If it is on a phone call, the Mac gets silence โ
|
|
242
|
+
and the stream does not recover on its own; restart the app. A USB microphone
|
|
243
|
+
avoids this entirely.
|
|
244
|
+
|
|
245
|
+
**More speakers than people.** Voice prints drift with volume and connection
|
|
246
|
+
quality, so one person can end up split across several labels. Set the number of
|
|
247
|
+
people before the meeting, or merge them at export โ the export carries the voice
|
|
248
|
+
prints, so this works after the fact.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## ๐ ๏ธ Development
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
git clone https://github.com/colakang/echoai_helper.git
|
|
256
|
+
cd echoai_helper
|
|
257
|
+
uv venv --python 3.12 .venv
|
|
258
|
+
uv pip install --python .venv/bin/python -r requirements-macos.txt # or requirements.txt
|
|
259
|
+
.venv/bin/python -m pytest tests/ -q
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
[`docs/macos-audio-setup.md`](docs/macos-audio-setup.md) covers the audio
|
|
263
|
+
routing, what has been measured, and where the sharp edges are.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## ๐ Known limitations
|
|
268
|
+
|
|
269
|
+
- **A dead microphone stream does not recover.** Seen on a real call: capture
|
|
270
|
+
stops silently and the app looks like it is still working. Restarting fixes it.
|
|
271
|
+
This is the most consequential item on the list.
|
|
272
|
+
- **Speaker labelling is tuned against a clean two-party recording** and
|
|
273
|
+
over-splits on group calls over a lossy connection. Merging at export is the
|
|
274
|
+
workaround, not the cure.
|
|
275
|
+
- **The Windows capture path is untested** since the segmentation rework. Its
|
|
276
|
+
detector threshold was lowered to pass silence through, because segmentation
|
|
277
|
+
now happens on pauses and a recogniser that only reports speech never delivers
|
|
278
|
+
them โ reasoned, not verified. Reports welcome.
|
|
279
|
+
- **macOS audio routing is a shared setting.** Selecting the Multi-Output changes
|
|
280
|
+
the output for every app, and macOS sometimes moves it back after sleep.
|
|
281
|
+
Checked at every launch.
|
|
282
|
+
|
|
283
|
+
## ๐ค Contributing
|
|
284
|
+
|
|
285
|
+
Pull requests welcome; for anything substantial, open an issue first. See
|
|
286
|
+
[CONTRIBUTING.md](CONTRIBUTING.md).
|
|
287
|
+
|
|
288
|
+
## ๐ Credits
|
|
289
|
+
|
|
290
|
+
- [FunASR](https://github.com/modelscope/FunASR) โ speech recognition and speaker
|
|
291
|
+
embeddings
|
|
292
|
+
- [silero-vad](https://github.com/snakers4/silero-vad) โ voice activity detection
|
|
293
|
+
- [WhisperLiveKit](https://github.com/QuentinFuxa/WhisperLiveKit) โ the
|
|
294
|
+
LocalAgreement idea behind stable partial transcripts
|
|
295
|
+
- [BlackHole](https://existential.audio/blackhole/) โ virtual audio device on macOS
|
|
296
|
+
- [CustomTkinter](https://github.com/TomSchimansky/CustomTkinter) โ interface
|
|
297
|
+
- [Ecoute](https://github.com/SevaSk/ecoute) โ the original inspiration
|
|
298
|
+
- [@zixing0131](https://github.com/zixing0131) โ core audio processing
|
|
299
|
+
|
|
300
|
+
## ๐ Contact
|
|
301
|
+
|
|
302
|
+
[echo365.ai](https://www.echo365.ai) ยท [Issues](https://github.com/colakang/echoai_helper/issues)
|
|
303
|
+
|
|
304
|
+
## ๐ License
|
|
305
|
+
|
|
306
|
+
MIT โ see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# ๐๏ธ EchoAI Helper
|
|
2
|
+
|
|
3
|
+
[](https://github.com/colakang/echoai_helper/stargazers)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://python.org)
|
|
6
|
+
[](#-install)
|
|
7
|
+
[](#windows)
|
|
8
|
+
|
|
9
|
+
Real-time meeting transcription and interview assistance, running on your own
|
|
10
|
+
machine. It records both sides of a conversation โ your microphone and whatever
|
|
11
|
+
the meeting app is playing โ transcribes them as they happen, labels who is
|
|
12
|
+
speaking, and exports readable notes.
|
|
13
|
+
|
|
14
|
+
Speech recognition is local. Audio never leaves the machine unless you ask a
|
|
15
|
+
language model to clean up the finished transcript.
|
|
16
|
+
|
|
17
|
+
<p>
|
|
18
|
+
<a href="https://www.producthunt.com/posts/echoai-interview-copilot?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-echoai-interview-copilot" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=601490&theme=light" alt="EchoAI Interview Copilot  - Real-time conversation with LLM responses | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<p align="center">
|
|
22
|
+
<img width="800" alt="EchoAI Helper Interface" src="https://github.com/colakang/echoai_helper/raw/main/docs/images/ui.png">
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## โจ What it does
|
|
28
|
+
|
|
29
|
+
- **Local speech recognition** โ FunASR / SenseVoice, on-device, GPU-accelerated
|
|
30
|
+
where one is available (Metal on Apple Silicon, CUDA on Windows)
|
|
31
|
+
- **Automatic language detection** โ Mandarin, Cantonese, English, Japanese and
|
|
32
|
+
Korean, switching per utterance, including mid-sentence code-switching
|
|
33
|
+
- **Both sides of the call** โ your microphone and the far end, on separate tracks
|
|
34
|
+
- **Speaker labelling** โ voices on the far-end track are told apart, with the
|
|
35
|
+
number of people configurable when you know it
|
|
36
|
+
- **Pause-based segmentation** โ sentences are cut where people actually pause,
|
|
37
|
+
not on a fixed timer, so the model sees whole utterances
|
|
38
|
+
- **Crash-safe recording** โ every settled sentence is written to disk as it is
|
|
39
|
+
produced; a crash costs the last line, not the meeting
|
|
40
|
+
- **LLM cleanup on export** โ an optional pass that fixes mis-heard words using
|
|
41
|
+
the surrounding conversation, through an API key or through a coding-agent CLI
|
|
42
|
+
on a subscription you already pay for
|
|
43
|
+
- **Markdown and JSON export** โ Markdown to read, JSON as a complete record
|
|
44
|
+
- **Live reply suggestions** โ for interviews, where a prompt is wanted while the
|
|
45
|
+
other person is still talking
|
|
46
|
+
|
|
47
|
+
## ๐ก Two modes
|
|
48
|
+
|
|
49
|
+
| | Meeting notes | Live interview |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| Text appears | at each pause | as you speak (~0.6s) |
|
|
52
|
+
| Model calls | one per sentence | roughly three times as many |
|
|
53
|
+
| Best for | an accurate record | a prompt you can act on |
|
|
54
|
+
|
|
55
|
+
Switch in the app; the several settings that differ move together.
|
|
56
|
+
|
|
57
|
+
## ๐ฌ Demo
|
|
58
|
+
|
|
59
|
+
https://github.com/user-attachments/assets/0d627e4a-960b-4628-8bbc-8d892f02cfd1
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## โก Install
|
|
64
|
+
|
|
65
|
+
### macOS
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
uv tool install echoai-helper # uv brings its own Python 3.12
|
|
69
|
+
echoai-helper setup # audio routing โ one password prompt
|
|
70
|
+
echoai-helper install-launcher # adds an icon to Launchpad
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Launch from Launchpad, or run `echoai-helper`.
|
|
74
|
+
|
|
75
|
+
`setup` installs a virtual audio device and builds the Multi-Output that lets
|
|
76
|
+
you hear a meeting while it is being recorded. macOS asks for a password once,
|
|
77
|
+
because that installs an audio driver โ nothing else needs a privilege, and
|
|
78
|
+
Audio MIDI Setup is not involved.
|
|
79
|
+
|
|
80
|
+
The app takes the audio output while it runs and gives it back silently when it
|
|
81
|
+
quits, including after a crash. `echoai-helper setup --restore` does it by hand;
|
|
82
|
+
`--status` shows what routing is in place.
|
|
83
|
+
|
|
84
|
+
<details>
|
|
85
|
+
<summary>Prefer Homebrew?</summary>
|
|
86
|
+
|
|
87
|
+
A formula is in [`packaging/`](packaging/echoai-helper.rb) for a tap. Homebrew
|
|
88
|
+
can declare the virtual audio device as a dependency, which removes the one step
|
|
89
|
+
that needs a password.
|
|
90
|
+
</details>
|
|
91
|
+
|
|
92
|
+
### Windows
|
|
93
|
+
|
|
94
|
+
```powershell
|
|
95
|
+
uv tool install echoai-helper
|
|
96
|
+
echoai-helper
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
No audio setup step: Windows exposes WASAPI loopback directly, so the far end of
|
|
100
|
+
a call is capturable without a virtual device. The macOS-only commands (`setup`,
|
|
101
|
+
`install-launcher`) report that there is nothing to do. See
|
|
102
|
+
[known limitations](#-known-limitations) โ this path has not been re-tested since
|
|
103
|
+
the segmentation rework.
|
|
104
|
+
|
|
105
|
+
### First run
|
|
106
|
+
|
|
107
|
+
Speech models (~1.5GB) download on first launch. Nothing else is needed.
|
|
108
|
+
|
|
109
|
+
<details>
|
|
110
|
+
<summary>Why Python 3.12 specifically</summary>
|
|
111
|
+
|
|
112
|
+
Not caution. The vendored `src/custom_speech_recognition` imports `aifc` and
|
|
113
|
+
`audioop` at module level, and **both were removed from the standard library in
|
|
114
|
+
Python 3.13**. `uv` installs a suitable interpreter itself, and its 3.12 build
|
|
115
|
+
ships tkinter, so there is no separate Tk step.
|
|
116
|
+
</details>
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## ๐ฏ Using it
|
|
121
|
+
|
|
122
|
+
1. Open the app. If audio routing is not in place, it offers to finish it.
|
|
123
|
+
2. Pick a mode, and set the number of people if you know it.
|
|
124
|
+
3. Hold your meeting. Nothing needs touching.
|
|
125
|
+
4. **Export** โ one dialog covers format, cleanup, which model to clean with,
|
|
126
|
+
and merging over-split speakers.
|
|
127
|
+
|
|
128
|
+
Cleanup runs in the background with a progress bar and an estimate, and can be
|
|
129
|
+
stopped: whatever finished is kept.
|
|
130
|
+
|
|
131
|
+
### Choosing a cleanup backend
|
|
132
|
+
|
|
133
|
+
| | Cost | Speed (measured) |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| **API** (`conf.yaml`) | per token | 5โ8s per batch of lines |
|
|
136
|
+
| **Claude CLI** | included in a subscription | 20โ50s per batch |
|
|
137
|
+
|
|
138
|
+
Both are offered at export, and the dialog turns the per-batch figure into an
|
|
139
|
+
estimate for the transcript in hand. The live reply suggestions always use the
|
|
140
|
+
configured API โ a CLI takes seconds per answer, which is too late to be useful
|
|
141
|
+
while someone is still talking.
|
|
142
|
+
|
|
143
|
+
### Past recordings
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
echoai-helper sessions # list them
|
|
147
|
+
echoai-helper sessions --export 0 # export one again
|
|
148
|
+
echoai-helper sessions --delete 0
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Re-exporting is the point: a different format, another pass of cleanup, a
|
|
152
|
+
different number of speakers, without re-recording anything. An unfinished
|
|
153
|
+
session from the last 12 hours is offered on the next launch.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## โ๏ธ Configuration
|
|
158
|
+
|
|
159
|
+
Model settings live in `conf.yaml`; everything else is in the app. Installed
|
|
160
|
+
from a wheel the shipped copy sits inside the package, so make yourself an
|
|
161
|
+
editable one:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
echoai-helper config # writes conf.yaml where you can reach it, and prints the path
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
That copy overrides the defaults. You will not usually need it โ both values
|
|
168
|
+
below already ship as `auto`.
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
FunASR:
|
|
172
|
+
model_name: "iic/SenseVoiceSmall"
|
|
173
|
+
device: "auto" # cuda, then mps, then cpu
|
|
174
|
+
language: "auto" # zh, en, yue, ja, ko
|
|
175
|
+
|
|
176
|
+
LLM:
|
|
177
|
+
provider: "openai" # openai | litellm | cli
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Both `auto` values are load-bearing rather than lazy defaults:
|
|
181
|
+
|
|
182
|
+
- **`device: "auto"`** โ measured on an M4, dual-track real-time factor is 2.04
|
|
183
|
+
on cpu (falling behind twice over) against 0.35 on Metal. Landing on cpu by
|
|
184
|
+
accident means transcription that cannot keep up. Naming a device explicitly is
|
|
185
|
+
also wrong on every machine that does not have it, and this file travels.
|
|
186
|
+
- **`language: "auto"`** โ pinning a language does not bias the model, it forces
|
|
187
|
+
the syllables onto words of that language. A Cantonese call transcribed with
|
|
188
|
+
`language: "en"` comes back as fluent nonsense.
|
|
189
|
+
|
|
190
|
+
An OpenAI key goes in `.env` (see `.env.example`), or in a file called `.llm`
|
|
191
|
+
holding nothing else. Both are gitignored.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## ๐ Troubleshooting
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
echoai-helper check-audio # what is being captured, and from where
|
|
199
|
+
echoai-helper setup --status # what routing is in place
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Nothing from the far end (macOS).** The meeting app has its own audio settings
|
|
203
|
+
and remembers them. Set its speaker to `EchoAI Meeting`.
|
|
204
|
+
|
|
205
|
+
**Nothing from the microphone over Bluetooth.** A Bluetooth headset can only send
|
|
206
|
+
its microphone to one device. If it is on a phone call, the Mac gets silence โ
|
|
207
|
+
and the stream does not recover on its own; restart the app. A USB microphone
|
|
208
|
+
avoids this entirely.
|
|
209
|
+
|
|
210
|
+
**More speakers than people.** Voice prints drift with volume and connection
|
|
211
|
+
quality, so one person can end up split across several labels. Set the number of
|
|
212
|
+
people before the meeting, or merge them at export โ the export carries the voice
|
|
213
|
+
prints, so this works after the fact.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## ๐ ๏ธ Development
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
git clone https://github.com/colakang/echoai_helper.git
|
|
221
|
+
cd echoai_helper
|
|
222
|
+
uv venv --python 3.12 .venv
|
|
223
|
+
uv pip install --python .venv/bin/python -r requirements-macos.txt # or requirements.txt
|
|
224
|
+
.venv/bin/python -m pytest tests/ -q
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
[`docs/macos-audio-setup.md`](docs/macos-audio-setup.md) covers the audio
|
|
228
|
+
routing, what has been measured, and where the sharp edges are.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## ๐ Known limitations
|
|
233
|
+
|
|
234
|
+
- **A dead microphone stream does not recover.** Seen on a real call: capture
|
|
235
|
+
stops silently and the app looks like it is still working. Restarting fixes it.
|
|
236
|
+
This is the most consequential item on the list.
|
|
237
|
+
- **Speaker labelling is tuned against a clean two-party recording** and
|
|
238
|
+
over-splits on group calls over a lossy connection. Merging at export is the
|
|
239
|
+
workaround, not the cure.
|
|
240
|
+
- **The Windows capture path is untested** since the segmentation rework. Its
|
|
241
|
+
detector threshold was lowered to pass silence through, because segmentation
|
|
242
|
+
now happens on pauses and a recogniser that only reports speech never delivers
|
|
243
|
+
them โ reasoned, not verified. Reports welcome.
|
|
244
|
+
- **macOS audio routing is a shared setting.** Selecting the Multi-Output changes
|
|
245
|
+
the output for every app, and macOS sometimes moves it back after sleep.
|
|
246
|
+
Checked at every launch.
|
|
247
|
+
|
|
248
|
+
## ๐ค Contributing
|
|
249
|
+
|
|
250
|
+
Pull requests welcome; for anything substantial, open an issue first. See
|
|
251
|
+
[CONTRIBUTING.md](CONTRIBUTING.md).
|
|
252
|
+
|
|
253
|
+
## ๐ Credits
|
|
254
|
+
|
|
255
|
+
- [FunASR](https://github.com/modelscope/FunASR) โ speech recognition and speaker
|
|
256
|
+
embeddings
|
|
257
|
+
- [silero-vad](https://github.com/snakers4/silero-vad) โ voice activity detection
|
|
258
|
+
- [WhisperLiveKit](https://github.com/QuentinFuxa/WhisperLiveKit) โ the
|
|
259
|
+
LocalAgreement idea behind stable partial transcripts
|
|
260
|
+
- [BlackHole](https://existential.audio/blackhole/) โ virtual audio device on macOS
|
|
261
|
+
- [CustomTkinter](https://github.com/TomSchimansky/CustomTkinter) โ interface
|
|
262
|
+
- [Ecoute](https://github.com/SevaSk/ecoute) โ the original inspiration
|
|
263
|
+
- [@zixing0131](https://github.com/zixing0131) โ core audio processing
|
|
264
|
+
|
|
265
|
+
## ๐ Contact
|
|
266
|
+
|
|
267
|
+
[echo365.ai](https://www.echo365.ai) ยท [Issues](https://github.com/colakang/echoai_helper/issues)
|
|
268
|
+
|
|
269
|
+
## ๐ License
|
|
270
|
+
|
|
271
|
+
MIT โ see [LICENSE](LICENSE).
|