Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: CI

on:
push:
branches: [main]
branches: [main, "agent/**"]
pull_request:
branches: [main]

Expand All @@ -20,7 +20,8 @@ jobs:
- name: Validate scripts
run: |
zsh -n scripts/*.sh Resources/install_runtime.sh
python3 -m py_compile worker/asr_worker.py worker/text_worker.py scripts/collect_github_stats.py
python3 -m py_compile worker/asr_worker.py worker/media_worker.py worker/text_worker.py scripts/collect_github_stats.py
python3 -m unittest discover -s tests -v
VOICESWITCH_SETUP_VALIDATE_ONLY=1 \
Resources/install_runtime.sh \
"$RUNNER_TEMP/VoiceSwitch-Runtime" \
Expand All @@ -47,6 +48,17 @@ jobs:
printf '%s\n' "$output" | grep -q '__VOICESWITCH_SETUP_ERROR__'
grep -q 'Устанавливаю изолированный Python 3.12' "$runtime_root/install.log"

- name: Validate clean GigaAM dependency install
run: |
VOICESWITCH_SETUP_DEPENDENCIES_ONLY=1 \
VOICESWITCH_RETRY_DELAY_SECONDS=0 \
Resources/install_runtime.sh \
"$RUNNER_TEMP/VoiceSwitch-GigaAM-Dependencies" \
worker/asr_worker.py \
worker/text_worker.py \
gigaam
test ! -f "$RUNNER_TEMP/VoiceSwitch-GigaAM-Dependencies/install-complete.txt"

- name: Build VoiceSwitch
run: swift build -c release

Expand All @@ -56,3 +68,25 @@ jobs:
./scripts/build_app.sh "$RUNNER_TEMP/VoiceSwitch"
codesign --verify --deep --strict "$RUNNER_TEMP/VoiceSwitch/VoiceSwitch.app"
plutil -lint "$RUNNER_TEMP/VoiceSwitch/VoiceSwitch.app/Contents/Info.plist"
test -f "$RUNNER_TEMP/VoiceSwitch/VoiceSwitch.app/Contents/Resources/media_worker.py"

- name: Package pull request test build
if: github.event_name == 'pull_request'
run: |
ditto -c -k --sequesterRsrc --keepParent \
"$RUNNER_TEMP/VoiceSwitch/VoiceSwitch.app" \
"$RUNNER_TEMP/VoiceSwitch-v0.4.0-beta-test.zip"
cd "$RUNNER_TEMP"
shasum -a 256 VoiceSwitch-v0.4.0-beta-test.zip \
> VoiceSwitch-v0.4.0-beta-test.zip.sha256

- name: Upload pull request test build
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v7
with:
name: VoiceSwitch-v0.4.0-beta-macos-arm64-test
path: |
${{ runner.temp }}/VoiceSwitch-v0.4.0-beta-test.zip
${{ runner.temp }}/VoiceSwitch-v0.4.0-beta-test.zip.sha256
if-no-files-found: error
retention-days: 7
20 changes: 20 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,30 @@ jobs:
- name: Checkout
uses: actions/checkout@v7

- name: Validate release source
run: |
zsh -n scripts/*.sh Resources/install_runtime.sh
python3 -m py_compile worker/asr_worker.py worker/media_worker.py worker/text_worker.py
python3 -m unittest discover -s tests -v
bundle_version=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' Resources/Info.plist)
tag_version="${GITHUB_REF_NAME#v}"
test "$bundle_version" = "${tag_version%%-*}"

- name: Validate clean GigaAM dependency install
run: |
VOICESWITCH_SETUP_DEPENDENCIES_ONLY=1 \
VOICESWITCH_RETRY_DELAY_SECONDS=0 \
Resources/install_runtime.sh \
"$RUNNER_TEMP/VoiceSwitch-GigaAM-Dependencies" \
worker/asr_worker.py \
worker/text_worker.py \
gigaam

- name: Build release archive
run: |
chmod +x scripts/*.sh Resources/install_runtime.sh
./scripts/package_release.sh "${GITHUB_REF_NAME#v}"
test -f "dist/VoiceSwitch-${GITHUB_REF_NAME#v}-macos-arm64/VoiceSwitch.app/Contents/Resources/media_worker.py"

- name: Publish GitHub release
env:
Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
```zsh
swift build
zsh -n scripts/*.sh Resources/install_runtime.sh
python3 -m py_compile worker/asr_worker.py worker/text_worker.py scripts/collect_github_stats.py
python3 -m py_compile worker/asr_worker.py worker/media_worker.py worker/text_worker.py scripts/collect_github_stats.py
python3 -m unittest discover -s tests -v
```

Для изменения распознавания желательно приложить обезличенный набор тестовых
Expand Down
26 changes: 25 additions & 1 deletion INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ Mac. Вернитесь в VoiceSwitch и нажмите **Проверить с
буфере обмена, поэтому при проблеме его можно вставить вручную через
`Command + V`.

### 7. Проверка аудио или видео

1. В меню VoiceSwitch переключите **Диктовка** на **Файл**.
2. Оставьте GigaAM либо выберите установленный Whisper/Qwen.
3. Нажмите **Выбрать аудио или видео…** и укажите локальный файл.
4. После завершения нажмите **Показать файлы**.

VoiceSwitch распознаёт только аудиодорожку и сохраняет `transcript.txt`,
`transcript.srt`, `transcript.vtt` и `transcript.json` в локальной папке
Application Support. Кадры видео не анализируются. Метки SRT/VTT приблизительные:
это границы блоков распознавания, а не точное время каждого слова.

Если остановить длинную задачу, уже завершённые блоки останутся в checkpoint.
Повторно выберите тот же неизменённый файл, тот же движок и контекст, чтобы
продолжить. Apple SpeechAnalyzer в файловом режиме пока недоступен.

### Если загрузка моделей прервалась

Не удаляйте папку Runtime. Нажмите **Продолжить установку** в меню
Expand Down Expand Up @@ -157,13 +173,21 @@ tccutil reset Accessibility io.github.mitimaicode.VoiceSwitch
~/Library/Application Support/VoiceSwitch
```

Готовые расшифровки файлов находятся в подпапке `Transcripts`. VoiceSwitch
удаляет временный нормализованный WAV, но сохраняет TXT/SRT/VTT/JSON и
checkpoint для продолжения. Удалить конкретную расшифровку можно обычным
удалением её папки через Finder.

Чтобы полностью удалить VoiceSwitch, удалите приложение и эту папку. Записи
речи не архивируются: временный WAV удаляется после распознавания.
диктовки не архивируются: временный WAV удаляется после распознавания.

## Известные ограничения beta

- только Apple Silicon и macOS 14+;
- Apple SpeechAnalyzer доступен только на macOS 26+;
- импорт видео распознаёт только аудиодорожку и не захватывает системный звук;
- SRT/VTT используют примерные границы блоков, без word-level timestamps;
- файловый режим поддерживает GigaAM, Whisper и Qwen, но пока не Apple;
- рекомендуемая установка требует около 2,5 ГБ; полный комплект — около 10 ГБ;
- приложение пока не подписано сертификатом Apple Developer ID;
- автоматическое обновление ещё не реализовано.
Expand Down
49 changes: 41 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
<img src="assets/banner.svg" alt="VoiceSwitch — локальная диктовка для macOS" width="100%">
</p>

> Локальная диктовка и редактура текста для macOS.
> Локальная диктовка и расшифровка аудио/видео для macOS.

[![CI](https://github.com/mitimaicode/VoiceSwitch/actions/workflows/ci.yml/badge.svg)](https://github.com/mitimaicode/VoiceSwitch/actions/workflows/ci.yml)
[![Latest release](https://img.shields.io/github/v/release/mitimaicode/VoiceSwitch?include_prereleases)](https://github.com/mitimaicode/VoiceSwitch/releases)
[![Downloads](https://img.shields.io/github/downloads/mitimaicode/VoiceSwitch/total)](https://github.com/mitimaicode/VoiceSwitch/releases)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

VoiceSwitch записывает речь по глобальной горячей клавише, распознаёт её
полностью локально и вставляет текст в активное приложение.
полностью локально и вставляет текст в активное приложение. Отдельный режим
«Файл» расшифровывает аудиодорожку локального аудио или видео, умеет продолжить
прерванную задачу и сохраняет TXT, SRT, VTT и JSON.

<p align="center">
<a href="assets/voiceswitch-demo.mp4">
Expand All @@ -31,6 +33,8 @@ VoiceSwitch записывает речь по глобальной горяче
- **Qwen3-4B (MLX)** — локально исправляет или сокращает расшифровку;
- режимы текста **Дословно**, **Исправить** и **Кратко**;
- `fn + ⌥ Option` — начать или остановить запись;
- локальный импорт аудио и видео с прогрессом, отменой и продолжением;
- экспорт TXT, SRT, VTT и JSON; временные метки субтитров — по минутным блокам;
- HUD показывает запись, расшифровку, локальную редактуру и результат;
- аудио и текст не отправляются во внешние API;
- журнал сравнения помогает выбрать модель под собственную речь.
Expand Down Expand Up @@ -88,6 +92,8 @@ VoiceSwitch записывает речь по глобальной горяче

## Использование

### Диктовка

1. Выберите GigaAM, Whisper, Qwen или Apple в меню VoiceSwitch.
2. Выберите режим текста: **Дословно**, **Исправить** или **Кратко**.
3. Нажмите `fn + ⌥ Option`, чтобы начать запись.
Expand All @@ -106,6 +112,25 @@ VoiceSwitch записывает речь по глобальной горяче
компактное сообщение для переписки. Если редактор вернёт ошибку, VoiceSwitch
автоматически вставит исходную расшифровку.

### Аудио и видеофайлы

1. Переключите источник с **Диктовка** на **Файл**.
2. Выберите GigaAM, Whisper или Qwen и нажмите **Выбрать аудио или видео…**.
3. Дождитесь завершения либо остановите задачу. При повторном выборе того же
неизменённого файла VoiceSwitch продолжит с сохранённого блока.
4. Нажмите **Показать файлы**, чтобы открыть TXT, SRT, VTT и JSON, или
**Скопировать текст**.

VoiceSwitch извлекает и распознаёт только звуковую дорожку: кадры видео не
анализируются. Длинный материал делится на блоки по 60 секунд с перекрытием
1,5 секунды; повторяющиеся слова на стыках удаляются. Поэтому метки SRT/VTT
показывают примерные границы блоков, а не точное время каждого слова.

Файловый режим пока не использует Apple SpeechAnalyzer и не применяет режимы
«Исправить»/«Кратко»: изменение длинного текста нарушило бы соответствие
субтитрам. Обработка выполняется последовательно, чтобы не держать две копии
тяжёлой модели в памяти.

Модель загружается лениво. Если выбранный движок ещё не установлен,
VoiceSwitch покажет его размер и предложит загрузить только этот компонент.
При переключении предыдущая загруженная модель
Expand All @@ -126,6 +151,12 @@ Runtime и веса моделей:
~/Library/Application Support/VoiceSwitch/comparison.jsonl
```

Расшифровки импортированных файлов:

```text
~/Library/Application Support/VoiceSwitch/Transcripts
```

В журнале сохраняются модель, длительность записи, время распознавания, RTF,
определённый язык, исходная расшифровка, результат локальной редактуры, её
режим и ваша оценка. Журнал остаётся на Mac. Временные аудиофайлы удаляются
Expand Down Expand Up @@ -187,7 +218,7 @@ chmod +x scripts/*.sh Resources/install_runtime.sh
Создание компактного release-архива без весов моделей:

```zsh
./scripts/package_release.sh 0.3.3-beta
./scripts/package_release.sh 0.4.0-beta
```

Публичный release-скрипт по умолчанию использует ad-hoc подпись. Для стабильной
Expand Down Expand Up @@ -229,11 +260,13 @@ VoiceSwitch не связан с авторами перечисленных п
<details>
<summary>English summary</summary>

VoiceSwitch is a local macOS dictation menu-bar app for Apple Silicon. It
switches between GigaAM, Whisper Large V3 Turbo, Qwen3-ASR 1.7B, and Apple
SpeechAnalyzer. A local Qwen3-4B model can clean up or shorten the transcript.
Press `fn + Option` to start or stop recording. Audio and transcripts stay on
the Mac. Apple SpeechAnalyzer requires macOS 26 or newer.
VoiceSwitch is a local macOS dictation and media-transcription menu-bar app for
Apple Silicon. It switches between GigaAM, Whisper Large V3 Turbo, Qwen3-ASR
1.7B, and Apple SpeechAnalyzer. Press `fn + Option` to dictate, or import a
local audio/video file and export TXT, SRT, VTT, and JSON. Video import
transcribes the audio track only; subtitle timestamps are coarse chunk
boundaries. Audio and transcripts stay on the Mac. Apple SpeechAnalyzer
requires macOS 26 or newer and is currently limited to dictation mode.
See [INSTALL.md](INSTALL.md) for installation details and use GitHub Issues or
Discussions for feedback.

Expand Down
48 changes: 48 additions & 0 deletions RELEASE_NOTES_v0.4.0-beta.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# VoiceSwitch v0.4.0-beta

Локальная расшифровка теперь работает не только с микрофоном, но и с аудио-
или видеофайлами. VoiceSwitch извлекает звуковую дорожку на Mac, обрабатывает
длинный материал частями и сохраняет результат без отправки во внешние API.

## Что нового

- Новый источник **Файл** рядом с обычной диктовкой.
- Импорт локального аудио или видео для GigaAM, Whisper и Qwen3-ASR.
- Обработка блоками по 60 секунд с перекрытием 1,5 секунды и удалением
повторяющихся слов на стыках.
- Видимый прогресс и безопасная остановка длинной задачи.
- Атомарный checkpoint после каждого блока: повторный выбор того же файла,
движка и контекста продолжает незавершённую работу.
- Локальный экспорт `transcript.txt`, `transcript.srt`, `transcript.vtt` и
`transcript.json`.
- Файловая задача запускается отдельно от worker диктовки, чтобы освободить
память перед загрузкой большой модели.
- Исправлена чистая установка GigaAM из
[issue #6](https://github.com/mitimaicode/VoiceSwitch/issues/6): `torch` и
`torchaudio` теперь устанавливаются явно в проверенных версиях.
- CI проверяет алгоритм блоков, дедупликацию, checkpoint, экспорт и выполняет
чистую установку/import зависимостей GigaAM без загрузки веса модели;
release workflow повторяет эти проверки до сборки файлов.

## Важные ограничения

- Из видео распознаётся только аудиодорожка. VoiceSwitch не анализирует кадры
и не захватывает системный звук.
- Временные метки SRT/VTT соответствуют примерным границам блоков, а не
отдельным словам.
- Apple SpeechAnalyzer пока работает только в режиме диктовки.
- Режимы «Исправить» и «Кратко» не применяются к файловой расшифровке, чтобы
текст не расходился с субтитрами.
- Это beta для Apple Silicon и macOS 14+. Публичная сборка подписана ad-hoc и
не нотарифицирована Apple.

## Обновление

Завершите VoiceSwitch, перенесите новую версию из DMG в «Программы» с заменой
и откройте её через правый клик → **Открыть**. Runtime v4, модели, настройки и
старый журнал остаются в `~/Library/Application Support/VoiceSwitch`, поэтому
повторная загрузка работающих моделей не требуется.

Если прежняя установка GigaAM остановилась на ошибке `No module named
'torch'`, нажмите **Продолжить установку** — новый установщик восстановит
окружение и использует уже загруженные данные.
4 changes: 2 additions & 2 deletions Resources/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.3.3</string>
<string>0.4.0</string>
<key>CFBundleVersion</key>
<string>12</string>
<string>13</string>
<key>LSMinimumSystemVersion</key>
<string>14.0</string>
<key>LSUIElement</key>
Expand Down
Loading