[Open source, JavaScript, Голосовые интерфейсы] Навыки для виртуальных ассистентов на веб-технологиях
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Недавно Cбер запустил Салют — семейство виртуальных ассистентов, которые работают на разных платформах. Мы в SberDevices, кроме самого ассистента, занимаемся разработкой инструментов, позволяющих любому разработчику удобно создавать навыки, которые называются смартапы. Кроме общеизвестных диалоговых сценариев в формате чата — ChatApp, можно создавать смартапы в формате веб-приложения на любых известных веб-технологиях — Canvas App. О том, как создать простейший смартап такого типа, и пойдет сегодня речь.Canvas App — стандартное веб-приложение в привычном понимании, которое запускается и работает внутри WebView, но есть свои особенности.
Как это работает по шагам:
- Пользователь произносит ключевую фразу, например «Салют, какие у меня задачи на сегодня».
- Голосовой запрос приходит в NLP-платформу, где разбирается на фонемы, там же определяется его эмоциональный окрас и т.д..
- В БД зарегистрированных смартапов находится тот, которому соответствует активационная фраза. Регистрация происходит через SmartApp Studio и доступна всем разработчикам без исключения.
- Во время регистрации смартапа в SmartApp Studio разработчик указывает два эндпоинта: один для веб-приложения, второй для сценарного бэкенда. Именно их достанет из БД NLP-платформа, когда найдет соответствующий смартап.
- В эндпоинт сценарного бэкенда будет отправлено сообщение с распознанной активационной фразой. Формат сообщений подробно описан в документации SmartApp API.
- Эндпоинт веб-приложения будет указан для загрузки в WebView.
- Ответ от сценарного бэкенда придёт в веб-приложение в качестве JS-события, подписавшись на которое, можно управлять веб-приложением.
Упрощенная схема для наглядностиПредмет нашего разговора – веб-приложение. Делать будем смартап для ведения тудушек. Поскольку SmartApp Studio предоставляет онлайн-среду разработки сценариев, не будем подробно на этом останавливаться, а воспользуемся форком готового сценария, который в качестве примера доступен на GitHub. В одной из следующих статей расскажем, как написать такой сценарий на NodeJS.В SmartApp Graph/IDE, той самой онлайн-среде, в качестве источника можно указать git-репозиторий, чем мы и воспользуемся, чтобы получить эндпоинт до сценарного бэкенда. Далее его надо указать при регистрации нашего смартапа в SmartApp Studio. В качестве эндпоинта веб-приложения укажем любой известный веб-ресурс, например, sberdevices.ru. Позже поменяем на URL нашего веб-приложения.Шаблон проектаДля примера будем делать веб-приложение на React. К React нет никакой привязки и пример ниже может быть написан на чём угодно. Для нетерпеливых выложили конечный результат на GitHub.Итак, что мы хотим от приложения:
- добавлять задачи;
- выполнять задачи;
- удалять задачи;
- и все это голосом, но не сразу.
Для создания базового проекта воспользуемся CRA.> npx create-react-app todo-canvas-appДля реализации UI нам понадобится как минимум пара компонентов и форма. Код формы
export const App: FC = memo(() => {
const [note, setNote] = useState("");
return (
<main className="container">
<form
onSubmit={(event) => {
event.preventDefault();
setNote("");
}}
>
<input
className="add-note"
type="text"
value={note}
onChange={({ target: { value } }) => setNote(value)}
/>
</form>
<ul className="notes">
{appState.notes.map((note, index) => (
<li className="note" key={note.id}>
<span>
<span style={{ fontWeight: "bold" }}>{index + 1}. </span>
<span
style={{
textDecorationLine: note.completed ? "line-through" : "none",
}}
>
{note.title}
</span>
</span>
<input
className="done-note"
type="checkbox"
checked={note.completed}
/>
</li>
))}
</ul>
</main>
);
});
Дальше нам надо сделать базовую логику нашего приложения. Пользоваться будем стандартными средствами React, используя useReducer.Код редьюсера
const reducer = (state, action) => {
switch (action.type) {
case "add_note":
return {
...state,
notes: [
...state.notes,
{
id: Math.random().toString(36).substring(7),
title: action.note,
completed: false,
},
],
};
case "done_note":
return {
...state,
notes: state.notes.map((note) =>
note.id === action.id ? { ...note, completed: !note.completed } : note
),
};
case "delete_note":
return {
...state,
notes: state.notes.filter(({ id }) => id !== action.id),
};
default:
throw new Error();
}
};
Далее будем диспатчить экшены их обработчиков на форме.Код подключения
export const App: FC = memo(() => {
const [appState, dispatch] = useReducer(reducer, { notes: [] });
//...
return (
<main className="container">
<form
onSubmit={(event) => {
event.preventDefault();
dispatch({ type: "add_note", note });
setNote("");
}}
>
<input
className="add-note"
type="text"
placeholder="Add Note"
value={note}
onChange={({ target: { value } }) => setNote(value)}
required
autoFocus
/>
</form>
<ul className="notes">
{appState.notes.map((note, index) => (
<li className="note" key={note.id}>
<span>
<span style={{ fontWeight: "bold" }}>{index + 1}. </span>
<span
style={{
textDecorationLine: note.completed ? "line-through" : "none",
}}
>
{note.title}
</span>
</span>
<input
className="done-note"
type="checkbox"
checked={note.completed}
onChange={() => dispatch({ type: "done_note", id: note.id })}
/>
</li>
))}
</ul>
</main>
);
});
Запускаем и проверяем.npm start
Работа с голосомКогда наше приложение базово работает, можно добавить немного магии голосового управления. Для этого надо установить Assistant Client — библиотеку для взаимодействия с виртуальным ассистентом.npm i @sberdevices/assistant-clientВ момент открытия WebView платформа инжектит JS API для взаимодействия с ассистентом. Это биндиги до нативных методов платформы. Assistant Client — обёртка, которая в дев-режиме позволяет отлаживать взаимодействие с ассистентом в браузере, а в продакшене предоставляет удобный для веб-приложений API.Идём в app.js и там же, где наш основной редюсер, создаем инстанс Assistant Client.
const initializeAssistant = () => {
if (process.env.NODE_ENV === "development") {
return createSmartappDebugger({
token: process.env.REACT_APP_TOKEN ?? "",
initPhrase: `Запусти ${process.env.REACT_APP_SMARTAPP}`,
});
}
return createAssistant();
};
Судя по коду выше, нужен некий токен. Токен обеспечивает авторизацию сообщений в NLP-платформе. Токен автоматически приклеивается к сообщениям, когда смартап запускается на устройстве, но в нашем случае это браузер, поэтому токен надо передать вручную. Токен генерируется автоматически для каждого разработчика в SmartApp Studio.
После этого перезапустим наше приложение. Теперь мы видим панельку ассистента с лавашаром и текстовым полем. Лавашар это такое визуальное представление ассистента. По нажатию на лавашар включится микрофон и вы сможете отправить команду ассистенту так же, как вы бы это сделали, запуская смартап на устройстве. Относитесь к этому не как к эмулятору, а как к дев-тулзам, в продакшене всё это за нас будет делать платформа. Те же самые команды вы можете посылать не только голосом, но и текстом, используя текстовое поле рядом с лавашаром, чтобы не будить своих домашних по ночам.
Ассистент присылает структурированные команды в формате JSON. Полное описание формата можно найти в документации Assistant Client на GitHub.
interface AssistantSmartAppCommand {
// Тип команды
type: "smart_app_data";
// Любые данные, которые нужны смартапу
smart_app_data: Record<string, any>;
sdkMeta: {
requestId: string;
};
}
Теперь подпишем наши экшены на команды от ассистента. Для этого в коде нашего сценария определены специальные интенты — ключевые слова в фразах, которые может говорить пользователь. Разные интенты генерируют разные команды веб-приложению.
export const App: FC = memo(() => {
const [appState, dispatch] = useReducer(reducer, { notes: [] });
const [note, setNote] = useState("");
const assistantRef = useRef();
useEffect(() => {
assistantRef.current = initializeAssistant();
assistantRef.current.on("data", ({ action }) => {
if (action) {
dispatch(action);
}
});
}, []);
// ...
Сохраняем, запускаем — ничего не работает. Не волнуйтесь, так и должно быть. Я приоткрою завесу того, как на самом деле работает магия. Дело в том, что ваш сценарий сам по себе только лишь по фразе пользователя не может узнать то, что у вас сейчас на экране. Чтобы эта магия работала, к каждому голосовому запросу необходимо клеить стейт веб-приложения. Тут мы приходим к осознанию, что сценарный бэкенд получает на вход не только разобранную фразу, но и данные с экрана — стейт. Задача сценария провести пользователя к следующему шагу по этим двум параметрам, отправив команду веб-приложению на изменение стейта. Можно мыслить себе это как голосовой аналог клика. Разница лишь в том, что элемент управления для такого клика в интерфейсе может и не существовать физически. Например, если бы мы делали интернет-магазин, то кнопку добавления в корзину можно было бы и опустить в пользу голосовой команды «Афина, добавь в корзину красные туфли».Для того, чтобы это было удобно делать из веб-приложения, в Assistant Client есть API для передачи состояния — getState. В нашем случае стейт – это список тудушек и некоторая мета-информация.Дополним код инициализации Asisstant Client.
const initializeAssistant = (getState) => {
if (process.env.NODE_ENV === "development") {
return createSmartappDebugger({
token: process.env.REACT_APP_TOKEN ?? "",
initPhrase: `Запусти ${process.env.REACT_APP_SMARTAPP}`,
getState,
});
}
return createAssistant({ getState });
};
И передадим стейт в обработку ассистенту. Формат стейта также описан в документации Asisstant Client.
export const App: FC = memo(() => {
// ...
const assistantStateRef = useRef<AssistantAppState>();
// ...
useEffect(() => {
assistantRef.current = initializeAssistant(() => assistantStateRef.current);
// ...
}, []);
useEffect(() => {
assistantStateRef.current = {
item_selector: {
items: appState.notes.map(({ id, title }, index) => ({
number: index + 1,
id,
title,
})),
},
};
}, [appState]);
// ...
Из кода выше видим появление мета-информации в виде нумерации. Зачем? Согласитесь, тудухи могут быть довольными длинными и иногда удобнее было бы говорить «Джой, я сделал первую задачу» вместо полного заголовка. Но погодите, как это работает? Где единичка превращается в «первую»? Эту магию кастования натуральных фраз, которые мы привыкли использовать в повседневной речи, в машинный формат делает за нас NLP-платформа. То же самое происходит, например, с командами навигации.
Тудух может скопиться достаточное количество, чтобы они не влезли в экран. Само собой, мы хотим уметь скроллить экран, чтобы иметь возможность прочитать всё, что скопилось. На устройствах, где нет тач-интерфейса, например, на SberBox, мы можем скроллить пультом ДУ или голосом. Нажатия кнопок на пульте превращаются в события нажатий на стрелки клавиатуры на window, но что делать с голосом?Голосовые паттерны навигации встроены в NLP-платформу, и разработчику сценария ничего не надо делать самому. А для разработчика веб-приложения достаточно подписаться на специальный тип команд, приходящих от ассистента через Assistant Client. Все вариации навигационных фраз будут кастится в конечное число навигационных команд. Их всего пять: UP, DOWN, LEFT, RIGHT, BACK.
assistant.on('data', (command) => {
if (command.navigation) {
switch(command.navigation.command) {
case 'UP':
window.scrollTo(0, 0);
break;
case 'DOWN':
window.scrollTo(0, 1000);
break;
}
}
});
Перезапускаем наше приложение и пробуем после нажатия на лавашар сказать: «Напомни купить коту корм». И вуаля!Если у вас есть устройство под рукой, то можно проверить работу смартапа на нём. Для этого не обязательно его публиковать или деплоить куда-либо. Достаточно создать тоннель с локального хоста, например, с помощью ngrok.ngrok http 3000
Полученный URL с https указываем в SmartApp Studio, сохраняем черновик и говорим ассистенту: «Сбер, какие у меня задачи на сегодня?». Это cработает, если вы залогинены под одним и тем же SberID на устройстве и в SmartApp Studio. Черновики по-умолчанию доступны к запуску на устройствах разработчика.Вместо эпилогаСмысл статьи — в наглядной демонстрации того, как голосовое управление прозрачным образом можно интегрировать не только в специально для этого созданные приложения, но и в уже существующие. Например, если у вас уже есть рабочий веб-сервис, то научить его работать на платформе Салют не составит большого труда. Этот короткое интро — скорее, обзор возможностей на искусственном примере. Как сделать смартап с компонентами, оплатой, автотестами, обязательно расскажем в следующих статьях. Спасибо за внимание, ещё увидимся!По всем вопросам разработки смартапов можно обращаться в сообщество разработчиков SmartMarket в телеграмме.
===========
Источник:
habr.com
===========
Похожие новости:
- [JavaScript, ReactJS] React Server Components — что это?
- [JavaScript] Странные применения валидации
- [Разработка веб-сайтов, JavaScript, VueJS, TypeScript] Какой будет новая версия Vuex? (перевод)
- [Open source, *nix] FOSS News №48 – дайджест новостей и других материалов о свободном и открытом ПО за 21-27 декабря 2020 года
- [Разработка веб-сайтов, Open source, JavaScript, ReactJS, TypeScript] Что выбрать в качестве библиотеки компонентов для React-проекта
- [Open source, Сетевые технологии, Kubernetes] Шифрование передаваемых данных в Calico Enterprise
- [Open source, DevOps, Kubernetes] Безопасность конфиденциальных данных с Traefik Enterprise и Vault (перевод)
- [Open source, Сетевые технологии, Kubernetes] Решение проблем связанности микросервисов с помощью сетевых журналов (перевод)
- [Машинное обучение, Разработка робототехники, Робототехника, Подготовка технической документации] Manipulation Process Efficiency (MPE) Benchmark
- [Ruby, Oracle, Python, JavaScript, Java] Опыт сопряжения Java, JavaScript, Ruby и Python в одном проекте посредством GraalVM
Теги для поиска: #_open_source, #_javascript, #_golosovye_interfejsy (Голосовые интерфейсы), #_javascript, #_golosovye_assistenty (голосовые ассистенты), #_react, #_vebrazrabotka (веб-разработка), #_blog_kompanii_sber (
Блог компании Сбер
), #_blog_kompanii_sberdevices (
Блог компании SberDevices
), #_open_source, #_javascript, #_golosovye_interfejsy (
Голосовые интерфейсы
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:32
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Недавно Cбер запустил Салют — семейство виртуальных ассистентов, которые работают на разных платформах. Мы в SberDevices, кроме самого ассистента, занимаемся разработкой инструментов, позволяющих любому разработчику удобно создавать навыки, которые называются смартапы. Кроме общеизвестных диалоговых сценариев в формате чата — ChatApp, можно создавать смартапы в формате веб-приложения на любых известных веб-технологиях — Canvas App. О том, как создать простейший смартап такого типа, и пойдет сегодня речь.Canvas App — стандартное веб-приложение в привычном понимании, которое запускается и работает внутри WebView, но есть свои особенности. Как это работает по шагам:
Упрощенная схема для наглядностиПредмет нашего разговора – веб-приложение. Делать будем смартап для ведения тудушек. Поскольку SmartApp Studio предоставляет онлайн-среду разработки сценариев, не будем подробно на этом останавливаться, а воспользуемся форком готового сценария, который в качестве примера доступен на GitHub. В одной из следующих статей расскажем, как написать такой сценарий на NodeJS.В SmartApp Graph/IDE, той самой онлайн-среде, в качестве источника можно указать git-репозиторий, чем мы и воспользуемся, чтобы получить эндпоинт до сценарного бэкенда. Далее его надо указать при регистрации нашего смартапа в SmartApp Studio. В качестве эндпоинта веб-приложения укажем любой известный веб-ресурс, например, sberdevices.ru. Позже поменяем на URL нашего веб-приложения.Шаблон проектаДля примера будем делать веб-приложение на React. К React нет никакой привязки и пример ниже может быть написан на чём угодно. Для нетерпеливых выложили конечный результат на GitHub.Итак, что мы хотим от приложения:
export const App: FC = memo(() => {
const [note, setNote] = useState(""); return ( <main className="container"> <form onSubmit={(event) => { event.preventDefault(); setNote(""); }} > <input className="add-note" type="text" value={note} onChange={({ target: { value } }) => setNote(value)} /> </form> <ul className="notes"> {appState.notes.map((note, index) => ( <li className="note" key={note.id}> <span> <span style={{ fontWeight: "bold" }}>{index + 1}. </span> <span style={{ textDecorationLine: note.completed ? "line-through" : "none", }} > {note.title} </span> </span> <input className="done-note" type="checkbox" checked={note.completed} /> </li> ))} </ul> </main> ); }); const reducer = (state, action) => {
switch (action.type) { case "add_note": return { ...state, notes: [ ...state.notes, { id: Math.random().toString(36).substring(7), title: action.note, completed: false, }, ], }; case "done_note": return { ...state, notes: state.notes.map((note) => note.id === action.id ? { ...note, completed: !note.completed } : note ), }; case "delete_note": return { ...state, notes: state.notes.filter(({ id }) => id !== action.id), }; default: throw new Error(); } }; export const App: FC = memo(() => {
const [appState, dispatch] = useReducer(reducer, { notes: [] }); //... return ( <main className="container"> <form onSubmit={(event) => { event.preventDefault(); dispatch({ type: "add_note", note }); setNote(""); }} > <input className="add-note" type="text" placeholder="Add Note" value={note} onChange={({ target: { value } }) => setNote(value)} required autoFocus /> </form> <ul className="notes"> {appState.notes.map((note, index) => ( <li className="note" key={note.id}> <span> <span style={{ fontWeight: "bold" }}>{index + 1}. </span> <span style={{ textDecorationLine: note.completed ? "line-through" : "none", }} > {note.title} </span> </span> <input className="done-note" type="checkbox" checked={note.completed} onChange={() => dispatch({ type: "done_note", id: note.id })} /> </li> ))} </ul> </main> ); }); Работа с голосомКогда наше приложение базово работает, можно добавить немного магии голосового управления. Для этого надо установить Assistant Client — библиотеку для взаимодействия с виртуальным ассистентом.npm i @sberdevices/assistant-clientВ момент открытия WebView платформа инжектит JS API для взаимодействия с ассистентом. Это биндиги до нативных методов платформы. Assistant Client — обёртка, которая в дев-режиме позволяет отлаживать взаимодействие с ассистентом в браузере, а в продакшене предоставляет удобный для веб-приложений API.Идём в app.js и там же, где наш основной редюсер, создаем инстанс Assistant Client. const initializeAssistant = () => {
if (process.env.NODE_ENV === "development") { return createSmartappDebugger({ token: process.env.REACT_APP_TOKEN ?? "", initPhrase: `Запусти ${process.env.REACT_APP_SMARTAPP}`, }); } return createAssistant(); }; После этого перезапустим наше приложение. Теперь мы видим панельку ассистента с лавашаром и текстовым полем. Лавашар это такое визуальное представление ассистента. По нажатию на лавашар включится микрофон и вы сможете отправить команду ассистенту так же, как вы бы это сделали, запуская смартап на устройстве. Относитесь к этому не как к эмулятору, а как к дев-тулзам, в продакшене всё это за нас будет делать платформа. Те же самые команды вы можете посылать не только голосом, но и текстом, используя текстовое поле рядом с лавашаром, чтобы не будить своих домашних по ночам. Ассистент присылает структурированные команды в формате JSON. Полное описание формата можно найти в документации Assistant Client на GitHub. interface AssistantSmartAppCommand {
// Тип команды type: "smart_app_data"; // Любые данные, которые нужны смартапу smart_app_data: Record<string, any>; sdkMeta: { requestId: string; }; } export const App: FC = memo(() => {
const [appState, dispatch] = useReducer(reducer, { notes: [] }); const [note, setNote] = useState(""); const assistantRef = useRef(); useEffect(() => { assistantRef.current = initializeAssistant(); assistantRef.current.on("data", ({ action }) => { if (action) { dispatch(action); } }); }, []); // ... const initializeAssistant = (getState) => {
if (process.env.NODE_ENV === "development") { return createSmartappDebugger({ token: process.env.REACT_APP_TOKEN ?? "", initPhrase: `Запусти ${process.env.REACT_APP_SMARTAPP}`, getState, }); } return createAssistant({ getState }); }; export const App: FC = memo(() => {
// ... const assistantStateRef = useRef<AssistantAppState>(); // ... useEffect(() => { assistantRef.current = initializeAssistant(() => assistantStateRef.current); // ... }, []); useEffect(() => { assistantStateRef.current = { item_selector: { items: appState.notes.map(({ id, title }, index) => ({ number: index + 1, id, title, })), }, }; }, [appState]); // ... Тудух может скопиться достаточное количество, чтобы они не влезли в экран. Само собой, мы хотим уметь скроллить экран, чтобы иметь возможность прочитать всё, что скопилось. На устройствах, где нет тач-интерфейса, например, на SberBox, мы можем скроллить пультом ДУ или голосом. Нажатия кнопок на пульте превращаются в события нажатий на стрелки клавиатуры на window, но что делать с голосом?Голосовые паттерны навигации встроены в NLP-платформу, и разработчику сценария ничего не надо делать самому. А для разработчика веб-приложения достаточно подписаться на специальный тип команд, приходящих от ассистента через Assistant Client. Все вариации навигационных фраз будут кастится в конечное число навигационных команд. Их всего пять: UP, DOWN, LEFT, RIGHT, BACK. assistant.on('data', (command) => {
if (command.navigation) { switch(command.navigation.command) { case 'UP': window.scrollTo(0, 0); break; case 'DOWN': window.scrollTo(0, 1000); break; } } }); Полученный URL с https указываем в SmartApp Studio, сохраняем черновик и говорим ассистенту: «Сбер, какие у меня задачи на сегодня?». Это cработает, если вы залогинены под одним и тем же SberID на устройстве и в SmartApp Studio. Черновики по-умолчанию доступны к запуску на устройствах разработчика.Вместо эпилогаСмысл статьи — в наглядной демонстрации того, как голосовое управление прозрачным образом можно интегрировать не только в специально для этого созданные приложения, но и в уже существующие. Например, если у вас уже есть рабочий веб-сервис, то научить его работать на платформе Салют не составит большого труда. Этот короткое интро — скорее, обзор возможностей на искусственном примере. Как сделать смартап с компонентами, оплатой, автотестами, обязательно расскажем в следующих статьях. Спасибо за внимание, ещё увидимся!По всем вопросам разработки смартапов можно обращаться в сообщество разработчиков SmartMarket в телеграмме. =========== Источник: habr.com =========== Похожие новости:
Блог компании Сбер ), #_blog_kompanii_sberdevices ( Блог компании SberDevices ), #_open_source, #_javascript, #_golosovye_interfejsy ( Голосовые интерфейсы ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:32
Часовой пояс: UTC + 5