Голосовые инструкции являются одним из ключевых компонентов навигационных приложений. Они позволяют сопровождать маршрут аудиоподсказками, информируя пользователя о предстоящих манёврах, изменениях направления движения, съездах с магистралей, приближении к пункту назначения и других событиях маршрута.
В экосистеме Mapbox голосовые инструкции формируются сервисом маршрутизации и передаются вместе с данными маршрута. Mapbox GL JS отвечает за визуализацию карты, тогда как воспроизведение голосовых подсказок обычно реализуется средствами браузера через Web Speech API или сторонние механизмы синтеза речи.
Типичная архитектура выглядит следующим образом:
При включении поддержки голосовых инструкций сервис маршрутизации возвращает дополнительную информацию внутри шагов маршрута.
Пример запроса:
const url =
'https://api.mapbox.com/directions/v5/mapbox/driving/' +
`${startLng},${startLat};${endLng},${endLat}` +
'?steps=true' +
'&voice_instructions=true' +
'&access_token=' + mapboxgl.accessToken;
Параметр:
voice_instructions=true
активирует генерацию голосовых подсказок.
Фрагмент ответа может выглядеть следующим образом:
{
"voiceInstructions": [
{
"distanceAlongGeometry": 250,
"announcement": "Через 250 метров поверните направо",
"ssmlAnnouncement": "<speak>Через 250 метров поверните направо</speak>"
}
]
}
Каждая инструкция содержит несколько важных полей.
Наиболее часто используемое поле:
{
"announcement": "Поверните налево"
}
Содержит обычный текст, предназначенный для отображения или озвучивания.
Использование:
const text =
voiceInstruction.announcement;
Полученный текст может быть напрямую передан синтезатору речи.
SSML (Speech Synthesis Markup Language) позволяет более точно управлять произношением.
Пример:
<speak>
Через
<say-as interpret-as="cardinal">
300
</say-as>
метров поверните налево
</speak>
Поле:
voiceInstruction.ssmlAnnouncement
может использоваться при интеграции с облачными голосовыми движками:
Для встроенного Web Speech API обычно применяется обычное поле
announcement.
Показывает расстояние до точки выполнения манёвра.
Пример:
{
"distanceAlongGeometry": 500
}
Это означает, что инструкция должна быть воспроизведена за 500 метров до манёвра.
Использование:
const distance =
voiceInstruction.distanceAlongGeometry;
Значение применяется для определения момента воспроизведения подсказки.
После получения маршрута необходимо пройти по его шагам.
Пример:
const route =
data.routes[0];
route.legs.forEach(leg => {
leg.steps.forEach(step => {
if (step.voiceInstructions) {
console.log(
step.voiceInstructions
);
}
});
});
Результат:
[
{
distanceAlongGeometry: 500,
announcement:
"Через 500 метров поверните направо"
},
{
distanceAlongGeometry: 100,
announcement:
"Поверните направо"
}
]
Для одного манёвра может существовать несколько голосовых предупреждений.
Удобно собрать все инструкции в единый массив.
const instructions = [];
route.legs.forEach(leg => {
leg.steps.forEach(step => {
if (!step.voiceInstructions) {
return;
}
step.voiceInstructions.forEach(
instruction => {
instructions.push(
instruction
);
}
);
});
});
После обработки:
console.log(instructions);
можно получить полный список голосовых сообщений маршрута.
Большинство браузеров поддерживает встроенный механизм синтеза речи.
Простейшее воспроизведение:
function speak(text) {
const utterance =
new SpeechSynthesisUtterance(
text
);
speechSynthesis.speak(
utterance
);
}
Вызов:
speak(
"Через 300 метров поверните налево"
);
озвучит текст через системный голос устройства.
Для корректного произношения необходимо задавать язык.
function speak(text) {
const utterance =
new SpeechSynthesisUtterance(
text
);
utterance.lang = 'ru-RU';
speechSynthesis.speak(
utterance
);
}
Популярные значения:
'ru-RU'
'en-US'
'de-DE'
'fr-FR'
'es-ES'
'it-IT'
Получение списка доступных голосов:
const voices =
speechSynthesis.getVoices();
console.log(voices);
Выбор:
const utterance =
new SpeechSynthesisUtterance(
text
);
utterance.voice =
voices.find(
voice =>
voice.lang === 'ru-RU'
);
Это позволяет использовать наиболее качественный голос на устройстве пользователя.
Параметр:
utterance.rate
контролирует скорость произношения.
Пример:
utterance.rate = 0.9;
Варианты:
0.5
0.8
1.0
1.2
1.5
Для автомобильной навигации чаще используется диапазон:
0.9 – 1.1
Настройка тона:
utterance.pitch = 1;
Примеры:
0.8
1.0
1.2
Повышенный тон иногда используется для предупреждающих сообщений.
utterance.volume = 1;
Диапазон:
0.0 - 1.0
Пример:
utterance.volume = 0.8;
Для своевременного воспроизведения инструкций требуется получать текущие координаты.
navigator.geolocation.watchPosition(
position => {
const lng =
position.coords.longitude;
const lat =
position.coords.latitude;
updateLocation(
lng,
lat
);
}
);
Получаемые координаты используются для сравнения с маршрутом.
Каждый шаг содержит геометрию движения.
Пример:
const currentStep =
route.legs[0].steps[
activeStepIndex
];
Далее вычисляется расстояние от текущей позиции до конца шага.
const distanceToTurn =
calculateDistance(
userLocation,
turnLocation
);
Если расстояние становится меньше порогового значения, запускается голосовая подсказка.
Каждую инструкцию необходимо озвучивать только один раз.
Пример:
const spokenInstructions =
new Set();
Проверка:
if (
!spokenInstructions.has(
instruction.id
)
) {
speak(
instruction.announcement
);
spokenInstructions.add(
instruction.id
);
}
Без такой защиты голосовые сообщения будут постоянно повторяться.
Для одного манёвра часто существует несколько сообщений:
Через 1000 метров поверните направо
Через 300 метров поверните направо
Поверните направо
Каждое предупреждение имеет собственное значение:
distanceAlongGeometry
Логика может выглядеть следующим образом:
if (
distanceToTurn <=
instruction.distanceAlongGeometry
) {
speak(
instruction.announcement
);
}
Если инструкции поступают слишком часто, полезно организовать очередь.
const queue = [];
Добавление:
queue.push(
instruction.announcement
);
Воспроизведение:
function processQueue() {
if (
speechSynthesis.speaking
) {
return;
}
const text =
queue.shift();
if (!text) {
return;
}
speak(text);
}
Запуск:
setInterval(
processQueue,
500
);
Очередь предотвращает наложение сообщений друг на друга.
Иногда требуется немедленно остановить речь.
speechSynthesis.cancel();
Пример использования:
if (
routeRecalculated
) {
speechSynthesis.cancel();
}
После перестроения маршрута устаревшие инструкции становятся неактуальными.
При сходе пользователя с маршрута необходимо:
Пример:
spokenInstructions.clear();
instructions.length = 0;
После получения нового маршрута инструкции формируются повторно.
Directions API поддерживает различные языки.
Пример:
const url =
'https://api.mapbox.com/directions/v5/mapbox/driving/' +
coordinates +
'?steps=true' +
'&voice_instructions=true' +
'&language=ru' +
'&access_token=' +
mapboxgl.accessToken;
Параметр:
language=ru
заставляет сервис возвращать инструкции на русском языке.
Примеры:
language=en
language=de
language=fr
language=es
language=it
Голосовые инструкции часто сопровождаются визуальными подсказками.
Пример отображения:
instructionPanel.textContent =
instruction.announcement;
Одновременно запускается речь:
speak(
instruction.announcement
);
Такой подход улучшает восприятие навигации в шумной среде или при отключённом звуке.
Хотя Mapbox GL JS предназначен главным образом для веб-картографии, его можно использовать как основу навигационного интерфейса.
Типичная схема:
Mapbox GL JS
+
Directions API
+
Geolocation API
+
Web Speech API
Компоненты выполняют разные функции:
| Компонент | Назначение |
|---|---|
| Mapbox GL JS | Отображение карты |
| Directions API | Построение маршрута |
| Geolocation API | Получение координат |
| Web Speech API | Озвучивание инструкций |
Подобная архитектура позволяет реализовать полноценную браузерную навигацию с визуальными и голосовыми подсказками без использования нативных мобильных SDK.