Локальный аналог Wispr Flow на Mac: меню-бар приложение с Whisper | AiManual
AiManual Logo Ai / Manual.
28 Янв 2026 Инструмент

Как создать локальный аналог Wispr Flow: меню-бар приложение для транскрипции на Mac с Whisper

Создайте свое меню-бар приложение для транскрипции аудио на Mac с WhisperKit и CoreML. Полностью офлайн, бесплатно и с уважением к приватности.

Зачем вообще это нужно? (И почему Wispr Flow иногда бесит)

Wispr Flow – отличная штука. Но он облачный. Это значит, что каждый ваш разговор летит куда-то на сервер, жрет токены, а если интернет упал – вы в ауте. На Mac с Neural Engine это вообще кощунство. Зачем платить и ждать, когда можно все делать локально, быстрее и без слежки?

Я собрал свой меню-бар апп за выходные. Работает офлайн, вставляет текст куда угодно по хоткею, и не просит ни копейки. Вот как.

Что будем использовать в 2026 году

Все уже придумано до нас. Главное – выбрать актуальные инструменты.

  • WhisperKit 5.3 – последняя стабильная версия на январь 2026. Поддерживает Whisper v4 Large, оптимизирована под CoreML и Neural Engine. Берет аудио с микрофона в реальном времени.
  • Xcode 18 – потому что без него на Mac никуда. Swift 6.2 уже умеет в concurrency без боли.
  • CoreML 7 – фреймворк для запуска моделей на Apple Silicon. WhisperKit конвертирует модель в .mlpackage, который летает на Neural Engine.
  • SwiftUI для меню-бара – да, теперь можно делать меню-бар приложения на SwiftUI без костылей. Спасибо Apple.
💡
Если вы не хотите собирать все с нуля, посмотрите сравнение локальных STT-решений. Но для меню-бара на Mac WhisperKit – король.

1Ставим WhisperKit и качаем модель

Открываем терминал. Не пугайтесь.

git clone https://github.com/argmaxinc/WhisperKit.git
cd WhisperKit
swift package update

Модели Whisper лежат на Hugging Face. Но WhisperKit умеет качать их сам. Выбираем версию – для баланса скорости и точности я взял whisper-large-v4. Но если у вас MacBook Air с базовым M3, возможно, стоит взять whisper-medium.

# Внутри проекта Swift, но проще через Python-скрипт, который идет в WhisperKit
python scripts/download_models.py --model large-v4 --quantization int8

Инт8 квантование – чтобы модель заняла меньше памяти и работала быстрее. Точность почти не страдает.

Внимание: большая модель займет около 3 ГБ. Убедитесь, что есть место. Если нет, используйте medium или small.

2Создаем проект меню-бара в Xcode

Запускаем Xcode. Новый проект → macOS → App. Выбираем SwiftUI. Называем, например, LocalWispr.

Добавляем пакет WhisperKit как зависимость: File → Add Packages → вставляем URL репозитория.

Теперь самое важное: меню-бар. В SwiftUI это делается через MenuBarExtra. Открываем LocalWisprApp.swift и пишем:

import SwiftUI

@main
struct LocalWisprApp: App {
    var body: some Scene {
        MenuBarExtra("LocalWispr", systemImage: "mic.fill") {
            ContentView()
        }
        .menuBarExtraStyle(.window)
    }
}

Да, вот так просто. ContentView – ваше меню, которое выпадает при клике на иконку в меню-баре.

3Подключаем Whisper и записываем аудио

В ContentView нужно добавить кнопку для старта записи и отображения текста. Но сначала импортируем WhisperKit и AVFoundation для аудио.

Создаем класс-менеджер, который будет управлять записью и транскрипцией. Вот упрощенная версия:

import WhisperKit
import AVFoundation

class TranscriptionManager: ObservableObject {
    @Published var transcribedText = ""
    private var whisper: WhisperKit?
    private var audioEngine = AVAudioEngine()
    
    init() {
        setupWhisper()
    }
    
    func setupWhisper() {
        Task {
            do {
                // Указываем путь к модели, которую скачали
                let modelPath = "/path/to/whisper-large-v4-int8.mlpackage"
                whisper = try await WhisperKit(
                    modelPath: modelPath,
                    computeUnits: .cpuAndNeuralEngine
                )
            } catch {
                print("Ошибка инициализации Whisper: \(error)")
            }
        }
    }
    
    func startRecording() {
        // Настраиваем аудиосессию и запись
        let inputNode = audioEngine.inputNode
        let recordingFormat = inputNode.outputFormat(forBus: 0)
        
        inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { buffer, time in
            // Здесь буфер аудио отправляем в Whisper
            self.processAudioBuffer(buffer)
        }
        
        audioEngine.prepare()
        try? audioEngine.start()
    }
    
    func stopRecording() {
        audioEngine.stop()
        audioEngine.inputNode.removeTap(onBus: 0)
        // Финализируем транскрипцию
        finalizeTranscription()
    }
    
    func processAudioBuffer(_ buffer: AVAudioPCMBuffer) {
        // Конвертируем аудио в формат, понятный Whisper
        // И отправляем в модель
        Task {
            if let whisper = self.whisper {
                let segments = try? await whisper.transcribe(audioArray: buffer.floatChannelData![0], sampleCount: Int(buffer.frameLength))
                if let text = segments?.first?.text {
                    DispatchQueue.main.async {
                        self.transcribedText += text + " "
                    }
                }
            }
        }
    }
    
    func finalizeTranscription() {
        // Можно добавить постобработку текста
    }
}

Это базовая реализация. В реальности нужно обрабатывать ошибки, управлять памятью, возможно, использовать буфер для накопления аудио.

💡
Если не хотите возиться с аудио-буферами, WhisperKit имеет встроенный рекордер. Но для меню-бара лучше контроль над записью.

4Добавляем глобальный хоткей и авто-вставку

Без хоткея приложение бесполезно. Нужно, чтобы можно было нажать, например, Cmd+Shift+Space и начать диктовать.

Используем Carbon или EventTap. Но в 2026 году есть более простой способ – через KeyboardShortcuts от Sindre Sorhus. Добавляем пакет.

import KeyboardShortcuts

KeyboardShortcuts.onKeyDown(for: .startRecording) {
    // Начать запись
    transcriptionManager.startRecording()
}

Определяем шорткат в настройках. Пользователь сможет сам назначить комбинацию.

Авто-вставка: после транскрипции нужно вставить текст в активное приложение. Используем Accessibility API. Добавляем в Info.plist разрешения.

import ApplicationServices

func pasteText(_ text: String) {
    let source = CGEventSource(stateID: .combinedSessionState)
    let pasteCommand = CGEvent(keyboardEventSource: source, virtualKey: 0x09, keyDown: true) // Cmd+V
    pasteCommand?.flags = .maskCommand
    pasteCommand?.post(tap: .cgAnnotatedSessionEventTap)
}

Но это хак. Лучше использовать AXUIElement для доступности. Однако для простоты можно скопировать текст в буфер обмена и вставить с помощью событий клавиатуры.

Предупреждение: Accessibility API требует, чтобы пользователь вручную дал разрешение приложению в настройках безопасности. Иначе не сработает.

5Собираем, тестируем, фиксим баги

Запускаем приложение. Иконка появляется в меню-баре. Нажимаем хоткей – говорим – отпускаем – текст появляется в буфере и вставляется.

Если что-то не работает, проверьте:

  • Разрешения на микрофон и доступность.
  • Модель загружена и находится по правильному пути.
  • Не забыли добавить фоновый режим в Capabilities.

Теперь сравним с альтернативами.

Чем это лучше или хуже Wispr Flow и других

ИнструментЛокальныйСкорость на M3 MaxТочностьЦена
Наше приложениеДа~0.7x реального времениКак у Whisper Large v4Бесплатно
Wispr FlowНетЗависит от интернетаВысокая (но модель неизвестна)Подписка
Whisper.cppДа~1.2x реального времениТочность оригиналаБесплатно
ScriberrДа~0.9x реального времениХорошаяБесплатно

Whisper.cpp – отличная вещь, но для меню-бара на Mac менее удобен, чем нативный Swift пакет. Scriberr – тоже хорош, но в 2026 году WhisperKit обгоняет по интеграции с CoreML.

Если вы не хотите собирать приложение сами, посмотрите обзор лучших AI-приложений для диктовки. Но там в основном облачные решения.

Кому это подойдет? (А кому нет)

Беритесь за этот проект, если:

  • У вас Mac на Apple Silicon (M1 или новее). Neural Engine ускорит транскрипцию в разы.
  • Вам надоело платить за токены или беспокоиться о конфиденциальности.
  • Хотите кастомные фичи: например, транскрипцию сразу в Markdown или интеграцию с локальной LLM.
  • Вы разработчик и готовы потратить пару дней на сборку.

Не стоит, если:

  • Вы не готовы к тому, что что-то сломается после обновления macOS. Локальные решения требуют поддержки.
  • Вам нужна транскрипция на лету с субтитрами – тогда смотрите Whisper.cpp в продакшене.
  • Вы хотите готовое решение без программирования – тогда EasyWhisperUI или TranscriptionSuite.

Для Windows-пользователей есть свои варианты, например, локальный диктофон для Windows.

А теперь – неочевидный совет. Если вы сделали это приложение, добавьте возможность выбора модели на лету. И сохраняйте историю транскрипций в SQLite. Потому что через месяц вы забудете, что диктовали, а это может быть важно.

Удачи. И помните: лучший инструмент – тот, который вы сделали сами под свои нужды.