Між розмовою і завданням лишалося забагато ручної роботи
Мій робочий день значною мірою складається з розмов: із самим собою, ШІ-агентом і клієнтом на дзвінку. Майже все сказане потім перетворюється на текст і завдання. Наговорити думку виходить у рази швидше, ніж набрати її на клавіатурі. А після годинного дзвінка ще треба переслухати запис і витягти з нього домовленості.
Готові сервіси це нібито розв'язують, але кожен живе у своїй хмарі: завдання в одному, розшифровка мовлення в іншому, облік часу в третьому, і твої дані лежать на чужих серверах, а не поряд із кодом. Мені хотілося навпаки: щоб інструмент був вбудований у редактор, де я і так весь день, а дані лишалися моїми. Так з'явилася Sonara.
Запис мітингу проходить шлях до канбан-дошки
Sonara зібрана навколо одного робочого циклу. Наговорив завдання чи додав запис мітингу - розширення розшифровує її локально. Текст віддаєш ШІ-агенту: він стискає двогодинну розмову в три абзаци домовленостей і пропонує список завдань. Після звірки з клієнтом завдання переходять у канбан-дошку, де по них уже ведеться робота.
Ключовий виграш - у найвищій ланці: більше не треба переслуховувати довгий запис. Мітинг вкладається в кілька абзаців рішення, клієнт ставить палець угору, і можна йти робити.
Дані лишаються звичайними файлами поряд із кодом
Sonara не потребує акаунта, не надсилає дані в хмару й не збирає телеметрію. Усе, що вона зберігає, лежить усередині проєкту в теці .vscode/sonara/ і переміщується разом із кодом. Що додати до спільного репозиторію, а що лишити тільки в себе, вирішує сам користувач.
| Що | Де лежить | Формат |
|---|---|---|
| Завдання | tasks/ |
markdown, по файлу на завдання |
| Історія диктувань | voice-log/ |
рядковий JSON |
| Розшифровки записів | voice-transcripts/ |
markdown |
| Облік часу | time-tracker/ |
JSON по днях |
| Словник термінів | vocabulary.md |
markdown |
Нічого пропрієтарного: завдання можна відкрити й відредагувати звичайним текстовим редактором, розшифровку - прочитати без жодного застосунку. І все це працює офлайн: інтернет потрібен рівно один раз - під час першого запуску, щоб завантажити локальну модель розпізнавання мовлення.
Чотири робочі поверхні вміщуються в одному редакторі
Усередині одного розширення - чотири робочі поверхні, і кожна заточена під свою частину циклу.
Важка модель прокидається лише на запит
Локальна модель розпізнавання мовлення займає кілька гігабайтів пам'яті. Якщо тримати її ввімкненою постійно, вона забирає ресурси в редактора та решти інструментів. Тому Sonara керує її життєвим циклом сама, не перекладаючи контроль пам'яті на користувача.
- Лінивий старт. Рушій розпізнавання не запущений, поки ти не почнеш перше диктування. Не диктуєш - пам'ять вільна.
- Перемикач у статус-барі. Одним кліком можна вимкнути рушій, і модель одразу вивантажується з пам'яті; під час наступного запису Sonara запитає, чи вмикати назад.
- Само-вивантаження за простою. Поки рушій увімкнений, але ним не користуються кілька хвилин, він сам вимикається і звільняє пам'ять, а на наступному диктуванні піднімається знову.
- Відновлення після браку пам'яті. Якщо посеред розшифровки на відеокарті закінчується пам'ять, Sonara не падає мовчки, а пропонує повторити на процесорі або на меншій моделі - і потім повертає твою звичайну.
Ця логіка з'явилася з реальних збоїв, на які я натрапляв сам. Інструмент має переживати брак пам'яті на відеокарті й звільняти ресурси, коли голос зараз не використовується.
Одне обмеження від платформи, інше від технології
Частину можливостей довелося обмежити, і причини в них різні.
Запис голосу поки що працює тільки на Linux - звук береться через системний звуковий шар (PulseAudio/PipeWire). Задачі й облік часу працюють усюди, а на macOS і Windows голосові команди прямо повідомляють, що запис недоступний, замість тихого збою.
Була й гілка, яка не піддалася. Я пробував синхронний переклад: говориш своєю мовою, чуєш англійську, у реальному часі. І вперся в природне обмеження. Справжній синхрон вимагає передбачати, що ти збираєшся сказати за секунду, а розпізнавання мовлення так не вміє: воно працює за вже сказаним.
Тому переклад виходив не синхронним, а "договори до кінця, потім усе разом". Перебити його на півслові було не можна, він договорював перекладений шматок і лише потім слухав далі. Висновок для мене виявився ціннішим за саму функцію: живий переклад будується не на самому розпізнаванні мовлення, а на моделі, яка тримає контекст і передбачає продовження. Цю гілку я відклав.
Відкритий проєкт показує рішення цілком
Sonara я зробив для себе з інтересу зібрати весь цикл власними руками. Інші мої внутрішні інструменти пов'язані з речами, які я не хочу відкривати, а цей вийшов окремим і самодостатнім. Тому код опубліковано під вільною ліцензією: кому підходить такий процес, може зібрати розширення в себе й користуватися.
Коду тут небагато, і половина цінності не в ньому, а в рішеннях: тримати дані в користувача, а не в чужій хмарі; не дати важкій моделі мовчки з'їсти пам'ять; спроєктувати інструмент навколо того, як реально йде робота, а не навколо списку можливостей. Рівно це судження я приношу і в клієнтські проєкти - просто там воно сховане за NDA, а тут його видно цілком, аж до коду.
Sonara відкрита під ліцензією MIT і лежить на GitHub: github.com/ArtisanWebLab/sonara. Це поки що збірка для себе, але база під нею міцна - є на чому розвивати далі.
Хороший інструмент знає міру: робить свою справу й тихо йде з дороги, не просячи ні акаунта, ні зайвої пам'яті, ні твоєї уваги.
Це наш проєкт, тому показуємо його внутрішній устрій без застережень - аж до архітектури та коду.

