Compare commits

...

673 commits

Author SHA1 Message Date
Raivis Dejus
1346c68c72
Pre release polishes (#1416) 2026-03-08 08:47:19 +00:00
Raivis Dejus
36f2d41557
Mac UI adjustments (#1415) 2026-03-07 22:27:52 +00:00
Raivis Dejus
14cacf6acf
Recording transcriber improvements (#1414)
Adding option to hide unconfirmed and variable transcriptions in append and replace mode
2026-03-07 19:26:29 +00:00
Raivis Dejus
c9db73722e
Live recording improvements (#1413) 2026-03-07 14:48:41 +00:00
Raivis Dejus
04c07c6cae
Adding VAD to whisper.cpp to reduce hallucinations on audio w silences (#1412) 2026-03-07 05:58:04 +00:00
Raivis Dejus
981dd3a758
Pre release polishes (#1411) 2026-03-06 19:26:19 +02:00
Raivis Dejus
7f2bf348b6
Adding flatpak release notes (#1407) 2026-03-01 10:16:25 +00:00
Raivis Dejus
a881a70a6f
Recording transcriber improvements (#1405) 2026-02-28 17:32:10 +00:00
Raivis Dejus
187d15b8e8
Add auto update check for Windows adn Mac (#1404) 2026-02-28 14:39:04 +00:00
Raivis Dejus
3869ac08db
1329 improve folder watch (#1402) 2026-02-27 17:49:38 +00:00
Raivis Dejus
f545a84ba6
Add cvs export (#1400) 2026-02-27 14:14:18 +00:00
Raivis Dejus
ff1f521a6a
1389 add folder import (#1398) 2026-02-27 09:11:51 +00:00
Raivis Dejus
b2f98f139e
Youtube download update (#1396) 2026-02-26 20:24:35 +00:00
Raivis Dejus
0f77deb17b
Additional tests (#1393) 2026-02-22 18:00:23 +00:00
Raivis Dejus
4c9b249c50
Recordint transcriber improvements (#1392) 2026-02-22 17:46:20 +02:00
Raivis Dejus
bb546acbf9
Fix for windows crashes (#1387) 2026-02-20 15:47:13 +02:00
Raivis Dejus
ca8b7876fd
Adding translations (#1382) 2026-02-08 16:26:55 +00:00
Raivis Dejus
795da67f20
1026 translation improvements (#1380) 2026-02-08 15:13:21 +02:00
Raivis Dejus
749d9e6e4d
UI glitch fixes for recording transcriber (#1379) 2026-02-07 10:40:40 +00:00
Raivis Dejus
125e924613
Fix recording transcriber (#1377) 2026-02-06 20:50:19 +00:00
Anantharaman R
156ec35246
Added copy-to-clipboard button in recording transcribe widget (#1370) 2026-02-06 20:29:58 +02:00
Raivis Dejus
c4d7971e04
Fix for speech separation error (#1371) 2026-02-06 14:38:28 +02:00
Raivis Dejus
37f5628c49
Speaker identification improvements (#1372) 2026-02-06 10:42:08 +02:00
albanobattistella
7f14fbe576
Update Italian translations in buzz.po (#1365) 2026-01-26 08:13:14 +00:00
Raivis Dejus
a94d8fbd0d
Will validate audio before transcribing (#1364) 2026-01-25 18:44:49 +00:00
Raivis Dejus
0d446a9964
Will increase build workflow timeout (#1363) 2026-01-25 11:37:52 +00:00
Raivis Dejus
6f6bc53c54
Fix for whisper.cpp on older cpus (#1362) 2026-01-25 09:42:09 +00:00
Raivis Dejus
7594763154
Fix for gpt-4o models (#1361) 2026-01-24 18:30:15 +00:00
Raivis Dejus
b14cf0e386
Fix for HF hub SSL sertificate validation on Windows 10 (#1356) 2026-01-17 05:59:27 +00:00
Raivis Dejus
97b1619902
Fix chinease word level timestamps (#1355) 2026-01-16 12:31:48 +00:00
Raivis Dejus
92fc405c4a
1347 add ending extender (#1354) 2026-01-16 10:23:48 +00:00
Raivis Dejus
08ae8ba43f
Fix for HF hub download certificates (#1353) 2026-01-16 09:18:27 +00:00
Ikko Eltociear Ashimine
e9502881fc
docs: add Japanese README (#1352) 2026-01-16 08:22:08 +00:00
Rob Siera
dc27281e34
Fix missing spaces after punctuation in speaker identification (#1344)
Co-authored-by: Robrecht Siera <rob.developer.securemail@holoncom.eu>
2026-01-10 16:58:27 +00:00
Rob Siera
f1bc725e2b
Fix speaker identification chunk size error for long transcriptions (#1342)
Co-authored-by: Robrecht Siera <rob.developer.securemail@holoncom.eu>
2026-01-10 09:38:55 +00:00
Raivis Dejus
43214f5c3d
Update documentation (#1337) 2026-01-05 06:37:30 +00:00
Raivis Dejus
85d70c1e64
Fix wheels (#1336) 2026-01-03 22:16:34 +02:00
Raivis Dejus
b0a53b4c2f
1329 fix folder watch (#1335) 2026-01-03 11:53:33 +00:00
albanobattistella
6f075da3d3
Update buzz.po (#1334) 2026-01-03 11:01:47 +00:00
Raivis Dejus
7099dcd9f1
1329 fix folder watch (#1333) 2026-01-03 08:05:43 +00:00
Raivis Dejus
b4d73f62e0
Fix for certificate issue (#1328) 2025-12-24 11:11:18 +00:00
David Olowomeye
6e54b5cb02
Implemented presentation window for live transcripts #1306 (#1323)
Co-authored-by: Raivis Dejus <orvils@gmail.com>
2025-12-23 19:29:34 +00:00
Raivis Dejus
47ddc1461c
Fix for file being missing for speaker identification (#1325) 2025-12-23 12:11:47 +00:00
Raivis Dejus
665d21b391
1314 add download retry (#1322) 2025-12-22 08:21:33 +00:00
Raivis Dejus
734bd99d17
978 add youtube title (#1321) 2025-12-21 18:02:39 +00:00
Raivis Dejus
c93d8c9d03
Fic for HF downloads on Windows (#1319) 2025-12-21 14:38:02 +00:00
Raivis Dejus
de2a5b88ee
Fix for GPU setting on macs (#1318) 2025-12-19 12:49:26 +00:00
Raivis Dejus
4dbde2b948
491 add mms (#1313) 2025-12-18 20:49:39 +02:00
Raivis Dejus
7af79b6bc3
Fix for SSL errors on model downloading (#1316) 2025-12-17 08:00:54 +00:00
Raivis Dejus
ebcd42c8eb
Fix for speaker identification crash (#1315) 2025-12-16 08:40:42 +00:00
Raivis Dejus
b666a6a099
Minor improvements (#1312) 2025-12-13 10:44:18 +00:00
Raivis Dejus
dc0dc6b3d2
Adding speech extraction option to CLI (#1311) 2025-12-13 06:05:55 +00:00
Raivis Dejus
463121bb4b
Adding debug for audio issues (#1310) 2025-12-12 21:03:45 +00:00
Raivis Dejus
9d8ee2112d
Adjusting library load and versions (#1309) 2025-12-12 20:41:44 +02:00
Raivis Dejus
20ed2be44c
Search improvement (#1307) 2025-12-11 19:28:10 +00:00
David Olowomeye
1c146631c9
Added video support in transcription playback #906 (#1295)
Co-authored-by: Raivis Dejus <orvils@gmail.com>
2025-12-10 10:18:00 +02:00
Raivis Dejus
11e59dba2b
1292 fix speech dependencies (#1302) 2025-12-06 16:51:40 +00:00
Shlomi
76b8e52fe5
Shlomi/main panel improvements (#1239)
Co-authored-by: Raivis Dejus <orvils@gmail.com>
2025-12-06 15:14:05 +02:00
Raivis Dejus
5eea1fe721
Fix speech separation (#1301) 2025-12-05 22:57:14 +02:00
Raivis Dejus
454a03bb59
Fix for app cleanup (#1299) 2025-12-04 07:41:08 +00:00
Raivis Dejus
97408c6a98
Fixes for app cleanup during close (#1298) 2025-12-03 19:39:00 +00:00
Raivis Dejus
73376a63ac
Add speaker identification2 (#1290)
Co-authored-by: David Olowomeye <100958002+greatdaveo@users.noreply.github.com>
2025-12-02 21:39:24 +02:00
Raivis Dejus
cabbd487f9
Improvements (#1296) 2025-11-28 21:30:36 +02:00
Raivis Dejus
252db3c3ed
Adding option to delete saved models and files on uninstall (#1291) 2025-11-24 19:59:21 +00:00
David Olowomeye
f3765a586f
Implemented resume functionality for downloading models #1287 (#1289) 2025-11-24 09:20:12 +02:00
Raivis Dejus
5a81c715d1
Adjusting Windows build notes (#1288) 2025-11-20 05:50:56 +00:00
Raivis Dejus
de1ed90f50
Fix for snap (#1286) 2025-11-18 16:22:10 +00:00
Raivis Dejus
93559530ab
Adjusting flatpak meta (#1285) 2025-11-17 20:53:06 +00:00
albanobattistella
629fa9f1f7
Update buzz.po (#1282) 2025-11-09 20:36:33 +00:00
Raivis Dejus
070d9f17d5
Documentation adjustments (#1281) 2025-11-09 19:57:39 +00:00
Raivis Dejus
ccdeb09ac9
Fix for translator test (#1280) 2025-11-09 09:52:20 +00:00
Raivis Dejus
79d8aadf2f
Inline demucs (#1279) 2025-11-08 19:21:19 +00:00
Raivis Dejus
10e74edf89
Add test timeout (#1277) 2025-11-06 11:51:01 +00:00
Raivis Dejus
e5843d7668
Fix for pipy release (#1274) 2025-11-03 18:55:56 +00:00
Raivis Dejus
fd8db37d6b
Updating macOS build actions (#1271) 2025-11-02 18:13:51 +00:00
prschopf
c5a0be6a26
Updated Portuguese Translation (#1270) 2025-11-02 01:20:41 +02:00
Raivis Dejus
2becec192a
Upgrade of metainfo (#1269) 2025-11-01 17:28:41 +00:00
Raivis Dejus
71e04b7350
Whispercpp cli uv (#1264) 2025-11-01 18:31:01 +02:00
Eric Duarte
44dae86f05
translation Catalan 10/2025 (#1262) 2025-10-17 09:38:10 +00:00
prschopf
a4e6135eef
Updated translations for pt_br (#1259) 2025-10-06 09:07:00 +03:00
Raivis Dejus
dfb8ba6614
Will let select from all media files by default (#1258) 2025-10-05 09:20:04 +00:00
Raivis Dejus
d53bd6df18
Fixing jitter in audio playback while following segments in transcrip… (#1257) 2025-10-04 17:53:21 +00:00
Raivis Dejus
7d58cdaf7b
Adding tests (#1256) 2025-10-04 11:23:59 +00:00
Raivis Dejus
89d9fd13b2
1250 timestamp editing (#1255) 2025-10-04 04:53:22 +00:00
Raivis Dejus
dfa7d50ab3
Fix for menu buttons (#1254) 2025-10-03 12:03:55 +00:00
Raivis Dejus
a03f2e0beb
Will make advanced settings dialog wider (#1251) 2025-10-03 08:52:01 +00:00
Raivis Dejus
bc478974d9
Adjusting column widths to fit content (#1249) 2025-09-20 09:39:51 +00:00
David Olowomeye
44e962d1e2
Created option for text viewer by adding BUZZ_PARAGRAPH_SPLIT_TIME environment variable (#1246)
Co-authored-by: Raivis Dejus <orvils@gmail.com>
2025-09-20 07:51:47 +00:00
Raivis Dejus
862701a9ef
Fix for download progeress closing too soon (#1244) 2025-09-17 04:25:58 +00:00
Raivis Dejus
f80a0c8d2e
Fix for row highlighting on Windows (#1243) 2025-09-16 18:37:04 +00:00
Eric Duarte
22803556fb
Spanish translation update, september 2025 (#1242)
Co-authored-by: Raivis Dejus <raivisd@scandiweb.com>
2025-09-16 11:50:36 +00:00
Raivis Dejus
34b2a56198
Adding translatin update by @prschopf (#1241) 2025-09-08 14:17:46 +00:00
Raivis Dejus
b9569eb0f4
Adding missing translations (#1234) 2025-09-05 18:17:06 +00:00
Raivis Dejus
abe12c5d13
Adding latvian translations and fix for documentation pages (#1231) 2025-09-03 10:45:13 +00:00
Shlomi
d285e6e43d
Add speed control (#1224)
Co-authored-by: Raivis Dejus <orvils@gmail.com>
2025-09-03 11:38:46 +03:00
Raivis Dejus
ad176beb47
Adding Setting in the UI to force CPU (#1228) 2025-08-30 17:20:41 +00:00
Raivis Dejus
08174301a5
Fix for latest macos builds (#1227) 2025-08-30 10:48:03 +00:00
Raivis Dejus
11429a612d
Fix for language detection in whisper.cpp (#1226) 2025-08-30 09:02:33 +00:00
Raivis Dejus
15bbd010f6
Fix for Intel macs for whisper.cpp (#1225) 2025-08-30 07:46:45 +00:00
Raivis Dejus
888715e28b
Will not force standard palette (#1219) 2025-08-24 17:23:22 +00:00
Raivis Dejus
f4c04019da
Fix dark themes (#1217) 2025-08-23 15:39:59 +00:00
Raivis Dejus
be716b1305
Fix for dark theme detection (#1216) 2025-08-23 14:54:56 +00:00
Raivis Dejus
f2356b4638
Fix for onnxruntime crash on Windows (#1215) 2025-08-19 06:46:19 +00:00
Raivis Dejus
460c4ce988
Fix for faster whisper on windows (#1211) 2025-08-10 06:10:02 +00:00
Raivis Dejus
1c5bea1c48
1205 fix windows (#1210) 2025-08-08 16:42:18 +00:00
Raivis Dejus
fdde496b38
Fix for windows blinking on windows (#1209) 2025-08-08 10:16:39 +00:00
Raivis Dejus
44fc608bc6
Updated docs (#1208) 2025-08-08 07:18:39 +00:00
Raivis Dejus
d27b5a13d1
Adding support to force cpu (#1203) 2025-08-05 04:43:02 +00:00
Raivis Dejus
ce0cc5bd81
Fix for windows (#1204) 2025-08-04 18:08:08 +00:00
Eric Duarte
94bb0af427
updating translations in Catalan and Spanish July 2025 (#1200) 2025-07-31 15:33:10 +00:00
Raivis Dejus
261e532818
Fix for whisper server language detection (#1198) 2025-07-22 18:57:59 +00:00
prschopf
86e7051123
Update pt_BR po file (#1195)
Co-authored-by: Raivis Dejus <raivisd@scandiweb.com>
2025-07-21 20:48:01 +00:00
Raivis Dejus
645a97c176
Updating pytinstaller (#1196) 2025-07-21 18:50:51 +00:00
Raivis Dejus
93afbead37
Adding support for Vulkan for whisper.cpp (#1194) 2025-07-20 16:53:36 +03:00
Raivis Dejus
8fa065eb95
Crash fixes and library updates (#1188) 2025-07-06 21:00:07 +03:00
prschopf
137d456a51
Adding translation to pt_BR (#1190)
Co-authored-by: Raivis Dejus <raivisd@scandiweb.com>
2025-07-06 18:57:02 +03:00
Raivis Dejus
b6a62bacb0
Add tests (#1193) 2025-07-06 18:08:17 +03:00
Raivis Dejus
4b786595c3
Adding support for word level timings in Whisper API and Whisper.cpp … (#1183) 2025-06-18 13:33:31 +00:00
Raivis Dejus
eb58067145
Will not transcribe if there is no input for live transcripts (#1181) 2025-06-08 08:47:12 +00:00
albanobattistella
a2c024d9bc
Update buzz.po (#1179) 2025-05-30 20:34:02 +03:00
Raivis Dejus
778121e7ba
Fix for subtitle resize crash on macOS (#1176) 2025-05-25 21:46:40 +03:00
Raivis Dejus
039ab908f9
Fix for initialising the DB (#1175) 2025-05-25 06:15:51 +00:00
Raivis Dejus
146c7f87a8
Update win libs (#1174) 2025-05-24 23:45:18 +03:00
Raivis Dejus
09640d6b74
Updating Windows libraries (#1173) 2025-05-24 08:45:28 +00:00
Raivis Dejus
0630c40ce1
Fix for Faster whisper on Windows (#1172) 2025-05-23 19:43:18 +03:00
Raivis Dejus
3844fc0ba2
Adding option to upload live transcripts to a server (#1171) 2025-05-23 11:47:51 +00:00
Raivis Dejus
5810ac4a2e
Fix for Faster whisper (#1170) 2025-05-18 13:33:46 +00:00
Raivis Dejus
ecdf8da9c6
Fix for UTF characters in file path (#1169) 2025-05-18 11:11:40 +00:00
Eric Duarte
d98cdc6c17
updating and correcting Catalan and Spanish translations (#1168)
Co-authored-by: Raivis Dejus <raivisd@scandiweb.com>
2025-05-17 17:24:57 +00:00
Raivis Dejus
84500e4380
Adding extra models (#1167) 2025-05-17 16:51:11 +00:00
Raivis Dejus
3adef43255
Fix for restoring main window size on Mac (#1166) 2025-05-16 17:42:19 +03:00
GoldMath
9dbb57d682
Update 3_translations.md (#1158) 2025-05-16 07:05:12 +00:00
Thilo R.
9ac88f7a67
fix: correct pip install command option typo (#1156) 2025-05-10 09:24:03 +00:00
Raivis Dejus
806546282d
Transcript viewer UX improvements for translations (#1151) 2025-04-25 07:10:52 +00:00
Chidi Williams
fa6bab952c
Remove Ubuntu 20.04 (#1148) 2025-04-21 13:49:07 +01:00
Raivis Dejus
e136cebf31
Will split intel macOS build to use older torch (#1138) 2025-04-05 09:27:29 +00:00
Raivis Dejus
c861675947
Adding PostHog telemetry of os and machine architecture (#1137) 2025-04-03 18:20:48 +00:00
Raivis Dejus
b80b47807c
Adding notes on local build and example image (#1136) 2025-03-30 16:23:19 +00:00
Raivis Dejus
afd70eab1d
Fix for CUDA on Windows (#1133) 2025-03-24 09:52:30 +02:00
Raivis Dejus
a37c366672
Fix for speech extraction on Windows (#1132) 2025-03-23 17:46:09 +00:00
Raivis Dejus
bc5d4b1c71
Fix for clips with large silences (#1131) 2025-03-23 15:04:07 +00:00
Raivis Dejus
12a2678c2b
Will include demucs data files in windows installer (#1129) 2025-03-23 13:30:42 +02:00
Raivis Dejus
e74bd6ac10
Pyinstaller update to fix windows numba issue (#1128) 2025-03-23 05:51:51 +00:00
Heimen Stoffels
0401fb6204
Added Dutch translation (#1123) 2025-03-22 20:53:47 +00:00
Raivis Dejus
404aecf75b
Adding Dutch locale build and some notes (#1126) 2025-03-22 20:19:54 +00:00
Aryo
fe8398f750
Update README.md with alternative Windows install (#1120) 2025-03-17 16:45:11 +00:00
Raivis Dejus
dab715fbeb
Adding note on flatpak themes for Gnome (#1119) 2025-03-16 17:49:11 +00:00
Raivis Dejus
9db878b3c3
Will download directly to model path to avoid tmp file issues in Flatpak (#1118) 2025-03-16 16:47:45 +00:00
Raivis Dejus
eb1d4309ad
Updating PyQt (#1117) 2025-03-16 10:54:03 +00:00
Raivis Dejus
a6fcef3740
Flatpak manifest update (#1115) 2025-03-16 07:22:16 +00:00
Raivis Dejus
e56569a8f9
Update dependencies (#1112) 2025-03-15 21:37:07 +00:00
Raivis Dejus
77e98938f9
Adding german translations (#1107) 2025-03-06 17:46:40 +00:00
Raivis Dejus
59fe8ce941
Adding default en_US locale and fix for locale generation (#1105) 2025-03-04 19:37:40 +00:00
Raivis Dejus
2a9eab3cb7
Updated screenshots (#1104) 2025-03-04 18:17:11 +00:00
Raivis Dejus
92efe9bf92
Updated Flatpak icon (#1099) 2025-03-01 17:55:59 +00:00
Raivis Dejus
4af8ae96e1
Adding demucs to the package file list (#1092) 2025-02-27 19:48:57 +00:00
Raivis Dejus
342551cc75
Update for Flathub metadata (#1098) 2025-02-27 18:56:52 +00:00
Raivis Dejus
8a8588213f
Update for Flathub metadata (#1097) 2025-02-27 17:28:50 +00:00
Raivis Dejus
0e80695186
Fix for speech separation failing on intel Macs (#1091) 2025-02-23 08:13:53 +00:00
Raivis Dejus
4b75efdf50
Adding language switcher and localizable language list (#1090) 2025-02-23 05:36:40 +00:00
Raivis Dejus
373f7f9108
Pinning Flatpak screenshots to fixed commit (#1089) 2025-02-22 14:58:56 +00:00
Raivis Dejus
09519db946
Fix for folder watch if model is not downloaded yet (#1088) 2025-02-22 06:18:12 +00:00
Raivis Dejus
ed54b94603
Will remove auto connected permissions (#1087) 2025-02-21 18:26:10 +00:00
Raivis Dejus
6c0773ae07
Will update ffmpeg installation action (#1085) 2025-02-20 08:25:12 +02:00
Raivis Dejus
7861e2bd85
Will enable GPU for windows for recording transcriber (#1083) 2025-02-16 18:21:11 +00:00
Raivis Dejus
3c672369a4
1080 hide ffmpeg windows (#1082) 2025-02-16 19:36:40 +02:00
Raivis Dejus
914c5201dc
Add flatpak (#1081)
Co-authored-by: Chidi Williams <williamschidi1@gmail.com>
2025-02-16 13:13:53 +00:00
Raivis Dejus
658ff87525
Snap remove pulseaudio (#1076) 2025-02-08 13:19:06 +00:00
Raivis Dejus
e40ae5134e
Fix for faster whisper offline (#1074) 2025-02-08 08:44:03 +00:00
Li Chenghao (李成浩)
e773d15658
Update index.md (#1068) 2025-02-04 08:22:23 +02:00
Li Chenghao (李成浩)
63cf3175e6
update (#1066) 2025-02-02 15:26:11 +02:00
Li Chenghao (李成浩)
9dbab8464d
Cn doc support0201 (#1064) 2025-02-02 11:38:31 +02:00
Raivis Dejus
86f461c676
Fix for word-timestamp CLI option (#1062) 2025-02-01 10:25:52 +00:00
Raivis Dejus
56263c7bf4
Will use previous ffmpeg action on Intel Macs (#1061) 2025-02-01 09:59:07 +00:00
Raivis Dejus
8ac5172239
Will use system architecture for ffmpeg (#1059) 2025-01-31 16:23:40 +02:00
Raivis Dejus
2b974ea1f0
987 add localized documentation (#1058) 2025-01-31 11:34:09 +00:00
Li Chenghao (李成浩)
8ff3f79789
CN update (#1049)
Co-authored-by: Raivis Dejus <raivisd@scandiweb.com>
2025-01-22 08:37:58 +00:00
Li Chenghao (李成浩)
156433e81d
Update buzz.po (#1048) 2025-01-22 10:09:36 +02:00
Li Chenghao (李成浩)
6286c4aa86
Cn language support (#1046)
Co-authored-by: Raivis Dejus <raivisd@scandiweb.com>
2025-01-20 07:20:29 +00:00
Ole Guldberg
ec9fde0409
Danish translation (#1045) 2025-01-20 06:45:14 +00:00
Li Chenghao (李成浩)
3b886af992
Update buzz.po (#1044) 2025-01-12 17:21:03 +02:00
Raivis Dejus
70fa7aa7f2
Fix for wheels build (#1042)
Co-authored-by: Li Chenghao (李成浩) <94270615+Chenghao999@users.noreply.github.com>
2025-01-10 09:01:59 +02:00
Li Chenghao (李成浩)
9921d61a67
Cn language support (#1039)
Co-authored-by: Raivis Dejus <raivisd@scandiweb.com>
2025-01-09 22:04:35 +02:00
Raivis Dejus
e76c1bb0ad
Fix for API key check (#1041) 2025-01-09 18:58:25 +00:00
Raivis Dejus
32945e0572
Adding note on setting environment variables (#1038) 2025-01-02 16:13:11 +00:00
Raivis Dejus
a33270bf91
Adding option to extract speech (#1037) 2025-01-02 12:28:53 +02:00
Raivis Dejus
9d5ec9cc89
Adding UI improvements to the subtitle merging (#1033) 2024-12-29 19:04:50 +00:00
Raivis Dejus
6037287244
Adding improved options to resize subtitles (#1032) 2024-12-29 11:15:06 +02:00
Raivis Dejus
a1a81c1a06
Will start translation on settings dialog close (#1025) 2024-12-15 14:51:37 +00:00
Raivis Dejus
4e46e41a68
Updated faster whisper to latest 1.1.0 (#1023) 2024-12-12 06:52:20 +00:00
Raivis Dejus
08af80e180
Will use GPU for faster whisper on Windows (#1022) 2024-12-11 20:53:07 +02:00
Raivis Dejus
ea572829f6
Adding option to disable GPU (#1016) 2024-12-01 10:38:31 +00:00
albanobattistella
f96bb7b2cf
Update buzz.po (#1009)
@albanobattistella Thanks for the update!
2024-11-24 16:24:24 +02:00
Raivis Dejus
e012cf9fe3
Fixed FAQ (#1008) 2024-11-24 10:52:48 +00:00
Raivis Dejus
5165e953f0
Adding url import icon to main toolbar (#1004) 2024-11-24 09:59:35 +00:00
Raivis Dejus
21e7c2c251
Will delete old Buzz files when installing new version (#1007) 2024-11-24 09:30:44 +00:00
Raivis Dejus
5255cefc8e
Fix for macOS release builds (#1006) 2024-11-24 08:04:01 +00:00
Raivis Dejus
220e630421
Adding option to import urls via CLI (#1003) 2024-11-23 19:43:37 +00:00
Raivis Dejus
6c9d379a7f
Will not run app during the build (#1002) 2024-11-23 18:41:04 +00:00
Raivis Dejus
bd0cbc8f12
Adding option to hide GUI window in CLI mode (#996) 2024-11-18 17:02:35 +00:00
Raivis Dejus
29e3a94395
Will close the app on task finish in CLI (#995) 2024-11-18 13:01:53 +00:00
Raivis Dejus
c181a287d0
Fix for disabled folder watch running on startup (#994) 2024-11-18 10:32:06 +00:00
Raivis Dejus
3069512510
Adding support for cookiefile for Youtube downloads (#988) 2024-11-10 15:57:05 +00:00
Raivis Dejus
73a052e723
Adding option to copy transcription source from transcription table (#986) 2024-11-09 07:08:23 +00:00
Raivis Dejus
f61701f0b0
Adding locale override (#985) 2024-11-08 20:05:01 +00:00
Li Chenghao (李成浩)
df63b9d05a
Cn language support (#982)
Co-authored-by: Raivis Dejus <raivisd@scandiweb.com>
2024-11-05 18:13:22 +00:00
Raivis Dejus
725031ebb8
Adding Core ML support for WhisperCpp (#976)
This also changes how models for Whisper.cpp are downloaded. After update of the app models will need to be re-downloaded if you have them already downloaded.
2024-11-05 19:41:26 +02:00
Li Chenghao (李成浩)
ce3bfeaef3
Update buzz.po (#973)
Co-authored-by: Raivis Dejus <raivisd@scandiweb.com>
2024-11-03 14:26:32 +00:00
albanobattistella
1a67b3e546
Update buzz.po (#977) 2024-11-03 15:53:40 +02:00
Raivis Dejus
386c1513b2
Adding word level timestamps for Huggingface (transformers) whisper (#971) 2024-11-01 14:13:14 +00:00
Roshanlal
8a1a967720
Update README.md (#970)
Co-authored-by: Raivis Dejus <raivisd@scandiweb.com>
2024-11-01 13:17:16 +00:00
Raivis Dejus
b868e61245
Fix for column visibility on Macs (#969) 2024-11-01 11:27:13 +00:00
Raivis Dejus
807b43f9bf
Adding turbo models (#967) 2024-11-01 07:47:12 +00:00
Li Chenghao (李成浩)
76509927f8
Update buzz.po (#966) 2024-10-31 15:42:53 +00:00
Raivis Dejus
4772a127a1
Fix for url imports (#965) 2024-10-27 16:09:54 +00:00
Raivis Dejus
b354d302b7
Adding notes to FAQ (#962) 2024-10-26 07:27:27 +00:00
Raivis Dejus
c94671f3d6
Fix for row height on long transcriptions with a lot of rows (#960) 2024-10-25 17:02:38 +00:00
Raivis Dejus
5ff9694b1a
Adding note on offline usage (#959) 2024-10-25 16:25:25 +00:00
Raivis Dejus
e134654fc8
Mitigation for incomplete downloads (#958) 2024-10-24 16:59:08 +00:00
Raivis Dejus
a0c07c9fa2
Adding support for Turbo model (#953) 2024-10-24 19:26:22 +03:00
Raivis Dejus
56d7835677
Adding cudnn to LD_LIBRARY_PATH for snap (#951) 2024-10-18 08:28:23 +00:00
Raivis Dejus
2c15298b80
Adding warning on possibly invalid API key (#950) 2024-10-18 06:10:20 +00:00
Raivis Dejus
b35267d422
Fix for changing font for Windows dark mode (#947) 2024-10-13 09:40:27 +00:00
Raivis Dejus
d5d95a5b51
Will not check process return code, but error (#945) 2024-10-12 10:13:13 +00:00
Raivis Dejus
03e882eebf
Adding path to ffmpeg for installed app on windows (#942) 2024-10-12 09:20:14 +00:00
Raivis Dejus
724fdea33f
Fix for safetensor model detection (#943) 2024-10-12 06:34:44 +00:00
Raivis Dejus
1baccef5e5
Removing post processing on uls downloads (#941) 2024-10-11 23:38:22 +03:00
Raivis Dejus
3b76b42047
Adding logging to url download case (#938) 2024-10-08 20:58:01 +03:00
Raivis Dejus
d97d77d715
Fix for url import dialog (#937) 2024-10-08 05:33:44 +00:00
Raivis Dejus
950e56ea6f
Live recording sliding window (#933) 2024-10-06 11:29:42 +00:00
Raivis Dejus
d98383d7d3
Fallback for queued_at having no value (#932) 2024-10-05 18:47:23 +00:00
Raivis Dejus
c6d19b0eaf
Fix for dark theme on Windows 11 (#930) 2024-10-05 13:19:43 +03:00
Raivis Dejus
2dbe80f537
Will remember column visibility and add context menu to table header (#929) 2024-10-05 09:09:37 +00:00
Raivis Dejus
6723821cb8
Will set custom dark mode only on windows (#927) 2024-10-05 06:34:23 +00:00
Raivis Dejus
6bd3e672fd
Adding support for dark themed OSes (#926) 2024-10-04 14:34:07 +00:00
Raivis Dejus
cf9033497d
Will build Windows with GPU support (#920) 2024-10-04 12:03:58 +00:00
Raivis Dejus
566f6b505c
Adding note on Windows warning (#919) 2024-09-30 05:58:31 +00:00
Raivis Dejus
0f7d3fd5c8
Adding translation for ok/cancel buttons (#918) 2024-09-29 16:31:46 +00:00
Raivis Dejus
29271ae48e
Adding note installation for Macs (#917) 2024-09-29 15:39:04 +00:00
Raivis Dejus
81bc364b91
Adding note on dll backup for windows (#916) 2024-09-29 13:26:45 +00:00
Raivis Dejus
6f049e6d09
Adding setting for favorite languages (#915) 2024-09-29 06:16:21 +00:00
Raivis Dejus
e63e644c6c
Updated local GPU notes (#914) 2024-09-28 16:02:28 +00:00
Raivis Dejus
7f1fd31f43
Adding word level timestamps to CLI (#913) 2024-09-28 12:30:28 +00:00
Raivis Dejus
b592550299
Fix for exporting just resized segments (#912) 2024-09-28 12:05:34 +00:00
Raivis Dejus
d1916ee940
Update translations (#911) 2024-09-27 09:35:40 +00:00
Nunawa
0c6d21f80e
Add Japanese translation (#909) 2024-09-27 07:53:55 +00:00
Raivis Dejus
64442600bd
Will add Mac arch to release file names (#905) 2024-09-14 18:45:43 +00:00
Chidi Williams
ee818dc44a
Upgrade to 1.1.0 (#900) 2024-09-07 17:39:31 +00:00
Lucyeoh
35ebd58742
Create CODE_OF_CONDUCT.md (#896) 2024-08-31 07:29:28 +00:00
Raivis Dejus
4d9547d9c1
Adding option to specify custom model root (#894) 2024-08-27 17:43:37 +00:00
Raivis Dejus
f6fc65eeae
Adding option to specify different API for translation (#893) 2024-08-26 16:51:31 +00:00
Raivis Dejus
a25c384440
Adding option to set n_threads for Whisper.cpp (#892) 2024-08-25 20:29:49 +03:00
Raivis Dejus
5d83950382
Fix for duplicate segments in whisper.cpp (#891) 2024-08-19 07:02:44 +00:00
Raivis Dejus
12c1ac8b57
Fix for extra spaces in whisper.cpp transcripts (#890) 2024-08-17 15:48:06 +00:00
Raivis Dejus
6fa9c8db06
Will combine sentences into paragraphs when exporting txt (#889) 2024-08-17 14:50:27 +00:00
Raivis Dejus
717f855288
Adding ability to resize subtitles (#888) 2024-08-17 10:03:28 +00:00
Raivis Dejus
1c26bec57f
Adding note on running buzz from source on macos (#886) 2024-08-16 18:42:38 +00:00
Raivis Dejus
67fea79cd3
Adding note on running buzz from source on macos (#885) 2024-08-16 16:47:25 +00:00
Raivis Dejus
ab1590a639
Will build universal binary on macOS (#881) 2024-08-16 06:19:17 +00:00
Raivis Dejus
a71ec85195
Adding note on ffmpeg + fix for faster whisper on macOS (#882) 2024-08-10 19:07:37 +00:00
Raivis Dejus
ecb85aeb92
Will revert to using windows dll from backup (#880) 2024-08-10 10:43:31 +00:00
Raivis Dejus
218b16cbad
Fix for macOS 13 test (#876) 2024-08-10 09:39:23 +00:00
Raivis Dejus
62eb2096f6
Adding note on CUDA 12 for Faster whisper (#875) 2024-08-07 18:56:37 +00:00
Raivis Dejus
dc9121b0b6
Adding note on PaErrorCode-9999 (#874) 2024-08-07 16:59:45 +00:00
Raivis Dejus
38e1254adf
Add documantation (#872) 2024-08-04 16:31:52 +00:00
Raivis Dejus
3c78593319
Will prevent duplicate tasks in folder watch (#871) 2024-08-03 20:19:26 +00:00
Raivis Dejus
326ffbc0c5
Will print progress while processing with Huggingface (#870) 2024-08-03 21:12:02 +03:00
Raivis Dejus
db6d8b7e39
Will restore "Run" button on progress cancellation (#869) 2024-08-03 10:53:48 +00:00
Raivis Dejus
0bea55507b
Will disable CUDA for faster whisper on Windows to prevent error (#868) 2024-08-03 13:19:07 +03:00
Raivis Dejus
76c5a0bd99
Will remove win32 dlls (#867) 2024-08-02 20:20:02 +00:00
Raivis Dejus
ebb7cde23a
862 fix for multi part model lownload (#865) 2024-08-02 06:54:13 +00:00
Raivis Dejus
6c3959d0ff
Fix for finnish huggingface model download (#864) 2024-07-31 00:30:56 +03:00
Raivis Dejus
9877977824
Adding cibuildwheels to build wheels (#842) 2024-07-30 21:00:26 +03:00
Raivis Dejus
490aa7f47c
Fix for build failing to generate translation mo (#847) 2024-07-16 06:23:52 +00:00
Yevhen Popok
eb89cc4ac3
Add Ukrainian translation (#846) 2024-07-16 05:52:07 +00:00
Raivis Dejus
60a70bec36
Fix for language detection (#844) 2024-07-14 15:21:27 +00:00
Raivis Dejus
af48f32b44
Fix for API key check (#841) 2024-07-11 17:23:44 +00:00
Raivis Dejus
3ac0988489
Upgrade to 1.0.1 (#839) 2024-07-11 05:55:59 +00:00
Raivis Dejus
352646957a
Will build wheels in actions for testing (#838) 2024-07-11 06:52:55 +03:00
Raivis Dejus
7e8154619f
Will ensure snaps have localizations (#837) 2024-07-10 20:01:19 +00:00
Raivis Dejus
f0975e897f
Fix for whisper.dll (#834) 2024-07-10 22:33:53 +03:00
Raivis Dejus
50d6653dc5
Will ensure snaps have localizations (#835) 2024-07-10 09:43:35 +03:00
Raivis Dejus
0dfe0c5d65
Adding support for alternate faster whisper model name (#832) 2024-07-08 19:31:26 +00:00
Raivis Dejus
fc5579a029
Fixed typo (#831) 2024-07-08 18:59:35 +00:00
Raivis Dejus
a72a7bee95
Fixes snap localizations (#829) 2024-07-07 17:49:54 +00:00
Raivis Dejus
635b332574
Adding notes on custom apis and translation (#828) 2024-07-07 15:26:37 +00:00
Chidi Williams
621be2c46d
Upgrade to 1.0.0 (#825) 2024-07-06 11:21:39 +00:00
Raivis Dejus
ea58afa892
Adding ability to change application font size (#822) 2024-07-02 19:36:22 +00:00
Raivis Dejus
300b4fe244
Adding translations (#821) 2024-07-02 18:30:22 +00:00
Raivis Dejus
2eeb03a251
Adding custom model size for Whisper.cpp and Faster Whisper (#820) 2024-07-02 20:51:39 +03:00
Raivis Dejus
4d06273305
Will filter out junk whisper adds on silence (#816) 2024-06-28 20:19:53 +00:00
Raivis Dejus
a98ec9fa58
Fix for large v3 faster whisper model (#815) 2024-06-26 17:54:52 +00:00
Raivis Dejus
3d8f5da492
Switching to pipeline for HF whisper (#814) 2024-06-25 07:29:03 +03:00
Raivis Dejus
cf340bc7d4
Adding support for Groq.com API (#813) 2024-06-22 17:21:39 +00:00
Raivis Dejus
004613906c
Fix for default HF model (#812) 2024-06-22 16:20:22 +00:00
Raivis Dejus
2d5684c6f4
Adding translation for Yes/No buttons (#811) 2024-06-22 08:38:54 +00:00
Raivis Dejus
98947602e4
Adding note CUDA / GPU support for Windows (#810) 2024-06-22 06:48:57 +00:00
Raivis Dejus
2e7dbab958
Adding CUDA / GPU support to whisper model (#809) 2024-06-21 18:54:01 +00:00
Raivis Dejus
9e6d722ca9
Switch whisper model cache to /models/ (#808) 2024-06-21 12:05:13 +00:00
Raivis Dejus
4726d58af6
Adding support for Whisper API in live recordings (#807) 2024-06-21 05:26:49 +00:00
Raivis Dejus
0a9eddb346
Fix for locales in *.whl and snaps (#806) 2024-06-20 17:09:19 +00:00
Raivis Dejus
9b45e4d6d3
Adding translations to tasks and ok/cancel buttons (#805) 2024-06-19 19:27:33 +00:00
Raivis Dejus
826f62c558
Fix for macOS actions cache (#804) 2024-06-19 04:46:42 +00:00
Raivis Dejus
900f6c9915
801 add large v2 v3 models (#803) 2024-06-18 21:55:13 +00:00
Raivis Dejus
82da36f540
Fix for API key validation (#802) 2024-06-18 19:31:32 +00:00
Raivis Dejus
fe1a1e5b6b
Updating for compatability with Ubuntu 24.04 (#799) 2024-06-16 19:02:46 +00:00
Raivis Dejus
777989922a
Adding translation usage instructions (#798) 2024-06-15 11:48:49 +03:00
Raivis Dejus
eb92568381
Add llm translations (#791) 2024-06-15 09:25:01 +03:00
Raivis Dejus
3d44a45476
Fix for snap audio playback (#795) 2024-06-10 20:20:25 +00:00
Raivis Dejus
2def2b9087
Will re-enable audio player on Linux (#793) 2024-06-09 17:57:32 +00:00
Raivis Dejus
bb86083a33
Add snap notice (#792) 2024-06-09 16:03:20 +00:00
Raivis Dejus
3bb9dd8044
Adding notice on snap permissions (#790) 2024-06-09 10:54:59 +00:00
Raivis Dejus
2f0b826d37
Fix for not remembering word level timings in folder watch preferences (#789) 2024-06-09 07:17:06 +00:00
Raivis Dejus
c19e7acf08
Fix for live transcription with Faster whisper (#787) 2024-06-08 16:13:14 +00:00
Raivis Dejus
d737b50134
Fix for record button being "record" and not "stop" when model downlo… (#786) 2024-06-08 07:31:03 +00:00
Raivis Dejus
401665b184
Adding setting for custom OpenAI base url (#785) 2024-06-07 19:32:08 +00:00
Raivis Dejus
8fbaf013b9
Add live transcript export (#784) 2024-06-07 17:21:57 +00:00
Raivis Dejus
5904f84ec2
Will also pass codecov token as env (#780) 2024-06-07 06:26:47 +00:00
Raivis Dejus
c664221563
Updating manual build actions (#783) 2024-06-06 07:44:23 +00:00
Raivis Dejus
7bb835ad04
Adding snap build to manual build action (#782) 2024-06-06 09:48:10 +03:00
Raivis Dejus
74e629bf9a
Adding manual build github action (#781) 2024-06-06 08:56:12 +03:00
Raivis Dejus
b51aa3fe43
Fix for HF downlaod progress in SNAPs (#779) 2024-06-04 22:49:30 +03:00
Raivis Dejus
40643dacd5
Fixed link (#777) 2024-06-04 13:42:45 +00:00
Raivis Dejus
045bd211b3
Will download HF models to Buzz cache folder (#775) 2024-06-04 09:47:08 +00:00
Raivis Dejus
905716c5c4
Test build for GPU snap (#773) 2024-06-03 21:03:29 +03:00
Raivis Dejus
6457e96f84
Updating codecov to v4 (#770)
Co-authored-by: Chidi Williams <williamschidi1@gmail.com>
2024-06-03 16:45:23 +00:00
Raivis Dejus
ddebcccc64
Adding GPU support for Huggingface models (#772) 2024-06-02 12:05:56 +03:00
Raivis Dejus
d33068bb37
Adding notes on system audio on Windows and Linux (#771) 2024-06-01 17:44:50 +03:00
Raivis Dejus
b3bcfc146e
Fixing preference checkboxes (#769) 2024-06-01 11:56:32 +03:00
Raivis Dejus
a318c36bb2
Updating github actions (#768) 2024-06-01 11:09:21 +03:00
Raivis Dejus
34933c8c3d
Fixing snap build (#767) 2024-06-01 07:21:04 +03:00
Raivis Dejus
c10373ab7c
Add documentation (#766) 2024-05-30 21:56:22 +03:00
Raivis Dejus
bc1465ffd1
Adding option to delete settings on uninstall (#765) 2024-05-30 09:20:13 +03:00
Raivis Dejus
618b75a62b
Adding notes on running Buzz locally (#764) 2024-05-29 21:15:14 +03:00
Raivis Dejus
60991ccf02
Will allow window to be resized smaller. (#762) 2024-05-28 10:03:30 +03:00
Raivis Dejus
731efd7d38
Refactored model downloading (#761) 2024-05-28 09:07:00 +03:00
Raivis Dejus
7820952616
Will add huggingface model id to the transcription table (#758) 2024-05-26 19:17:05 +03:00
Raivis Dejus
5ba8eaa1f4
Snab build fix (#757) 2024-05-26 15:41:02 +03:00
Raivis Dejus
52c0e52795
Limit Huggingface model download size (#754) 2024-05-26 09:38:39 +03:00
Raivis Dejus
9ffb2f9c40
Adding missing translation (#756) 2024-05-26 05:47:24 +00:00
Raivis Dejus
78fcdf2cbd
Test improvements (#755) 2024-05-25 12:13:57 +03:00
Raivis Dejus
c921b4795a
Fix for localizations, adding Latvian translatiosn (#752) 2024-05-24 12:28:14 +03:00
Raivis Dejus
a5fa313947
Fix macos build (#751) 2024-05-24 12:27:21 +03:00
Raivis Dejus
36d6b3d015
Adding contribution section on gathering troubleshooting information (#749) 2024-05-23 11:42:38 +00:00
Raivis Dejus
027385fe0d
Will add more media formats (#750) 2024-05-23 12:15:38 +01:00
Raivis Dejus
702c0188d0
Will check if model from settings is supported for live transctiption (#740) 2024-05-19 19:27:56 +00:00
Raivis Dejus
fb4f86c61b
Will make default app screen fit all columns (#744) 2024-05-19 12:06:02 +01:00
Raivis Dejus
38f5d26672
Adding fix for multi-byte segments in whisper.cpp (#734)
Co-authored-by: Chidi Williams <williamschidi1@gmail.com>
2024-05-14 23:29:43 +00:00
Raivis Dejus
ca49b8e865
Will remember previously used used huggingface model (#736) 2024-05-14 23:13:59 +00:00
Chidi Williams
8990dcdf4c
Update Python version (#737) 2024-05-14 22:52:05 +00:00
Sebastian
30debafea6
New Polish translation (#721) 2024-04-11 14:14:46 +00:00
Chidi Williams
d4838647ef
feat: add macOS build (#711) 2024-03-24 21:05:01 +00:00
Chidi Williams
33956e8417
chore: add test line to build script (#710) 2024-03-24 02:41:24 +00:00
Chidi Williams
32137cceb9
chore: update dependencies (#707) 2024-03-23 20:55:50 +00:00
Chidi Williams
20a76cf8ba
feat: enable prompt option for Whisper.cpp and OpenAI API (#706) 2024-03-23 16:57:37 +00:00
albanobattistella
a4a3369dce
Update buzz.po (#695) 2024-03-16 22:46:46 +00:00
albanobattistella
309f98e45d
Update buzz.po (#689) 2024-03-15 19:33:02 +00:00
Chidi Williams
3d27a9caa4
Upgrade to 0.9.0 (#687) 2024-03-15 17:58:45 +00:00
Chidi Williams
ba522a58cd
add transcript viewer (#686) 2024-03-15 17:38:35 +00:00
Chidi Williams
8ae8300afc chore: update logo 2024-03-15 01:28:59 +00:00
Chidi Williams
ebe9539605 fix: move schema file to build folder 2024-03-15 00:50:07 +00:00
Chidi Williams
3280de9742
fix: handle keyring store exception (#685) 2024-03-14 22:05:42 +00:00
Chidi Williams
939549266e test: update timeout 2024-03-14 17:03:49 +00:00
Chidi Williams
7aec7a902a test: update timeout 2024-03-14 16:55:19 +00:00
Chidi Williams
cc028ff0ba test: skip cli test for linux 2024-03-14 16:41:48 +00:00
Chidi Williams
b48349e82f test: skip cli test for linux 2024-03-14 16:38:24 +00:00
Chidi Williams
eb1d56c117 test: download model before running 2024-03-14 16:29:28 +00:00
Chidi Williams
3e546ccb18 test: add cli tests 2024-03-14 15:39:51 +00:00
Chidi Williams
bb8d22e6c3 test: add cli tests 2024-03-14 15:16:50 +00:00
Chidi Williams
ad6a5bc431 fix: make msgfmt.py executable 2024-03-14 11:56:31 +00:00
Chidi Williams
4a7f42e32b fix: make msgfmt.py executable 2024-03-14 11:51:48 +00:00
Chidi Williams
5df9af05a2 fix: put translations in buzz folder 2024-03-14 11:38:37 +00:00
Chidi Williams
f7f5229468 fix: put translations in buzz folder 2024-03-14 11:26:20 +00:00
Chidi Williams
65de47607f chore: remove Homebrew build 2024-03-14 01:54:37 +00:00
Chidi Williams
ae5af308b2
feat: save transcriptions to sqlite (#682) 2024-03-14 01:51:06 +00:00
Chidi Williams
dfac983f13
fix: cli producing blank filenames (#681) 2024-02-24 12:10:45 +00:00
Chidi Williams
397dadd7a2 fix: openai transcription model response 2024-01-11 09:35:56 +00:00
Chidi Williams
43c3f66aa7 fix: openai transcription file and language 2024-01-11 09:06:49 +00:00
Chidi Williams
ad784c1be8 fix: include ffprobe in build 2024-01-10 23:11:43 +00:00
Chidi Williams
903edc0b15 fix: include ffprobe in build 2024-01-10 23:10:15 +00:00
Chidi Williams
1448f70c2c fix: assets missing in PyInstaller build 2024-01-10 22:42:45 +00:00
Chidi Williams
a0ee06109b fix: assets missing in PyInstaller build 2024-01-10 20:15:34 +00:00
Chidi Williams
d98c0666fd fix: whisper binary missing error message 2024-01-10 09:31:53 +00:00
Chidi Williams
5cda68a598 fix: whisper binary missing in package
https://github.com/chidiwilliams/buzz/issues/630#issuecomment-1882934761
2024-01-10 09:28:30 +00:00
Chidi Williams
ab912deaf8
feat: import URL for transcription (#665) 2024-01-08 01:45:30 +00:00
Jordi Mas
b8e5cd4c19
Update Catalan translation (#664) 2024-01-08 00:38:44 +00:00
Chidi Williams
0d678fe695
chore: update whisper.cpp (#663) 2024-01-06 21:14:26 +00:00
Chidi Williams
3cbeb97ef9
chore: upgrade faster whisper and openai whisper (#662) 2024-01-06 19:59:32 +00:00
Chidi Williams
b922d65ffa
chore: upgrade OpenAI (#661) 2024-01-06 19:02:58 +00:00
Chidi Williams
c7be2f1578
fix: disable whisper, faster_whisper, and hugging_face transcriptions in linux build (#659) 2024-01-05 19:09:26 +00:00
Chidi Williams
5456774d96
fix: snapcraft build (#656) 2024-01-03 21:54:39 +00:00
Sebastian
c758a25a41
Update buzz.po (#658) 2024-01-03 21:20:15 +00:00
Chidi Williams
2b839c35cb
feat: add folder watch (#655) 2023-12-27 10:25:13 +00:00
Chidi Williams
1120723681
fix: openai api transcriber (#652) 2023-12-23 10:32:53 +00:00
Chidi Williams
f163aabcfe
feat: update transcription tasks columns (#649) 2023-12-21 19:57:44 +00:00
Adolfo Jayme-Barrientos
68207970b1
Update Spanish translation (#628) 2023-11-09 19:41:06 +00:00
Chidi Williams
43aa719fa4
Upgrade to Whisper v3 (#626) 2023-11-09 09:20:38 +00:00
Chidi Williams
2567d7f65b Update docs 2023-10-29 16:22:08 +00:00
Chidi Williams
fe926b87e0 Add script 2023-10-29 16:21:19 +00:00
Chidi Williams
69d1dd56f2
Add publish PyPI step (#617) 2023-10-28 18:57:54 +00:00
Chidi Williams
eedc2ab2f9
Add pip installation (#615) 2023-10-28 18:32:31 +01:00
Chidi Williams
a3b54891e8
Update docs with preferences (#602) 2023-09-19 19:53:56 +00:00
albanobattistella
775bb4a0f2
Update buzz.po (#592) 2023-09-02 14:54:03 +00:00
Chidi Williams
4587cd55f0
Fix translator (#591) 2023-09-02 13:30:23 +00:00
Chidi Williams
0da553a827
Upgrade to 0.8.4 (#579) 2023-08-20 10:40:38 +00:00
Chidi Williams
9376ea9b36
Upgrade whisper.cpp (#578) 2023-08-20 01:38:50 +00:00
Chidi Williams
f29b3aa521
Add captions to audio player (#573) 2023-08-19 01:29:13 +00:00
Chidi Williams
f4b6b529b6
Fix JSONDecodeError while reading tasks list (#572) 2023-08-19 01:12:20 +00:00
Chidi Williams
c498e60949
Add black formatting (#571) 2023-08-18 22:32:18 +00:00
Chidi Williams
f5f77b3908
Add default file name setting (#559) 2023-08-05 01:02:20 +00:00
Chidi Williams
64b15f1804
Fix Snap execstack (#537) 2023-08-04 13:58:30 -07:00
Chidi Williams
8b253ffc1c
Add audio player (#558) 2023-08-04 20:23:43 +00:00
Chidi Williams
af4d57b881
Add delete model and show model location options (#557) 2023-08-03 04:41:59 +00:00
Chidi Williams
f1550f80ad
Update translations (#556) 2023-08-02 22:15:59 +00:00
Chidi Williams
f0c3c054b8
Delete stale.yml 2023-07-16 08:52:27 +01:00
Chidi Williams
fb93be4296
Fix Faster Whisper large transcription (#524) 2023-07-04 22:42:41 +00:00
Chidi Williams
59d9dc2243
Fix Faster Whisper large model selection (#523) 2023-07-04 21:52:45 +00:00
Chidi Williams
cffd4f4a2e
Upgrade to 0.8.3 (#520) 2023-07-04 09:18:57 +01:00
Chidi Williams
f83d2d63d3
Move transcriptions to individual cache files (#519) 2023-07-04 01:28:47 +01:00
felipe
2042947642
spanish strings translation (#510) 2023-07-04 00:26:51 +00:00
Chidi Williams
2dc0797e64
Refactor transcribers class (#508) 2023-06-26 07:46:17 +00:00
Chidi Williams
fa08e5344e
Add installation docs (#506) 2023-06-23 10:43:29 +01:00
Chidi Williams
798d623a38
Fix brew cask deployment (#502) 2023-06-20 17:12:51 +00:00
Chidi Williams
b68663f324
Add docs (#500) 2023-06-20 14:12:18 +00:00
Chidi Williams
5ca72dd992
Upgrade to 0.8.2 (#499) 2023-06-20 11:23:50 +00:00
Chidi Williams
6854d172f1
Upload Snapcraft build (#495) 2023-06-17 10:26:57 +00:00
Chidi Williams
530bf28407
Fix terminal value in .desktop file (#487) 2023-06-17 07:35:10 +01:00
Chidi Williams
1b13a366cb
Add Snapcraft (#486) 2023-06-12 13:09:08 +01:00
Chidi Williams
c1d90bf0c2
Add DEB bundle (#483) 2023-06-06 09:31:53 +01:00
Chidi Williams
d63ccb970c
Fix key error when loading output formats from settings (#482) 2023-06-05 10:22:48 +00:00
faveoled
162c2031a7
Add Linux desktop entry sample (#480) 2023-06-05 10:35:38 +01:00
Chidi Williams
c8bc9c5d02
Fix model loader 'stop' attribute (#478) 2023-05-31 00:56:23 +01:00
Chidi Williams
df35d548d8
Remove Windows .tar.gz (#477) 2023-05-30 23:09:01 +00:00
Chidi Williams
e907614e7a
Add duration for completed files (#463) 2023-05-21 01:09:45 +00:00
Chidi Williams
806b691d02
Change os.rename to shutil.move when downloading models (#459) 2023-05-16 22:24:39 +00:00
Chidi Williams
c281684ad7
Fix Ubuntu release artifacts (#451) 2023-05-06 18:49:26 +00:00
Chidi Williams
a489c88342 Add App Store docs for Mac Silicon 2023-05-02 07:34:04 +01:00
c469591
78ce227627
Add Simplified Chinese and Traditional Chinese translation (#437) 2023-05-01 16:50:02 +01:00
Chidi Williams
5892e3a2a1
Add new lines in TXT segments (#436) 2023-05-01 10:15:41 +00:00
Chidi Williams
0804c2743c
Upgrade to 0.8.1 (#434) 2023-05-01 08:44:45 +00:00
Chidi Williams
9b4c76d97d Fix Homebrew GitHub token 2023-05-01 09:15:36 +01:00
Chidi Williams
bfe3683d81
Fix Windows 10 build (#431) 2023-05-01 00:56:42 +01:00
Chidi Williams
6528bbcd07 Fix Windows no stderr error 2023-04-30 14:50:05 +01:00
Chidi Williams
da1b7b00a8
Update to 0.8.0 (#430) 2023-04-30 13:47:48 +00:00
Chidi Williams
32af05da30
Add CLI (#424) 2023-04-29 21:23:20 +00:00
Chidi Williams
66bd9a1834
Fix Whisper.cpp on Windows (#422) 2023-04-29 19:30:40 +00:00
Chidi Williams
cb5ad74620
Add models preferences (#421) 2023-04-28 22:28:05 +01:00
Chidi Williams
0a4be2b195
Try to load API key only when needed (#420) 2023-04-26 22:10:42 +00:00
Chidi Williams
bf76627998
Fix queue waiting (#419) 2023-04-26 08:21:41 +00:00
Chidi Williams
84ab53d5bd
Add benchmarks (#417) 2023-04-25 19:27:40 +01:00
Piciok
158aa0b8ff
UI localization to Polish (#413) 2023-04-24 23:51:21 +01:00
Chidi Williams
a7e7776fed
Update Whisper.cpp (#415) 2023-04-24 15:40:27 +01:00
Chidi Williams
3af07c65c4 Update docs to emphasize resource-intensive nature of live recording
#414
2023-04-24 08:47:35 +01:00
Chidi Williams
37b7275d38
Fix transcription tasks table column resizing (#412) 2023-04-23 22:21:24 +00:00
Chidi Williams
d68c2b9461
Add keyring store for API keys (#411) 2023-04-23 20:37:50 +00:00
Chidi Williams
49a3151117
Add transcript editor (#410) 2023-04-23 15:36:45 +01:00
Chidi Williams
b4a095ef3a
Add keyboard shortcuts (#409) 2023-04-23 08:38:30 +01:00
Chidi Williams
474f4c5050
Save settings (#401) 2023-04-10 22:56:43 +01:00
Chidi Williams
86626aa818
Add Faster Whisper (#400) 2023-04-10 12:34:46 +00:00
Chidi Williams
b8073027ce
Export transcription before preview (#399) 2023-04-09 15:59:15 +01:00
Chidi Williams
7474ad4ec8
Drag and drop to import file (#398) 2023-04-09 12:28:40 +00:00
Chidi Williams
010b89f53a
Create stale.yml 2023-04-01 09:18:47 +01:00
Chidi Williams
cc6302fa59
Add link to Mac app (#385) 2023-03-24 08:20:21 +00:00
Chidi Williams
62ed04d97f
Add support for OpenAI Whisper API (#371) 2023-03-09 13:24:11 +00:00
Chidi Williams
3a59172403
Stop opening transcription after completion (#370) 2023-03-08 09:01:42 +00:00
Chidi Williams
c9045dc376
Add csv export (#368) 2023-03-05 10:38:15 +00:00
Chidi Williams
5d2ac6a3fa
Highlight search text (#367) 2023-03-04 19:48:20 +00:00
Jordi Mas
4f22a08860
Update Catalan translation (#355) 2023-03-04 19:40:19 +00:00
Chidi Williams
fa3108d868
Add Swift app (#366) 2023-03-04 19:14:45 +00:00
Chidi Williams
bc51c581c2
Fix Linux build (#341) 2023-01-24 01:10:24 +00:00
Chidi Williams
354d67528c
Set transcription table to multi-select (#340) 2023-01-19 09:31:46 +00:00
Chidi Williams
abf30a34df
Fix recording window shutting down (#326) 2023-01-09 10:05:38 +00:00
Chidi Williams
70ad8f9b1d
Upgrade whisper.cpp (#325) 2023-01-08 16:49:33 +00:00
Chidi Williams
97c9283b8b
Upgrade stable ts (#324) 2023-01-08 16:32:31 +00:00
Chidi Williams
9345b6d4dc
Cancel transcription tasks (#318) 2023-01-07 18:07:36 +00:00
Chidi Williams
2d986237dc
Fix 'No Python frame' crash when the transcriber worker thread is quit while waiting for new tasks (#309) 2023-01-06 00:07:58 +00:00
Jordi Mas
f53d4a6649
Update Catalan translation (#307) 2023-01-05 08:51:43 +00:00
Chidi Williams
7c4f27e553
Add internationalization (#306) 2023-01-05 00:30:30 +00:00
Chidi Williams
e31b215d12
upgrade to 0.7.2 (#301) 2023-01-03 22:07:54 +00:00
Chidi Williams
78d80c2739
Fix error message (#296) 2023-01-03 21:30:43 +00:00
Chidi Williams
1e7d3941d9
Fail transcription task if whisper transcription fails with non-zero exit code (#295) 2023-01-03 20:56:50 +00:00
Chidi Williams
614b395962
Add segments debug logging (#294) 2023-01-03 20:21:59 +00:00
Chidi Williams
40b0236f8c
Fix transcription viewer opening before transcription completes (#293) 2023-01-03 19:46:29 +00:00
Chidi Williams
d91a279b44
Fix Mac code-signing (#291) 2023-01-03 14:26:50 +00:00
Chidi Williams
ed856a50aa
Fix about dialog (#288) 2023-01-02 20:13:35 +00:00
Chidi Williams
926f633bb1
Upgrade to 0.7.0 (#287) 2023-01-02 16:53:56 +00:00
Chidi Williams
380e975870
Fix recording transcriber (#286) 2023-01-02 15:42:15 +00:00
Chidi Williams
611e623a3a
Fix Windows styling and layout (#285) 2023-01-02 14:58:19 +00:00
Chidi Williams
9ea5341d01
Update whisper.cpp (#283) 2023-01-02 10:57:50 +00:00
Chidi Williams
820594ee35
Add recording amplitude indicator (#282) 2023-01-01 23:21:06 +00:00
Chidi Williams
5f9045c347
Use comma as SRT separator (#280) 2023-01-01 12:45:39 +00:00
Chidi Williams
f6ef2d5fe3
Fix intermittently failing tests (#277) 2022-12-31 09:13:52 +00:00
Chidi Williams
cfcb4f6c28
Disable Whisper.cpp when DLL is not loaded (#275) 2022-12-30 23:11:20 +00:00
Chidi Williams
6e89684ac8
Clean up recording transcriber (#270) 2022-12-30 21:58:57 +00:00
Chidi Williams
8e643b45c2
Fix transformers package loading __init__.py dynamically (#273) 2022-12-30 16:43:29 +00:00
faveoled
41dc2881fd
Fix typo (#268) 2022-12-28 12:40:47 +00:00
Chidi Williams
3dceb11c4d
Add support for Hugging Face models (#264) 2022-12-26 12:48:45 +00:00
Chidi Williams
82bdd30fb8
Download Whisper.cpp models from Hugging Face (#262) 2022-12-21 20:44:07 +00:00
Chidi Williams
44aeef95c2
Change model progress update from int to float (#261) 2022-12-21 15:39:28 +00:00
Chidi Williams
711a1b95be
Cache task queue on app exit (#260) 2022-12-21 14:19:11 +00:00
Chidi Williams
4747a5f655
Select multiple input files (#259) 2022-12-20 19:59:27 +00:00
Chidi Williams
0e086bd593
Add task queue (#253) 2022-12-20 18:49:00 +00:00
Chidi Williams
acd2d93e69
Fix app icon (#257) 2022-12-20 07:01:56 +00:00
Chidi Williams
8025e13b16
Add model selector box (#254) 2022-12-17 11:57:10 +00:00
Chidi Williams
99a301190b
Upload code coverage (#249) 2022-12-16 13:54:05 +00:00
Chidi Williams
02d5dd8fb6
Add transcription options group box (#248) 2022-12-16 12:51:52 +00:00
Chidi Williams
f53e49a688
Disable file transcriber widget test (#247) 2022-12-16 01:52:47 +00:00
Chidi Williams
7395de653f
Add transcription viewer (#246) 2022-12-16 01:23:29 +00:00
Chidi Williams
cccc8cea00
Delete model selector (#244) 2022-12-15 05:18:31 +00:00
Chidi Williams
fe108afbba
Make file transcribers QObjects (#242) 2022-12-15 05:08:45 +00:00
Chidi Williams
d8adf21c72
Make model loader QObject (#237) 2022-12-12 14:48:32 +00:00
Chidi Williams
05e7b76fc8
Add advanced settings on Buzz (#235) 2022-12-12 10:27:53 +00:00
Chidi Williams
3ddd6c1db2
Fix release workflow (#234) 2022-12-12 05:06:12 +00:00
Chidi Williams
3899c3611e
Upgrade to 0.6.4 (#232) 2022-12-11 18:07:21 +00:00
Chidi Williams
bdbab0ffd3
Add error message for encoding error (#231) 2022-12-11 18:01:05 +00:00
Chidi Williams
47ddb4a541
Add Mac codesigning (#229) 2022-12-10 11:48:27 +00:00
Chidi Williams
1f5964f03b
Add large model SHA (#227) 2022-12-10 01:33:15 +00:00
Chidi Williams
bc322714c9
Add GitHub upgrade script (#226) 2022-12-09 08:14:02 +00:00
Chidi Williams
c7f9b2e248
Upgrade to 0.6.3 (#225) 2022-12-09 08:03:56 +00:00
Chidi Williams
ce10bebdb7
Rollback dependency upgrades (#224) 2022-12-09 07:49:41 +00:00
Chidi Williams
fe7bdf9e6f
Add no-op stderr when running as Windows GUI (#222) 2022-12-09 00:05:48 +00:00
Chidi Williams
6d53af247a
Update release instructions (#220) 2022-12-08 13:13:11 +00:00
Chidi Williams
690394d604
0.6.2 (#217) 2022-12-08 06:44:31 +00:00
Chidi Williams
fec11af700
Remove Linux build from release (#216) 2022-12-08 06:34:36 +00:00
Chidi Williams
077684294e
Upgrade to 0.6.1 (#215) 2022-12-08 05:41:11 +00:00
Chidi Williams
8f9d08ee5e
Reduce duration of test audio (#214) 2022-12-08 05:28:12 +00:00
Chidi Williams
d95db970eb
Add large (v1 and v2) Whisper models (#212) 2022-12-08 04:37:59 +00:00
Chidi Williams
195bcaea91
Refactor Whisper transcriber to QRunnable (#207) 2022-12-05 22:41:37 +00:00
Chidi Williams
8b077e69a1
Upgrade Whisper.cpp (#205) 2022-12-04 21:02:49 +00:00
Chidi Williams
35d7b2b58a
Fix Windows build (#204) 2022-12-04 20:23:35 +00:00
Chidi Williams
209c0af3b8
Put FileTranscriber in QRunnable (#203) 2022-12-04 18:30:24 +00:00
Rui Chen
fe2292c833
docs: add homebrew installation note (#199) 2022-12-02 20:42:09 +00:00
Chidi Williams
2804159981
Add more supported file format type (#194) 2022-11-29 01:19:24 +00:00
Chidi Williams
f358809043
Refactor module structure (#192) 2022-11-28 13:59:15 +00:00
Chidi Williams
219f20d0e2
Refactor model loading (#191) 2022-11-28 13:10:39 +00:00
Chidi Williams
3486056dea
Add word-level timings to docs (#189) 2022-11-26 13:41:36 +00:00
Chidi Williams
be73a0d490
Add stable-ts as Python dependency (#186) 2022-11-26 10:47:14 +00:00
Jordi Mas
06abf0bf36
Include git clone --recurse-submodules (#187)
Co-authored-by: Chidi Williams <williamschidi1@gmail.com>
2022-11-26 09:46:25 +00:00
Chidi Williams
60e586b20e
Add reset settings to default (#178) 2022-11-21 19:12:13 +00:00
Chidi Williams
1869c71c9d
Upgrade to 0.5.8 (#174) 2022-11-15 08:09:18 +00:00
Chidi Williams
54c0841819
Fix DLL directory on Mac (#173) 2022-11-15 07:53:01 +00:00
Chidi Williams
7956ce528d
Add windows source files to build (#166) 2022-11-13 16:37:15 +00:00
Chidi Williams
b5d22a2fed
Upgrade to 0.5.7 (#165) 2022-11-13 14:50:27 +00:00
Chidi Williams
7f0c206d43
Fix Windows DLL loading (#162) 2022-11-13 12:21:17 +00:00
Chidi Williams
59d491a505
0.5.6 (#164) 2022-11-13 10:35:32 +00:00
Chidi Williams
8f854005b5
Update to 0.5.5 (#160) 2022-11-12 16:48:46 +00:00
Chidi Williams
392f9cb469
Add stable timings (#159) 2022-11-12 16:31:08 +00:00
Chidi Williams
a1b9097133
Re-enable whisper.cpp on Windows (#155) 2022-11-11 10:38:11 +00:00
Chidi Williams
3de06b0e6f
Fix process shutting down on Windows (#153) 2022-11-11 00:43:24 +00:00
Chidi Williams
58b9b53022
Fix file transcription (#151) 2022-11-10 15:54:28 +00:00
Chidi Williams
f263cec3dd
Upgrade to 0.5.4 (#150) 2022-11-10 14:33:04 +00:00
Chidi Williams
59df17d482
Fix microphone access on Mac (#149) 2022-11-10 13:54:56 +00:00
Chidi Williams
891a076ce5
Fix whisper.cpp library (#147) 2022-11-10 10:49:28 +00:00
Chidi Williams
570b47bc57
Cache ffmpeg (#148)
Cache ffmpeg
2022-11-09 21:38:20 +00:00
Chidi Williams
e4cef70ec4
Add medium model (#145)
- Add requirements.txt
2022-11-07 09:02:00 +00:00
Chidi Williams
b5d06210fc
Add minimum Mac version (#141) 2022-11-02 23:00:21 +00:00
Chidi Williams
b745592291
Add button to check for updates (#140) 2022-11-02 08:51:03 +00:00
Chidi Williams
d1087a7f9d
Add demo videos to README 2022-10-31 09:09:11 +00:00
Chidi Williams
b4685b1234
Update install instructions 2022-10-30 14:30:57 +00:00
Chidi Williams
a59f09b852
Fix process stopping on Windows (#138) 2022-10-30 14:30:44 +00:00
Joshua
a174210e4f
Add banner image to README (#137) 2022-10-30 13:54:58 +00:00
Chidi Williams
4b8c90feeb
Upgrade to 0.5.3 (#134) 2022-10-29 14:25:35 +00:00
Chidi Williams
8a985420c0
Add about dialog (#125) 2022-10-29 11:49:24 +00:00
Chidi Williams
27274b7f56
Fix multiprocessing on windows (#133) 2022-10-29 11:17:39 +00:00
Chidi Williams
a97aa4ad63
Add Windows exe (#132) 2022-10-29 10:16:06 +00:00
Chidi Williams
1cf2e97698
Fix Windows build (#130) 2022-10-28 14:32:46 +00:00
Chidi Williams
d11b5de4d0
Fix SHA256 for GGML models (#129) 2022-10-28 08:30:26 +00:00
Chidi Williams
493d36d17f
Fix event handling in recording transcriber (#128) 2022-10-28 06:33:21 +00:00
Chidi Williams
937684b33b
Load model and transcribe file in child process (#127) 2022-10-27 23:59:09 +01:00
Chidi Williams
6de5bf8b30
Fix segfaults from progress dialogs (#126) 2022-10-23 21:39:38 +01:00
Chidi Williams
b1c3ecb770
Add demo videos to README (#122) 2022-10-22 23:01:04 +00:00
Chidi Williams
2f5f223234
Upgrade to 0.5.2 (#121) 2022-10-22 22:26:01 +01:00
Chidi Williams
bfbceb5704
Add Pylint (#120) 2022-10-22 21:23:40 +00:00
Chidi Williams
68aff48be6
Shut down file transcription gracefully on window close (#119) 2022-10-22 21:02:03 +00:00
Chidi Williams
6edd6ee95a
Stop recording on close recording window (#118) 2022-10-22 20:48:30 +00:00
Chidi Williams
a59347041e
Fix ffmpeg not found in PATH (#117) 2022-10-22 20:02:49 +00:00
Chidi Williams
03ae675db4
Upgrade to v0.5.1 (#114) 2022-10-22 16:40:29 +01:00
Chidi Williams
d7dd994393
Add tag to workflow (#113) 2022-10-22 16:39:06 +01:00
Chidi Williams
ca0cebb2da
Upgrade to v0.5.0 (#112) 2022-10-22 14:53:24 +00:00
Chidi Williams
6424b5d5df
Add help text for slow transcriptions (#111) 2022-10-22 14:46:44 +00:00
Chidi Williams
6d66d5f7e2
Add file import and FAQ to docs (#110) 2022-10-22 14:19:38 +00:00
Chidi Williams
fd49e21b0d
Add output format input box (#109) 2022-10-22 12:26:33 +00:00
Chidi Williams
956d232dea
Disable GGML inference on Windows (#108) 2022-10-22 11:03:58 +00:00
Chidi Williams
01dfc5a020
Fix workflow artifacts names (#107) 2022-10-22 11:57:44 +01:00
Chidi Williams
a1503dd071
Add support for whisper.cpp (#97) 2022-10-22 08:45:52 +01:00
Chidi Williams
c02a8b3afa
Remove delay combo box (#99) 2022-10-19 22:29:36 +00:00
faveoled
04d309c03c
Add video file formats to filters (#98) 2022-10-19 08:54:27 +01:00
faveoled
67d5156c93
Add .ogg to allowed file extensions (#93) 2022-10-16 19:40:56 +00:00
Chidi Williams
7feb4d82a8
Fix crashing on quit on Mac (#94) 2022-10-16 19:37:59 +00:00
Chidi Williams
0e84abe3f4
Run CI workflow on pull requests (#96) 2022-10-16 19:32:58 +00:00
Chidi Williams
baefa69586
Run CI workflow on pull requests (#95) 2022-10-16 19:23:26 +00:00
Chidi Williams
9e10d0452b
Upgrade to PyQt6 (#92) 2022-10-16 15:54:26 +00:00
Chidi Williams
5cdcb3aec5
Add code-signing for ffmpeg binary (#90) 2022-10-16 10:05:57 +00:00
Chidi Williams
2b35c7bade
Fix tar build path (#88) 2022-10-16 10:57:15 +01:00
Chidi Williams
cd86e02beb
Update windows build instructions (#86) 2022-10-16 09:23:03 +00:00
Chidi Williams
cf76c7820e
Update version to 0.4.2 (#85) 2022-10-16 08:51:13 +00:00
Chidi Williams
042cf55a0a
Add ffmpeg to ci.yml (#84) 2022-10-16 08:46:25 +00:00
Chidi Williams
22d8960a25
Fix exception when no default audio device exists (#82) 2022-10-15 18:37:14 +00:00
Chidi Williams
b6e6cd095a
Upgrade to 0.4.1 (#79) 2022-10-15 17:25:21 +00:00
Chidi Williams
96ad5cd24e
Fix disabled record button after recording starts (#77) 2022-10-15 17:22:00 +00:00
Chidi Williams
93682350e4
Upgrade to 0.4.0 (#75) 2022-10-15 16:47:29 +00:00
Chidi Williams
9d6598ad9c
Make detect language default (#73) 2022-10-15 16:36:56 +00:00
Chidi Williams
4e45467338
Allow cancelling model download (#72) 2022-10-15 16:15:32 +00:00
Chidi Williams
bba0b3ebde
Fix TranscriberProgressDialog centralization (#71) 2022-10-15 14:17:52 +00:00
Chidi Williams
ec0aef39b5
Replace models combo box with quality (#69) 2022-10-15 13:47:29 +00:00
Chidi Williams
5a17cf63fe
Add file import transcriber (#67) 2022-10-15 13:10:10 +01:00
Chidi Williams
8a4242c56e
Add mic tests (#63) 2022-10-13 07:38:10 +00:00
Chidi Williams
c8a6b57938
Add support for opening new window from menu bar (#64) 2022-10-13 07:31:10 +00:00
Chidi Williams
9ef3731540
Use default system mic (#61) 2022-10-12 19:43:07 +00:00
Chidi Williams
8c9f9be25a
Upgrade to 0.3.4 (#59) 2022-10-12 18:45:56 +00:00
Chidi Williams
ab4f5ee1bf
Add timer label (#58) 2022-10-12 07:58:49 +00:00
Chidi Williams
f4b518688e
Fix multiprocessing fork crashing on Windows (#55) 2022-10-12 07:04:42 +01:00
Chidi Williams
f7a78f0620
Update icons (#54) 2022-10-11 20:25:08 +00:00
Chidi Williams
eecc168648
Fix audio entitlement (#53) 2022-10-11 20:21:06 +00:00
Chidi Williams
a563633c62
Upgrade to 0.3.3 (#52) 2022-10-11 19:52:11 +00:00
Chidi Williams
3b2675543c
Add file logging (#51) 2022-10-11 19:13:05 +00:00
Chidi Williams
4781a24147 Add file logging 2022-10-11 20:04:28 +01:00
Chidi Williams
9ab09e89b6
Add app icon (#49) 2022-10-11 07:49:42 +00:00
Chidi Williams
e267ade613
Set multiprocessing start method to fork (#47) 2022-10-11 08:14:45 +01:00
Chidi Williams
55203306b6
Fix transcribe and translate task selection (#44) 2022-10-10 18:29:56 +00:00
Chidi Williams
f24bdcd017
Upgrade to 0.3.2 (#41) 2022-10-10 06:57:23 +01:00
Chidi Williams
a3a503678d
Fix build artifacts (#40) 2022-10-10 05:52:27 +00:00
Chidi Williams
ff46486e7d
Upgrade to 0.3.1 (#39) 2022-10-10 05:34:39 +00:00
Chidi Williams
b168ba8313
Fix randomly opened windows in PyInstaller app (#38) 2022-10-09 23:24:38 +01:00
Chidi Williams
eff14400e0
Upgrade to 0.3.0 (#37) 2022-10-09 19:48:43 +01:00
Chidi Williams
9e0021a218
Show download progress (#36) 2022-10-09 18:38:42 +00:00
Chidi Williams
b10665b99a
Remove visual styles (#35) 2022-10-09 16:50:41 +00:00
Chidi Williams
c39ace3c9d
Patch whisper.load_model to use requests module (#33) 2022-10-09 17:20:06 +01:00
Chidi Williams
cf99a8a68d
Fix Mac build (#30)
- Add codesigning and notarizing steps to PyInstaller binary
2022-10-09 16:11:03 +00:00
Chidi Williams
053fa0ad73
Fix Windows installation instructions (#27) 2022-10-06 07:43:56 +00:00
Chidi Williams
2213c92260
Fix float sample rate (#26) 2022-10-06 07:35:34 +00:00
Chidi Williams
1caad5f2d7
Use Whisper sample rate by default (#24) 2022-10-04 20:58:52 +00:00
Chidi Williams
0c61940bd0
Fix Linux build command (#23) 2022-10-04 21:54:16 +01:00
Chidi Williams
14765badc6
Use microphone default sample rate (#20) 2022-10-04 20:41:23 +01:00
faveoled
67b280718c
Fix description (#22) 2022-10-04 16:19:51 +01:00
Chidi Williams
15f3ac9e9e
Add available operating systems to README (#19) 2022-10-04 07:19:48 +00:00
Chidi Williams
7c596a44c3
Fix operating system header (#17) 2022-10-03 07:55:52 +00:00
Chidi Williams
cba6ed7b67
Add Intel label to Mac download instructions (#16) 2022-10-02 16:31:18 +00:00
Chidi Williams
b49e754e67
Sort languages alphabetically (#15) 2022-10-02 08:28:47 +00:00
Chidi Williams
7ca8bf0763
Merge pull request #14 from chidiwilliams/set-application-window-title
Set application window title
2022-10-02 07:22:58 +01:00
Chidi Williams
b89b25c6c7 Fix default selected device id 2022-10-01 19:14:36 +01:00
Chidi Williams
f573448f9c Set application window title 2022-10-01 18:55:39 +01:00
Chidi Williams
1af2e49d89
Merge pull request #9 from chidiwilliams/upgrade-package-version
Upgrade package version to 0.2.1
2022-10-01 10:05:59 +01:00
Chidi Williams
b5cf81d69a Upgrade package version to 0.2.1 2022-10-01 10:05:30 +01:00
Chidi Williams
19ef818f42
Merge pull request #7 from chidiwilliams/gh-action-windows
Add build command for Windows
2022-10-01 10:01:54 +01:00
Chidi Williams
91b1da7cd0 Add release job 2022-10-01 09:13:59 +01:00
Chidi Williams
1e62ae7005 Add release job 2022-10-01 08:49:39 +01:00
Chidi Williams
988a195302 Add release job 2022-10-01 08:41:42 +01:00
Chidi Williams
671d395c93 Add release job 2022-10-01 08:40:12 +01:00
Chidi Williams
50a869ba76 Fix build and run instructions 2022-10-01 08:04:55 +01:00
Chidi Williams
3acff81d94 Add platform specific styling 2022-10-01 07:51:30 +01:00
Chidi Williams
e2f266da76 Change archive file extension type to .tar.gz 2022-10-01 07:35:09 +01:00
Chidi Williams
9effe34fba Add installation instructions 2022-10-01 07:34:24 +01:00
Chidi Williams
86d2f4af43 Change archive file extension type to .tar.gz 2022-10-01 07:29:36 +01:00
Chidi Williams
969554b5f1 Add build command for Windows 2022-09-30 09:38:12 +01:00
Chidi Williams
c5226301dd Add build command for Windows 2022-09-29 21:35:56 +01:00
Chidi Williams
06b2e1cd94 Add build command for Windows 2022-09-29 21:25:25 +01:00
Chidi Williams
e98b627314 Add build command for Windows 2022-09-29 21:20:27 +01:00
Chidi Williams
7ab295f3cf Add build command for Windows 2022-09-29 21:19:33 +01:00
Chidi Williams
7c7a621f4a Add build command for Windows 2022-09-29 21:05:03 +01:00
Chidi Williams
b77c263164
Merge pull request #4 from chidiwilliams:add-loom-to-readme
Add Loom to README
2022-09-28 20:07:37 +01:00
Chidi Williams
09bf985873 Add Loom to README 2022-09-28 20:07:24 +01:00
Chidi Williams
b79a29858a
Merge pull request #3 from chidiwilliams:update-0.2.0
Update to 0.2.0
2022-09-28 08:51:51 +01:00
Chidi Williams
6a2a709855 Update to 0.2.0 2022-09-28 08:51:38 +01:00
Chidi Williams
f02a375921
Merge pull request #2 from chidiwilliams:update-readme-img
Update README image with delay
2022-09-28 00:56:31 +01:00
Chidi Williams
b7ab9fc73f Update README image with delay 2022-09-28 00:56:19 +01:00
Chidi Williams
7251703b95
Merge pull request #1 from chidiwilliams/add-delay-button
Add delay combo box
2022-09-28 00:46:47 +01:00
Chidi Williams
83c43b203d Skip text updates if text is empty 2022-09-28 00:45:49 +01:00
Chidi Williams
7bfede581a Update how to use section of README 2022-09-28 00:32:21 +01:00
Chidi Williams
44e7c391c1 Add max queue size 2022-09-28 00:18:15 +01:00
Chidi Williams
17d4b42913 Add delay combo box 2022-09-28 00:01:37 +01:00
Chidi Williams
aaf99a3fd8 Update build commands 2022-09-27 23:27:01 +01:00
Chidi Williams
0a69549547 Update build commands 2022-09-27 23:00:21 +01:00
307 changed files with 76447 additions and 1389 deletions

19
.coveragerc Normal file
View file

@ -0,0 +1,19 @@
[run]
omit =
buzz/whisper_cpp/*
buzz/transcriber/local_whisper_cpp_server_transcriber.py
*_test.py
demucs/*
whisper_diarization/*
deepmultilingualpunctuation/*
ctc_forced_aligner/*
[report]
exclude_also =
if sys.platform == "win32":
if platform.system\(\) == "Windows":
if platform.system\(\) == "Linux":
if platform.system\(\) == "Darwin":
[html]
directory = coverage/html

View file

@ -1,33 +1,402 @@
---
name: CI
'on': push
on:
push:
branches:
- main
tags:
- "*"
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
ci:
runs-on: ubuntu-latest
test:
runs-on: ${{ matrix.os }}
env:
BUZZ_DISABLE_TELEMETRY: true
strategy:
fail-fast: false
matrix:
include:
- os: macos-15-intel
- os: macos-latest
- os: windows-latest
- os: ubuntu-22.04
- os: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: actions/checkout@v4
with:
python-version: '3.10.6'
submodules: recursive
- name: Install Poetry Action
uses: snok/install-poetry@v1.3.1
# Should be removed with next update to whisper.cpp
- name: Downgrade Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
virtualenvs-create: true
virtualenvs-in-project: true
xcode-version: '16.0.0'
if: matrix.os == 'macos-latest'
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install Vulkan SDK
if: "startsWith(matrix.os, 'ubuntu-') || matrix.os == 'windows-latest'"
uses: humbletim/install-vulkan-sdk@v1.2
with:
version: 1.4.309.0
cache: true
- name: Install uv
uses: astral-sh/setup-uv@v6
- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v3
id: cached-uv-dependencies
uses: actions/cache@v4
with:
path: .venv
key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}-${{ hashFiles('**/package-lock.json') }}-2
key: venv-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/uv.lock') }}
- run: pip install poetry
- run: poetry install
- run: poetry run make buzz
- uses: actions/upload-artifact@v3
- uses: AnimMouse/setup-ffmpeg@v1
id: setup-ffmpeg
with:
name: pyinstaller
path: dist/*
version: ${{ matrix.os == 'macos-15-intel' && '7.1.1' || matrix.os == 'macos-latest' && '80' || '8.0' }}
- name: Test ffmpeg
run: ffmpeg -i ./testdata/audio-long.mp3 ./testdata/audio-long.wav
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
if: runner.os == 'Windows'
- name: Install apt dependencies
run: |
sudo apt-get update
if [ "$(lsb_release -rs)" == "22.04" ]; then
sudo apt-get install libegl1-mesa
# Add ubuntu-toolchain-r PPA for newer libstdc++6 with GLIBCXX_3.4.32
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
sudo apt-get update
sudo apt-get install -y libstdc++6
fi
sudo apt-get install libyaml-dev libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-shape0 libxcb-cursor0 libportaudio2 gettext libpulse0 libgl1-mesa-dev libvulkan-dev ccache
if: "startsWith(matrix.os, 'ubuntu-')"
- name: Install dependencies
run: uv sync
- name: Test
run: |
uv run make test
shell: bash
env:
PYTHONFAULTHANDLER: "1"
- name: Upload coverage reports to Codecov with GitHub Action
uses: codecov/codecov-action@v4
with:
flags: ${{ runner.os }}
token: ${{ secrets.CODECOV_TOKEN }}
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
build:
runs-on: ${{ matrix.os }}
timeout-minutes: 90
env:
BUZZ_DISABLE_TELEMETRY: true
strategy:
fail-fast: false
matrix:
include:
- os: macos-15-intel
- os: macos-latest
- os: windows-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
# Should be removed with next update to whisper.cpp
- name: Downgrade Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16.0.0'
if: matrix.os == 'macos-latest'
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install Vulkan SDK
if: "startsWith(matrix.os, 'ubuntu-') || matrix.os == 'windows-latest'"
uses: humbletim/install-vulkan-sdk@v1.2
with:
version: 1.4.309.0
cache: true
- name: Install uv
uses: astral-sh/setup-uv@v6
- name: Load cached venv
id: cached-uv-dependencies
uses: actions/cache@v4
with:
path: .venv
key: venv-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/uv.lock') }}
- name: Install Inno Setup on Windows
uses: crazy-max/ghaction-chocolatey@v3
with:
args: install innosetup --yes
if: runner.os == 'Windows'
- name: Install apt dependencies
run: |
sudo apt-get update
if [ "$(lsb_release -rs)" == "22.04" ]; then
sudo apt-get install libegl1-mesa
# Add ubuntu-toolchain-r PPA for newer libstdc++6 with GLIBCXX_3.4.32
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
sudo apt-get update
sudo apt-get install -y libstdc++6
fi
sudo apt-get install libyaml-dev libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-shape0 libxcb-cursor0 libportaudio2 gettext libpulse0 libgl1-mesa-dev libvulkan-dev ccache
if: "startsWith(matrix.os, 'ubuntu-')"
- name: Install dependencies
run: uv sync
- uses: AnimMouse/setup-ffmpeg@v1
id: setup-ffmpeg
with:
version: ${{ matrix.os == 'macos-15-intel' && '7.1.1' || matrix.os == 'macos-latest' && '80' || '8.0' }}
- name: Install MSVC for Windows
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
uv add msvc-runtime
uv pip install -U torch==2.8.0+cu129 torchaudio==2.8.0+cu129 --index-url https://download.pytorch.org/whl/cu129
uv pip install nvidia-cublas-cu12==12.9.1.4 nvidia-cuda-cupti-cu12==12.9.79 nvidia-cuda-runtime-cu12==12.9.79 --extra-index-url https://pypi.ngc.nvidia.com
uv cache clean
uv run pip cache purge
fi
shell: bash
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
if: runner.os == 'Windows'
- uses: ruby/setup-ruby@v1
with:
ruby-version: "3.0"
bundler-cache: true
if: "startsWith(matrix.os, 'ubuntu-')"
- name: Install FPM
run: gem install fpm
if: "startsWith(matrix.os, 'ubuntu-')"
- name: Clear space on Windows
if: runner.os == 'Windows'
run: |
rm 'C:\Android\android-sdk\' -r -force
rm 'C:\Program Files (x86)\Google\' -r -force
rm 'C:\tools\kotlinc\' -r -force
rm 'C:\tools\php\' -r -force
rm 'C:\selenium\' -r -force
shell: pwsh
- name: Bundle
run: |
if [ "$RUNNER_OS" == "macOS" ]; then
brew install create-dmg
sudo pkill -9 XProtect >/dev/null || true;
while pgrep XProtect; do sleep 3; done;
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
xcrun notarytool store-credentials --apple-id "$APPLE_ID" --password "$APPLE_APP_PASSWORD" --team-id "$APPLE_TEAM_ID" notarytool --validate
uv run make bundle_mac
elif [ "$RUNNER_OS" == "Windows" ]; then
cp -r ./dll_backup ./buzz/
uv run make bundle_windows
fi
env:
BUZZ_CODESIGN_IDENTITY: ${{ secrets.BUZZ_CODESIGN_IDENTITY }}
BUZZ_KEYCHAIN_NOTARY_PROFILE: ${{ secrets.BUZZ_KEYCHAIN_NOTARY_PROFILE }}
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
shell: bash
- uses: actions/upload-artifact@v4
with:
name: Buzz-${{ runner.os }}-${{ runner.arch }}
path: |
dist/Buzz*-windows.exe
dist/Buzz*-windows-*.bin
dist/Buzz*-mac.dmg
build_wheels:
runs-on: ${{ matrix.os }}
env:
BUZZ_DISABLE_TELEMETRY: true
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-15-intel, macos-latest]
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
# Should be removed with next update to whisper.cpp
- name: Downgrade Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16.0.0'
if: matrix.os == 'macos-latest'
- name: Install Vulkan SDK
if: "startsWith(matrix.os, 'ubuntu-') || matrix.os == 'windows-latest'"
uses: humbletim/install-vulkan-sdk@v1.2
with:
version: 1.4.309.0
cache: true
- name: Install uv
uses: astral-sh/setup-uv@v6
- name: Build wheels
run: uv build --wheel
shell: bash
- uses: actions/upload-artifact@v4
with:
name: buzz-wheel-${{ runner.os }}-${{ runner.arch }}
path: ./dist/*.whl
publish_pypi:
needs: [build_wheels, test]
runs-on: ubuntu-latest
env:
BUZZ_DISABLE_TELEMETRY: true
environment: pypi
permissions:
id-token: write
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/download-artifact@v4
with:
pattern: buzz-wheel-*
path: dist
merge-multiple: true
- uses: pypa/gh-action-pypi-publish@release/v1
with:
verbose: true
password: ${{ secrets.PYPI_TOKEN }}
release:
runs-on: ${{ matrix.os }}
env:
BUZZ_DISABLE_TELEMETRY: true
strategy:
fail-fast: false
matrix:
include:
- os: macos-15-intel
- os: macos-latest
- os: windows-latest
needs: [build, test]
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/download-artifact@v4
with:
name: Buzz-${{ runner.os }}-${{ runner.arch }}
- name: Rename .dmg files
if: runner.os == 'macOS'
run: |
for file in Buzz*.dmg; do
mv "$file" "${file%.dmg}-${{ runner.arch }}.dmg"
done
- name: Release
uses: softprops/action-gh-release@v2
with:
files: |
Buzz*-unix.tar.gz
Buzz*.exe
Buzz*.bin
Buzz*.dmg
# Brew Cask deployment fails and the app is deprecated on Brew.
# deploy_brew_cask:
# runs-on: macos-latest
# env:
# BUZZ_DISABLE_TELEMETRY: true
# needs: [release]
# if: startsWith(github.ref, 'refs/tags/')
# steps:
# - uses: actions/checkout@v4
# with:
# submodules: recursive
#
# # Should be removed with next update to whisper.cpp
# - name: Downgrade Xcode
# uses: maxim-lobanov/setup-xcode@v1
# with:
# xcode-version: '16.0.0'
# if: matrix.os == 'macos-latest'
#
# - name: Install uv
# uses: astral-sh/setup-uv@v6
#
# - name: Set up Python
# uses: actions/setup-python@v5
# with:
# python-version: "3.12"
#
# - name: Install dependencies
# run: uv sync
#
# - name: Upload to Brew
# run: uv run make upload_brew
# env:
# HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}

32
.github/workflows/gh-pages.yml vendored Normal file
View file

@ -0,0 +1,32 @@
---
name: GitHub Pages
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
cache-dependency-path: docs/package-lock.json
- name: Install dependencies
run: npm ci
working-directory: docs
- name: Build
run: npm run build
working-directory: docs
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs/build

94
.github/workflows/manual-build.yml vendored Normal file
View file

@ -0,0 +1,94 @@
---
name: Manual Build
on: workflow_dispatch
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ${{ matrix.os }}
env:
BUZZ_DISABLE_TELEMETRY: true
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest
- os: windows-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/setup-python@v5
with:
python-version: "3.11.9"
- name: Install Poetry Action
uses: snok/install-poetry@v1.3.1
with:
virtualenvs-create: true
virtualenvs-in-project: true
- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v4
with:
path: .venv
key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}-2
- uses: FedericoCarboni/setup-ffmpeg@v3.1
id: setup-ffmpeg
with:
ffmpeg-version: release
architecture: 'x64'
github-token: ${{ github.server_url == 'https://github.com' && github.token || '' }}
- name: Install dependencies
run: poetry install
- name: Bundle
run: |
if [ "$RUNNER_OS" == "macOS" ]; then
brew install create-dmg
poetry run make bundle_mac_unsigned
elif [ "$RUNNER_OS" == "Windows" ]; then
poetry run make bundle_windows
fi
shell: bash
- uses: actions/upload-artifact@v4
with:
name: Buzz-${{ runner.os }}
path: |
dist/Buzz*-windows.exe
dist/Buzz*-mac.dmg
build-snap:
runs-on: ubuntu-latest
env:
BUZZ_DISABLE_TELEMETRY: true
outputs:
snap: ${{ steps.snapcraft.outputs.snap }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: snapcore/action-build@v1
id: snapcraft
- run: |
sudo apt-get update
sudo apt-get install libportaudio2
- run: sudo snap install --devmode *.snap
- run: |
cd $HOME
xvfb-run buzz --version
- uses: actions/upload-artifact@v4
with:
name: snap
path: ${{ steps.snapcraft.outputs.snap }}

106
.github/workflows/snapcraft.yml vendored Normal file
View file

@ -0,0 +1,106 @@
---
name: Snapcraft
on:
push:
branches:
- main
tags:
- "*"
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-24.04
timeout-minutes: 90
env:
BUZZ_DISABLE_TELEMETRY: true
outputs:
snap: ${{ steps.snapcraft.outputs.snap }}
steps:
# Ideas from https://github.com/orgs/community/discussions/25678
- name: Remove unused build tools
run: |
sudo apt-get remove -y azure-cli google-cloud-sdk hhvm google-chrome-stable firefox powershell mono-devel || true
sudo apt-get autoremove -y
sudo apt-get clean
python -m pip cache purge
rm -rf /opt/hostedtoolcache || true
- name: Check available disk space
run: |
echo "=== Disk space ==="
df -h
echo "=== Memory ==="
free -h
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Snapcraft and dependencies
run: |
set -x
# Ensure snapd is ready
sudo systemctl start snapd.socket
sudo snap wait system seed.loaded
echo "=== Installing snapcraft ==="
sudo snap install --classic snapcraft
echo "=== Installing gnome extension dependencies ==="
sudo snap install gnome-46-2404 || { echo "Failed to install gnome-46-2404"; sudo journalctl -u snapd --no-pager -n 50; exit 1; }
sudo snap install gnome-46-2404-sdk || { echo "Failed to install gnome-46-2404-sdk"; sudo journalctl -u snapd --no-pager -n 50; exit 1; }
echo "=== Installing build-snaps ==="
sudo snap install --classic astral-uv || { echo "Failed to install astral-uv"; sudo journalctl -u snapd --no-pager -n 50; exit 1; }
echo "=== Installed snaps ==="
snap list
- name: Check disk space before build
run: df -h
- name: Build snap
id: snapcraft
env:
SNAPCRAFT_BUILD_ENVIRONMENT: host
run: |
sudo -E snapcraft pack --verbose --destructive-mode
echo "snap=$(ls *.snap)" >> $GITHUB_OUTPUT
- run: sudo snap install --devmode *.snap
- run: |
cd $HOME
xvfb-run buzz --version
- uses: actions/upload-artifact@v4
with:
name: snap
path: ${{ steps.snapcraft.outputs.snap }}
upload-edge:
runs-on: ubuntu-latest
needs: [ build ]
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/download-artifact@v4
with:
name: snap
- uses: snapcore/action-publish@v1
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_TOKEN }}
with:
snap: ${{ needs.build.outputs.snap }}
release: edge
upload-stable:
runs-on: ubuntu-latest
needs: [ build ]
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/download-artifact@v4
with:
name: snap
- uses: snapcore/action-publish@v1
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_TOKEN }}
with:
snap: ${{ needs.build.outputs.snap }}
release: stable

33
.gitignore vendored
View file

@ -1,5 +1,36 @@
dist/
__pycache__/
build/
.pytest_cache/
.coverage*
!.coveragerc
.env
.DS_Store
htmlcov/
coverage.xml
.idea/
.venv/
venv/
*.wav
.claude/
# whisper_cpp
whisper_cpp
*.exe
*.dll
*.dylib
*.so
buzz/whisper_cpp/*
# Internationalization - compiled binaries
*.mo
*.po~
benchmarks.json
.eggs
*.egg-info
/coverage/
/wheelhouse/
/.flatpak-builder
/repo
/nemo_msdd_configs

15
.gitmodules vendored Normal file
View file

@ -0,0 +1,15 @@
[submodule "whisper.cpp"]
path = whisper.cpp
url = https://github.com/ggerganov/whisper.cpp
[submodule "whisper_diarization"]
path = whisper_diarization
url = https://github.com/MahmoudAshraf97/whisper-diarization
[submodule "demucs_repo"]
path = demucs_repo
url = https://github.com/MahmoudAshraf97/demucs.git
[submodule "deepmultilingualpunctuation"]
path = deepmultilingualpunctuation
url = https://github.com/oliverguhr/deepmultilingualpunctuation.git
[submodule "ctc_forced_aligner"]
path = ctc_forced_aligner
url = https://github.com/MahmoudAshraf97/ctc-forced-aligner.git

16
.pre-commit-config.yaml Normal file
View file

@ -0,0 +1,16 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.3
hooks:
- id: ruff
args: [ --fix, --exit-non-zero-on-fix ]
- id: ruff-format

4
.pylintrc Normal file
View file

@ -0,0 +1,4 @@
[MASTER]
disable=
C0114, # missing-module-docstring
C0116, # missing-function-docstring

1
.python-version Normal file
View file

@ -0,0 +1 @@
3.12

30
.run/pytest.run.xml Normal file
View file

@ -0,0 +1,30 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="pytest" type="tests" factoryName="py.test" nameIsGenerated="true">
<module name="buzz" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<option name="SDK_HOME" value="$PROJECT_DIR$/.venv/bin/python" />
<option name="SDK_NAME" value="Poetry (buzz) (2)" />
<option name="WORKING_DIRECTORY" value="" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="net.ashald.envfile">
<option name="IS_ENABLED" value="false" />
<option name="IS_SUBST" value="false" />
<option name="IS_PATH_MACRO_SUPPORTED" value="false" />
<option name="IS_IGNORE_MISSING_FILES" value="false" />
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" />
<ENTRIES>
<ENTRY IS_ENABLED="true" PARSER="runconfig" IS_EXECUTABLE="false" />
</ENTRIES>
</EXTENSION>
<option name="_new_keywords" value="&quot;&quot;" />
<option name="_new_parameters" value="&quot;&quot;" />
<option name="_new_additionalArguments" value="&quot;-s&quot;" />
<option name="_new_target" value="&quot;&quot;" />
<option name="_new_targetType" value="&quot;CUSTOM&quot;" />
<method v="2" />
</configuration>
</component>

4
.vscode/launch.json vendored
View file

@ -9,7 +9,7 @@
"type": "python",
"request": "launch",
"module": "main",
"justMyCode": true
"justMyCode": false
}
]
}
}

12
.vscode/settings.json vendored
View file

@ -1,6 +1,8 @@
{
"files.associations": {
"Buzz.spec": "python"
".coveragerc": "ini",
"Buzz.spec": "python",
"iosfwd": "cpp"
},
"files.exclude": {
"**/.git": true,
@ -9,5 +11,11 @@
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true
}
},
"python.testing.pytestArgs": ["."],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"cmake.sourceDirectory": "${workspaceFolder}/whisper.cpp"
}

158
Buzz.spec
View file

@ -1,29 +1,126 @@
# -*- mode: python ; coding: utf-8 -*-
import os
import os.path
import platform
import shutil
from PyInstaller.utils.hooks import collect_data_files, copy_metadata
datas = []
datas += collect_data_files('torch')
datas += copy_metadata('tqdm')
datas += copy_metadata('torch')
datas += copy_metadata('regex')
datas += copy_metadata('requests')
datas += copy_metadata('packaging')
datas += copy_metadata('filelock')
datas += copy_metadata('numpy')
datas += copy_metadata('tokenizers')
datas += collect_data_files('whisper')
from buzz.__version__ import VERSION
datas = []
datas += collect_data_files("torch")
datas += collect_data_files("demucs")
datas += copy_metadata("tqdm")
datas += copy_metadata("torch")
datas += copy_metadata("regex")
datas += copy_metadata("requests")
datas += copy_metadata("packaging")
datas += copy_metadata("filelock")
datas += copy_metadata("numpy")
datas += copy_metadata("tokenizers")
datas += copy_metadata("huggingface-hub")
datas += copy_metadata("safetensors")
datas += copy_metadata("pyyaml")
datas += copy_metadata("julius")
datas += copy_metadata("openunmix")
datas += copy_metadata("lameenc")
datas += copy_metadata("diffq")
datas += copy_metadata("einops")
datas += copy_metadata("hydra-core")
datas += copy_metadata("hydra-colorlog")
datas += copy_metadata("museval")
datas += copy_metadata("submitit")
datas += copy_metadata("treetable")
datas += copy_metadata("soundfile")
datas += copy_metadata("dora-search")
datas += copy_metadata("lhotse")
# Allow transformers package to load __init__.py file dynamically:
# https://github.com/chidiwilliams/buzz/issues/272
datas += collect_data_files("transformers", include_py_files=True)
datas += collect_data_files("faster_whisper", include_py_files=True)
datas += collect_data_files("stable_whisper", include_py_files=True)
datas += collect_data_files("whisper")
datas += collect_data_files("demucs", include_py_files=True)
datas += collect_data_files("whisper_diarization", include_py_files=True)
datas += collect_data_files("deepmultilingualpunctuation", include_py_files=True)
datas += collect_data_files("ctc_forced_aligner", include_py_files=True, excludes=["build"])
datas += collect_data_files("nemo", include_py_files=True)
datas += collect_data_files("lightning_fabric", include_py_files=True)
datas += collect_data_files("pytorch_lightning", include_py_files=True)
datas += [("buzz/assets/*", "assets")]
datas += [("buzz/locale", "locale")]
datas += [("buzz/schema.sql", ".")]
block_cipher = None
DEBUG = os.environ.get("PYINSTALLER_DEBUG", "").lower() in ["1", "true"]
if DEBUG:
options = [("v", None, "OPTION")]
else:
options = []
def find_dependency(name: str) -> str:
paths = os.environ["PATH"].split(os.pathsep)
candidates = []
for path in paths:
exe_path = os.path.join(path, name)
if os.path.isfile(exe_path):
candidates.append(exe_path)
# Check for chocolatery shims
shim_path = os.path.normpath(os.path.join(path, "..", "lib", "ffmpeg", "tools", "ffmpeg", "bin", name))
if os.path.isfile(shim_path):
candidates.append(shim_path)
if not candidates:
return None
# Pick the largest file
return max(candidates, key=lambda f: os.path.getsize(f))
if platform.system() == "Windows":
binaries = [
(find_dependency("ffmpeg.exe"), "."),
(find_dependency("ffprobe.exe"), "."),
]
else:
binaries = [
(shutil.which("ffmpeg"), "."),
(shutil.which("ffprobe"), "."),
]
binaries.append(("buzz/whisper_cpp/*", "buzz/whisper_cpp"))
if platform.system() == "Windows":
datas += [("dll_backup", "dll_backup")]
datas += collect_data_files("msvc-runtime")
binaries.append(("dll_backup/SDL2.dll", "dll_backup"))
a = Analysis(
['main.py'],
["main.py"],
pathex=[],
binaries=[],
binaries=binaries,
datas=datas,
hiddenimports=['apiclient', 'sounddevice', 'pytorch', '“sklearn.utils._cython_blas”', '“sklearn.neighbors.typedefs”',
'“sklearn.neighbors.quad_tree”', '“sklearn.tree”', '“sklearn.tree._utils”'],
hiddenimports=[
"dora", "dora.log",
"julius", "julius.core", "julius.resample",
"openunmix", "openunmix.filtering",
"lameenc",
"diffq",
"einops",
"hydra", "hydra.core", "hydra.core.global_hydra",
"hydra_colorlog",
"museval",
"submitit",
"treetable",
"soundfile",
"_soundfile_data",
"lhotse",
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
@ -38,19 +135,20 @@ pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
[],
options,
icon="./assets/buzz.ico",
exclude_binaries=True,
name='Buzz',
debug=False,
name="Buzz",
debug=DEBUG,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False,
console=DEBUG,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
codesign_identity=os.environ.get("BUZZ_CODESIGN_IDENTITY"),
entitlements_file="entitlements.plist" if platform.system() == "Darwin" else None,
)
coll = COLLECT(
exe,
@ -58,17 +156,19 @@ coll = COLLECT(
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx=False,
upx_exclude=[],
name='Buzz',
name="Buzz",
)
app = BUNDLE(
coll,
name='Buzz.app',
icon=None,
bundle_identifier=None,
version='0.0.1',
name="Buzz.app",
icon="./assets/buzz.icns",
bundle_identifier="com.chidiwilliams.buzz",
version=VERSION,
info_plist={
'NSMicrophoneUsageDescription': 'Please provide microphone access to continue'
}
"NSPrincipalClass": "NSApplication",
"NSHighResolutionCapable": "True",
"NSMicrophoneUsageDescription": "Allow Buzz to record audio from your microphone.",
},
)

1
CLAUDE.md Normal file
View file

@ -0,0 +1 @@
- Use uv to run tests and any scripts

134
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,134 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official email address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
williamschidi1@gmail.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

123
CONTRIBUTING.md Executable file
View file

@ -0,0 +1,123 @@
# Buzz Contribution Guide
## Internationalization
To contribute a new language translation to Buzz:
1. Run `make translation_po locale=[locale]`. `[locale]` is a string with the format "language\[_script\]\[_country\]",
where:
- "language" is a lowercase, two-letter ISO 639 language code,
- "script" is a titlecase, four-letter, ISO 15924 script code, and
- "country" is an uppercase, two-letter, ISO 3166 country code.
For example: `make translation_po locale=en_US`.
2. Fill in the translations in the `.po` file generated in `locale/[locale]/LC_MESSAGES`.
3. Run `make translation_mo` to compile the translations, then test your changes.
4. Create a new pull request with your changes.
## Troubleshooting
If you encounter any issues, please open an issue on the Buzz GitHub repository. Here are a few tips to gather data about the issue, so it is easier for us to fix.
**Provide details**
What version of the Buzz are you using? On what OS? What are steps to reproduce it? What settings were selected, like what model type and size was used.
**Logs**
Log files contain valuable information about what the Buzz was doing before the issue occurred. You can get the logs like this:
* Linux run the app from the terminal and check the output.
* Mac get logs from `~/Library/Logs/Buzz`.
* Windows paste this into the Windows Explorer address bar `%USERPROFILE%\AppData\Local\Buzz\Buzz\Logs` and check the logs file.
**Test on latest version**
To see if your issue has already been fixed, try running the latest version of the Buzz. To get it log in to the GitHub and go to [Actions section](https://github.com/chidiwilliams/buzz/actions/workflows/ci.yml?query=branch%3Amain). Latest development versions attached to Artifacts section of successful builds.
Linux versions get also pushed to the snap. To install latest development version use `snap install buzz --channel latest/edge`
## Running Buzz locally
### Linux (Ubuntu)
1. Clone the repository `git clone --recursive https://github.com/chidiwilliams/buzz.git`
2. Enter repo folder `cd buzz`
3. Install uv `curl -LsSf https://astral.sh/uv/install.sh | sh` (or see [uv installation docs](https://docs.astral.sh/uv/getting-started/installation/))
4. Install system dependencies you may be missing
```
sudo apt-get install --no-install-recommends libyaml-dev libtbb-dev libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-shape0 libxcb-cursor0 libportaudio2 gettext libpulse0 ffmpeg
```
On versions prior to Ubuntu 24.04 install `sudo apt-get install --no-install-recommends libegl1-mesa`
5. Install the dependencies `uv sync`
6. Run Buzz `uv run buzz`
#### Necessary dependencies for Faster Whisper on GPU
All the dependencies for GPU support should be included in the dependency packages already installed,
but if you get issues running Faster Whisper on GPU, install [CUDA 12](https://developer.nvidia.com/cuda-downloads), [cuBLASS](https://developer.nvidia.com/cublas) and [cuDNN](https://developer.nvidia.com/cudnn).
#### Error for Faster Whisper on GPU `Could not load library libcudnn_ops_infer.so.8`
You need to add path to the library to the `LD_LIBRARY_PATH` environment variable.
Check exact path to your uv virtual environment, it may be different for you.
```
export LD_LIBRARY_PATH=/path/to/buzz/.venv/lib/python3.12/site-packages/nvidia/cudnn/lib/:$LD_LIBRARY_PATH
```
#### For Whisper.cpp you will need to install Vulkan SDK
Follow the instructions for your distribution https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html
### Mac
1. Clone the repository `git clone --recursive https://github.com/chidiwilliams/buzz.git`
2. Enter repo folder `cd buzz`
3. Install uv `curl -LsSf https://astral.sh/uv/install.sh | sh` (or `brew install uv`)
4. Install system dependencies you may be missing `brew install ffmpeg`
5. Install the dependencies `uv sync`
6. Run Buzz `uv run buzz`
### Windows
Assumes you have [Git](https://git-scm.com/downloads) and [python](https://www.python.org/downloads) installed and added to PATH.
1. Install the chocolatey package manager for Windows. [More info](https://docs.chocolatey.org/en-us/choco/setup)
```
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
```
2. Install the build tools. `choco install make cmake`
3. Install the ffmpeg. `choco install ffmpeg`
4. Download [Build Tools for Visual Studio 2022](https://visualstudio.microsoft.com/vs/older-downloads/) and install "Desktop development with C++" workload.
5. Add location of `namke` to your PATH environment variable. Usually it is `C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.44.35207\bin\Hostx64\x86`
6. Install Vulkan SDK from https://vulkan.lunarg.com/sdk/home
7. Clone the repository `git clone --recursive https://github.com/chidiwilliams/buzz.git`
8. Enter repo folder `cd buzz`
9. Install uv `powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"`
10. Install the dependencies `uv sync`
11. Build Whisper.cpp `uv run make buzz/whisper_cpp`
12. `cp -r .\dll_backup\ .\buzz\`
13. Run Buzz `uv run buzz`
Note: It should be safe to ignore any "syntax errors" you see during the build. Buzz will work. Also you can ignore any errors for FFmpeg. Buzz tries to load FFmpeg by several different means and some of them throw errors, but FFmpeg should eventually be found and work.
#### GPU Support
GPU support on Windows with Nvidia GPUs is included out of the box in the `.exe` installer.
To add GPU support for source or `pip` installed version switch torch library to GPU version. For more info see https://pytorch.org/get-started/locally/ .
```
uv add --index https://download.pytorch.org/whl/cu128 torch==2.7.1+cu128 torchaudio==2.7.1+cu128
uv add --index https://pypi.ngc.nvidia.com nvidia-cublas-cu12==12.8.3.14 nvidia-cuda-cupti-cu12==12.8.57 nvidia-cuda-nvrtc-cu12==12.8.61 nvidia-cuda-runtime-cu12==12.8.57 nvidia-cudnn-cu12==9.7.1.26 nvidia-cufft-cu12==11.3.3.41 nvidia-curand-cu12==10.3.9.55 nvidia-cusolver-cu12==11.7.2.55 nvidia-cusparse-cu12==12.5.4.2 nvidia-cusparselt-cu12==0.6.3 nvidia-nvjitlink-cu12==12.8.61 nvidia-nvtx-cu12==12.8.55
```
To use Faster Whisper on GPU, install the following libraries:
* [cuBLAS](https://developer.nvidia.com/cublas)
* [cuDNN](https://developer.nvidia.com/cudnn)

242
Makefile
View file

@ -1,2 +1,242 @@
buzz:
# Change also in pyproject.toml and buzz/__version__.py
version := 1.4.4
mac_app_path := ./dist/Buzz.app
mac_zip_path := ./dist/Buzz-${version}-mac.zip
mac_dmg_path := ./dist/Buzz-${version}-mac.dmg
bundle_windows: dist/Buzz
iscc installer.iss
bundle_mac: dist/Buzz.app codesign_all_mac zip_mac notarize_zip staple_app_mac dmg_mac
bundle_mac_unsigned: dist/Buzz.app zip_mac dmg_mac_unsigned
clean:
ifeq ($(OS), Windows_NT)
-rmdir /s /q buzz\whisper_cpp
-rmdir /s /q whisper.cpp\build
-rmdir /s /q dist
-Remove-Item -Recurse -Force buzz\whisper_cpp
-Remove-Item -Recurse -Force whisper.cpp\build
-Remove-Item -Recurse -Force dist\*
-rm -rf buzz/whisper_cpp
-rm -rf whisper.cpp/build
-rm -rf dist/*
-rm -rf buzz/__pycache__ buzz/**/__pycache__ buzz/**/**/__pycache__ buzz/**/**/**/__pycache__
-for /d /r buzz %%d in (__pycache__) do @if exist "%%d" rmdir /s /q "%%d"
else
rm -rf buzz/whisper_cpp || true
rm -rf whisper.cpp/build || true
rm -rf dist/* || true
find buzz -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
endif
COVERAGE_THRESHOLD := 70
test: buzz/whisper_cpp
# A check to get updates of yt-dlp. Should run only on local as part of regular development operations
# Sort of a local "update checker"
ifndef CI
uv lock --upgrade-package yt-dlp
endif
pytest -s -vv --cov=buzz --cov-report=xml --cov-report=html --benchmark-skip --cov-fail-under=${COVERAGE_THRESHOLD} --cov-config=.coveragerc
benchmarks: buzz/whisper_cpp
pytest -s -vv --benchmark-only --benchmark-json benchmarks.json
dist/Buzz dist/Buzz.app: buzz/whisper_cpp
pyinstaller --noconfirm Buzz.spec
version:
echo "VERSION = \"${version}\"" > buzz/__version__.py
buzz/whisper_cpp: translation_mo
ifeq ($(OS), Windows_NT)
# Build Whisper with Vulkan support.
# The _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR is needed to prevent mutex lock issues on Windows
# https://github.com/actions/runner-images/issues/10004#issuecomment-2156109231
# -DCMAKE_[C|CXX]_COMPILER_WORKS=TRUE is used to prevent issue in building test program that fails on CI
# GGML_NATIVE=OFF ensures we don't use -march=native (which would target the build machine's CPU)
cmake -S whisper.cpp -B whisper.cpp/build/ -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_RPATH='$$ORIGIN' -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DCMAKE_C_FLAGS="-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR" -DCMAKE_CXX_FLAGS="-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR" -DCMAKE_C_COMPILER_WORKS=TRUE -DCMAKE_CXX_COMPILER_WORKS=TRUE -DGGML_VULKAN=1 -DGGML_NATIVE=OFF
cmake --build whisper.cpp/build -j --config Release --verbose
-mkdir buzz/whisper_cpp
cp whisper.cpp/build/bin/Release/whisper-cli.exe buzz/whisper_cpp/
cp whisper.cpp/build/bin/Release/whisper-server.exe buzz/whisper_cpp/
cp dll_backup/SDL2.dll buzz/whisper_cpp
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "if (-not (Test-Path 'buzz\whisper_cpp\ggml-silero-v6.2.0.bin')) { Start-BitsTransfer -Source https://huggingface.co/ggml-org/whisper-vad/resolve/main/ggml-silero-v6.2.0.bin -Destination 'buzz\whisper_cpp\ggml-silero-v6.2.0.bin' }"
endif
ifeq ($(shell uname -s), Linux)
# Build Whisper with Vulkan support
# GGML_NATIVE=OFF ensures we don't use -march=native (which would target the build machine's CPU)
# This enables portable SSE4.2/AVX/AVX2 optimizations that work on most x86_64 CPUs
rm -rf whisper.cpp/build || true
-mkdir -p buzz/whisper_cpp
cmake -S whisper.cpp -B whisper.cpp/build/ -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_RPATH='$$ORIGIN' -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DGGML_VULKAN=1 -DGGML_NATIVE=OFF
cmake --build whisper.cpp/build -j --config Release --verbose
cp whisper.cpp/build/bin/whisper-cli buzz/whisper_cpp/ || true
cp whisper.cpp/build/bin/whisper-server buzz/whisper_cpp/ || true
cp -P whisper.cpp/build/src/libwhisper.so* buzz/whisper_cpp/ || true
cp -P whisper.cpp/build/ggml/src/libggml.so* buzz/whisper_cpp/ || true
cp -P whisper.cpp/build/ggml/src/libggml-base.so* buzz/whisper_cpp/ || true
cp -P whisper.cpp/build/ggml/src/libggml-cpu.so* buzz/whisper_cpp/ || true
cp -P whisper.cpp/build/ggml/src/ggml-vulkan/libggml-vulkan.so* buzz/whisper_cpp/ || true
test -f buzz/whisper_cpp/ggml-silero-v6.2.0.bin || curl -L -o buzz/whisper_cpp/ggml-silero-v6.2.0.bin https://huggingface.co/ggml-org/whisper-vad/resolve/main/ggml-silero-v6.2.0.bin
endif
# Build on Macs
ifeq ($(shell uname -s), Darwin)
-rm -rf whisper.cpp/build || true
-mkdir -p buzz/whisper_cpp
ifeq ($(shell uname -m), arm64)
cmake -S whisper.cpp -B whisper.cpp/build/ -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DWHISPER_COREML=1
else
# Intel
cmake -S whisper.cpp -B whisper.cpp/build/ -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DGGML_VULKAN=0 -DGGML_METAL=0
endif
cmake --build whisper.cpp/build -j --config Release --verbose
cp whisper.cpp/build/bin/whisper-cli buzz/whisper_cpp/ || true
cp whisper.cpp/build/bin/whisper-server buzz/whisper_cpp/ || true
cp whisper.cpp/build/src/libwhisper.dylib buzz/whisper_cpp/ || true
cp whisper.cpp/build/ggml/src/libggml* buzz/whisper_cpp/ || true
test -f buzz/whisper_cpp/ggml-silero-v6.2.0.bin || curl -L -o buzz/whisper_cpp/ggml-silero-v6.2.0.bin https://huggingface.co/ggml-org/whisper-vad/resolve/main/ggml-silero-v6.2.0.bin
endif
# Prints all the Mac developer identities used for code signing
print_identities_mac:
security find-identity -p basic -v
dmg_mac:
ditto -x -k "${mac_zip_path}" dist/dmg
create-dmg \
--volname "Buzz" \
--volicon "./assets/buzz.icns" \
--window-pos 200 120 \
--window-size 600 300 \
--icon-size 100 \
--icon "Buzz.app" 175 120 \
--hide-extension "Buzz.app" \
--app-drop-link 425 120 \
--codesign "$$BUZZ_CODESIGN_IDENTITY" \
--notarize "$$BUZZ_KEYCHAIN_NOTARY_PROFILE" \
--filesystem APFS \
"${mac_dmg_path}" \
"dist/dmg/"
dmg_mac_unsigned:
ditto -x -k "${mac_zip_path}" dist/dmg
create-dmg \
--volname "Buzz" \
--volicon "./assets/buzz.icns" \
--window-pos 200 120 \
--window-size 600 300 \
--icon-size 100 \
--icon "Buzz.app" 175 120 \
--hide-extension "Buzz.app" \
--app-drop-link 425 120 \
"${mac_dmg_path}" \
"dist/dmg/"
staple_app_mac:
xcrun stapler staple ${mac_app_path}
notarize_zip:
xcrun notarytool submit ${mac_zip_path} --keychain-profile "$$BUZZ_KEYCHAIN_NOTARY_PROFILE" --wait
zip_mac:
ditto -c -k --keepParent "${mac_app_path}" "${mac_zip_path}"
codesign_all_mac: dist/Buzz.app
for i in $$(find dist/Buzz.app/Contents/Resources/torch/bin -name "*" -type f); \
do \
codesign --force --options=runtime --sign "$$BUZZ_CODESIGN_IDENTITY" --timestamp "$$i"; \
done
for i in $$(find dist/Buzz.app/Contents/Resources -name "*.dylib" -o -name "*.so" -type f); \
do \
codesign --force --options=runtime --sign "$$BUZZ_CODESIGN_IDENTITY" --timestamp "$$i"; \
done
for i in $$(find dist/Buzz.app/Contents/MacOS -name "*.dylib" -o -name "*.so" -o -name "Qt*" -o -name "Python" -type f); \
do \
codesign --force --options=runtime --sign "$$BUZZ_CODESIGN_IDENTITY" --timestamp "$$i"; \
done
codesign --force --options=runtime --sign "$$BUZZ_CODESIGN_IDENTITY" --timestamp dist/Buzz.app/Contents/MacOS/Buzz
codesign --force --options=runtime --sign "$$BUZZ_CODESIGN_IDENTITY" --entitlements ./entitlements.plist --timestamp dist/Buzz.app
codesign --verify --deep --strict --verbose=2 dist/Buzz.app
# HELPERS
# Get the build logs for a notary upload
notarize_log:
xcrun notarytool log ${id} --keychain-profile "$$BUZZ_KEYCHAIN_NOTARY_PROFILE"
# Make GGML model from whisper. Example: make ggml model_path=/Users/chidiwilliams/.cache/whisper/medium.pt
ggml:
python3 ./whisper.cpp/models/convert-pt-to-ggml.py ${model_path} .venv/lib/python3.12/site-packages/whisper dist
upload_brew:
brew bump-cask-pr --version ${version} --verbose buzz
UPGRADE_VERSION_BRANCH := upgrade-to-${version}
gh_upgrade_pr:
git checkout main && git pull
git checkout -B ${UPGRADE_VERSION_BRANCH}
make version version=${version}
git commit -am "Upgrade to ${version}"
git push --set-upstream origin ${UPGRADE_VERSION_BRANCH}
gh pr create --fill
gh pr merge ${UPGRADE_VERSION_BRANCH} --auto --squash
# Internationalization
translation_po_all:
$(MAKE) translation_po locale=ca_ES
$(MAKE) translation_po locale=da_DK
$(MAKE) translation_po locale=de_DE
$(MAKE) translation_po locale=en_US
$(MAKE) translation_po locale=es_ES
$(MAKE) translation_po locale=it_IT
$(MAKE) translation_po locale=ja_JP
$(MAKE) translation_po locale=lv_LV
$(MAKE) translation_po locale=nl
$(MAKE) translation_po locale=pl_PL
$(MAKE) translation_po locale=pt_BR
$(MAKE) translation_po locale=uk_UA
$(MAKE) translation_po locale=zh_CN
$(MAKE) translation_po locale=zh_TW
TMP_POT_FILE_PATH := $(shell mktemp)
PO_FILE_PATH := buzz/locale/${locale}/LC_MESSAGES/buzz.po
translation_po:
mkdir -p buzz/locale/${locale}/LC_MESSAGES
xgettext --from-code=UTF-8 --add-location=file -o "${TMP_POT_FILE_PATH}" -l python $(shell find buzz -name '*.py')
sed -i.bak 's/CHARSET/UTF-8/' ${TMP_POT_FILE_PATH}
if [ ! -f ${PO_FILE_PATH} ]; then \
msginit --no-translator --input=${TMP_POT_FILE_PATH} --output-file=${PO_FILE_PATH}; \
fi
rm ${TMP_POT_FILE_PATH}.bak
msgmerge -U ${PO_FILE_PATH} ${TMP_POT_FILE_PATH}
# On windows we can have two ways to compile locales, one for CI the other for local builds
# Will try both and ignore errors if they fail
translation_mo:
ifeq ($(OS), Windows_NT)
-forfiles /p buzz\locale /c "cmd /c python ..\..\msgfmt.py -o @path\LC_MESSAGES\buzz.mo @path\LC_MESSAGES\buzz.po"
-for dir in buzz/locale/*/ ; do \
python msgfmt.py -o $$dir/LC_MESSAGES/buzz.mo $$dir/LC_MESSAGES/buzz.po; \
done
else
for dir in buzz/locale/*/ ; do \
python3 msgfmt.py -o $$dir/LC_MESSAGES/buzz.mo $$dir/LC_MESSAGES/buzz.po; \
done
endif
lint:
ruff check . --fix
ruff format .

98
README.ja_JP.md Normal file
View file

@ -0,0 +1,98 @@
# Buzz
[ドキュメント](https://chidiwilliams.github.io/buzz/)
パソコン上でオフラインで音声の文字起こしと翻訳を行います。OpenAIの[Whisper](https://github.com/openai/whisper)を使用しています。
![MIT License](https://img.shields.io/badge/license-MIT-green)
[![CI](https://github.com/chidiwilliams/buzz/actions/workflows/ci.yml/badge.svg)](https://github.com/chidiwilliams/buzz/actions/workflows/ci.yml)
[![codecov](https://codecov.io/github/chidiwilliams/buzz/branch/main/graph/badge.svg?token=YJSB8S2VEP)](https://codecov.io/github/chidiwilliams/buzz)
![GitHub release (latest by date)](https://img.shields.io/github/v/release/chidiwilliams/buzz)
[![Github all releases](https://img.shields.io/github/downloads/chidiwilliams/buzz/total.svg)](https://GitHub.com/chidiwilliams/buzz/releases/)
![Buzz](./buzz/assets/buzz-banner.jpg)
## 機能
- 音声・動画ファイルまたはYouTubeリンクの文字起こし
- マイクからのリアルタイム音声文字起こし
- イベントやプレゼンテーション中に便利なプレゼンテーションウィンドウ
- ノイズの多い音声でより高い精度を得るための、文字起こし前の話者分離
- 文字起こしメディアでの話者識別
- 複数のWhisperバックエンドをサポート
- Nvidia GPU向けCUDAアクセラレーション対応
- Mac向けApple Silicon対応
- Whisper.cppでのVulkanアクセラレーション対応統合GPUを含むほとんどのGPUで利用可能
- TXT、SRT、VTT形式での文字起こしエクスポート
- 検索、再生コントロール、速度調整機能を備えた高度な文字起こしビューア
- 効率的なナビゲーションのためのキーボードショートカット
- 新しいファイルの自動文字起こしのための監視フォルダ
- スクリプトや自動化のためのコマンドラインインターフェース
## インストール
### macOS
[SourceForge](https://sourceforge.net/projects/buzz-captions/files/)から`.dmg`ファイルをダウンロードしてください。
### Windows
[SourceForge](https://sourceforge.net/projects/buzz-captions/files/)からインストールファイルを入手してください。
アプリは署名されていないため、インストール時に警告が表示されます。`詳細情報` -> `実行`を選択してください。
### Linux
Buzzは[Flatpak](https://flathub.org/apps/io.github.chidiwilliams.Buzz)または[Snap](https://snapcraft.io/buzz)として利用可能です。
Flatpakをインストールするには、以下を実行してください
```shell
flatpak install flathub io.github.chidiwilliams.Buzz
```
[![Download on Flathub](https://flathub.org/api/badge?svg&locale=en)](https://flathub.org/en/apps/io.github.chidiwilliams.Buzz)
Snapをインストールするには、以下を実行してください
```shell
sudo apt-get install libportaudio2 libcanberra-gtk-module libcanberra-gtk3-module
sudo snap install buzz
```
[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/buzz)
### PyPI
[ffmpeg](https://www.ffmpeg.org/download.html)をインストールしてください。
Python 3.12環境を使用していることを確認してください。
Buzzをインストール
```shell
pip install buzz-captions
python -m buzz
```
**PyPIでのGPUサポート**
PyPIでインストールしたバージョンでWindows上のNvidia GPUのGPUサポートを有効にするには、[torch](https://pytorch.org/get-started/locally/)のCUDAサポートを確認してください。
```
pip3 install -U torch==2.8.0+cu129 torchaudio==2.8.0+cu129 --index-url https://download.pytorch.org/whl/cu129
pip3 install nvidia-cublas-cu12==12.9.1.4 nvidia-cuda-cupti-cu12==12.9.79 nvidia-cuda-runtime-cu12==12.9.79 --extra-index-url https://pypi.ngc.nvidia.com
```
### 最新開発版
最新の機能やバグ修正を含む最新開発版の入手方法については、[FAQ](https://chidiwilliams.github.io/buzz/docs/faq#9-where-can-i-get-latest-development-version)をご覧ください。
### スクリーンショット
<div style="display: flex; flex-wrap: wrap;">
<img alt="ファイルインポート" src="share/screenshots/buzz-1-import.png" style="max-width: 18%; margin-right: 1%;" />
<img alt="メイン画面" src="share/screenshots/buzz-2-main_screen.png" style="max-width: 18%; margin-right: 1%; height:auto;" />
<img alt="設定" src="share/screenshots/buzz-3-preferences.png" style="max-width: 18%; margin-right: 1%; height:auto;" />
<img alt="モデル設定" src="share/screenshots/buzz-3.2-model-preferences.png" style="max-width: 18%; margin-right: 1%; height:auto;" />
<img alt="文字起こし" src="share/screenshots/buzz-4-transcript.png" style="max-width: 18%; margin-right: 1%; height:auto;" />
<img alt="ライブ録音" src="share/screenshots/buzz-5-live_recording.png" style="max-width: 18%; margin-right: 1%; height:auto;" />
<img alt="リサイズ" src="share/screenshots/buzz-6-resize.png" style="max-width: 18%;" />
</div>

126
README.md
View file

@ -1,76 +1,106 @@
[[简体中文](readme/README.zh_CN.md)] <- 点击查看中文页面。
# Buzz
![Buzz](buzz.png)
[Documentation](https://chidiwilliams.github.io/buzz/)
Transcribe and translate audio offline on your personal computer. Powered by
OpenAI's [Whisper](https://github.com/openai/whisper).
![MIT License](https://img.shields.io/badge/license-MIT-green)
[![CI](https://github.com/chidiwilliams/buzz/actions/workflows/ci.yml/badge.svg)](https://github.com/chidiwilliams/buzz/actions/workflows/ci.yml)
[![codecov](https://codecov.io/github/chidiwilliams/buzz/branch/main/graph/badge.svg?token=YJSB8S2VEP)](https://codecov.io/github/chidiwilliams/buzz)
![GitHub release (latest by date)](https://img.shields.io/github/v/release/chidiwilliams/buzz)
[![Github all releases](https://img.shields.io/github/downloads/chidiwilliams/buzz/total.svg)](https://GitHub.com/chidiwilliams/buzz/releases/)
Buzz transcribes audio from your computer's microphones to text using OpenAI's [Whisper](https://github.com/openai/whisper).
![Buzz](https://raw.githubusercontent.com/chidiwilliams/buzz/refs/heads/main/buzz/assets/buzz-banner.jpg)
## Requirements
## Features
- Transcribe audio and video files or Youtube links
- Live realtime audio transcription from microphone
- Presentation window for easy accessibility during events and presentations
- Speech separation before transcription for better accuracy on noisy audio
- Speaker identification in transcribed media
- Multiple whisper backend support
- CUDA acceleration support for Nvidia GPUs
- Apple Silicon support for Macs
- Vulkan acceleration support for Whisper.cpp on most GPUs, including integrated GPUs
- Export transcripts to TXT, SRT, and VTT
- Advanced Transcription Viewer with search, playback controls, and speed adjustment
- Keyboard shortcuts for efficient navigation
- Watch folder for automatic transcription of new files
- Command-Line Interface for scripting and automation
To set up Buzz, first install ffmpeg ([needed to run Whisper](https://github.com/openai/whisper#setup)).
## Installation
```text
# on Ubuntu or Debian
sudo apt update && sudo apt install ffmpeg
### macOS
# on MacOS using Homebrew (https://brew.sh/)
brew install ffmpeg
Download the `.dmg` from the [SourceForge](https://sourceforge.net/projects/buzz-captions/files/).
# on Windows using Chocolatey (https://chocolatey.org/)
choco install ffmpeg
### Windows
# on Windows using Scoop (https://scoop.sh/)
scoop install ffmpeg
Get the installation files from the [SourceForge](https://sourceforge.net/projects/buzz-captions/files/).
App is not signed, you will get a warning when you install it. Select `More info` -> `Run anyway`.
### Linux
Buzz is available as a [Flatpak](https://flathub.org/apps/io.github.chidiwilliams.Buzz) or a [Snap](https://snapcraft.io/buzz).
To install flatpak, run:
```shell
flatpak install flathub io.github.chidiwilliams.Buzz
```
## How to use
[![Download on Flathub](https://flathub.org/api/badge?svg&locale=en)](https://flathub.org/en/apps/io.github.chidiwilliams.Buzz)
To record from a system microphone, select a model, language, microphone, and task, then click Record.
To install snap, run:
```shell
sudo apt-get install libportaudio2 libcanberra-gtk-module libcanberra-gtk3-module
sudo snap install buzz
```
See the [Whisper docs](https://github.com/openai/whisper) for more information about the model types, languages, and tasks.
[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/buzz)
### Record audio playing from computer
### PyPI
To record audio playing out from your computer, you'll need to install an audio loopback driver (a program that lets you create virtual audio devices). The rest of this guide will use [BlackHole](https://github.com/ExistentialAudio/BlackHole) on Mac, but you can use other alternatives for your operating system (see [LoopBeAudio](https://nerds.de/en/loopbeaudio.html), [LoopBack](https://rogueamoeba.com/loopback/), and [Virtual Audio Cable](https://vac.muzychenko.net/en/)).
Install [ffmpeg](https://www.ffmpeg.org/download.html)
1. Install [BlackHole via Homebrew](https://github.com/ExistentialAudio/BlackHole#option-2-install-via-homebrew)
Ensure you use Python 3.12 environment.
Install Buzz
```shell
brew install blackhole-2ch
pip install buzz-captions
python -m buzz
```
2. Open Audio MIDI Setup from Spotlight or from `/Applications/Utilities/Audio Midi Setup.app`.
**GPU support for PyPI**
![](https://existential.audio/howto/img/spotlight.png)
To have GPU support for Nvidia GPUS on Windows, for PyPI installed version ensure, CUDA support for [torch](https://pytorch.org/get-started/locally/)
3. Click the '+' icon at the lower left corner and select 'Create Multi-Output Device'.
![](https://existential.audio/howto/img/createmulti-output.png)
4. Add your default speaker and BlackHole to the multi-output device.
![Screenshot of multi-output device](https://existential.audio/howto/img/multi-output.png)
5. Select this multi-output device as your speaker (application or system-wide) to play audio into BlackHole.
6. Open Buzz, select BlackHole as your microphone, and record as before to see transcriptions from the audio playing through BlackHole.
## Build
To build Buzz, install the dependencies:
```shell
# using pip
pip install .
# using poetry
poetry install
```
pip3 install -U torch==2.8.0+cu129 torchaudio==2.8.0+cu129 --index-url https://download.pytorch.org/whl/cu129
pip3 install nvidia-cublas-cu12==12.9.1.4 nvidia-cuda-cupti-cu12==12.9.79 nvidia-cuda-runtime-cu12==12.9.79 --extra-index-url https://pypi.ngc.nvidia.com
```
Then run:
### Latest development version
For info on how to get latest development version with latest features and bug fixes see [FAQ](https://chidiwilliams.github.io/buzz/docs/faq#9-where-can-i-get-latest-development-version).
### Support Buzz
You can help the Buzz by starring 🌟 the repo and sharing it with your friends.
### Screenshots
<div style="display: flex; flex-wrap: wrap;">
<img alt="File import" src="https://github.com/chidiwilliams/buzz/raw/main/share/screenshots/buzz-1-import.png" style="max-width: 18%; margin-right: 1%;" />
<img alt="Main screen" src="https://github.com/chidiwilliams/buzz/raw/main/share/screenshots/buzz-2-main_screen.png" style="max-width: 18%; margin-right: 1%; height:auto;" />
<img alt="Preferences" src="https://github.com/chidiwilliams/buzz/raw/main/share/screenshots/buzz-3-preferences.png" style="max-width: 18%; margin-right: 1%; height:auto;" />
<img alt="Model preferences" src="https://github.com/chidiwilliams/buzz/raw/main/share/screenshots/buzz-3.2-model-preferences.png" style="max-width: 18%; margin-right: 1%; height:auto;" />
<img alt="Transcript" src="https://github.com/chidiwilliams/buzz/raw/main/share/screenshots/buzz-4-transcript.png" style="max-width: 18%; margin-right: 1%; height:auto;" />
<img alt="Live recording" src="https://github.com/chidiwilliams/buzz/raw/main/share/screenshots/buzz-5-live_recording.png" style="max-width: 18%; margin-right: 1%; height:auto;" />
<img alt="Resize" src="https://github.com/chidiwilliams/buzz/raw/main/share/screenshots/buzz-6-resize.png" style="max-width: 18%;" />
</div>
```shell
make buzz
```

BIN
assets/buzz.icns Normal file

Binary file not shown.

BIN
assets/buzz.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

17
buzz.desktop Normal file
View file

@ -0,0 +1,17 @@
[Desktop Entry]
Type=Application
Encoding=UTF-8
Name=Buzz
Comment=Buzz transcribes and translates audio offline on your personal computer.
Path=/opt/buzz
Exec=/opt/buzz/Buzz
Icon=buzz
Terminal=false

BIN
buzz.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

0
buzz/__init__.py Normal file
View file

4
buzz/__main__.py Normal file
View file

@ -0,0 +1,4 @@
import buzz.buzz
if __name__ == "__main__":
buzz.buzz.main()

1
buzz/__version__.py Normal file
View file

@ -0,0 +1 @@
VERSION = "1.4.4"

23
buzz/action.py Normal file
View file

@ -0,0 +1,23 @@
import typing
from PyQt6.QtGui import QAction, QKeySequence
class Action(QAction):
def setShortcut(
self,
shortcut: typing.Union["QKeySequence", "QKeySequence.StandardKey", str, int],
) -> None:
super().setShortcut(shortcut)
self.setToolTip(Action.get_tooltip(self))
@classmethod
def get_tooltip(cls, action: QAction):
tooltip = action.toolTip()
shortcut = action.shortcut()
if shortcut.isEmpty():
return tooltip
shortcut_text = shortcut.toString(QKeySequence.SequenceFormat.NativeText)
return f"<p style='white-space:pre'>{tooltip}&nbsp;&nbsp;<code style='font-size:small'>{shortcut_text}</code></p>"

12
buzz/assets.py Normal file
View file

@ -0,0 +1,12 @@
import os
import sys
APP_BASE_DIR = (
getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
if getattr(sys, "frozen", False)
else os.path.dirname(__file__)
)
def get_path(path: str):
return os.path.join(APP_BASE_DIR, path)

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="M21.65 38.85v-12.5H9.15v-4.7h12.5V9.15h4.7v12.5h12.5v4.7h-12.5v12.5Z"/></svg>

After

Width:  |  Height:  |  Size: 150 B

BIN
buzz/assets/buzz-banner.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

BIN
buzz/assets/buzz.icns Normal file

Binary file not shown.

BIN
buzz/assets/buzz.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

BIN
buzz/assets/buzz.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

23
buzz/assets/buzz.svg Normal file
View file

@ -0,0 +1,23 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_945_8)">
<rect width="1024" height="1024" fill="#CD0000"/>
<rect width="1024" height="1024" fill="url(#paint0_linear_945_8)"/>
<path d="M871 512C871 710.27 710.27 871 512 871C313.73 871 153 710.27 153 512C153 313.73 313.73 153 512 153C710.27 153 871 313.73 871 512Z"
stroke="white" stroke-width="72"/>
<circle cx="512.5" cy="512.5" r="237.5" fill="url(#paint1_radial_945_8)"/>
</g>
<defs>
<linearGradient id="paint0_linear_945_8" x1="512" y1="0" x2="512" y2="1024" gradientUnits="userSpaceOnUse">
<stop stop-color="#CD0000" stop-opacity="0"/>
<stop offset="1" stop-opacity="0.2"/>
</linearGradient>
<radialGradient id="paint1_radial_945_8" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"
gradientTransform="translate(446 454.906) rotate(45) scale(320.761 365.853)">
<stop offset="0.578998" stop-color="white"/>
<stop offset="0.873177" stop-color="#E6E6E6"/>
</radialGradient>
<clipPath id="clip0_945_8">
<rect width="1024" height="1024" rx="185" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="m16.9 33.6 7.1-7.1 7.1 7.1 2.5-2.5-7.1-7.1 7.1-7.1-2.5-2.5-7.1 7.1-7.1-7.1-2.5 2.5 7.1 7.1-7.1 7.1ZM24 45.25q-4.4 0-8.275-1.65T8.95 39.05q-2.9-2.9-4.55-6.775Q2.75 28.4 2.75 24q0-4.45 1.65-8.325 1.65-3.875 4.55-6.75t6.775-4.55Q19.6 2.7 24 2.7q4.45 0 8.325 1.675 3.875 1.675 6.75 4.55t4.55 6.75Q45.3 19.55 45.3 24q0 4.4-1.675 8.275t-4.55 6.775q-2.875 2.9-6.75 4.55T24 45.25Zm0-4.7q6.9 0 11.725-4.825Q40.55 30.9 40.55 24q0-6.9-4.825-11.725Q30.9 7.45 24 7.45q-6.9 0-11.725 4.825Q7.45 17.1 7.45 24q0 6.9 4.825 11.725Q17.1 40.55 24 40.55ZM24 24Z"/></svg>

After

Width:  |  Height:  |  Size: 621 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="M12.65 43.25q-2 0-3.375-1.35T7.9 38.55V10.9H5V6.2h11.55V3.8H31.4v2.4H43v4.7h-2.9v27.65q0 1.95-1.4 3.325-1.4 1.375-3.35 1.375Zm22.7-32.35h-22.7v27.65h22.7ZM17.7 34.65h3.85V14.7H17.7Zm8.75 0h3.9V14.7h-3.9ZM12.65 10.9v27.65Z"/></svg>

After

Width:  |  Height:  |  Size: 303 B

View file

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
</svg>

After

Width:  |  Height:  |  Size: 210 B

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.75 1C6.33579 1 6 1.33579 6 1.75V3.50559C5.96824 3.53358 5.93715 3.56276 5.9068 3.59311L1.66416 7.83575C0.883107 8.6168 0.883107 9.88313 1.66416 10.6642L5.19969 14.1997C5.98074 14.9808 7.24707 14.9808 8.02812 14.1997L12.2708 9.95707C13.0518 9.17602 13.0518 7.90969 12.2708 7.12864L8.73522 3.59311C8.39027 3.24816 7.95066 3.05555 7.5 3.0153V1.75C7.5 1.33579 7.16421 1 6.75 1ZM6 5.62123V6.25C6 6.66421 6.33579 7 6.75 7C7.16421 7 7.5 6.66421 7.5 6.25V4.54033C7.56363 4.56467 7.62328 4.60249 7.67456 4.65377L11.2101 8.1893C11.2995 8.27875 11.348 8.39366 11.3555 8.51071H3.11052L6 5.62123ZM6.26035 13.1391L3.132 10.0107H10.0958L6.96746 13.1391C6.77219 13.3343 6.45561 13.3343 6.26035 13.1391Z" fill="#212121"/>
<path d="M2 17.5V12.4143L3.5 13.9143V17.5C3.5 18.0523 3.94772 18.5 4.5 18.5H19.5C20.0523 18.5 20.5 18.0523 20.5 17.5V6.5C20.5 5.94771 20.0523 5.5 19.5 5.5H12.0563L10.5563 4H19.5C20.8807 4 22 5.11929 22 6.5V17.5C22 18.8807 20.8807 20 19.5 20H4.5C3.11929 20 2 18.8807 2 17.5Z" fill="#212121"/>
<path d="M11 14.375C11 13.8816 11.1541 13.4027 11.3418 12.9938C11.5325 12.5784 11.7798 12.1881 12.0158 11.8595C12.2531 11.5289 12.4888 11.247 12.6647 11.0481C12.7502 10.9515 12.9062 10.7867 12.9642 10.7254L12.9697 10.7197C13.2626 10.4268 13.7374 10.4268 14.0303 10.7197L14.3353 11.0481C14.5112 11.247 14.7469 11.5289 14.9842 11.8595C15.2202 12.1881 15.4675 12.5784 15.6582 12.9938C15.8459 13.4027 16 13.8816 16 14.375C16 15.7654 14.9711 17 13.5 17C12.0289 17 11 15.7654 11 14.375ZM13.7658 12.7343C13.676 12.6092 13.5858 12.4916 13.5 12.3844C13.4142 12.4916 13.324 12.6092 13.2342 12.7343C13.0327 13.015 12.8425 13.32 12.7051 13.6195C12.5647 13.9253 12.5 14.1808 12.5 14.375C12.5 15.0663 12.9809 15.5 13.5 15.5C14.0191 15.5 14.5 15.0663 14.5 14.375C14.5 14.1808 14.4353 13.9253 14.2949 13.6195C14.1575 13.32 13.9673 13.015 13.7658 12.7343Z" fill="#212121"/>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.7092 2.29502C21.8041 2.3904 21.8757 2.50014 21.9241 2.61722C21.9727 2.73425 21.9996 2.8625 22 2.997L22 3V9C22 9.55228 21.5523 10 21 10C20.4477 10 20 9.55228 20 9V5.41421L14.7071 10.7071C14.3166 11.0976 13.6834 11.0976 13.2929 10.7071C12.9024 10.3166 12.9024 9.68342 13.2929 9.29289L18.5858 4H15C14.4477 4 14 3.55228 14 3C14 2.44772 14.4477 2 15 2H20.9998C21.2749 2 21.5242 2.11106 21.705 2.29078L21.7092 2.29502Z" fill="#000000"/>
<path d="M10.7071 14.7071L5.41421 20H9C9.55228 20 10 20.4477 10 21C10 21.5523 9.55228 22 9 22H3.00069L2.997 22C2.74301 21.9992 2.48924 21.9023 2.29502 21.7092L2.29078 21.705C2.19595 21.6096 2.12432 21.4999 2.07588 21.3828C2.02699 21.2649 2 21.1356 2 21V15C2 14.4477 2.44772 14 3 14C3.55228 14 4 14.4477 4 15V18.5858L9.29289 13.2929C9.68342 12.9024 10.3166 12.9024 10.7071 13.2929C11.0976 13.6834 11.0976 14.3166 10.7071 14.7071Z" fill="#000000"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 14 14" role="img" focusable="false" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><path d="M 7.5291661,11.795909 C 7.4168129,11.419456 7.3406864,10.225625 7.3406864,9.29222 c 0,-0.11438 -0.029767,-0.221667 -0.081573,-0.314893 0.051933,-0.115773 0.08132,-0.24358 0.08132,-0.378226 l 0,-1.709364 c 0,-0.511733 -0.416226,-0.927959 -0.9279585,-0.927959 l -0.8772919,0 C 5.527203,5.856265 5.52163,5.751005 5.518336,5.648406 5.514666,5.556066 5.513396,5.470313 5.513016,5.385826 5.511876,5.296776 5.5132694,5.224073 5.517196,5.160866 5.524666,5.024193 5.541009,4.891827 5.565076,4.773647 5.591043,4.646981 5.619669,4.564774 5.630689,4.535134 c 0.0019,-0.0052 0.0038,-0.01013 0.00557,-0.01533 0.00709,-0.02039 0.0133,-0.03559 0.017227,-0.04446 C 6.0127121,3.789698 5.750766,2.938499 5.0665137,2.5737 4.8642273,2.466034 4.6367344,2.409034 4.4084814,2.408147 4.1801018,2.409034 3.9526089,2.466037 3.7504492,2.5737 3.066197,2.938499 2.8042508,3.789698 3.1634768,4.475344 c 0.00393,0.0087 0.01026,0.02394 0.017227,0.04446 0.00177,0.0052 0.00367,0.01013 0.00557,0.01533 0.01102,0.02951 0.039647,0.111847 0.065613,0.238513 0.024067,0.11818 0.040533,0.250546 0.04788,0.387219 0.00393,0.06321 0.00532,0.135914 0.00418,0.22496 -5.066e-4,0.08449 -0.00165,0.17024 -0.00532,0.26258 -0.00329,0.102599 -0.00887,0.207859 -0.016847,0.313372 l -0.8772919,0 c -0.5117324,0 -0.9279584,0.416226 -0.9279584,0.927959 l 0,1.709364 c 0,0.134646 0.029387,0.262453 0.08132,0.378226 -0.051807,0.09323 -0.081573,0.200513 -0.081573,0.314893 0,0.933278 -0.076126,2.127236 -0.1884796,2.503689 C 1.0571435,11.985782 1.0131902,12.254315 1.0562568,12.453434 1.1748167,13 1.7477291,13 1.9359554,13 c 0.437506,0 1.226258,-0.07676 1.2595712,-0.08005 0.05092,-0.0051 0.1001932,-0.01596 0.1468065,-0.03179 0.049907,0.01241 0.1018398,0.01913 0.1546597,0.01925 l 0.9114918,0.0044 0.9114918,-0.0044 c 0.05282,-1.27e-4 0.1047532,-0.007 0.1546598,-0.01925 0.046613,0.01583 0.095886,0.02673 0.1468064,0.03179 C 5.6547556,12.92315 6.4436346,13 6.8810138,13 c 0.1882264,0 0.7612654,0 0.8796986,-0.546566 0.043067,-0.199119 -7.6e-4,-0.467652 -0.2315463,-0.657525 z m -1.833117,0.502486 -0.3480794,-1.518478 -0.1741664,1.503658 -1.6846638,-7.6e-4 -0.3680927,-0.885399 0,0.900979 c 0,0 -1.7672504,0.173279 -1.3861111,0 0.3811394,-0.173154 0.3811394,-2.980082 0.3811394,-2.980082 l 2.2924095,0 2.2924095,0 c 0,0 0,2.806928 0.3811394,2.980082 0.381266,0.173279 -1.3859844,0 -1.3859844,0 z M 10.219055,1 7.3387864,1 5.8932688,5.377719 l 0.9449318,0 c 0.3536527,0 0.6674055,0.17138 0.8650052,0.434593 l 0.04864,-0.18392 0.9107318,-2.702555 0.2962729,-0.0016 0.9543051,2.889769 -2.2085564,0 C 7.839499,5.994632 7.9204389,6.217692 7.9204389,6.459878 l 0,1.257038 2.3962751,0 0.423193,1.60917 2.218563,0 L 10.219055,1 Z"/></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="-0.5 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.93994 9.39998V5.48999C8.93994 5.20999 9.15994 4.98999 9.43994 4.98999H20.9999C21.2799 4.98999 21.4999 5.20999 21.4999 5.48999V13.09C21.4999 13.37 21.2799 13.59 20.9999 13.59L17.0599 13.6" stroke="#0F0F0F" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M17.7301 8.72998L16.4301 10.03" stroke="#0F0F0F" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 11.4H14.56C14.84 11.4 15.06 11.62 15.06 11.9V19.51C15.06 19.79 14.84 20.01 14.56 20.01H3C2.72 20.01 2.5 19.79 2.5 19.51V11.9C2.5 11.63 2.72 11.4 3 11.4Z" stroke="#0F0F0F" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19.32 10.03V7.64001C19.32 7.36001 19.1 7.14001 18.82 7.14001H16.42" stroke="#0F0F0F" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 7C12.5523 7 13 7.44772 13 8V13C13 13.5523 12.5523 14 12 14C11.4477 14 11 13.5523 11 13V8C11 7.44772 11.4477 7 12 7Z" fill="#FF8C00"/>
<path d="M12 17C12.5523 17 13 16.5523 13 16C13 15.4477 12.5523 15 12 15C11.4477 15 11 15.4477 11 16C11 16.5523 11.4477 17 12 17Z" fill="#FF8C00"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2ZM4 12C4 7.58172 7.58172 4 12 4C16.4183 4 20 7.58172 20 12C20 16.4183 16.4183 20 12 20C7.58172 20 4 16.4183 4 12Z" fill="#FFD700"/>
</svg>

After

Width:  |  Height:  |  Size: 733 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="M24 28.55q-2.75 0-4.6-1.95-1.85-1.95-1.85-4.75V9.55q0-2.65 1.875-4.525Q21.3 3.15 24 3.15t4.6 1.875Q30.5 6.9 30.5 9.55v12.3q0 2.8-1.875 4.75Q26.75 28.55 24 28.55Zm0-12.7ZM21.95 44.3v-6.95q-6-.65-9.95-5.05-3.95-4.4-3.95-10.45h4.15q0 4.85 3.45 8.2Q19.1 33.4 24 33.4q4.9 0 8.35-3.35 3.45-3.35 3.45-8.2h4.15q0 6.05-3.95 10.45-3.95 4.4-9.95 5.05v6.95ZM24 23.85q.8 0 1.275-.6.475-.6.475-1.4V9.55q0-.7-.525-1.2T24 7.85q-.7 0-1.225.5-.525.5-.525 1.2v12.3q0 .8.5 1.4.5.6 1.25.6Z"/></svg>

After

Width:  |  Height:  |  Size: 550 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="M5.15 42.85v-16.7h4.7v8.65L34.8 9.85h-8.65v-4.7h16.7v16.7h-4.7V13.2L13.2 38.15h8.65v4.7Z"/></svg>

After

Width:  |  Height:  |  Size: 170 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>

After

Width:  |  Height:  |  Size: 189 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M8 5v14l11-7z"/></svg>

After

Width:  |  Height:  |  Size: 171 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 96 960 960" width="48"><path d="M388.218 873Q286 873 212.5 803.718 139 734.436 139 634q0-100.436 73.733-169.718Q286.466 395 388 395h253l-97-97 66-66 211 210-211 210-66-66 97-97H387q-63.019 0-108.01 41.5Q234 572 234 634t44.99 103.5Q323.981 779 387 779h307v94H388.218Z"/></svg>

After

Width:  |  Height:  |  Size: 339 B

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="800px" height="800px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect width="16" height="16" id="icon-bound" fill="none" />
<path d="M2,8L8,8L8,14L6,14L6,11.4L1.4,16L-0.014,14.586L4.572,10L2,10L2,8ZM8,2L10,2L10,4.6L14.6,0L16.014,1.414L11.428,6L14,6L14,8L8,8L8,2Z" />
</svg>

After

Width:  |  Height:  |  Size: 399 B

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<svg height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 493.347 493.347" xml:space="preserve">
<g>
<path style="fill:#010002;" d="M191.936,385.946c-14.452,0-29.029-1.36-43.319-4.04l-5.299-0.996l-66.745,37.15v-63.207
l-6.629-4.427C25.496,320.716,0,277.045,0,230.617c0-85.648,86.102-155.33,191.936-155.33c17.077,0,33.623,1.838,49.394,5.239
c-50.486,27.298-84.008,74.801-84.008,128.765c0,72.969,61.25,134.147,142.942,149.464
C269.41,375.892,232.099,385.946,191.936,385.946z"/>
<path style="fill:#010002;" d="M437.777,304.278l-6.629,4.427v48.075l-50.933-28.343l-0.125,0.024l-5.167,0.967
c-11.444,2.142-23.104,3.228-34.673,3.228c-1.241,0-2.47-0.054-3.705-0.078c-82.707-1.599-149.387-56.268-149.387-123.287
c0-52.109,40.324-96.741,97.129-114.791c14.47-4.594,30.001-7.471,46.219-8.3c3.228-0.167,6.468-0.274,9.75-0.274
c84.413,0,153.092,55.343,153.092,123.365C493.347,246.053,473.089,280.679,437.777,304.278z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" height="800px" width="800px" version="1.1" id="anna_vital_language_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 256 256" enable-background="new 0 0 256 256" xml:space="preserve">
<path d="M62.4,101c-1.5-2.1-2.1-3.4-1.8-3.9c0.2-0.5,1.6-0.7,3.9-0.5c2.3,0.2,4.2,0.5,5.8,0.9c1.5,0.4,2.8,1,3.8,1.7
c1,0.7,1.8,1.5,2.3,2.6c0.6,1,1,2.3,1.4,3.7c0.7,2.8,0.5,4.7-0.5,5.7c-1.1,1-2.6,0.8-4.6-0.6c-2.1-1.4-3.9-2.8-5.5-4.2
C65.5,105.1,63.9,103.2,62.4,101z M40.7,190.1c4.8-2.1,9-4.2,12.6-6.4c3.5-2.1,6.6-4.4,9.3-6.8c2.6-2.3,5-4.9,7-7.7
c2-2.7,3.8-5.8,5.4-9.2c1.3,1.2,2.5,2.4,3.8,3.5c1.2,1.1,2.5,2.2,3.8,3.4c1.3,1.2,2.8,2.4,4.3,3.8c1.5,1.4,3.3,2.8,5.3,4.5
c0.7,0.5,1.4,0.9,2.1,1c0.7,0.1,1.7,0,3.1-0.6c1.3-0.5,3-1.4,5.1-2.8c2.1-1.3,4.7-3.1,7.9-5.4c1.6-1.1,2.4-2,2.3-2.7
c-0.1-0.7-1-1-2.7-0.9c-3.1,0.1-5.9,0.1-8.3-0.1c-2.5-0.2-5-0.6-7.4-1.4c-2.4-0.8-4.9-1.9-7.5-3.4c-2.6-1.5-5.6-3.6-9.1-6.2
c1-3.9,1.8-8,2.4-12.4c0.3-2.5,0.6-4.3,0.8-5.6c0.2-1.2,0.5-2.4,0.9-3.3c0.3-0.8,0.4-1.4,0.5-1.9c0.1-0.5-0.1-1-0.4-1.6
c-0.4-0.5-1-1.1-1.9-1.7c-0.9-0.6-2.2-1.4-3.9-2.3c2.4-0.9,5.1-1.7,7.9-2.6c2.7-0.9,5.7-1.8,8.8-2.7c3-0.9,4.5-1.9,4.6-3.1
c0.1-1.2-0.9-2.3-3.2-3.5c-1.5-0.8-2.9-1.1-4.3-0.9c-1.4,0.2-3.2,0.9-5.4,2.2c-0.6,0.4-1.8,0.9-3.4,1.6c-1.7,0.7-3.6,1.5-6,2.5
c-2.4,1-5,2-7.8,3.1c-2.9,1.1-5.8,2.2-8.7,3.2c-2.9,1.1-5.7,2-8.2,2.8c-2.6,0.8-4.6,1.4-6.1,1.6c-3.8,0.8-5.8,1.6-5.9,2.4
c0,0.8,1.5,1.6,4.4,2.4c1.2,0.3,2.3,0.6,3.1,0.6c0.8,0.1,1.7,0.1,2.5,0c0.8-0.1,1.6-0.3,2.4-0.5c0.8-0.3,1.7-0.7,2.8-1.1
c1.6-0.8,3.9-1.7,6.9-2.8c2.9-1,6.6-2.4,11.2-4c0.9,2.7,1.4,6,1.4,9.8c0,3.8-0.4,8.1-1.4,13c-1.3-1.1-2.7-2.3-4.2-3.6
c-1.5-1.3-2.9-2.6-4.3-3.9c-1.6-1.5-3.2-2.5-4.7-3c-1.6-0.5-3.4-0.5-5.5,0c-3.3,0.9-5,1.9-4.9,3.1c0,1.2,1.3,1.8,3.8,1.9
c0.9,0.1,1.8,0.3,2.7,0.6c0.9,0.3,1.9,0.9,3.2,1.8c1.3,0.9,2.9,2.2,4.7,3.8c1.8,1.6,4.2,3.7,7,6.3c-1.2,2.9-2.6,5.6-4.1,8
c-1.5,2.5-3.4,5-5.5,7.3c-2.2,2.4-4.7,4.8-7.7,7.2c-3,2.5-6.6,5.1-10.8,7.8c-4.3,2.8-6.5,4.7-6.5,5.6C35,192.1,37,191.7,40.7,190.1z
M250.5,81.8v165.3l-111.6-36.4L10.5,253.4V76.1l29.9-10V10.4l81.2,28.7L231.3,2.6v73.1L250.5,81.8z M124.2,50.6L22.3,84.6v152.2
l101.9-33.9V50.6L124.2,50.6z M219.4,71.9V19L138.1,46L219.4,71.9z M227,201.9L196.5,92L176,85.6l-30.9,90.8l18.9,5.9l5.8-18.7
l31.9,10l5.7,22.3L227,201.9z M174.8,147.7l22.2,6.9l-10.9-42.9L174.8,147.7z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 96 960 960" width="48"><path d="M267 873v-94h306q63.423 0 108.712-41.5Q727 696 727 634t-45.288-103.5Q636.423 489 573 489H319l97 97-66 66-211-210 211-210 66 66-97 97h253q101.534 0 175.267 69.282Q821 533.564 821 634q0 100.436-73.733 169.718Q673.534 873 572 873H267Z"/></svg>

After

Width:  |  Height:  |  Size: 336 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M160-200v-60h640v60H160Zm320-136L280-536l42-42 128 128v-310h60v310l128-128 42 42-200 200Z" transform="rotate(180 480 -480)"/></svg>

After

Width:  |  Height:  |  Size: 229 B

19
buzz/assets/url.svg Normal file
View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 -0.5 21 21" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>url [#1423]</title>
<desc>Created with Sketch.</desc>
<defs>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Dribbble-Light-Preview" transform="translate(-339.000000, -600.000000)" fill="#000000">
<g id="icons" transform="translate(56.000000, 160.000000)">
<path d="M286.388001,443.226668 C288.054626,441.639407 290.765027,441.639407 292.431651,443.226668 L293.942296,444.665378 L295.452942,443.226668 L293.942296,441.787958 C291.439155,439.404014 287.380498,439.404014 284.877356,441.787958 C282.374215,444.171902 282.374215,448.03729 284.877356,450.421235 L286.388001,451.859945 L287.898647,450.421235 L286.388001,448.982525 C284.721377,447.395264 284.721377,444.813929 286.388001,443.226668 L286.388001,443.226668 Z M302.122644,449.578765 L300.611999,448.139038 L299.101353,449.578765 L300.611999,451.017475 C302.277554,452.603719 302.277554,455.186071 300.611999,456.773332 C298.945374,458.359576 296.233905,458.359576 294.568349,456.773332 L293.057704,455.333605 L291.54599,456.773332 L293.057704,458.212042 C295.560845,460.595986 299.619502,460.595986 302.122644,458.212042 C304.625785,455.828098 304.625785,451.96271 302.122644,449.578765 L302.122644,449.578765 Z M288.653969,443.946023 L299.856676,454.61425 L298.344962,456.053977 L287.143324,445.384733 L288.653969,443.946023 Z" id="url-[#1423]">
</path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 96 960 960" width="48"><path d="M480.118 726Q551 726 600.5 676.382q49.5-49.617 49.5-120.5Q650 485 600.382 435.5q-49.617-49.5-120.5-49.5Q409 386 359.5 435.618q-49.5 49.617-49.5 120.5Q310 627 359.618 676.5q49.617 49.5 120.5 49.5ZM480 652q-40 0-68-28t-28-68q0-40 28-68t68-28q40 0 68 28t28 68q0 40-28 68t-68 28Zm0 227q-154 0-278-90T17 556q61-143 185-233t278-90q154 0 278 90t185 233q-61 143-185 233t-278 90Zm0-323Zm-.08 240q120.454 0 221.267-65.5T855 556q-53-109-153.733-174.5Q600.533 316 480.08 316q-120.454 0-221.267 65.5T104 556q54 109 154.733 174.5Q359.467 796 479.92 796Z"/></svg>

After

Width:  |  Height:  |  Size: 644 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 96 960 960" width="48"><path d="m634 624-77-76q21-44-12.5-69t-62.5-6l-70-71q15-8 33-12t35-4q71 0 120.5 49.5T650 556q0 16-4 36t-12 32Zm148 150-55-56q44-35 76.5-77t52.5-85q-52-110-150.5-175T490 316q-42 0-82 7t-59 16l-66-66q35-16 92.5-28T485 233q147 0 272 85t186 238q-25 66-67.5 121.5T782 774Zm25 227L653 849q-35 14-80 22t-93 8q-151 0-276.5-85.5T17 556q18-51 55-103t86-100L35 232l50-52 769 769-47 52ZM216 410q-36 29-66 68.5T104 556q52 111 153 175.5T488 796q27 0 55.5-3t44.5-11l-64-64q-8 4-20.5 6t-23.5 2q-70 0-120-49t-50-121q0-11 1.5-23t4.5-21L216 410Zm323 128Zm-137 69Z"/></svg>

After

Width:  |  Height:  |  Size: 640 B

102
buzz/buzz.py Normal file
View file

@ -0,0 +1,102 @@
import faulthandler
import logging
import multiprocessing
import os
import platform
import sys
from pathlib import Path
from typing import TextIO
# Set up CUDA library paths before any torch imports
# This must happen before platformdirs or any other imports that might indirectly load torch
import buzz.cuda_setup # noqa: F401
from platformdirs import user_log_dir, user_cache_dir, user_data_dir
# Will download all Huggingface data to the app cache directory
os.environ.setdefault("HF_HOME", user_cache_dir("Buzz"))
from buzz.assets import APP_BASE_DIR
# Check for segfaults if not running in frozen mode
# Note: On Windows, faulthandler can print "Windows fatal exception" messages
# for non-fatal RPC errors (0x800706be) during multiprocessing operations.
# These are usually harmless but noisy, so we disable faulthandler on Windows.
if getattr(sys, "frozen", False) is False and platform.system() != "Windows":
faulthandler.enable()
# Sets stdout/stderr to no-op TextIO when None (run as Windows GUI with --noconsole).
# stdout fix: torch.hub uses sys.stdout.write() for download progress and crashes if None.
# stderr fix: Resolves https://github.com/chidiwilliams/buzz/issues/221
if sys.stdout is None:
sys.stdout = TextIO()
if sys.stderr is None:
sys.stderr = TextIO()
# Adds the current directory to the PATH, so the ffmpeg binary get picked up:
# https://stackoverflow.com/a/44352931/9830227
os.environ["PATH"] += os.pathsep + APP_BASE_DIR
# Add the app directory to the DLL list: https://stackoverflow.com/a/64303856
if platform.system() == "Windows":
os.add_dll_directory(APP_BASE_DIR)
dll_backup_dir = os.path.join(APP_BASE_DIR, "dll_backup")
if os.path.isdir(dll_backup_dir):
os.add_dll_directory(dll_backup_dir)
onnx_dll_dir = os.path.join(APP_BASE_DIR, "onnxruntime", "capi")
if os.path.isdir(onnx_dll_dir):
os.add_dll_directory(onnx_dll_dir)
def main():
if platform.system() == "Linux":
multiprocessing.set_start_method("spawn")
# Fixes opening new window when app has been frozen on Windows:
# https://stackoverflow.com/a/33979091
multiprocessing.freeze_support()
log_dir = user_log_dir(appname="Buzz")
os.makedirs(log_dir, exist_ok=True)
log_format = (
"[%(asctime)s] %(module)s.%(funcName)s:%(lineno)d %(levelname)s -> %(message)s"
)
logging.basicConfig(
filename=os.path.join(log_dir, "logs.txt"),
level=logging.DEBUG,
format=log_format,
)
# Silence noisy third-party library loggers
logging.getLogger("matplotlib").setLevel(logging.WARNING)
logging.getLogger("graphviz").setLevel(logging.WARNING)
logging.getLogger("nemo_logger").setLevel(logging.ERROR)
logging.getLogger("nemo_logging").setLevel(logging.ERROR)
logging.getLogger("numba").setLevel(logging.WARNING)
logging.getLogger("torio._extension.utils").setLevel(logging.WARNING)
logging.getLogger("export_config_manager").setLevel(logging.WARNING)
logging.getLogger("training_telemetry_provider").setLevel(logging.ERROR)
logging.getLogger("default_recorder").setLevel(logging.WARNING)
logging.getLogger("config").setLevel(logging.WARNING)
if getattr(sys, "frozen", False) is False:
stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setLevel(logging.DEBUG)
stdout_handler.setFormatter(logging.Formatter(log_format))
logging.getLogger().addHandler(stdout_handler)
from buzz.cli import parse_command_line
from buzz.widgets.application import Application
logging.debug("app_dir: %s", APP_BASE_DIR)
logging.debug("log_dir: %s", log_dir)
logging.debug("cache_dir: %s", user_cache_dir("Buzz"))
logging.debug("data_dir: %s", user_data_dir("Buzz"))
app = Application(sys.argv)
parse_command_line(app)
app.show_main_window()
sys.exit(app.exec())

79
buzz/cache.py Normal file
View file

@ -0,0 +1,79 @@
import json
import logging
import os
import pickle
from typing import List
from platformdirs import user_cache_dir
from buzz.transcriber.transcriber import FileTranscriptionTask
class TasksCache:
def __init__(self, cache_dir=user_cache_dir("Buzz")):
os.makedirs(cache_dir, exist_ok=True)
self.cache_dir = cache_dir
self.pickle_cache_file_path = os.path.join(cache_dir, "tasks")
self.tasks_list_file_path = os.path.join(cache_dir, "tasks.json")
def save(self, tasks: List[FileTranscriptionTask]):
self.save_json_tasks(tasks=tasks)
def load(self) -> List[FileTranscriptionTask]:
if os.path.exists(self.tasks_list_file_path):
return self.load_json_tasks()
try:
with open(self.pickle_cache_file_path, "rb") as file:
return pickle.load(file)
except FileNotFoundError:
return []
except (
pickle.UnpicklingError,
AttributeError,
ValueError,
): # delete corrupted cache
os.remove(self.pickle_cache_file_path)
return []
def load_json_tasks(self) -> List[FileTranscriptionTask]:
task_ids: List[int]
try:
with open(self.tasks_list_file_path) as file:
task_ids = json.load(file)
except json.JSONDecodeError:
logging.debug(
"Got JSONDecodeError while reading tasks list file path, "
"resetting cache..."
)
task_ids = []
tasks = []
for task_id in task_ids:
try:
with open(self.get_task_path(task_id=task_id)) as file:
tasks.append(FileTranscriptionTask.from_json(file.read()))
except (FileNotFoundError, json.JSONDecodeError):
pass
return tasks
def save_json_tasks(self, tasks: List[FileTranscriptionTask]):
json_str = json.dumps([task.id for task in tasks])
with open(self.tasks_list_file_path, "w") as file:
file.write(json_str)
for task in tasks:
file_path = self.get_task_path(task_id=task.id)
json_str = task.to_json()
with open(file_path, "w") as file:
file.write(json_str)
def get_task_path(self, task_id: int):
path = os.path.join(self.cache_dir, "transcriptions", f"{task_id}.json")
os.makedirs(os.path.dirname(path), exist_ok=True)
return path
def clear(self):
if os.path.exists(self.pickle_cache_file_path):
os.remove(self.pickle_cache_file_path)

253
buzz/cli.py Normal file
View file

@ -0,0 +1,253 @@
import enum
import sys
import typing
import urllib.parse
from PyQt6.QtCore import QCommandLineParser, QCommandLineOption
from buzz.model_loader import (
ModelType,
WhisperModelSize,
TranscriptionModel,
ModelDownloader,
)
from buzz.store.keyring_store import get_password, Key
from buzz.transcriber.transcriber import (
Task,
FileTranscriptionTask,
FileTranscriptionOptions,
TranscriptionOptions,
LANGUAGES,
OutputFormat,
)
from buzz.widgets.application import Application
class CommandLineError(Exception):
def __init__(self, message: str):
super().__init__(message)
class CommandLineModelType(enum.Enum):
WHISPER = "whisper"
WHISPER_CPP = "whispercpp"
HUGGING_FACE = "huggingface"
FASTER_WHISPER = "fasterwhisper"
OPEN_AI_WHISPER_API = "openaiapi"
def parse_command_line(app: Application):
parser = QCommandLineParser()
try:
parse(app, parser)
except CommandLineError as exc:
print(f"Error: {str(exc)}\n", file=sys.stderr)
print(parser.helpText())
sys.exit(1)
def is_url(path: str) -> bool:
parsed = urllib.parse.urlparse(path)
return all([parsed.scheme, parsed.netloc])
def parse(app: Application, parser: QCommandLineParser):
parser.addPositionalArgument("<command>", "One of the following commands:\n- add")
parser.parse(app.arguments())
args = parser.positionalArguments()
if len(args) == 0:
parser.addHelpOption()
parser.addVersionOption()
parser.process(app)
return
command = args[0]
if command == "add":
parser.clearPositionalArguments()
parser.addPositionalArgument("files", "Input file paths", "[file file file...]")
task_option = QCommandLineOption(
["t", "task"],
f"The task to perform. Allowed: {join_values(Task)}. Default: {Task.TRANSCRIBE.value}.",
"task",
Task.TRANSCRIBE.value,
)
model_type_option = QCommandLineOption(
["m", "model-type"],
f"Model type. Allowed: {join_values(CommandLineModelType)}. Default: {CommandLineModelType.WHISPER.value}.",
"model-type",
CommandLineModelType.WHISPER.value,
)
model_size_option = QCommandLineOption(
["s", "model-size"],
f"Model size. Use only when --model-type is whisper, whispercpp, or fasterwhisper. Allowed: {join_values(WhisperModelSize)}. Default: {WhisperModelSize.TINY.value}.",
"model-size",
WhisperModelSize.TINY.value,
)
hugging_face_model_id_option = QCommandLineOption(
["hfid"],
'Hugging Face model ID. Use only when --model-type is huggingface. Example: "openai/whisper-tiny"',
"id",
)
language_option = QCommandLineOption(
["l", "language"],
f'Language code. Allowed: {", ".join(sorted([k + " (" + LANGUAGES[k].title() + ")" for k in LANGUAGES]))}. Leave empty to detect language.',
"code",
"",
)
initial_prompt_option = QCommandLineOption(
["p", "prompt"], "Initial prompt.", "prompt", ""
)
word_timestamp_option = QCommandLineOption(
["w", "word-timestamps"], "Generate word-level timestamps."
)
extract_speech_option = QCommandLineOption(
["e", "extract-speech"], "Extract speech from audio before transcribing."
)
open_ai_access_token_option = QCommandLineOption(
"openai-token",
f"OpenAI access token. Use only when --model-type is {CommandLineModelType.OPEN_AI_WHISPER_API.value}. Defaults to your previously saved access token, if one exists.",
"token",
)
output_directory_option = QCommandLineOption(
["d", "output-directory"], "Output directory", "directory"
)
srt_option = QCommandLineOption(["srt"], "Output result in an SRT file.")
vtt_option = QCommandLineOption(["vtt"], "Output result in a VTT file.")
txt_option = QCommandLineOption("txt", "Output result in a TXT file.")
hide_gui_option = QCommandLineOption("hide-gui", "Hide the main application window.")
parser.addOptions(
[
task_option,
model_type_option,
model_size_option,
hugging_face_model_id_option,
language_option,
initial_prompt_option,
word_timestamp_option,
extract_speech_option,
open_ai_access_token_option,
output_directory_option,
srt_option,
vtt_option,
txt_option,
hide_gui_option,
]
)
parser.addHelpOption()
parser.addVersionOption()
parser.process(app)
# slice after first argument, the command
file_paths = parser.positionalArguments()[1:]
if len(file_paths) == 0:
raise CommandLineError("No input files")
task = parse_enum_option(task_option, parser, Task)
model_type = parse_enum_option(model_type_option, parser, CommandLineModelType)
model_size = parse_enum_option(model_size_option, parser, WhisperModelSize)
hugging_face_model_id = parser.value(hugging_face_model_id_option)
if (
hugging_face_model_id == ""
and model_type == CommandLineModelType.HUGGING_FACE
):
raise CommandLineError(
"--hfid is required when --model-type is huggingface"
)
model = TranscriptionModel(
model_type=ModelType[model_type.name],
whisper_model_size=model_size,
hugging_face_model_id=hugging_face_model_id,
)
ModelDownloader(model=model).run()
model_path = model.get_local_model_path()
if model_path is None:
raise CommandLineError("Model not found")
language = parser.value(language_option)
if language == "":
language = None
elif LANGUAGES.get(language) is None:
raise CommandLineError("Invalid language option")
initial_prompt = parser.value(initial_prompt_option)
word_timestamps = parser.isSet(word_timestamp_option)
extract_speech = parser.isSet(extract_speech_option)
output_formats: typing.Set[OutputFormat] = set()
if parser.isSet(srt_option):
output_formats.add(OutputFormat.SRT)
if parser.isSet(vtt_option):
output_formats.add(OutputFormat.VTT)
if parser.isSet(txt_option):
output_formats.add(OutputFormat.TXT)
openai_access_token = parser.value(open_ai_access_token_option)
if (
model.model_type == ModelType.OPEN_AI_WHISPER_API
and openai_access_token == ""
):
openai_access_token = get_password(key=Key.OPENAI_API_KEY)
if openai_access_token == "":
raise CommandLineError("No OpenAI access token found")
output_directory = parser.value(output_directory_option)
transcription_options = TranscriptionOptions(
model=model,
task=task,
language=language,
initial_prompt=initial_prompt,
word_level_timings=word_timestamps,
extract_speech=extract_speech,
openai_access_token=openai_access_token,
)
for file_path in file_paths:
path_is_url = is_url(file_path)
file_transcription_options = FileTranscriptionOptions(
file_paths=[file_path] if not path_is_url else None,
url=file_path if path_is_url else None,
output_formats=output_formats,
)
transcription_task = FileTranscriptionTask(
file_path=file_path if not path_is_url else None,
url=file_path if path_is_url else None,
source=FileTranscriptionTask.Source.FILE_IMPORT if not path_is_url else FileTranscriptionTask.Source.URL_IMPORT,
model_path=model_path,
transcription_options=transcription_options,
file_transcription_options=file_transcription_options,
output_directory=output_directory if output_directory != "" else None,
)
app.add_task(transcription_task, quit_on_complete=True)
if parser.isSet(hide_gui_option):
app.hide_main_window = True
T = typing.TypeVar("T", bound=enum.Enum)
def parse_enum_option(
option: QCommandLineOption, parser: QCommandLineParser, enum_class: typing.Type[T]
) -> T:
try:
return enum_class(parser.value(option))
except ValueError:
raise CommandLineError(f"Invalid value for --{option.names()[-1]} option.")
def join_values(enum_class: typing.Type[enum.Enum]) -> str:
return ", ".join([v.value for v in enum_class])

21
buzz/conn.py Normal file
View file

@ -0,0 +1,21 @@
import sys
from contextlib import contextmanager
from multiprocessing.connection import Connection
class ConnWriter:
def __init__(self, conn: Connection):
self.conn = conn
def write(self, s: str):
self.conn.send(s.strip())
@contextmanager
def pipe_stderr(conn: Connection):
sys.stderr = ConnWriter(conn)
try:
yield
finally:
sys.stderr = sys.__stderr__

130
buzz/cuda_setup.py Normal file
View file

@ -0,0 +1,130 @@
"""
CUDA library path setup for nvidia packages installed via pip.
This module must be imported BEFORE any torch or CUDA-dependent libraries are imported.
It handles locating and loading CUDA libraries (cuDNN, cuBLAS, etc.) from the nvidia
pip packages.
On Windows: Uses os.add_dll_directory() to add library paths
On Linux: Uses ctypes to preload libraries (LD_LIBRARY_PATH is read at process start)
On macOS: No action needed (CUDA not supported)
"""
import ctypes
import logging
import os
import platform
import sys
from pathlib import Path
logger = logging.getLogger(__name__)
def _get_nvidia_package_lib_dirs() -> list[Path]:
"""Find all nvidia package library directories in site-packages."""
lib_dirs = []
# Find site-packages directories
site_packages_dirs = []
for path in sys.path:
if "site-packages" in path:
site_packages_dirs.append(Path(path))
# Also check relative to the current module for frozen apps
if getattr(sys, "frozen", False):
# For frozen apps, check the _internal directory
frozen_lib_dir = Path(sys._MEIPASS) if hasattr(sys, "_MEIPASS") else Path(sys.executable).parent
nvidia_dir = frozen_lib_dir / "nvidia"
if nvidia_dir.exists():
for pkg_dir in nvidia_dir.iterdir():
if pkg_dir.is_dir():
lib_subdir = pkg_dir / "lib"
if lib_subdir.exists():
lib_dirs.append(lib_subdir)
# Some packages have bin directory on Windows
bin_subdir = pkg_dir / "bin"
if bin_subdir.exists():
lib_dirs.append(bin_subdir)
# Check each site-packages for nvidia packages
for sp_dir in site_packages_dirs:
nvidia_dir = sp_dir / "nvidia"
if nvidia_dir.exists():
for pkg_dir in nvidia_dir.iterdir():
if pkg_dir.is_dir():
lib_subdir = pkg_dir / "lib"
if lib_subdir.exists():
lib_dirs.append(lib_subdir)
# Some packages have bin directory on Windows
bin_subdir = pkg_dir / "bin"
if bin_subdir.exists():
lib_dirs.append(bin_subdir)
return lib_dirs
def _setup_windows_dll_directories():
"""Add nvidia library directories to Windows DLL search path."""
lib_dirs = _get_nvidia_package_lib_dirs()
for lib_dir in lib_dirs:
try:
os.add_dll_directory(str(lib_dir))
except (OSError, AttributeError) as e:
pass
def _preload_linux_libraries():
"""Preload CUDA libraries on Linux using ctypes.
On Linux, LD_LIBRARY_PATH is only read at process start, so we need to
manually load the libraries using ctypes before torch tries to load them.
"""
lib_dirs = _get_nvidia_package_lib_dirs()
# Libraries to skip - NVBLAS requires special configuration and causes issues
skip_patterns = ["libnvblas"]
loaded_libs = set()
for lib_dir in lib_dirs:
if not lib_dir.exists():
continue
# Find all .so files in the directory
for lib_file in sorted(lib_dir.glob("*.so*")):
if lib_file.name in loaded_libs:
continue
if lib_file.is_symlink() and not lib_file.exists():
continue
# Skip problematic libraries
if any(pattern in lib_file.name for pattern in skip_patterns):
continue
try:
# Use RTLD_GLOBAL so symbols are available to other libraries
ctypes.CDLL(str(lib_file), mode=ctypes.RTLD_GLOBAL)
loaded_libs.add(lib_file.name)
except OSError as e:
# Some libraries may have missing dependencies, that's ok
pass
def setup_cuda_libraries():
"""Set up CUDA library paths for the current platform.
This function should be called as early as possible, before any torch
or CUDA-dependent libraries are imported.
"""
system = platform.system()
if system == "Windows":
_setup_windows_dll_directories()
elif system == "Linux":
_preload_linux_libraries()
# macOS doesn't have CUDA support, so nothing to do
# Auto-run setup when this module is imported
setup_cuda_libraries()

0
buzz/db/__init__.py Normal file
View file

0
buzz/db/dao/__init__.py Normal file
View file

63
buzz/db/dao/dao.py Normal file
View file

@ -0,0 +1,63 @@
# Adapted from https://github.com/zhiyiYo/Groove
from abc import ABC
from typing import TypeVar, Generic, Any, Type, List
from PyQt6.QtSql import QSqlDatabase, QSqlQuery, QSqlRecord
from buzz.db.entity.entity import Entity
T = TypeVar("T", bound=Entity)
class DAO(ABC, Generic[T]):
entity: Type[T]
ignore_fields = []
def __init__(self, table: str, db: QSqlDatabase):
self.db = db
self.table = table
def insert(self, record: T):
query = self._create_query()
fields = [
field for field in record.__dict__.keys() if field not in self.ignore_fields
]
query.prepare(
f"""
INSERT INTO {self.table} ({", ".join(fields)})
VALUES ({", ".join([f":{key}" for key in fields])})
"""
)
for field in fields:
query.bindValue(f":{field}", getattr(record, field))
if not query.exec():
raise Exception(query.lastError().text())
def find_by_id(self, id: Any) -> T | None:
query = self._create_query()
query.prepare(f"SELECT * FROM {self.table} WHERE id = :id")
query.bindValue(":id", id)
return self._execute(query)
def to_entity(self, record: QSqlRecord) -> T:
kwargs = {record.fieldName(i): record.value(i) for i in range(record.count())}
return self.entity(**kwargs)
def _execute(self, query: QSqlQuery) -> T | None:
if not query.exec():
raise Exception(query.lastError().text())
if not query.first():
return None
return self.to_entity(query.record())
def _execute_all(self, query: QSqlQuery) -> List[T]:
if not query.exec():
raise Exception(query.lastError().text())
entities = []
while query.next():
entities.append(self.to_entity(query.record()))
return entities
def _create_query(self):
return QSqlQuery(self.db)

View file

@ -0,0 +1,320 @@
import uuid
from datetime import datetime
from uuid import UUID
from PyQt6.QtSql import QSqlDatabase
from buzz.db.dao.dao import DAO
from buzz.db.entity.transcription import Transcription
from buzz.transcriber.transcriber import FileTranscriptionTask
class TranscriptionDAO(DAO[Transcription]):
entity = Transcription
def __init__(self, db: QSqlDatabase):
super().__init__("transcription", db)
def create_transcription(self, task: FileTranscriptionTask):
query = self._create_query()
query.prepare(
"""
INSERT INTO transcription (
id,
export_formats,
file,
output_folder,
language,
model_type,
source,
status,
task,
time_queued,
url,
whisper_model_size,
hugging_face_model_id,
word_level_timings,
extract_speech,
name,
notes
) VALUES (
:id,
:export_formats,
:file,
:output_folder,
:language,
:model_type,
:source,
:status,
:task,
:time_queued,
:url,
:whisper_model_size,
:hugging_face_model_id,
:word_level_timings,
:extract_speech,
:name,
:notes
)
"""
)
query.bindValue(":id", str(task.uid))
query.bindValue(
":export_formats",
", ".join(
[
output_format.value
for output_format in task.file_transcription_options.output_formats
]
),
)
query.bindValue(":file", task.file_path)
query.bindValue(":output_folder", task.output_directory)
query.bindValue(":language", task.transcription_options.language)
query.bindValue(
":model_type", task.transcription_options.model.model_type.value
)
query.bindValue(":source", task.source.value)
query.bindValue(":status", FileTranscriptionTask.Status.QUEUED.value)
query.bindValue(":task", task.transcription_options.task.value)
query.bindValue(":time_queued", datetime.now().isoformat())
query.bindValue(":url", task.url)
query.bindValue(
":whisper_model_size",
task.transcription_options.model.whisper_model_size.value
if task.transcription_options.model.whisper_model_size
else None,
)
query.bindValue(
":hugging_face_model_id",
task.transcription_options.model.hugging_face_model_id
if task.transcription_options.model.hugging_face_model_id
else None,
)
query.bindValue(
":word_level_timings",
task.transcription_options.word_level_timings
)
query.bindValue(
":extract_speech",
task.transcription_options.extract_speech
)
query.bindValue(":name", None) # name is not available in FileTranscriptionTask
query.bindValue(":notes", None) # notes is not available in FileTranscriptionTask
if not query.exec():
raise Exception(query.lastError().text())
def copy_transcription(self, id: UUID) -> UUID:
query = self._create_query()
query.prepare("SELECT * FROM transcription WHERE id = :id")
query.bindValue(":id", str(id))
if not query.exec():
raise Exception(query.lastError().text())
if not query.next():
raise Exception("Transcription not found")
transcription_data = {field.name: query.value(field.name) for field in
self.entity.__dataclass_fields__.values()}
new_id = uuid.uuid4()
transcription_data["id"] = str(new_id)
transcription_data["time_queued"] = datetime.now().isoformat()
transcription_data["status"] = FileTranscriptionTask.Status.QUEUED.value
query.prepare(
"""
INSERT INTO transcription (
id,
export_formats,
file,
output_folder,
language,
model_type,
source,
status,
task,
time_queued,
url,
whisper_model_size,
hugging_face_model_id,
word_level_timings,
extract_speech,
name,
notes
) VALUES (
:id,
:export_formats,
:file,
:output_folder,
:language,
:model_type,
:source,
:status,
:task,
:time_queued,
:url,
:whisper_model_size,
:hugging_face_model_id,
:word_level_timings,
:extract_speech,
:name,
:notes
)
"""
)
for key, value in transcription_data.items():
query.bindValue(f":{key}", value)
if not query.exec():
raise Exception(query.lastError().text())
return new_id
def update_transcription_as_started(self, id: UUID):
query = self._create_query()
query.prepare(
"""
UPDATE transcription
SET status = :status, time_started = :time_started
WHERE id = :id
"""
)
query.bindValue(":id", str(id))
query.bindValue(":status", FileTranscriptionTask.Status.IN_PROGRESS.value)
query.bindValue(":time_started", datetime.now().isoformat())
if not query.exec():
raise Exception(query.lastError().text())
def update_transcription_as_failed(self, id: UUID, error: str):
query = self._create_query()
query.prepare(
"""
UPDATE transcription
SET status = :status, time_ended = :time_ended, error_message = :error_message
WHERE id = :id
"""
)
query.bindValue(":id", str(id))
query.bindValue(":status", FileTranscriptionTask.Status.FAILED.value)
query.bindValue(":time_ended", datetime.now().isoformat())
query.bindValue(":error_message", error)
if not query.exec():
raise Exception(query.lastError().text())
def update_transcription_as_canceled(self, id: UUID):
query = self._create_query()
query.prepare(
"""
UPDATE transcription
SET status = :status, time_ended = :time_ended
WHERE id = :id
"""
)
query.bindValue(":id", str(id))
query.bindValue(":status", FileTranscriptionTask.Status.CANCELED.value)
query.bindValue(":time_ended", datetime.now().isoformat())
if not query.exec():
raise Exception(query.lastError().text())
def update_transcription_progress(self, id: UUID, progress: float):
query = self._create_query()
query.prepare(
"""
UPDATE transcription
SET status = :status, progress = :progress
WHERE id = :id
"""
)
query.bindValue(":id", str(id))
query.bindValue(":status", FileTranscriptionTask.Status.IN_PROGRESS.value)
query.bindValue(":progress", progress)
if not query.exec():
raise Exception(query.lastError().text())
def update_transcription_as_completed(self, id: UUID):
query = self._create_query()
query.prepare(
"""
UPDATE transcription
SET status = :status, time_ended = :time_ended
WHERE id = :id
"""
)
query.bindValue(":id", str(id))
query.bindValue(":status", FileTranscriptionTask.Status.COMPLETED.value)
query.bindValue(":time_ended", datetime.now().isoformat())
if not query.exec():
raise Exception(query.lastError().text())
def update_transcription_file_and_name(self, id: UUID, file_path: str, name: str | None = None):
query = self._create_query()
query.prepare(
"""
UPDATE transcription
SET file = :file, name = COALESCE(:name, name)
WHERE id = :id
"""
)
query.bindValue(":id", str(id))
query.bindValue(":file", file_path)
query.bindValue(":name", name)
if not query.exec():
raise Exception(query.lastError().text())
def update_transcription_name(self, id: UUID, name: str):
query = self._create_query()
query.prepare(
"""
UPDATE transcription
SET name = :name
WHERE id = :id
"""
)
query.bindValue(":id", str(id))
query.bindValue(":name", name)
if not query.exec():
raise Exception(query.lastError().text())
if query.numRowsAffected() == 0:
raise Exception("Transcription not found")
def update_transcription_notes(self, id: UUID, notes: str):
query = self._create_query()
query.prepare(
"""
UPDATE transcription
SET notes = :notes
WHERE id = :id
"""
)
query.bindValue(":id", str(id))
query.bindValue(":notes", notes)
if not query.exec():
raise Exception(query.lastError().text())
if query.numRowsAffected() == 0:
raise Exception("Transcription not found")
def reset_transcription_for_restart(self, id: UUID):
"""Reset a transcription to queued status for restart"""
query = self._create_query()
query.prepare(
"""
UPDATE transcription
SET status = :status, progress = :progress, time_started = NULL, time_ended = NULL, error_message = NULL
WHERE id = :id
"""
)
query.bindValue(":id", str(id))
query.bindValue(":status", FileTranscriptionTask.Status.QUEUED.value)
query.bindValue(":progress", 0.0)
if not query.exec():
raise Exception(query.lastError().text())
if query.numRowsAffected() == 0:
raise Exception("Transcription not found")

View file

@ -0,0 +1,53 @@
from typing import List
from uuid import UUID
from PyQt6.QtSql import QSqlDatabase
from buzz.db.dao.dao import DAO
from buzz.db.entity.transcription_segment import TranscriptionSegment
class TranscriptionSegmentDAO(DAO[TranscriptionSegment]):
entity = TranscriptionSegment
ignore_fields = ["id"]
def __init__(self, db: QSqlDatabase):
super().__init__("transcription_segment", db)
def get_segments(self, transcription_id: UUID) -> List[TranscriptionSegment]:
query = self._create_query()
query.prepare(
f"""
SELECT * FROM {self.table}
WHERE transcription_id = :transcription_id
"""
)
query.bindValue(":transcription_id", str(transcription_id))
return self._execute_all(query)
def delete_segments(self, transcription_id: UUID):
query = self._create_query()
query.prepare(
f"""
DELETE FROM {self.table}
WHERE transcription_id = :transcription_id
"""
)
query.bindValue(":transcription_id", str(transcription_id))
if not query.exec():
raise Exception(query.lastError().text())
def update_segment_translation(self, segment_id: int, translation: str):
query = self._create_query()
query.prepare(
"""
UPDATE transcription_segment
SET translation = :translation
WHERE id = :id
"""
)
query.bindValue(":id", segment_id)
query.bindValue(":translation", translation)
if not query.exec():
raise Exception(query.lastError().text())

52
buzz/db/db.py Normal file
View file

@ -0,0 +1,52 @@
import logging
import os
import sqlite3
import tempfile
from PyQt6.QtSql import QSqlDatabase
from platformdirs import user_data_dir
from buzz.db.helpers import (
run_sqlite_migrations,
copy_transcriptions_from_json_to_sqlite,
mark_in_progress_and_queued_transcriptions_as_canceled,
)
def setup_app_db() -> QSqlDatabase:
data_dir = user_data_dir("Buzz")
os.makedirs(data_dir, exist_ok=True)
return _setup_db(os.path.join(data_dir, "Buzz.sqlite"))
def setup_test_db() -> QSqlDatabase:
return _setup_db(tempfile.mktemp())
def _setup_db(path: str) -> QSqlDatabase:
# Run migrations
db = sqlite3.connect(path, isolation_level=None, timeout=10.0)
try:
run_sqlite_migrations(db)
copy_transcriptions_from_json_to_sqlite(db)
mark_in_progress_and_queued_transcriptions_as_canceled(db)
db.commit()
finally:
db.close()
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(path)
if not db.open():
raise RuntimeError(f"Failed to open database connection: {db.databaseName()}")
db.exec('PRAGMA foreign_keys = ON')
logging.debug("Database connection opened: %s", db.databaseName())
return db
def close_app_db():
db = QSqlDatabase.database()
if not db.isValid():
return
if db.isOpen():
db.close()

View file

12
buzz/db/entity/entity.py Normal file
View file

@ -0,0 +1,12 @@
from abc import ABC
from PyQt6.QtSql import QSqlRecord
class Entity(ABC):
@classmethod
def from_record(cls, record: QSqlRecord):
entity = cls()
for i in range(record.count()):
setattr(entity, record.fieldName(i), record.value(i))
return entity

View file

@ -0,0 +1,66 @@
import datetime
import os
import uuid
from dataclasses import dataclass, field
from buzz.db.entity.entity import Entity
from buzz.model_loader import ModelType
from buzz.settings.settings import Settings
from buzz.transcriber.transcriber import OutputFormat, Task, FileTranscriptionTask
@dataclass
class Transcription(Entity):
status: str = FileTranscriptionTask.Status.QUEUED.value
task: str = Task.TRANSCRIBE.value
model_type: str = ModelType.WHISPER.value
whisper_model_size: str | None = None
hugging_face_model_id: str | None = None
word_level_timings: str | None = None
extract_speech: str | None = None
language: str | None = None
id: str = field(default_factory=lambda: str(uuid.uuid4()))
error_message: str | None = None
file: str | None = None
time_queued: str = datetime.datetime.now().isoformat()
progress: float = 0.0
time_ended: str | None = None
time_started: str | None = None
export_formats: str | None = None
output_folder: str | None = None
source: str | None = None
url: str | None = None
name: str | None = None
notes: str | None = None
@property
def id_as_uuid(self):
return uuid.UUID(hex=self.id)
@property
def status_as_status(self):
return FileTranscriptionTask.Status(self.status)
def get_output_file_path(
self,
output_format: OutputFormat,
output_directory: str | None = None,
):
input_file_name = os.path.splitext(os.path.basename(self.file))[0]
date_time_now = datetime.datetime.now().strftime("%d-%b-%Y %H-%M-%S")
export_file_name_template = Settings().get_default_export_file_template()
output_file_name = (
export_file_name_template.replace("{{ input_file_name }}", input_file_name)
.replace("{{ task }}", self.task)
.replace("{{ language }}", self.language or "")
.replace("{{ model_type }}", self.model_type)
.replace("{{ model_size }}", self.whisper_model_size or "")
.replace("{{ date_time }}", date_time_now)
+ f".{output_format.value}"
)
output_directory = output_directory or os.path.dirname(self.file)
return os.path.join(output_directory, output_file_name)

View file

@ -0,0 +1,13 @@
from dataclasses import dataclass
from buzz.db.entity.entity import Entity
@dataclass
class TranscriptionSegment(Entity):
start_time: int
end_time: int
text: str
translation: str
transcription_id: str
id: int = -1

89
buzz/db/helpers.py Normal file
View file

@ -0,0 +1,89 @@
import os
from datetime import datetime
from sqlite3 import Connection
from buzz.assets import get_path
from buzz.cache import TasksCache
from buzz.db.migrator import dumb_migrate_db
def copy_transcriptions_from_json_to_sqlite(conn: Connection):
cache = TasksCache()
if os.path.exists(cache.tasks_list_file_path):
tasks = cache.load()
cursor = conn.cursor()
for task in tasks:
cursor.execute(
"""
INSERT INTO transcription (id, error_message, export_formats, file, output_folder, progress, language, model_type, source, status, task, time_ended, time_queued, time_started, url, whisper_model_size, hugging_face_model_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, COALESCE(?, ?), ?, ?, ?, ?)
RETURNING id;
""",
(
str(task.uid),
task.error,
", ".join(
[
format.value
for format in task.file_transcription_options.output_formats
]
),
task.file_path,
task.output_directory,
task.fraction_completed,
task.transcription_options.language,
task.transcription_options.model.model_type.value,
task.source.value,
task.status.value,
task.transcription_options.task.value,
task.completed_at,
task.queued_at, datetime.now().isoformat(),
task.started_at,
task.url,
task.transcription_options.model.whisper_model_size.value
if task.transcription_options.model.whisper_model_size
else None,
task.transcription_options.model.hugging_face_model_id
if task.transcription_options.model.hugging_face_model_id
else None,
),
)
transcription_id = cursor.fetchone()[0]
for segment in task.segments:
cursor.execute(
"""
INSERT INTO transcription_segment (end_time, start_time, text, translation, transcription_id)
VALUES (?, ?, ?, ?, ?);
""",
(
segment.end,
segment.start,
segment.text,
segment.translation,
transcription_id,
),
)
# os.remove(cache.tasks_list_file_path)
conn.commit()
def run_sqlite_migrations(db: Connection):
schema_path = get_path("schema.sql")
with open(schema_path) as schema_file:
schema = schema_file.read()
dumb_migrate_db(db=db, schema=schema)
def mark_in_progress_and_queued_transcriptions_as_canceled(conn: Connection):
cursor = conn.cursor()
cursor.execute(
"""
UPDATE transcription
SET status = 'canceled', time_ended = ?
WHERE status = 'in_progress' OR status = 'queued';
""",
(datetime.now().isoformat(),),
)
conn.commit()

285
buzz/db/migrator.py Normal file
View file

@ -0,0 +1,285 @@
# coding: utf-8
# https://gist.github.com/simonw/664b4b0851c1899dc55e1fb655181037
"""Simple declarative schema migration for SQLite.
See <https://david.rothlis.net/declarative-schema-migration-for-sqlite>.
Author: William Manley <will@stb-tester.com>.
Copyright © 2019-2022 Stb-tester.com Ltd.
License: MIT.
"""
import logging
import re
import sqlite3
from textwrap import dedent
def dumb_migrate_db(db, schema, allow_deletions=False):
"""
Migrates a database to the new schema given by the SQL text `schema`
preserving the data. We create any table that exists in schema, delete any
old table that is no longer used and add/remove columns and indices as
necessary.
Under this scheme there are a set of changes that we can make to the schema
and this script will handle it fine:
1. Adding a new table
2. Adding, deleting or modifying an index
3. Adding a column to an existing table as long as the new column can be
NULL or has a DEFAULT value specified.
4. Changing a column to remove NULL or DEFAULT as long as all values in the
database are not NULL
5. Changing the type of a column
6. Changing the user_version
In addition this function is capable of:
1. Deleting tables
2. Deleting columns from tables
But only if allow_deletions=True. If the new schema requires a column/table
to be deleted and allow_deletions=False this function will raise
`RuntimeError`.
Note: When this function is called a transaction must not be held open on
db. A transaction will be used internally. If you wish to perform
additional migration steps as part of a migration use DBMigrator directly.
Any internally generated rowid columns by SQLite may change values by this
migration.
"""
with DBMigrator(db, schema, allow_deletions) as migrator:
migrator.migrate()
return bool(migrator.n_changes)
class DBMigrator:
def __init__(self, db, schema, allow_deletions=False):
self.db = db
self.schema = schema
self.allow_deletions = allow_deletions
self.pristine = sqlite3.connect(":memory:")
self.pristine.executescript(schema)
self.n_changes = 0
self.orig_foreign_keys = None
def log_execute(self, msg, sql, args=None):
# It's important to log any changes we're making to the database for
# forensics later
msg_tmpl = "Database migration: %s with SQL:\n%s"
msg_argv = (msg, _left_pad(dedent(sql)))
if args:
msg_tmpl += " args = %r"
msg_argv += (args,)
else:
args = []
# Uncomment this to get debugging information
# logging.info(msg_tmpl, *msg_argv)
self.db.execute(sql, args)
self.n_changes += 1
def __enter__(self):
self.orig_foreign_keys = self.db.execute("PRAGMA foreign_keys").fetchone()[0]
if self.orig_foreign_keys:
self.log_execute(
"Disable foreign keys temporarily for migration",
"PRAGMA foreign_keys = OFF",
)
# This doesn't count as a change because we'll undo it at the end
self.n_changes = 0
self.db.__enter__()
self.db.execute("BEGIN")
return self
def __exit__(self, exc_type, exc_value, exc_tb):
self.db.__exit__(exc_type, exc_value, exc_tb)
if exc_value is None:
# The SQLite docs say:
#
# > This pragma is a no-op within a transaction; foreign key
# > constraint enforcement may only be enabled or disabled when
# > there is no pending BEGIN or SAVEPOINT.
old_changes = self.n_changes
new_val = self._migrate_pragma("foreign_keys")
if new_val == self.orig_foreign_keys:
self.n_changes = old_changes
# SQLite docs say:
#
# > A VACUUM will fail if there is an open transaction on the database
# > connection that is attempting to run the VACUUM.
if self.n_changes:
self.db.execute("VACUUM")
else:
if self.orig_foreign_keys:
self.log_execute(
"Re-enable foreign keys after migration", "PRAGMA foreign_keys = ON"
)
def migrate(self):
# In CI the database schema may be changing all the time. This checks
# the current db and if it doesn't match database.sql we will
# modify it so it does match where possible.
pristine_tables = dict(
self.pristine.execute(
"""\
SELECT name, sql FROM sqlite_master
WHERE type = \"table\" AND name != \"sqlite_sequence\""""
).fetchall()
)
pristine_indices = dict(
self.pristine.execute(
"""\
SELECT name, sql FROM sqlite_master
WHERE type = \"index\""""
).fetchall()
)
tables = dict(
self.db.execute(
"""\
SELECT name, sql FROM sqlite_master
WHERE type = \"table\" AND name != \"sqlite_sequence\""""
).fetchall()
)
new_tables = set(pristine_tables.keys()) - set(tables.keys())
removed_tables = set(tables.keys()) - set(pristine_tables.keys())
if removed_tables and not self.allow_deletions:
raise RuntimeError(
"Database migration: Refusing to delete tables %r" % removed_tables
)
modified_tables = set(
name
for name, sql in pristine_tables.items()
if normalise_sql(tables.get(name, "")) != normalise_sql(sql)
)
# This PRAGMA is automatically disabled when the db is committed
self.db.execute("PRAGMA defer_foreign_keys = TRUE")
# New and removed tables are easy:
for tbl_name in new_tables:
self.log_execute("Create table %s" % tbl_name, pristine_tables[tbl_name])
for tbl_name in removed_tables:
self.log_execute("Drop table %s" % tbl_name, "DROP TABLE %s" % tbl_name)
for tbl_name in modified_tables:
# The SQLite documentation insists that we create the new table and
# rename it over the old rather than moving the old out of the way
# and then creating the new
create_table_sql = pristine_tables[tbl_name]
create_table_sql = re.sub(
r"\b%s\b" % re.escape(tbl_name),
tbl_name + "_migration_new",
create_table_sql,
)
self.log_execute(
"Columns change: Create table %s with updated schema" % tbl_name,
create_table_sql,
)
cols = set(
[x[1] for x in self.db.execute("PRAGMA table_info(%s)" % tbl_name)]
)
pristine_cols = set(
[
x[1]
for x in self.pristine.execute("PRAGMA table_info(%s)" % tbl_name)
]
)
removed_columns = cols - pristine_cols
if not self.allow_deletions and removed_columns:
logging.warning(
"Database migration: Refusing to remove columns %r from "
"table %s. Current cols are %r attempting migration to %r",
removed_columns,
tbl_name,
cols,
pristine_cols,
)
raise RuntimeError(
"Database migration: Refusing to remove columns %r from "
"table %s" % (removed_columns, tbl_name)
)
logging.info("cols: %s, pristine_cols: %s", cols, pristine_cols)
self.log_execute(
"Migrate data for table %s" % tbl_name,
"""\
INSERT INTO {tbl_name}_migration_new ({common})
SELECT {common} FROM {tbl_name}""".format(
tbl_name=tbl_name,
common=", ".join(cols.intersection(pristine_cols)),
),
)
# Don't need the old table any more
self.log_execute(
"Drop old table %s now data has been migrated" % tbl_name,
"DROP TABLE %s" % tbl_name,
)
self.log_execute(
"Columns change: Move new table %s over old" % tbl_name,
"ALTER TABLE %s_migration_new RENAME TO %s" % (tbl_name, tbl_name),
)
# Migrate the indices
indices = dict(
self.db.execute(
"""\
SELECT name, sql FROM sqlite_master
WHERE type = \"index\""""
).fetchall()
)
for name in set(indices.keys()) - set(pristine_indices.keys()):
self.log_execute(
"Dropping obsolete index %s" % name, "DROP INDEX %s" % name
)
for name, sql in pristine_indices.items():
if name not in indices:
self.log_execute("Creating new index %s" % name, sql)
elif sql != indices[name]:
self.log_execute(
"Index %s changed: Dropping old version" % name,
"DROP INDEX %s" % name,
)
self.log_execute(
"Index %s changed: Creating updated version in its place" % name,
sql,
)
self._migrate_pragma("user_version")
if self.pristine.execute("PRAGMA foreign_keys").fetchone()[0]:
if self.db.execute("PRAGMA foreign_key_check").fetchall():
raise RuntimeError("Database migration: Would fail foreign_key_check")
def _migrate_pragma(self, pragma):
pristine_val = self.pristine.execute("PRAGMA %s" % pragma).fetchone()[0]
val = self.db.execute("PRAGMA %s" % pragma).fetchone()[0]
if val != pristine_val:
self.log_execute(
"Set %s to %i from %i" % (pragma, pristine_val, val),
"PRAGMA %s = %i" % (pragma, pristine_val),
)
return pristine_val
def _left_pad(text, indent=" "):
"""Maybe I can find a package in pypi for this?"""
return "\n".join(indent + line for line in text.split("\n"))
def normalise_sql(sql):
# Remove comments:
sql = re.sub(r"--[^\n]*\n", "", sql)
# Normalise whitespace:
sql = re.sub(r"\s+", " ", sql)
sql = re.sub(r" *([(),]) *", r"\1", sql)
# Remove unnecessary quotes
sql = re.sub(r'"(\w+)"', r"\1", sql)
return sql.strip()

View file

View file

@ -0,0 +1,79 @@
from typing import List
from uuid import UUID
from buzz.db.dao.transcription_dao import TranscriptionDAO
from buzz.db.dao.transcription_segment_dao import TranscriptionSegmentDAO
from buzz.db.entity.transcription_segment import TranscriptionSegment
from buzz.transcriber.transcriber import Segment
class TranscriptionService:
def __init__(
self,
transcription_dao: TranscriptionDAO,
transcription_segment_dao: TranscriptionSegmentDAO,
):
self.transcription_dao = transcription_dao
self.transcription_segment_dao = transcription_segment_dao
def create_transcription(self, task):
self.transcription_dao.create_transcription(task)
def copy_transcription(self, id: UUID) -> UUID:
return self.transcription_dao.copy_transcription(id)
def update_transcription_as_started(self, id: UUID):
self.transcription_dao.update_transcription_as_started(id)
def update_transcription_as_failed(self, id: UUID, error: str):
self.transcription_dao.update_transcription_as_failed(id, error)
def update_transcription_as_canceled(self, id: UUID):
self.transcription_dao.update_transcription_as_canceled(id)
def update_transcription_progress(self, id: UUID, progress: float):
self.transcription_dao.update_transcription_progress(id, progress)
def update_transcription_as_completed(self, id: UUID, segments: List[Segment]):
self.transcription_dao.update_transcription_as_completed(id)
for segment in segments:
self.transcription_segment_dao.insert(
TranscriptionSegment(
start_time=segment.start,
end_time=segment.end,
text=segment.text,
translation='',
transcription_id=str(id),
)
)
def update_transcription_file_and_name(self, id: UUID, file_path: str, name: str | None = None):
self.transcription_dao.update_transcription_file_and_name(id, file_path, name)
def update_transcription_name(self, id: UUID, name: str):
self.transcription_dao.update_transcription_name(id, name)
def update_transcription_notes(self, id: UUID, notes: str):
self.transcription_dao.update_transcription_notes(id, notes)
def reset_transcription_for_restart(self, id: UUID):
self.transcription_dao.reset_transcription_for_restart(id)
def replace_transcription_segments(self, id: UUID, segments: List[Segment]):
self.transcription_segment_dao.delete_segments(id)
for segment in segments:
self.transcription_segment_dao.insert(
TranscriptionSegment(
start_time=segment.start,
end_time=segment.end,
text=segment.text,
translation='',
transcription_id=str(id),
)
)
def get_transcription_segments(self, transcription_id: UUID):
return self.transcription_segment_dao.get_segments(transcription_id)
def update_segment_translation(self, segment_id: int, translation: str):
return self.transcription_segment_dao.update_segment_translation(segment_id, translation)

11
buzz/dialogs.py Normal file
View file

@ -0,0 +1,11 @@
from PyQt6.QtWidgets import QWidget, QMessageBox
def show_model_download_error_dialog(parent: QWidget, error: str):
message = (
parent.tr("An error occurred while loading the Whisper model")
+ f": {error}{'' if error.endswith('.') else '.'}"
+ parent.tr("Please retry or check the application logs for more information.")
)
QMessageBox.critical(parent, "", message)

View file

@ -0,0 +1,282 @@
import logging
import multiprocessing
import os
import queue
import ssl
import sys
from pathlib import Path
from typing import Optional, Tuple, List, Set
from uuid import UUID
# Fix SSL certificate verification for bundled applications (macOS, Windows)
# This must be done before importing demucs which uses torch.hub with urllib
try:
import certifi
os.environ.setdefault('REQUESTS_CA_BUNDLE', certifi.where())
os.environ.setdefault('SSL_CERT_FILE', certifi.where())
os.environ.setdefault('SSL_CERT_DIR', os.path.dirname(certifi.where()))
# Also update the default SSL context for urllib
ssl._create_default_https_context = lambda: ssl.create_default_context(cafile=certifi.where())
except ImportError:
pass
from PyQt6.QtCore import QObject, QThread, pyqtSignal, pyqtSlot, Qt
# Patch subprocess for demucs to prevent console windows on Windows
if sys.platform == "win32":
import subprocess
_original_run = subprocess.run
_original_check_output = subprocess.check_output
def _patched_run(*args, **kwargs):
if 'startupinfo' not in kwargs:
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
si.wShowWindow = subprocess.SW_HIDE
kwargs['startupinfo'] = si
if 'creationflags' not in kwargs:
kwargs['creationflags'] = subprocess.CREATE_NO_WINDOW
return _original_run(*args, **kwargs)
def _patched_check_output(*args, **kwargs):
if 'startupinfo' not in kwargs:
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
si.wShowWindow = subprocess.SW_HIDE
kwargs['startupinfo'] = si
if 'creationflags' not in kwargs:
kwargs['creationflags'] = subprocess.CREATE_NO_WINDOW
return _original_check_output(*args, **kwargs)
subprocess.run = _patched_run
subprocess.check_output = _patched_check_output
from demucs import api as demucsApi
from buzz.locale import _
from buzz.model_loader import ModelType
from buzz.transcriber.file_transcriber import FileTranscriber
from buzz.transcriber.openai_whisper_api_file_transcriber import (
OpenAIWhisperAPIFileTranscriber,
)
from buzz.transcriber.transcriber import FileTranscriptionTask, Segment
from buzz.transcriber.whisper_file_transcriber import WhisperFileTranscriber
class FileTranscriberQueueWorker(QObject):
tasks_queue: multiprocessing.Queue
current_task: Optional[FileTranscriptionTask] = None
current_transcriber: Optional[FileTranscriber] = None
current_transcriber_thread: Optional[QThread] = None
task_started = pyqtSignal(FileTranscriptionTask)
task_progress = pyqtSignal(FileTranscriptionTask, float)
task_download_progress = pyqtSignal(FileTranscriptionTask, float)
task_completed = pyqtSignal(FileTranscriptionTask, list)
task_error = pyqtSignal(FileTranscriptionTask, str)
completed = pyqtSignal()
trigger_run = pyqtSignal()
def __init__(self, parent: Optional[QObject] = None):
super().__init__(parent)
self.tasks_queue = queue.Queue()
self.canceled_tasks: Set[UUID] = set()
self.current_transcriber = None
self.speech_path = None
self.is_running = False
# Use QueuedConnection to ensure run() is called in the correct thread context
# and doesn't block signal handlers
self.trigger_run.connect(self.run, Qt.ConnectionType.QueuedConnection)
@pyqtSlot()
def run(self):
if self.is_running:
return
logging.debug("Waiting for next transcription task")
# Clean up of previous run.
if self.current_transcriber is not None:
self.current_transcriber.stop()
self.current_transcriber = None
# Get next non-canceled task from queue
while True:
self.current_task: Optional[FileTranscriptionTask] = self.tasks_queue.get()
# Stop listening when a "None" task is received
if self.current_task is None:
self.is_running = False
self.completed.emit()
return
if self.current_task.uid in self.canceled_tasks:
continue
break
# Set is_running AFTER we have a valid task to process
self.is_running = True
if self.current_task.transcription_options.extract_speech:
logging.debug("Will extract speech")
def separator_progress_callback(progress):
self.task_progress.emit(self.current_task, int(progress["segment_offset"] * 100) / int(progress["audio_length"] * 100))
separator = None
separated = None
try:
# Force CPU if specified, otherwise use CUDA if available
force_cpu = os.getenv("BUZZ_FORCE_CPU", "false").lower() == "true"
if force_cpu:
device = "cpu"
else:
import torch
device = "cuda" if torch.cuda.is_available() else "cpu"
separator = demucsApi.Separator(
device=device,
progress=True,
callback=separator_progress_callback,
)
_origin, separated = separator.separate_audio_file(Path(self.current_task.file_path))
task_file_path = Path(self.current_task.file_path)
self.speech_path = task_file_path.with_name(f"{task_file_path.stem}_speech.mp3")
demucsApi.save_audio(separated["vocals"], self.speech_path, separator.samplerate)
self.current_task.file_path = str(self.speech_path)
except Exception as e:
logging.error(f"Error during speech extraction: {e}", exc_info=True)
self.task_error.emit(
self.current_task,
_("Speech extraction failed! Check your internet connection — a model may need to be downloaded."),
)
self.is_running = False
return
finally:
# Release memory used by speech extractor
del separator, separated
try:
import torch
if torch.cuda.is_available():
torch.cuda.empty_cache()
except Exception:
pass
logging.debug("Starting next transcription task")
self.task_progress.emit(self.current_task, 0)
model_type = self.current_task.transcription_options.model.model_type
if model_type == ModelType.OPEN_AI_WHISPER_API:
self.current_transcriber = OpenAIWhisperAPIFileTranscriber(
task=self.current_task
)
elif (
model_type == ModelType.WHISPER_CPP
or model_type == ModelType.HUGGING_FACE
or model_type == ModelType.WHISPER
or model_type == ModelType.FASTER_WHISPER
):
self.current_transcriber = WhisperFileTranscriber(task=self.current_task)
else:
raise Exception(f"Unknown model type: {model_type}")
self.current_transcriber_thread = QThread(self)
self.current_transcriber.moveToThread(self.current_transcriber_thread)
self.current_transcriber_thread.started.connect(self.current_transcriber.run)
self.current_transcriber.completed.connect(self.current_transcriber_thread.quit)
self.current_transcriber.error.connect(self.current_transcriber_thread.quit)
self.current_transcriber.completed.connect(self.current_transcriber.deleteLater)
self.current_transcriber.error.connect(self.current_transcriber.deleteLater)
self.current_transcriber_thread.finished.connect(
self.current_transcriber_thread.deleteLater
)
self.current_transcriber.progress.connect(self.on_task_progress)
self.current_transcriber.download_progress.connect(
self.on_task_download_progress
)
self.current_transcriber.error.connect(self.on_task_error)
self.current_transcriber.completed.connect(self.on_task_completed)
# Wait for next item on the queue
self.current_transcriber.error.connect(lambda: self._on_task_finished())
self.current_transcriber.completed.connect(lambda: self._on_task_finished())
self.task_started.emit(self.current_task)
self.current_transcriber_thread.start()
def _on_task_finished(self):
"""Called when a task completes or errors, resets state and triggers next run"""
self.is_running = False
# Use signal to avoid blocking in signal handler context
self.trigger_run.emit()
def add_task(self, task: FileTranscriptionTask):
# Remove from canceled tasks if it was previously canceled (for restart functionality)
if task.uid in self.canceled_tasks:
self.canceled_tasks.remove(task.uid)
self.tasks_queue.put(task)
# If the worker is not currently running, trigger it to start processing
# Use signal to avoid blocking the main thread
if not self.is_running:
self.trigger_run.emit()
def cancel_task(self, task_id: UUID):
self.canceled_tasks.add(task_id)
if self.current_task is not None and self.current_task.uid == task_id:
if self.current_transcriber is not None:
self.current_transcriber.stop()
if self.current_transcriber_thread is not None:
if not self.current_transcriber_thread.wait(5000):
logging.warning("Transcriber thread did not terminate gracefully")
self.current_transcriber_thread.terminate()
def on_task_error(self, error: str):
if (
self.current_task is not None
and self.current_task.uid not in self.canceled_tasks
):
# Check if the error indicates cancellation
if "canceled" in error.lower() or "cancelled" in error.lower():
self.current_task.status = FileTranscriptionTask.Status.CANCELED
self.current_task.error = error
else:
self.current_task.status = FileTranscriptionTask.Status.FAILED
self.current_task.error = error
self.task_error.emit(self.current_task, error)
@pyqtSlot(tuple)
def on_task_progress(self, progress: Tuple[int, int]):
if self.current_task is not None:
self.task_progress.emit(self.current_task, progress[0] / progress[1])
def on_task_download_progress(self, fraction_downloaded: float):
if self.current_task is not None:
self.task_download_progress.emit(self.current_task, fraction_downloaded)
@pyqtSlot(list)
def on_task_completed(self, segments: List[Segment]):
if self.current_task is not None:
self.task_completed.emit(self.current_task, segments)
if self.speech_path is not None:
try:
Path(self.speech_path).unlink()
except Exception:
pass
self.speech_path = None
def stop(self):
self.tasks_queue.put(None)
if self.current_transcriber is not None:
self.current_transcriber.stop()

23
buzz/locale.py Normal file
View file

@ -0,0 +1,23 @@
import os
import logging
import gettext
from PyQt6.QtCore import QLocale
from buzz.assets import get_path
from buzz.settings.settings import APP_NAME, Settings
locale_dir = get_path("locale")
gettext.bindtextdomain("buzz", locale_dir)
settings = Settings()
languages = [
settings.value(settings.Key.UI_LOCALE, QLocale().name())
]
translate = gettext.translation(
APP_NAME.lower(), locale_dir, languages=languages, fallback=True
)
_ = translate.gettext

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

1009
buzz/model_loader.py Normal file

File diff suppressed because it is too large Load diff

5
buzz/paths.py Normal file
View file

@ -0,0 +1,5 @@
import os
def file_path_as_title(file_path: str):
return os.path.basename(file_path)

56
buzz/recording.py Normal file
View file

@ -0,0 +1,56 @@
from typing import Optional
import logging
import numpy as np
import sounddevice
from PyQt6.QtCore import QObject, pyqtSignal
class RecordingAmplitudeListener(QObject):
stream: Optional[sounddevice.InputStream] = None
amplitude_changed = pyqtSignal(float)
average_amplitude_changed = pyqtSignal(float)
ACCUMULATION_SECONDS = 1
def __init__(
self,
input_device_index: Optional[int] = None,
parent: Optional[QObject] = None,
):
super().__init__(parent)
self.input_device_index = input_device_index
self.buffer = np.ndarray([], dtype=np.float32)
self.accumulation_size = 0
self._active = True
def start_recording(self):
try:
self.stream = sounddevice.InputStream(
device=self.input_device_index,
dtype="float32",
channels=1,
callback=self.stream_callback,
)
self.stream.start()
self.accumulation_size = int(self.stream.samplerate * self.ACCUMULATION_SECONDS)
except Exception as e:
self.stop_recording()
logging.exception("Failed to start audio stream on device %s: %s", self.input_device_index, e)
def stop_recording(self):
self._active = False
if self.stream is not None:
self.stream.stop()
self.stream.close()
def stream_callback(self, in_data: np.ndarray, frame_count, time_info, status):
if not self._active:
return
chunk = in_data.ravel()
self.amplitude_changed.emit(float(np.sqrt(np.mean(chunk**2))))
self.buffer = np.append(self.buffer, chunk)
if self.buffer.size >= self.accumulation_size:
self.average_amplitude_changed.emit(float(np.sqrt(np.mean(self.buffer**2))))
self.buffer = np.ndarray([], dtype=np.float32)

34
buzz/schema.sql Normal file
View file

@ -0,0 +1,34 @@
CREATE TABLE transcription (
id TEXT PRIMARY KEY,
error_message TEXT,
export_formats TEXT,
file TEXT,
output_folder TEXT,
progress DOUBLE PRECISION DEFAULT 0.0,
language TEXT,
model_type TEXT,
source TEXT,
status TEXT,
task TEXT,
time_ended TIMESTAMP,
time_queued TIMESTAMP NOT NULL,
time_started TIMESTAMP,
url TEXT,
whisper_model_size TEXT,
hugging_face_model_id TEXT,
word_level_timings BOOLEAN DEFAULT FALSE,
extract_speech BOOLEAN DEFAULT FALSE,
name TEXT,
notes TEXT
);
CREATE TABLE transcription_segment (
id INTEGER PRIMARY KEY,
end_time INT DEFAULT 0,
start_time INT DEFAULT 0,
text TEXT NOT NULL,
translation TEXT DEFAULT '',
transcription_id TEXT,
FOREIGN KEY (transcription_id) REFERENCES transcription(id) ON DELETE CASCADE
);
CREATE INDEX idx_transcription_id ON transcription_segment(transcription_id);

View file

View file

@ -0,0 +1,7 @@
from enum import Enum
from buzz.locale import _
class RecordingTranscriberMode(Enum):
APPEND_BELOW = _("Append below")
APPEND_ABOVE = _("Append above")
APPEND_AND_CORRECT = _("Append and correct")

165
buzz/settings/settings.py Normal file
View file

@ -0,0 +1,165 @@
import enum
import typing
import logging
import uuid
from PyQt6.QtCore import QSettings
APP_NAME = "Buzz"
class Settings:
def __init__(self, application=""):
self.settings = QSettings(APP_NAME, application)
self.settings.sync()
class Key(enum.Enum):
RECORDING_TRANSCRIBER_TASK = "recording-transcriber/task"
RECORDING_TRANSCRIBER_MODEL = "recording-transcriber/model"
RECORDING_TRANSCRIBER_LANGUAGE = "recording-transcriber/language"
RECORDING_TRANSCRIBER_INITIAL_PROMPT = "recording-transcriber/initial-prompt"
RECORDING_TRANSCRIBER_ENABLE_LLM_TRANSLATION = "recording-transcriber/enable-llm-translation"
RECORDING_TRANSCRIBER_LLM_MODEL = "recording-transcriber/llm-model"
RECORDING_TRANSCRIBER_LLM_PROMPT = "recording-transcriber/llm-prompt"
RECORDING_TRANSCRIBER_EXPORT_ENABLED = "recording-transcriber/export-enabled"
RECORDING_TRANSCRIBER_EXPORT_FOLDER = "recording-transcriber/export-folder"
RECORDING_TRANSCRIBER_MODE = "recording-transcriber/mode"
RECORDING_TRANSCRIBER_SILENCE_THRESHOLD = "recording-transcriber/silence-threshold"
RECORDING_TRANSCRIBER_LINE_SEPARATOR = "recording-transcriber/line-separator"
RECORDING_TRANSCRIBER_TRANSCRIPTION_STEP = "recording-transcriber/transcription-step"
RECORDING_TRANSCRIBER_EXPORT_FILE_TYPE = "recording-transcriber/export-file-type"
RECORDING_TRANSCRIBER_EXPORT_MAX_ENTRIES = "recording-transcriber/export-max-entries"
RECORDING_TRANSCRIBER_EXPORT_FILE_NAME = "recording-transcriber/export-file-name"
RECORDING_TRANSCRIBER_HIDE_UNCONFIRMED = "recording-transcriber/hide-unconfirmed"
PRESENTATION_WINDOW_TEXT_COLOR = "presentation-window/text-color"
PRESENTATION_WINDOW_BACKGROUND_COLOR = "presentation-window/background-color"
PRESENTATION_WINDOW_TEXT_SIZE = "presentation-window/text-size"
PRESENTATION_WINDOW_THEME = "presentation-window/theme"
FILE_TRANSCRIBER_TASK = "file-transcriber/task"
FILE_TRANSCRIBER_MODEL = "file-transcriber/model"
FILE_TRANSCRIBER_LANGUAGE = "file-transcriber/language"
FILE_TRANSCRIBER_INITIAL_PROMPT = "file-transcriber/initial-prompt"
FILE_TRANSCRIBER_ENABLE_LLM_TRANSLATION = "file-transcriber/enable-llm-translation"
FILE_TRANSCRIBER_LLM_MODEL = "file-transcriber/llm-model"
FILE_TRANSCRIBER_LLM_PROMPT = "file-transcriber/llm-prompt"
FILE_TRANSCRIBER_WORD_LEVEL_TIMINGS = "file-transcriber/word-level-timings"
FILE_TRANSCRIBER_EXPORT_FORMATS = "file-transcriber/export-formats"
DEFAULT_EXPORT_FILE_NAME = "transcriber/default-export-file-name"
CUSTOM_OPENAI_BASE_URL = "transcriber/custom-openai-base-url"
OPENAI_API_MODEL = "transcriber/openai-api-model"
CUSTOM_FASTER_WHISPER_ID = "transcriber/custom-faster-whisper-id"
HUGGINGFACE_MODEL_ID = "transcriber/huggingface-model-id"
SHORTCUTS = "shortcuts"
FONT_SIZE = "font-size"
UI_LOCALE = "ui-locale"
USER_IDENTIFIER = "user-identifier"
TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY = (
"transcription-tasks-table/column-visibility"
)
TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER = (
"transcription-tasks-table/column-order"
)
TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS = (
"transcription-tasks-table/column-widths"
)
TRANSCRIPTION_TASKS_TABLE_SORT_STATE = (
"transcription-tasks-table/sort-state"
)
MAIN_WINDOW = "main-window"
TRANSCRIPTION_VIEWER = "transcription-viewer"
AUDIO_PLAYBACK_RATE = "audio/playback-rate"
FORCE_CPU = "force-cpu"
REDUCE_GPU_MEMORY = "reduce-gpu-memory"
LAST_UPDATE_CHECK = "update/last-check"
UPDATE_AVAILABLE_VERSION = "update/available-version"
def get_user_identifier(self) -> str:
user_id = self.value(self.Key.USER_IDENTIFIER, "")
if not user_id:
user_id = str(uuid.uuid4())
self.set_value(self.Key.USER_IDENTIFIER, user_id)
return user_id
def set_value(self, key: Key, value: typing.Any) -> None:
self.settings.setValue(key.value, value)
def save_custom_model_id(self, model) -> None:
from buzz.model_loader import ModelType
match model.model_type:
case ModelType.FASTER_WHISPER:
self.set_value(
Settings.Key.CUSTOM_FASTER_WHISPER_ID,
model.hugging_face_model_id,
)
case ModelType.HUGGING_FACE:
self.set_value(
Settings.Key.HUGGINGFACE_MODEL_ID,
model.hugging_face_model_id,
)
def load_custom_model_id(self, model) -> str:
from buzz.model_loader import ModelType
match model.model_type:
case ModelType.FASTER_WHISPER:
return self.value(
Settings.Key.CUSTOM_FASTER_WHISPER_ID,
"",
)
case ModelType.HUGGING_FACE:
return self.value(
Settings.Key.HUGGINGFACE_MODEL_ID,
"",
)
return ""
def value(
self,
key: Key,
default_value: typing.Any,
value_type: typing.Optional[type] = None,
) -> typing.Any:
val = self.settings.value(
key.value,
default_value,
value_type if value_type is not None else type(default_value),
)
if (value_type is bool or isinstance(default_value, bool)):
if isinstance(val, bool):
return val
if isinstance(val, str):
return val.lower() in ("true", "1", "yes", "on")
if isinstance(val, int):
return val != 0
return bool(val)
return val
def clear(self):
self.settings.clear()
def begin_group(self, group: Key) -> None:
self.settings.beginGroup(group.value)
def end_group(self) -> None:
self.settings.endGroup()
def sync(self):
self.settings.sync()
def get_default_export_file_template(self) -> str:
return self.value(
Settings.Key.DEFAULT_EXPORT_FILE_NAME,
"{{ input_file_name }} ({{ task }}d on {{ date_time }})",
)

Some files were not shown because too many files have changed in this diff Show more