Зачем вообще это всё

Мы живём в Мельбурне. Дочь растёт в русскоязычной семье, и мне хочется, чтобы русский был для неё не только «языком, на котором разговаривают дома», но и языком, на котором происходит что-то прикольное.

Я купил Яндекс Алису Макс и Алису Про. Для русского языка альтернатив толком нет: Amazon Echo, Apple HomePod, Google Nest, всё это про русский знает в лучшем случае на троечку. Яндекс другое дело: русская речь, русская музыка, русские команды, всё работает из коробки.

Но если зайти в Яндекс Диалоги и посмотреть, что там за навыки, становится грустно. Математические задачки, ролевые игры, сказки. Мёртвый продукт из эпохи до ChatGPT. Я смотрел на это и думал: ну ребята, можно же сделать что-то живое.

Так появилась идея навыка генерации музыки. Говоришь «создай песню про море», ждёшь минуту, и Алиса её играет.

На всё ушло два вечера. У меня уже был готовый шаблон инфраструктуры и пара похожих pet-проектов, так что я не начинал с нуля.

? Портал разработчика: dialogs.yandex.ru/developer
? Портал разработчика: dialogs.yandex.ru/developer

Как это выглядит со стороны пользователя

  1. «Алиса, запусти навык генерация музыки»

  2. Алиса: «Привет! Скажи: создай песню про что-нибудь и в каком стиле»

  3. «Создай песню про серого пса»

  4. Алиса: «Создаю песню, это займёт минуту. Спросите: готово?»

  5. «Готово?»

  6. Алиса: «Работаю. Осталось секунд тридцать. Спросите: готово?»

  7. «Готово?»

  8. Песня играет прямо на станции

Всё. Никаких приложений, никаких QR-кодов, никакого «зайдите на сайт».


Проблема первая: 4.5 секунды

Первая версия была наивной до неприличия. Пользователь просит песню, Lambda дёргает AI API, ждёт ответа, возвращает результат. Задеплоил, попробовал. Тишина.

Оказалось, у Яндекс Диалогов есть жёсткий таймаут: 4.5 секунды. Не уложился, сессия закрылась, до свидания.

? Документация про таймаут

А генерация музыки занимает от 30 секунд до двух минут. Ну то есть совсем не близко.

Решение: «ответь сразу, работай потом»

Пришлось переделать всё на асинхронный лад:

  1. Пользователь просит песню

  2. Навык сразу отвечает «создаю, спросите готово?» и в фоне запускает генерацию

  3. Пользователь спрашивает «готово?», навык лезет в DynamoDB смотреть статус

  4. Когда готово, играет

Чтобы человек не сидел в неведении, я сделал ответы зависящими от времени ожидания. И ещё подсмотрел один приятный трюк: в TTS есть тег sil <[2000]>, который делает паузу. Алиса как бы «думает» перед ответом, и это сильно меняет ощущение от общения:

  • До 40 секунд: «Только начала... [пауза] Это займёт около минуты.»

  • 40–80 секунд: «Работаю... [пауза] Осталось секунд тридцать.»

  • Больше 80: «Уже должно быть готово... [пауза] Спросите ещё раз.»

Мелочь, а живёт.


Проблема вторая: Lambda сидит и ждёт

Я переделал на асинхрон, но первая итерация была всё ещё кривая. Фоновая Lambda дёргала AI API синхронно и ждала ответа. То есть пользователю мы отвечали сразу, но Lambda внутри жила полторы минуты и кушала ресурсы.

А я выбрал Lambda именно потому, что не хочу платить за простой. Никто не пользуется, ничего не тикает. Lambda, которая две минуты сидит в await, это уже не serverless, это виртуалка на минималках.

Решение: webhooks от Replicate

У Replicate есть штука получше, чем replicate.run() (который блокирует до результата). Можно использовать predictions.create() и попросить дёрнуть webhook, когда всё будет готово:

const prediction = await client.predictions.create({
  model: 'google/lyria-3-pro',
  input: { images: [], prompt },
  webhook: `https://my-domain.com/alice/music/webhook?userId=${userId}`,
  webhook_events_filter: ['completed'],
});

Lambda запускает генерацию и тут же умирает. Когда Replicate закончит, постучится сам. Я плачу секунды вместо минут.


Проблема третья: а как вообще играть звук на Алисе?

Вот это был самый неожиданный сюрприз.

Первая попытка: S3 и audio_player

Логично же: положу MP3 в S3, дам Алисе URL, она сыграет. Документация описывает директиву audio_player:

{
  "directives": {
    "audio_player": {
      "action": "Play",
      "item": {
        "stream": {
          "url": "https://my-bucket.s3.amazonaws.com/songs/...",
          "token": "track_uuid",
          "offset_ms": 0
        }
      }
    }
  }
}

Алиса молчит. Я начал копать и нашёл целый букет граблей:

  • end_session обязан быть true (а у меня был false)

  • token не больше 128 символов (а у меня UUID + метаданные)

  • В тестовом чате консоли разработчика audio_player вообще не работает, только на реальных устройствах. То есть я отлаживал в пустоту.

Но главное: Алиса не умеет играть произвольный URL. Файл должен лежать в её собственном хранилище. S3 идёт лесом.

Правильный путь: Sound Storage Яндекс Диалогов

? Документация по загрузке аудио

1. Получить OAuth-токен

Идёте на oauth.yandex.ru, создаёте приложение с правами на Диалоги, получаете токен вида:

OAuth AQAAAAAB5vpbAAQ7o9abBlrUn0nshvcHZE4Irhw

Кладёте в переменные окружения Lambda как YANDEX_OAUTH_TOKEN.

2. Загрузить MP3

POST https://dialogs.yandex.net/api/v1/skills/{skill_id}/sounds
Authorization: OAuth <токен>
Content-Type: multipart/form-data

В ответе будет sound.id.

3. Подождать, пока Яндекс переварит файл

Он конвертирует в OPUS асинхронно. Опрашиваете:

GET https://dialogs.yandex.net/api/v1/skills/{skill_id}/sounds/{sound_id}

Когда придёт isProcessed: true, можно играть.

4. Играть

{
  "response": {
    "text": "Играю: название песни",
    "tts": "<speaker audio='dialogs-upload/{skill_id}/{sound_id}.opus'>",
    "end_session": false
  }
}

И вот это уже работает на всех устройствах без танцев с бубном.

Скриншот вкладки Ресурсы → Звуки в консоли разработчика
Скриншот вкладки Ресурсы → Звуки в консоли разработчика

Проблема четвёртая: какую модель брать

Minimax Music 2.5

Первой попробовал minimax/music-2.5. У неё есть отдельные поля для текста и для стиля, выглядит удобно. Но русский язык она поёт так себе: интонации мимо, произношение ломается, слушать неприятно.

Google Lyria 3 Pro

Перешёл на google/lyria-3-pro через Replicate. Тут один общий промпт, в него идёт и текст, и стиль. Зато по-русски поёт заметно лучше.

Замена модели в коде это одна строка:

const LYRIA_MODEL = 'google/lyria-3-pro';

За это люблю Replicate: единый интерфейс поверх разных моделей, переключение тривиальное.

А что же Suno

Suno делает треки сильно лучше, особенно русскоязычные. Но публичного API у них нет, и пока не предвидится. Lyria сейчас лучшее из того, к чему можно достучаться по нормальному API. Думаю, до конца года появятся модели поинтереснее.


Проблема пятая: модерация, которая воюет сама с собой

У Lyria нервная модерация, и работает она хитро. Модель сначала генерирует текст песни, а потом сама же его и заворачивает за «чувствительный контент». То есть банит собственную работу.

Самое забавное, что слово-триггер вообще не обязано быть в моём промпте. Я пишу «шансон». Дальше Lyria по ассоциации сочиняет текст про блатную романтику и сама себя банит. То же самое с death metal: попроси жанр, и она напишет что-то про смерть, после чего откажется отдавать. Жанр тянет ассоциации, ассоциации тянут лирику, лирика ловит модератор. Я в этой цепочке не участвую.

Решил добавить автоматический retry. Не прошло, webhook сразу запускает вторую попытку с тем же промптом, модель генерирует другой текст, обычно проскакивает. Промпт беру прямо из тела webhook-запроса (input.prompt), хранить отдельно смысла нет.


Сколько это стоит и где хранится

Яндекс Диалоги дают 1 ГБ под аудиофайлы навыка. Считается размер уже после конвертации в OPUS, и треки автоматически режутся до 2 минут. Получается примерно 1000 песен, потом лимит. Для публичного навыка пришлось бы делать ротацию старых файлов.

Генерация одной песни в Lyria стоит $0.08. Для публичного навыка без монетизации это дорого, особенно если кто-то решит наспамить. Поэтому навык я оставил приватным, только для семьи. Но исходники планирую выложить, чтобы каждый мог поднять у себя.


Что в итоге умеет навык

  • Создаёт песни по голосовой команде на любую тему

  • Играет последнюю песню: «играй»

  • Ищет по названию: «играй про море»

  • Переделывает: «измени», «перепиши»

  • Рассказывает про прогресс генерации

Стек: AWS Lambda + DynamoDB, Replicate (Google Lyria 3 Pro), Yandex Dialogs API, TypeScript.

Дочка довольна, песни про серых псов и про море крутятся по кругу. Цель достигнута.


Ссылки


Комментарии (6)


  1. Javian
    25.05.2026 09:39

    Достижение современной цивилизации: разогреваем атмосферу Земли песнями. /s


  1. parakhod_1
    25.05.2026 09:39

    Если не секрет - а зачем вы вообще пытаетесь заставлять ребёнка пользоваться русским языком? Просто у нас ситуация похожая, и мы пришли к выводу что ребёнок языком реально будет пользоваться, только если будет настоящий интерес. Попытки создать этот интерес искуственно дети раскусывают моментально, и это хорошо если вообще не работает, а может быть и хуже - это может вызывать противодействие.
    Если что - младшая дочь по-русски говорила когда была маленькая, но сейчас (9 с половиной лет, заканчивает 4й гласс) практически нет - всё вытеснили гораздо более полезные в ежедневной жизни итальянский и английский (оба абсолютно свободные). И, если честно, я не вижу в этом ничего ужасного. Захочеть в какой-то момент подтянуть русский (например чтобы разговаривать с нами и на русском, и книги в оригинале читать) - пусть, будем очень рады. Но вот давить? Совершенно не обязательно.


    1. SadeDV Автор
      25.05.2026 09:39

      Я как раз не давлю. Я делаю фан для себя, и ребёнок повторяет. Мои знакомые, которые переехали с родителями в детстве, уже забыли русский, и даже если захотят выучить, то это будет значительно тяжелее, чем в детстве.


      1. parakhod_1
        25.05.2026 09:39

        Мы пытались в детстве давать, и всё равно ушло. Потому что то что не используется в реальной жизни - уходит. Собственно и опыт ваших знакомых подсказывает что это так. И опыт и мой и всех моих знакомых с детьми тоже.

        И главное - вы так и не даёте ответа на вопрос "зачем". Та же самая история с нашими бабушками была, которые возмущались почему ребёнок с ними по-русски не говорит. А когда спрашиваешь их "попробуйте пожалуйста объяснить, а зачем ребёнок, который никогда даже не бывал в той далёкой стране, язык которой крайне маловероятно понадобится ему в реальной жизни, должен его с детства учить, пропробуйте привести аргументы" - они жутко надувались, краснели, и в конце выдавали: "ну как же, НАДО".

        Я просто к тому что пока у нас у самих не будет ответа получше чем "фан" и "НАДО", ничего из этого не получится.

        Да, сколько лет ребёнку если не секрет?


        1. funca
          25.05.2026 09:39

          Например, мы поддерживаем контакты с родственниками - те же бабушки, двоюродные братья, тетки и т.д. Периодически ездим в гости, хотя сейчас это стало дороже. Русский остаётся общим знаменателем.


          1. parakhod_1
            25.05.2026 09:39

            Мы тоже поддерживаем (правда сами не ездим давно, но к нам приезжают). Учитывая что это примерно меньше трети от тех гостей, что у нас бывают, и они тоже, как и все остальные гости, худо-бедно но говорят по-английски, то в чём ребёнку смысл прилагать дополнительные усилия? Она и со старшими сестрой и братом по-английски говорит, и никаких никому неудобств нет.