Идея
Мы делаем приложение Memo: есть куча гаджетов и сервисов вроде Plaud — это когда ты платишь за отдельную «умную» коробочку-диктофон, которая записывает встречу и сама делает из неё протокол.
Зачем покупать отдельную железку, если в кармане уже есть iPhone? Давайте соберём такой же «умный протоколщик» прямо на телефоне.
записать встречу (с телефона или с Apple Watch);
распознать речь — превратить звук в текст (это задача распознавания, ASR);
обработать текст — сделать из расшифровки нормальный протокол: о чём договорились, какие задачи, кому что делать, плюс можно собрать письмо по итогам или свой запрос (задача на LLM);
сгруппировать встречи — свести несколько встреч в один блок и выгрузить в свой ChatGPT или Claude, чтобы получить как бы личную цифровую память по своим рабочим разговорам.
В этой статье расскажу про две самые интересные (и болезненные) части: распознавание речи и обработку. Будет две части:
Как мы работаем с чужими моделями (OpenAI, OpenRouter) и почему пока не переехали на Яндекс и Сбер.
Наш заход на распознавание прямо на телефоне — где всё оказалось не так, как написано в документации.

Если совсем коротко: нажал «Запись» → приложение записало встречу → звук ушёл на распознавание → на выходе ты получаешь текст расшифровки и готовый протокол. Плюс можно накидать письмо по итогам или свой запрос. Всё крутится на iOS 26, писали на SwiftUI. Есть ещё версия для Apple Watch, чтобы можно было начать запись с руки.
Важная деталь про архитектуру: у нас нет своего бэкенда. Приложение пишет звук на телефоне и отправляет его напрямую выбранному провайдеру (OpenAI, OpenRouter и т.д.), ответ так же напрямую возвращается в приложение. Перехватить или залогировать запись на нашей стороне нельзя, потому что нашей стороны в этом маршруте нет.
Отсюда же требование: нужны свои ключи от провайдеров — мы не зашивали внутрь ни ключей, ни оплаты. Так проще с ревью Apple и не приходится возиться с перепродажей токенов: свои ключи, свои расходы, мы к деньгам не прикасаемся.
Главная техническая головная боль тут одна: звук надо надёжно превратить в текст, а потом текст — в нормальный документ. Вокруг этого вся история ниже.
Часть 1. Работа с внешними моделями
Логика работы
Распознавание речи (звук → текст) — OpenAI. По умолчанию модель
gpt-4o-mini-transcribe: она стоит 0.003$ за минуту записи (это ~0.18$ за час) — ровно вдвое дешевле старого whisper-1, у которого 0.006$ за минуту (~0.36$/час). Whisper-1 оставили для случаев, где нужны точные таймкоды по фразам (чтобы тапнуть по строке и перемотать аудио на это место).Текст → документы (протокол, задачи, письмо) — тут либо тот же OpenAI, либо OpenRouter с DeepSeek.
Важная деталь про устройство: распознавание и обработка — это два независимых «движка». Каждый можно направить на своего провайдера. Например, речь распознавать локально на iPhone, а документы собирать через YandexGPT — оба варианта работают без VPN. Эта развилка ещё пригодится дальше.
И сразу проговорю, потому что дальше это важно: всё это — нативное приложение под iOS (Swift + SwiftUI, только системные фреймворки Apple, без сторонних SDK). Поэтому и грабли ниже во многом именно iOS-специфические: фоновая загрузка через URLSession, работа со звуком через AVFoundation, встроенный движок распознавания речи.
Звучит просто: взял файл, отправил, получил ответ. На деле — нет.
Параметры микрофона
До всякой отправки в облако звук надо подготовить, и тут мы налетели на пару iOS-граблей, которые напрямую бьют по качеству распознавания:
Ресемплинг. Микрофон iPhone отдаёт звук в своём формате (обычно 48 кГц), а нам для распознавания нужно 16 кГц моно. Если просто писать буферы в файл — сэмплы «съезжают», запись получается растянутой и расстроенной, распознавать её бесполезно. Пришлось каждый кусок звука прогонять через конвертер AVFoundation в нужный формат.
Режим аудиосессии. Был неочевидный затык: «измерительный» режим записи глушит усиление микрофона — звук выходит слишком тихим, и модель распознаёт заметно хуже. Пришлось подбирать режим так, чтобы уровень был нормальный. То есть на качество распознавания влияет даже то, как именно ты открыл микрофон.
Чанкование записи
Встречи бывают длинные. Полтора-три часа — норма. Такой файл целиком никуда не отправишь:
У OpenAI жёсткий лимит на файл — 25 МБ (это касается всех их моделей распознавания).
Даже если бы лимита не было — большой файл по сети просто не доедет.
Тут важная деталь: мы физически в России, а OpenAI работает только через VPN. А VPN — это не стабильный канал. И вот тут начались весёлые наблюдения. Мы гоняли куски разного размера, и оказалось: тело запроса на ~6 МБ регулярно виснет прямо посреди отправки — и не падает с ошибкой, а просто застревает. А кусок на ~1.6–2 МБ проходит нормально почти всегда.
Вывод простой: режем запись на куски примерно по 5 минут. При нашем битрейте (16 кГц, моно, 48 kbps) это как раз ~2 МБ на кусок. Медленно, но доезжает.
Костыли для отправки
Когда у тебя не один запрос, а десятки кусков, которые уходят по кривому каналу, — начинаются аномалии:
Отправка в фоне. Загрузка идёт через фоновую сессию iOS, чтобы можно было свернуть приложение или заблокировать телефон, а куски продолжали улетать.
Таймауты. Тут был отличный сюрприз: у фоновой сессии таймаут по умолчанию — 7 дней. То есть зависший кусок не падал с ошибкой, а честно висел неделю. Пришлось руками ставить: нет байтов 60 секунд → отвалить и повторить; жёсткий потолок на кусок — 4 минуты.
Повторы. Если кусок отвалился — повторяем с нарастающей паузой, до 5 попыток.
Устойчивость к перезапуску. Приложение убили/перезапустили посреди загрузки — при старте оно смотрит, что не долилось, и добирает. Тут ещё пришлось следить, чтобы один и тот же кусок случайно не отправился дважды — иначе платим за него два раза.
Склейка. Когда все куски пришли обратно, надо сшить их в один текст и сдвинуть таймкоды (у второго куска время идёт не с нуля, а с той секунды, где он начался в записи).
По сути половина работы — не про AI вообще, а про то, чтобы куски звука надёжно доехали по плохому каналу и корректно собрались обратно.
Две модели распознавания
Пока подбирали, чем распознавать в облаке, вылезло ещё несколько вещей:
Две модели OpenAI — это не «одна лучше», а компромисс.
gpt-4o-mini-transcribeдешевле, но отдаёт просто текст.whisper-1дороже, зато возвращает таймкоды по фразам — а без них не работает фишка «тапнул по строке расшифровки → аудио перемоталось на это место». Оставили обе: mini по умолчанию (дёшево), whisper-1 — когда нужен точный переход по тексту.Мелкая, но злая засада API: параметр с таймкодами можно слать только для whisper-формата ответа. Если отправить его вместе с mini — прилетает ошибка 400. На такие штуки убиваешь время, пока не поймёшь, что вообще не так.
Язык распознавания задаём явно, а не по языку телефона. Иначе на англоязычном айфоне Whisper может решить, что русская встреча — на английском, и выдать кашу. Тот же принцип, что и с «языковым замком» у LLM ниже: язык нельзя пускать на самотёк.
Капризы LLM-части
Распознавание — это полдела. Дальше расшифровку надо скормить LLM, чтобы получить протокол, задачи и письмо. Мы гоняли на этой задаче разные облачные модели — OpenAI, DeepSeek через OpenRouter, YandexGPT — и вот на что натыкались.
Модель отвечает не на том языке. Самое неприятное: встреча русская, а протокол приходит по-английски. Оказалось, модель тянется к языку системы — на англоязычном айфоне тот же DeepSeek выдавал ответ по-английски, даже когда просишь по-русски. Пришлось в каждый запрос первой строкой вшивать жёсткую команду вида «отвечай всегда на русском». Особенно это важно для «своего запроса» пользователя — там языкового правила в тексте нет вообще, и без замка модель уплывает.
Промпты — чистым текстом, без разметки. Если дать модели волю, она начинает сыпать markdown (решётки, звёздочки) прямо в текст протокола — а он у нас ложится в обычные поля интерфейса, без рендера. Поэтому в промпте прямо просим plain text. И держим один общий шаблон промпта, а не отдельную копию под каждый язык: язык задаётся тем самым «замком», а не переписыванием всего промпта под русский/английский.
Стоимость у всех считается по-разному. OpenRouter возвращает реальную цену запроса, у OpenAI приходится прикидывать по числу токенов, а у YandexGPT и своего сервера цену из ответа вообще не узнать — там честно пишем «оплата на стороне провайдера». Единого способа нет, под каждого провайдера пришлось делать свой подсчёт.
Российский ASR
VPN для российского пользователя — это боль. Хочется, чтобы человек скачал приложение и оно просто работало, без танцев. Поэтому смотрим в сторону YandexGPT и GigaChat от Сбера — они работают из России напрямую.
С текстом (документами) всё более-менее: YandexGPT для протоколов и задач мы уже подключили, работает без VPN. Единственное — у них свой формат запросов, не как у всех:
авторизация не через привычный
Authorization: Bearer <ключ>, а черезAuthorization: Api-Key <ключ>;плюс нужно отдельным заголовком передавать ID каталога (
x-folder-id).
Мелочь, но каждый такой провайдер приходится подключать отдельно, они не взаимозаменяемы «из коробки».
А вот с распознаванием речи мы встряли. Яндексовый SpeechKit не принимает формат звука (m4a/AAC). По документации он берёт MP3, OggOpus и LPCM — то есть, по сути, MP3, «огг» или несжатый WAV. А WAV — несжатый звук, час записи весит больше сотни мегабайт. Отправлять такое куском нереально. Значит, либо жать в другой формат прямо на телефоне, либо заливать через их облачное хранилище — это уже другой объём работы. Пока отложили.
Что в итоге по первой части. По-хорошему хотелось бы сделать один гибкий слой «в стиле OpenAI API» и просто подключать к нему и Яндекс, и Сбер. Но на практике у каждого свои форматы и свои ограничения, и такая универсальная адаптация выходит заметно сложнее, чем кажется. Поэтому решили так: сначала доводим всё до ума на зарубежных API (они уже работают), а адаптацию под российские сервисы и локальную обработку делаем следующим этапом.
Часть 2. Заход на распознавание прямо на телефоне — и главная загадка
Идея была логичная: раз с облаком столько боли (VPN, деньги, нарезка) — а что если распознавать речь прямо на iPhone, без интернета? Бесплатно, приватно, никакого VPN. В iOS 26 для этого как раз завезли новые штуки. Плюс можно попробовать затащить на телефон whisper (тот же движок, что в облаке, только локально).
И вот тут мы упёрлись в загадку, которую честно пока не разгадали. Но сначала — матчасть, без неё не понять.
Как вообще устроено распознавание речи у Apple
Чтобы дальше было понятно, коротко разложу, что у Apple под капотом в iOS 26. Там не одна кнопка «распознать», а несколько разных моделей.
Всем дирижирует SpeechAnalyzer — это как бы менеджер: ты ему скармливаешь звук, он раздаёт его нужным движкам и собирает результат. Работает полностью на устройстве, без интернета. и сами движки:
SpeechTranscriber — новый, «взрослый» движок под нормальную речь и разговоры. Это то, что Apple советует для длинных записей вроде встреч. У него своя модель и свой список языков.
DictationTranscriber — по сути движок клавиатурной диктовки (тот, что срабатывает, когда жмёшь микрофончик на клавиатуре). Он заточен под короткие фразы, но зато у него шире охват языков и он умеет расставлять знаки препинания.
SpeechDetector — вспомогательный, просто ловит, где в записи есть речь, а где тишина. Работает в паре с движком выше, чтобы не тратить силы на распознавание тишины.
Важный момент про языки: этими языковыми моделями управляет сама система. Часть языков уже лежит на телефоне (те, что подтянулись с диктовкой и Siri), а недостающие приложение может попросить систему докачать — это отдельный механизм, ты не таскаешь модели в самой сборке. Звучит удобно. На практике именно с языками у нас и вышла засада.

Чтобы не ломать основное приложение, мы собрали отдельное маленькое приложение-полигон — гоняли на нём разные движки распознавания и просто смотрели, что живое, а что нет. Так безопаснее: основной проект не трогаешь, а эксперименты крутишь в песочнице.
И вот что получилось. По документации всё должно было работать: в официальном списке языков нового SpeechTranscriber русский (ru_RU) есть. То есть на бумаге — бери новый движок, он умеет русский, распознавай встречи локально.
А на устройстве — не завелось. И вот что странно:
Пробовали на двух разных айфонах, включая Pro-версию.
На реальном iPhone 14 (iOS 26.5) новый движок вернул список из 30 языков — и русского в нём нет. Хотя в документации он числится. Это подтверждено логом прямо с устройства, не «мне показалось».
А «взрослая» модель, которая должна была дать хорошее качество, на телефоне вообще не запускалась — падала на старте.
Получается расхождение: в документации русский для нового движка есть, а на живом телефоне его нет. Почему так — дело в регионе, в системном языке, в недокачанном пакете или Apple просто не выкатила русский для этого устройства — мы пока честно не разобрались.

Что при этом всё-таки заработало
А теперь хорошая новость: в итоге рабочий вариант был найден
Оказалось, что тот самый движок клавиатурной диктовки (DictationTranscriber) русский язык на iPhone 14 тянет — потому что диктовка с клавиатуры по-русски на телефоне работает, а значит нужный языковой пакет там уже есть. Мы это подключили, и приложение теперь умеет распознавать встречу полностью офлайн прямо на iPhone 14 — без интернета, без VPN и бесплатно.
Телефон греется — распознавание локально нагружает железо, особенно на длинной записи.
Движок диктовки заточен под короткие фразы: на сложном звуке (несколько человек говорят разом, музыка, шум) он теряет куски и слабее ставит знаки препинания. Для чистой речи одного спикера — отлично, для шумной встречи на пять голосов — уже похуже.
Whisper на телефоне тоже запускается, но для скорости ему нужен «ускоритель» под нейрочип айфона; без него он считает на обычном процессоре и делает это медленно. А та модель whisper, что дала бы лучшее качество, в память телефона просто не влезла.
Вывод по локальной обработке
Итог такой: локальное распознавание — не миф, оно реально работает, и пытаемся использовать. Офлайн-расшифровка на iPhone 14 есть — быстро, бесплатно и приватно, ценой того, что телефон греется, а на сложном звуке качество проседает.
Но как только хочешь качество как у облака — упираешься в стену: лёгкий движок теряет куски, а нормальную «взрослую» модель на наших устройствах либо не удалось получить с русским, либо она не запускалась вовсе. Вот эту часть загадки мы пока не закрыли. Поэтому по умолчанию в приложении осталось облако, а локалка живёт как опция «без интернета и бесплатно, но качество попроще».
Что дальше: iOS 27 и новые локальные модели Apple
iOS 26 (показали на WWDC 2025) — это то, на чём приложение собрано сейчас. Здесь появился новый движок распознавания речи (SpeechAnalyzer) — именно с ним мы и воевали во второй части: локально распознавать уже можно, но качество упирается в стену, а с русским у нового движка вышла загадка. Встроенная модель Apple для текста в iOS 26 тоже есть, но её для обработки документов мы пока не пробовали — это отдельная история, к ней вернусь ниже.
iOS 27 (показали на WWDC 2026, выходит осенью 2026) — это следующая версия, куда мы целимся. Здесь Apple прокачала локальные модели как раз в нужную нам сторону: новое поколение AFM 3, точнее диктовка, модель побольше, которая всё ещё влезает в телефон.
Если по-простому: на iOS 26 мы уперлись в потолок, а iOS 27 этот потолок поднимает. Дальше — что именно меняется и что нам это даёт.
Что важно про встроенные модели
Первое, что стоит понять: у Apple базовая модель уже встроена в саму iOS. Доступ к ней даёт фреймворк Foundation Models — и это прямо кайф для нас: без ключа, без интернета и без оплаты за токены. То есть для генерации документов (протокол, задачи, письмо) в теории можно вообще уйти от облака и делать всё на телефоне бесплатно.
Базовая модель — идёт вместе с системой, докачивать её не надо.
Кастомные штуки (дообученные «адаптеры» под конкретную задачу, ~160 МБ) — их уже качают отдельно, не кладут в саму сборку приложения.
Языковые пакеты для распознавания речи — тоже управляются системой и часть из них докачивается. Похоже, наша загадка с русским крутится где-то здесь.
Чем iOS 27 отличается от iOS 26 (AFM 3)
Главное новшество iOS 27 — третье поколение моделей Apple, AFM 3. По сравнению с тем, что мы имеем на iOS 26, разница для нас в двух вещах:
AFM 3 Core — базовая модель на 3 млрд параметров, работает на устройстве. Это развитие той встроенной модели, что уже есть в iOS 26.
AFM 3 Core Advanced — модель побольше, на 20 млрд параметров, но «разреженная»: при работе включается не вся сразу, а только нужный кусок (1–4 млрд), чтобы влезать по памяти телефона. Раньше модель такого размера на iPhone просто не запускалась (мы это и поймали во второй части — «взрослая» модель падала по памяти). И — это прямо про нашу боль — Apple заявляет, что она мультимодальная и даёт более точную диктовку. То есть iOS 27 должна закрыть ровно ту дыру, в которую мы уперлись на iOS 26: качество локального распознавания.
Коротко, в чём выигрыш перехода: на iOS 26 хорошая локальная модель либо не влезала в память, либо была недоступна с русским; iOS 27 даёт модель побольше, которая помещается в телефон, и обещает точнее распознавать речь.
Планы
Распознавание (ASR). Докопаться до загадки с русским: проверить, не решается ли она через системный язык/регион или явную докачку языкового пакета. И пощупать новую модель Apple — раз она официально «точнее в диктовке», возможно, именно она закроет вопрос качества локально. Плюс всё-таки собрать правильный «ускоритель» для whisper, если своё не хватит.
Обработка (LLM). Попробовать перенести генерацию документов на встроенную Foundation Models — это разом убирает и VPN, и оплату за токены, и вопросы приватности (текст никуда не уходит). Если качество устроит — это идеальный сценарий для российского пользователя.
Если получится довести и распознавание, и обработку до нормального уровня прямо на телефоне — снимаются сразу три боли: деньги, VPN и приватность. Ради этого стоит копать дальше.
Ради чего вся эта возня
Первое: перестал писать протоколы руками. Раньше на встрече либо конспектируешь и половину пропускаешь мимо ушей, либо потом восстанавливаешь по памяти и что-то теряешь. Сейчас нажимаю «Запись», нормально участвую в разговоре, а на выходе — готовый протокол с задачами.
Второе, менее очевидное. У Y-Combinator есть совет: записывать каждую коммуникацию, чтобы копить долгосрочную память по своей работе. Сейчас это стало практично: ИИ-агент полезен ровно настолько, насколько хорош контекст, который ты в него загрузил, — а этот контекст обычно растворён в устных разговорах и нигде не зафиксирован. Приложение превращает встречи в текст, их можно сгруппировать и одним блоком выгрузить в свой ChatGPT или Claude — и спрашивать «что мы решили с подрядчиком в мае» уже не у памяти, а у архива. Без отдельной железки-диктофона, просто с телефона.
Анонс
Самое главное: приложение уже собрано и работает. Удалось выложить сборку в TestFlight, так что попробовать его вживую уже можно — если интересно потестировать своём айфоне, напишите - дам доступ.
А про то, как мы вообще проходили путь до публикации в TestFlight (там отдельная история с Apple Developer аккаунтом и нервами) — расскажу отдельной статьёй.
