惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
P
Privacy & Cybersecurity Law Blog
G
GRAHAM CLULEY
T
The Exploit Database - CXSecurity.com
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Project Zero
Project Zero
S
Security @ Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
A
Arctic Wolf
Webroot Blog
Webroot Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
Security Latest
Security Latest
H
Heimdal Security Blog
N
News and Events Feed by Topic
N
News | PayPal Newsroom
T
Tor Project blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
GbyAI
GbyAI
The Last Watchdog
The Last Watchdog
Y
Y Combinator Blog
宝玉的分享
宝玉的分享
Scott Helme
Scott Helme
A
About on SuperTechFans
M
MIT News - Artificial intelligence
V
V2EX
V
Visual Studio Blog
Recorded Future
Recorded Future
博客园 - 叶小钗
F
Fortinet All Blogs
L
Lohrmann on Cybersecurity
The GitHub Blog
The GitHub Blog
博客园 - Franky
P
Proofpoint News Feed
MyScale Blog
MyScale Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
Secure Thoughts
D
DataBreaches.Net
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - 三生石上(FineUI控件)
I
InfoQ
SecWiki News
SecWiki News
Blog — PlanetScale
Blog — PlanetScale
Engineering at Meta
Engineering at Meta
J
Java Code Geeks
B
Blog RSS Feed
AWS News Blog
AWS News Blog
Know Your Adversary
Know Your Adversary
V
Vulnerabilities – Threatpost
H
Help Net Security

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Как я написал лучшее приложение для изучения иностранных языков с помощью SFSpeechRecognizer (нет)
ferreto · 2026-04-28 · via Все публикации подряд на Хабре

Уровень сложностиСредний

Время на прочтение5 мин

Охват и читатели297

Вообще-то, я бэкендер последние лет 20, но недавно остался без работы (и AI тут не причём), решил «замутить» свой «стартап», пока ищу новую работу Java-программиста. А заодно подтянуть новые технологии, поглубже изучить немецкий и английский и немного развеяться…

Писать приложения под iOS было моим хобби последние лет 10, и пару моих приложений до сих пор постоянно висят в топе в Российском AppStore, но это были всё «игрушки», а захотелось сделать что-то взаправду стоящее, и так возникла идея написать лучшее (ни больше ни меньше) приложение для изучения языков с помощью аудирования. Точнее, товарищ подсказал идею. А ещё точнее - идея давно была реализована под Андроид, но аналогов под iOS нет, а очень хотелось. И мне, и товарищу :-). Да и смартфона с андроидом у меня нет и никогда не было, не судите строго, но не люблю я вирусы и глюки.

Идея следующая: берёте любое аудио на любом нужном вам языке, загружаете в приложение, и оно автоматически (можно так же вручную) разбивает аудиофайл на нужные вам сегменты для «шэдоуинга», аудирования, многократного прослушивания и тому подобного. Аналогов в сторе я не нашёл, точнее, что-то отдалённо похожее там есть, но без своих настроек, без выбора своего контента для изучения, без красивой визуализации аудио, короче, без всего того, что нам бы хотелось иметь.

Итак, идея есть, какие технологии использовать? В старых моих приложениях был UIKit, Realm/CoreData, и, сториборды. Не судите строго, я как бэкэндер тогда не знал, что использование сторибордов среди «трушных» айосников считается плохим тоном и плохой приметой. Но теперь-то я решил использовать современные технологии! И выбрал такой стэк: SwiftUI, SwiftData, Speech Framework. Что касается последнего, то он вроде бы доступен ещё с iOS 10, но я решил, что технологии развиваются, и распознавание текста из аудио должно было бы сделать со времени iOS 10 огромный рывок вперёд. Но теперь я не так сильно в этом уверен, и об этом эта моя статья…

Почему не нейросети? Все их используют, это модно, круто, и вообще, скоро они заменят всех нас :-). Возможно, в ближайшем будущем, я прикручу какую-нибудь LLM-ку (об этом ниже), но сразу мне показалось это лишним, раз уж можно использовать нативные iOS-ные библиотеки. В итоге приложение получилось всего 3,5 мегабайт, несмотря на то, что количество исходных файлов уже перевалило за 60 и возможности приложения довольно внушительные.

Итак, идея: берём аудио, разбиваем на куски, с помощью плеера проигрываем, перематываем, повторяем… И причём здесь SFSpeechRecognizer? А притом, что мне захотелось видеть субтитры. К тому же, это — «киллер‑фича», — подумал я и стал «гуглить» у Дипсика, как транскрибировать речь из аудио. А теперь я расскажу, как я реализовал эту функцию, с какими проблемами столкнулся и как их решал (но до сих пор не решил).

Для распознавания мы используем SFSpeechRecognizer из Speech framework. На старте мы формируем список доступных локалей через SFSpeechRecognizer.supportedLocales() и даём пользователю выбрать язык. Перед первым запуском обязательно запрашиваем разрешение: SFSpeechRecognizer.requestAuthorization. Если пользователь отказывает — увы, генерация субтитров недоступна.

Для распознавания нам доступны два режима:
Онлайн — более точный, качественный, но использует серверные модели Apple и требует интернета. Офлайн — работает полностью на устройстве, что важно для конфиденциальности и для мест с плохой связью. Включается установкой флага requiresOnDeviceRecognition = true (доступно на iOS 16+). Не все языки поддерживают офлайн, и для них мы оставляем только онлайн.

Как только режим выбран, можно начинать распознавание. Но не всё так просто. Главная боль: длинные аудио. SFSpeechRecognizer рассчитан на короткие фразы. Отправив ему часовую запись, вы рискуете получить ошибку или результат только для первой минуты. Официальные ограничения не задокументированы, но практика показала:

  • Для онлайн режима комфортный размер фрагмента — около 40 секунд.

  • Для офлайн режима — 10 секунд.

В итоге я решил разрезать аудио на чанки с перекрытием в 2 секунды, чтобы не рубить слова на границах. Делаем это с помощью AVAssetExportSession, каждый фрагмент сохраняем во временный m4a файл, распознаём отдельно, а затем сдвигаем временные метки на начало чанка. После обработки временные файлы удаляются. Да, не очень рационально, но иначе как?

Код экспорта чанка выглядит так:

let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A)
exportSession.outputURL = tempURL
exportSession.outputFileType = .m4a
exportSession.timeRange = CMTimeRange(start: startTime, end: endTime)
await exportSession.export()

Для стиля «фразы» мы включаем shouldReportPartialResults = true, чтобы показывать пользователю текст ещё до окончания распознавания. Это реализовано через колбэк recognitionTask(with:), который вызывается многократно. Мы оборачиваем его в withCheckedThrowingContinuation для удобной работы с async/await и добавляем таймаут 120 секунд. Если распознавание затягивается (например, пропал интернет), задача принудительно отменяется.

Далее запускаем постобработку: при стиле «по словам» мы просто удаляем дубликаты субтитров с одинаковыми временными метками. Для стиля «по фразам» логика сложнее: группируем слова, если пауза между ними меньше 0,5 секунды, и объединяем их текст в одну фразу. Попутно убираем идущие подряд одинаковые слова — такое иногда случается при шумном аудио.

Если флаг ddsPunctuation = true (доступен с iOS 16+), система сама расставляет знаки препинания, но офлайн‑режим делает это менее аккуратно.

Результаты распознавания вместе с временными метками сохраняем в SRT файл и цепляем его к «проекту» с аудио и сегментами.

Что в итоге? Я как перфекционист не очень доволен, как распознается аудио. Результат в принципе хорош, но не идеален. Некоторые слова пропускаются, некоторые распознаются не точно. Что же касается пунктуации — тут вообще беда. Скажем так — терпимо. Но хочется ИДЕАЛЬНОГО результата (помните, я же собирался сделать лучшее приложение). Буду рад подсказкам от более опытных iOS‑разработчиков именно по работе с SFSpeechRecognizer.

Да, я знаю, что в iOS 26 появился SpeechAnalyzer и вроде бы он даёт лучший результат и работает с длинными аудио, но очень не хочется ограничивать пользователей iOS 26. На данный момент приложение поддерживает iOS 18+, а если перейти на iOS 26, то уже даже на iPhone 11 и SE приложение работать не будет :-(.

Пока что есть идея: прикрутить бэкенд на Java (или чём‑то более сейчас модным) и дёргать через него, скажем DeepSeek API для улучшения качества распознанного текста. Пробные попытки показали, что и с пунктуацией дипсик справится «на ура», и пропущенные слова вставит и неправильно распознанные заменит. Если у вас есть другие идеи — буду благодарен. Сразу скажу, использование Wisper не рассматриваю по идеологическим мотивам — не хочется гонять аудио по всему интернету, давайте остановимся хотя бы на тексте :-). Да и хочется использовать именно нативные библиотеки iOS. Иначе, зачем они существуют?