Это рассказ о том, как я в свободное время реализовал свою старую идею, и как мне в этом помог ИИ. Я решил сделать приложение, которое превращает Википедию в говорящий аудиогид и полностью написал его с помощью ИИ, хотя никогда раньше не занимался мобильной разработкой. ИИ использовался для создания аудио рассказов и для написания приложения.

Идея
Я люблю иногда ходить пешком или кататься на машине, и мне часто любопытно что находится вокруг меня. Просто хочется чтобы тебе в ухо кто то рассказывал что сейчас вокруг меня. В крупных туристических центрах можно найти какой-нибудь аудиогид по основным достопримечательностям, не по всем, конечно, но по основным. А если хочется узнать подробнее? А если отошел от основных туристических маршрутов, а если ты в своем любимом спальном квартале или где нибудь глубоко за городом? Тут уже готовые аудиогиды найти трудновато.
И вот мне пришла идея. А что если сделать мобильное приложение, которое по твоим координатам ищет информацию в Википедии. А потом вытаскивает из нее самое важное и озвучивает через TTS синтезатор голоса. Эта идея появилась у меня еще до расцвета GPT. Недавно меня осенило. Можно же всю обработку информации из Википедии поручить GPT. А еще можно использовать ИИ для написания кода приложения.
Выбор технологий
Далее по тексту под ИИ я буду подразумевать чат-боты типа ChatGPT и IDE со встроенным ИИ типа Cursor.
По новой традиции, я рассказал свою идею ИИ. На что ИИ воодушевленно ответил что идея отличная (кажется для него вообще любая идея "отличная") и я просто обязан ее реализовать, а он мне обязательно в этом поможет. Только вот проблема. Я никогда не разрабатывал приложения под мобильные устройства. У меня был опыт разработки на бэкенда на PHP, фронтэнда Vue.js, последние годы я Go-разработчик в больших и известных компаниях. Но это как бы не особо релевантно моей идее.
ИИ успокаивает меня, говорит что все отлично. Мы напишем бэк на знакомом мне PHP, а фронт на HTML+Vue.js. Потом упакуем это во что нибудь типа Electron и сделаем мобильное приложение. Ну что же, я почти готов начать, но меня терзают смутные сомнения. Спрашиваю, а не будет ли это тормозить, а стабильно ли будет работать фоновый режим для звука и обработки GPS, а надежно ли это…? И тут ИИ начинает мне рассказывать про кучу "нюансов" с таким кросс подходом, после чего мое воодушевление начинает резко падать. Я спрашиваю ИИ, ну какое решение будет надежным? ИИ предлагает мне заняться изучением нативной разработки под Android и iOS. М-да… Я хотел сделать маленький пет-проект, а мне предлагают освоить новую профессию.
Тут я вспоминаю что слышал про какой то Flutter, на котором можно создавать приложение под обе платформы, при этом никаких WebView, а нечто близкое к нативному коду. Спрашиваю об этом ИИ и его прорывает, что это идеальное решение, ведь изучить фреймворк Flutter и язык Dart для меня будет совсем просто с моим бэкграундом и мы сразу же получим нативные приложения и под Android и под iOS, сможем надежно реализовать работу с GPS, звуком, фоновыми режимами и вообще у нас все будет гладко и производительно. Итак решено, будем пробовать Flutter/Dart.
Если бы я вел себя как серьезный разработчик я бы пошел читать учебники и официальную документацию. Но в этот раз я пошел иным путем. Прошу ИИ "по быстрому" рассказать что такое Flutter и как на нем работать. Мне читают небольшой ликбез, что такое стейтфул виджеты, стейтлес виджеты, про деревья виджетов, провайдеры данных, и что самое модное и удобное для управления состояниями это Riverpod. Окей, я "все понял", мобильные приложение я сделаю на Dart.
Готовим данные
Теперь надо понять, а вообще много ли в Википедии статей привязанных к GPS координатам. Надо накидать какую нибудь тулзу, которая соберет данные для анализа. Самое простое, это просто накидать скрипты на PHP или Go, которые дергают API Википедии и собирают из нее данные. Тут мне помощь ИИ не нужна, все предельно просто и понятно. Хотя… пойдем все таки спросим, вдруг чего посоветуют. ИИ говорит что да, так и делай, будешь запускать CLI скрипты. Но еще есть такая штука как Jupiter Notebook. Те же скрипты, но только с удобным GUI, сможешь карты рисовать прямо там, графики всякие. Вот только основной язык Jupiter это не PHP или Go, а Python. Ну что же, думаю, дергать API и крутить циклы с условиям, я смогу и на не родном мне языке. Ок, решено. Подготовку и анализ данных буду делать на Jupiter/Python.
Где хранить данные? Я выбрал Postgres, так как хорошо его знаю, а еще ИИ любезно подсказал, что стоит поставить на него расширение PostGIS, если я собираюсь работать с геоданными.
Спрашиваю ИИ, а как мне собрать все точки в Википедии в районе моего родного Санкт-Петербурга. Мне предлагают сгенерировать сетку и в каждом узле сетки сделать запрос на 500 ближайших объектов. Вроде это самое типовое решение подобных задач. ИИ помогает сгенерировать ноутбук для Jupiter. Он простой и очевидный, но вручную я бы писал его несколько часов, а тут он готов за пару минут. Получаем около 7500 точек в районе Санкт-Петербурга. Неплохо, с этим можно работать. Сохраняем данные в Postgres. Смотрим их на карте прямо в Jupiter.

Теперь делаем ноутбуки которые скачивают в Postgres тела статей из Википедии и загружают основное фото из каждой стаитьи. Все! У нас есть необходимые данные для создания рассказов для аудиогида. Это еще не весь мир и не вся Россия, но для MVP подойдет.
Теперь надо скормить эту информацию в OpenAI API (ChatGPT) для того чтобы он на основе каждой статьи создал текст для короткой аудиоэкскурсии на 1.5-2.5 минуты. А заодно GPT оценит тематику и интересность информации по каждой точке. Пишем развернутый промпт в стиле "Ты аудиогид, который интересно рассказывает про достопримечательности. Вот тебе информация из Википедии. Результат выдай в виде JSON с такими то полями". На самом деле, промпт намного длиннее. Я видел лекцию от Андрея Ына где он как раз показывал примеры как делать такие промпты. Создаем ноутбук, запускаем. Получаем по каждой точке краткую выжимку из Википедии и всякие оценочные параметры в виде JSON-ов.
Уже позже выяснилось что промпты на доработать, потому как половина рассказов содержит фразы-паразиты типа "добро пожаловать...", "это не просто…", "представьте себе…", "это жемчужина….".
Я пробовал в OpenAI API использовать следующие модели:
gpt-4o - стоимость за статью 1.6 руб, время на генерацию 17 секунды
gpt-4o-mini - стоимость за статью 0.1 руб, время на генерацию 10 секунд
Кстати, дешевая gpt-4o-mini вполне нормально справляется. Тут ведь не надо особо думать, нужно лишь резюмировать данные из Википедии.
Теперь осталось сгенерировать голос. Со слов ИИ, лидер качества в русском TTS сейчас это Yandex SpeechKit. Вот его и используем. Создаем ноутбук, который отправляет эти статьи на генерацию голоса в API Яндекса. Получаем звуковые файлы. По цене это обошлось 2.3 рубля за статью, а время генерации 7.2 секунды на рассказ.
Так. Теперь надо как то все это впихать в приложение. А аудиофайлы не маленькие. Спрашиваю ИИ, как максимально сжать картинки и аудио для мобильных устройств. Мне ИИ предлагает использовать форматы WEBP для картинок и OGG для аудио, как современные и самые эффективные на данный момент. После нескольких попыток, нам с ИИ удается добиться весьма компактных размеров без заметной потери качества вот так:
magick "$src" -resize "640x640>" -quality 50 -define webp:method=6 -define webp:near-lossless=0 "$dst"
ffmpeg -y -i "$src"-ac 1 -ar 48000 -c:a libopus -b:a 16k -vbr on -compression_level 10 -application voip -frame_duration 60 "$dst"
Делаем экспорт данных из Postgres в виде JSON. Пока ограничиваюсь 2000 точками. В основном центр Санкт-Петербурга и мой родной спальный район. Вот кусочек этого файла.
...
[
"id": 14239,
"title": "Дворцовый мост — символ Петербурга",
"image": "14239.webp",
"audio": "14239.ogg",
"location": {"lat": 59.94111, "lng": 30.308475},
"tags": ["здание", "история", "архитектура", "транспорт"],
"scores": {
"children": 70, "adult": 85, "local": 60, "infrastructure": 75,
"tourist": 90, "historian": 80, "humanitarian": 75,
"technical": 70, "total": 78
},
"url": "https://ru.wikipedia.org/wiki/Дворцовый_мост"
],
...
Ну все! Данные для MVP у меня есть. Осталось написать мобильное приложение. Не имея опыта вообще. Итак приступим.
Создаем мобильное приложение
Ставлю Flutter SDK. Запускаю IDE Cursor. Прошу сгенерить приложение. Бойлерплейт запускаю на эмуляторах Android и iOS. Дальше описываю Курсору концепцию приложения, основные экраны и прошу их сгенерировать. И о чудо! Мне весьма неплохо генерируют экраны и навигацию. Я уже могу потыкать в кнопки и посмотреть как приложение будет выглядеть.
Прошу добавить карту, добавить аудиоплеер. В приложение зашиваю JSON файл с данными и все видео и аудио файлы. Приложение раздувается до 300+ Мб. Ну думаю, сойдет, сейчас приложения бывают и больше.
Интересно что ИИ достаточно хорошо понял мою идею и сделал даже больше чем я просил в чате-агенте IDE. Он сразу сгенерировал вполне приличный UI с не самым плохим оформлением. Когда я попросил его сделать список объектов, он не просто сделал простой скроллируемый список, а еще и реализовал поисковую строку к этому списку. В общем ИИ пытается работать с опережением и даже предсказывает мои хотелки.
Дальше, по шагам, я начинаю просить ИИ добавлять логику и обработку событий. ИИ генерирует провайдеры данных, обработчики. Все это более менее работает, хотя местами подглючивает. Пытаясь вчитываться в сгенерированный код, и тут меня начинают мучать сомнения, толи я не понимаю эстетику Flutter, то ли это классический код-шапша. Осмеливаюсь и начинаю задавать курсору вопросы, типа, а почему вот это в одном файле, а нельзя ли тут декомпозировать, а может быть здесь стоит вынести общий код. Курсор почти во всем соглашается, слащаво хвалит мою проницательность и начинает рефакторить. Но я понимаю что код хоть и работает, но он жутковатый. В конце добавляю постоянно хранимые настройки и список прослушанных треков через SharedPreferences.
Ну что же. После десятка вечеров. У меня рабочее приложение, со страшным кодом который стыдно показать профессионалу. Но оно работает. Надо испытать в деле. Выхожу в город, брожу, слушаю рассказы. Пробую прокатиться по своему району на машине, узнаю много нового о месте где я живу. Главная проблема, что в приложении нет полноценной поддержки фонового режима. Я это оставил на потом, но оказалось что для надежно работающего фонового режима нужна принципиально иная структура приложения. Печаль!
Рефакторим лапшу
Ладно думаю, я уже освоил основы Flutter, сейчас мы с ИИ отрефакторим кодовую лапшу которая меня уже реально начала удручать. Кроме того я узнал что есть такая модная встроенная БД для Flutter как Isar. Она обеспечивает быстрый доступ к данным, можно шарить данные между разными изолятами (а это необходимо для фонового режима) и к тому же обеспечивает реактивность прямо из коробки.
Начинаю рефакторить вместе с Курсором. И начинается боль. ИИ страстно пытается сохранить свою предыдущую лапшу. Долго борюсь с ним. В итоге вручную вычищаю всю старую логику и по сути оставляю только GUI. Только после этого Курсор помог мне создать новую логику. В этот раз я контролировал каждый его шаг больше не давая ему творить лапшу. По сути я был стал архитектором, а он исполнительным программистом. Теперь у меня есть приложение с приемлемой архитектурой, встроенной базой данных, и возможностью для добавления нормального фонового режима в будущем.
Выкладываем
Теперь надо выложить приложение в общий доступ. Спрашиваю у ИИ как это сделать попроще. И тут узнаю что оказывается я не могу вот так взять и опубликовать приложение больше 100 Мб весом. Эх, я не учел это, а ИИ не подсказал сразу. Ладно, переделываю приложение на загрузку данных из CDN.
Ну все! Теперь можно выкладывать в общий доступ. Для начала я выложил только Android приложение в RuStore. Там его можно найти по слову "GeoTalk". Буду ждать отзывы.
Планы на будущее
Если приложение вызовет интерес, тогда в следующих версиях я хочу сделать полное покрытие всей России, а это сотни тысяч объектов. Для этого нужен будет полноценный бэкенд. Наиболее популярные туристические центры можно обработать заранее (как сейчас), а менее популярные точки нужно будет обрабатывать по схеме on-demand. Генерация рассказа не происходит мгновенно. Надо скачать данные из Википедии (хотя можно импортировать все данные заранее, они предоставляются в виде дампов), обработать их LLM моделью, пропустить через TTS (локальный или удаленный), транскодировать и т.д. Все это занимает 20-30 секунд. Так что если решать задачу в лоб, то мы получим плохой UX. Нужно спроектировать механику генерации с опережением и предсказывать следующие точки.
Дальше можно расширить покрытие на всю Землю и добавить многоязычность. Причем многоязычность может быть и с точки зрения источника данных и с точки зрения озвученного рассказа. Так же стоит сделать ранжирование и фильтрацию по тематикам и оценкам. Еще есть мысль сделать возможность выбрать стиль рассказов, например с акцентами на "культуру", "инфраструктуру", "криминал", и т.п.
И конечно надо все таки довести до ума фоновый режим, чтобы при принудительном гашении экрана приложение стабильно продолжало анализировать GPS, и выбирать объекты.
Напишите, плиз, в комментах, стоит ли по вашему мнению развивать проект дальше.
Что я вынес для себя
Оказалось что с помощью современных ИИ можно очень быстро изучить основы и попробовать новые для себя технологии. Но пока для качественного кода, разработчик должен активно вмешиваться в процесс ИИ-кодогенерации. Надо действовать как ревьювер и архитектор, иначе получим очень плохой и трудно поддерживаемый код. Хотя для MVP или для хобби - вполне сойдет.
Уверен что подобного результата я бы не достиг, если бы у меня совсем не было опыта разработки в других областях.
А еще я теперь знаю много нового о своем районе.
BigBrother
Использовать в качестве источника информации только лишь статью Википедии не совсем правильно. Я, к примеру, перед посещением какой-нибудь достопримечательности, и так пробегаю глазами статью в Википедии. И я был бы разочарован, прослушав аудиогид с рерайтом той же самой статьи.
В рассказе должна быть своя изюминка, а не просто энциклопедические факты. Это скучно.
Ну и конечно с Izi Travel с его многолетней базой по всему миру будет непросто конкурировать.