Git Product home page Git Product logo

sberdevices / salutejs Goto Github PK

View Code? Open in Web Editor NEW
36.0 39.0 5.0 6.46 MB

SmartApp Framework для создания навыков семейства Виртуальных Ассистентов "Салют" на языке JavaScript

Home Page: https://sber.ru/salute

License: Other

TypeScript 98.60% JavaScript 1.40%
speech-recognition voice-assistant virtual-assistant nodejs artificial-intelligence

salutejs's Introduction

salutejs

SaluteJS

Set of minimalistic utils for Salute Assistants scenario implementation.

  • directly in code autocomplete for intents and app state;
  • strongly typed out of the box: whole SmartApp API types inside;
  • common types between scenario and Canvas Apps;
  • common API with Assistant Client;
  • runtime enitity variables and state validation;
  • nodejs web-frameworks integration support: expressjs, hapi, koa;
  • client frameworks integration support: NextJS, Gatsby;
  • any types of recognizers: RegExp, String Similarity, SmartApp Brain;
  • custom recognizer API;
  • intents and entities sync with SmartApp Brain;
  • session persisting adapters: memory, mongodb, redis;
  • assistants based phrases dictionary declaration support.

What's inside

Translations

SberDevices with ❤️

salutejs's People

Contributors

alexandrgil avatar awinogradov avatar burzachil avatar dependabot[bot] avatar emochalova avatar evgeniysemin avatar ivan-ushatsky avatar katekate avatar kvpolyanskiy avatar lamaeats avatar magom001 avatar sasha-tlt avatar sberdevices-eva avatar snyuryev avatar soulko avatar turanchoks avatar yeti-or avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

salutejs's Issues

Request/Response mocks

  • Написать моки для входящих/исходящих запросов
  • Замокать рекогнайзер (ответы Caila)

Assistant based phrases dictionary

i18n but for assistants: sber, afina, joy.

Proposal

phrases.i18n/sber.ts

export const sber = {
  initialMessage: 'Здравствуйте!',
  '{count} карточка': {
        one: '{count} карточка',
        some: '{count} карточки',
        many: '{count} карточек',
        none: '{count} карточек'
    },
}

phrases.i18n/sber.ts

export const joy = {
  initialMessage: 'Привет!',
  '{count} карточка': {
        one: '{count} карточка',
        some: '{count} карточки',
        many: '{count} карточек',
        none: '{count} карточек'
    },
}

phrases.i18n/sber.ts

export * from './sber';
export * from './joy';

scenario.ts

import i18nFactory, { setAssistant } from '@salutejs/i18n';

import * as keyset from './phrases.i18n';

const i18n = i18nFactory(keyset);

// ....

app.post('/hook', async ({ body }, response) => {
    const req = createSaluteRequest(body);
    const res = createSaluteResponse(body);

    setAssistant(req.character);

     // ...

    console.log(i18n('intitalMessage')); // !!!!
    console.log(i18n('{count} карточка', { count: 1 })); // !!!!

    await scenarioWalker({ req, res, session });
   
   // ...

    response.status(200).json(res.message);
});

Docs update

  • SmartApp Brain tokens
  • request API
  • response API
  • scenario children
  • dive logic
  • slot filling logic
  • matchers API
  • brain CLI intents.json
  • examples

Simple item_selector getter

Use const item req.state.select(note) (Ex) instead of
const item = req.state?.item_selector.items.find((i) => i.title.toLowerCase() === note.toLowerCase());

Вопрос по StringSimilarityRecognizer

В userScenario

Next: {
    match: text("продолжить"),
    handle: ({res}) => res.setPronounceText("хорошо, продолжаю"),
  },

Если отправить

"original_text": "Продолжить"

то не матчит

Если отправить

"original_text": "продолжить"

то матчит

Как сделать StringSimilarityRecognizer регистронезависимым?

appendBubble extra options

Expand policy

res.appendBubble('say', { expand: 'force_expand' });

Ref https://developer.sberdevices.ru/docs/ru/developer_tools/amp/smartapp_interface_elements

"expand_policy": "auto_expand"|"force_expand"|"preserve_panel_state" //optional, default value auto_expand
         //актуально для ассистента в девайсах
         //auto_expand - Если текст помещается в США, то он отобразится в ней, без разворачивания США.
                         Если текст не помещается в США, то США разверентся.
         //force_expand - США развернется принудительно.
         //preserve_panel_state -  Если США уже свернуто, текст отобразится в США, не зависимо от размера текста.
                                   Если США развернуто - текст отобразится в развернутой шторке ассистента (РаША).

Pronounce

res.appendBubble('say', { pronounce: true });

Instead of

res.setPronounceText('say');
res.appendBubble('say');

Лишняя вложенность при отправке команде через appendData

Отравляю команду следующим образом:

const helpPayload = { path: '/about' };
const helpCommand = { type: 'smart_app_data', payload: helpPayload };
res.appendCommand(helpCommand);

На клиент в onData приходит:

{"type":"smart_app_data","smart_app_data":{"type":"smart_app_data","payload":{"path":"/about"}},"sdk_meta":{"mid":1618346995063}}

кажется должно быть

{"type":"smart_app_data","smart_app_data":{"path":"/about"},"sdk_meta":{"mid":1618346995063}}

Runtime validation for variables and state

import * as yup from "yup";

let schema = yup
  .object()
  .shape({
    name: yup.string().required(),
    age: yup.number().required().positive().integer(),
    email: yup.string().email(),
    website: yup.string().url(),
    createdOn: yup.date().default(function () {
      return new Date();
    })
  })
  .required();

export const validateBody = <S extends yup.ObjectSchema<any>>({
  schema,
  body
}: {
  schema: S;
  body: any;
}) => {
  return schema.validate(body, {
    abortEarly: false,
    stripUnknown: true
  }) as Promise<yup.InferType<S>>;
};

const fn = async (q: any) => {
  const a = await validateBody({ schema, body: q });
}

Hasky

  • prepush tests
  • precommit conventional-commits

Add Configs

  • - tsconfig
  • - editorconfig
  • - eslintconfig
  • - prettier

error TS2536 в matchers.d.ts

node_modules/@salutejs/scenario/dist/lib/matchers.d.ts:9:36 - error TS2536: Type '"item_selector"' cannot be used to index type 'R["state"]'.

9     selectItem: (expected: Partial<R['state']['item_selector']['items'][number]>) => (req: R) => {
                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/@salutejs/scenario/dist/lib/matchers.d.ts:9:36 - error TS2536: Type '"items"' cannot be used to index type 'R["state"]["item_selector"]'.

9     selectItem: (expected: Partial<R['state']['item_selector']['items'][number]>) => (req: R) => {
                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/@salutejs/scenario/dist/lib/matchers.d.ts:9:36 - error TS2536: Type 'number' cannot be used to index type 'R["state"]["item_selector"]["items"]'.

9     selectItem: (expected: Partial<R['state']['item_selector']['items'][number]>) => (req: R) => {
                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/@salutejs/scenario/dist/lib/matchers.d.ts:18:37 - error TS2536: Type '"item_selector"' cannot be used to index type 'R["state"]'.

18     selectItems: (expected: Partial<R['state']['item_selector']['items'][number]>) => (req: R) => {
                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/@salutejs/scenario/dist/lib/matchers.d.ts:18:37 - error TS2536: Type '"items"' cannot be used to index type 'R["state"]["item_selector"]'.

18     selectItems: (expected: Partial<R['state']['item_selector']['items'][number]>) => (req: R) => {
                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/@salutejs/scenario/dist/lib/matchers.d.ts:18:37 - error TS2536: Type 'number' cannot be used to index type 'R["state"]["item_selector"]["items"]'.

18     selectItems: (expected: Partial<R['state']['item_selector']['items'][number]>) => (req: R) => {
                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

node_modules/@salutejs/scenario/dist/lib/matchers.d.ts:27:24 - error TS2536: Type '"type"' cannot be used to index type 'R["serverAction"]'.

27     action: (expected: R['serverAction']['type']) => (req: R) => boolean;
                          ~~~~~~~~~~~~~~~~~~~~~~~~~

Use lerna

  • @salutejs/scenario
  • @salutejs/cli
  • @salutejs/memory

Middleware similar handlers API

import { intents } from './intents';
import { createScenario } from '@salutejs/scenario';

const globalScenario = createScenario(intents);

globalScenario.handle(req => req.intent === 'run_app'), ({ req, res, session }) => {/*...*/});

const mainPageScenario = createScenario(intents);

mainPageScenario.handle(req => req.state.screen === 'tourPage'), ({ req, res, session }) => {/*...*/});
mainPageScenario.handle(req => req.state.screen === 'tourPage' && req.intent === 'yes'), ({ req, res, session }) => {/*...*/});
mainPageScenario.handle(req => req.state.screen === 'tourPage' && req.intent === 'no'), ({ req, res, session }) => {/*...*/});

globalScenario.handle(req => req.intent === 'mainPage'), ({ req, res, session }) => {/*...*/});
globalScenario.handle(req => req.intent === 'mainPage'), mainPageScenario);

With object predicates

globalScenario.handle(req => req.intent === 'run_app'), ({ req, res, session }) => {/*...*/});

const mainPageScenario = createScenario(intents);

mainPageScenario.handle({ req: { state: { screen: 'tourPage' } } }, ({ req, res, session }) => {/*...*/});
mainPageScenario.handle({ req: { intent: 'yes', state: { screen: 'tourPage' } } }, ({ req, res, session }) => {/*...*/});
mainPageScenario.handle({ req: { intent: 'no', state: { screen: 'tourPage' } } }, ({ req, res, session }) => {/*...*/});

globalScenario.handle({ req: { intent: 'mainPage' } }, ({ req, res, session }) => {/*...*/});
globalScenario.handle({ req: { intent: 'mainPage' } }, mainPageScenario);

Check hash for remote Brain intents

Храним локально хеш от интентов после пула
На пуше проверяем хеши и если не совпадают падаем с ошибкой и предложением сделать пулл

Guides

  • Contribution
  • Code of conduct

Warn for nonexistent inferred intent in intentsDict

Если рекогнайзер распознал интент, но его нет в локальном словаре интентов, то шлем варнинг. Потому что кажется, что надо сделать brain pull.

Prepublish

  • files section: README.md, LICENSE.txt
  • symbolic links: .npmrc, LICENSE.txt

Ошибка в модуле @salute/types

Error: Cannot find module '.../node_modules/@salutejs/types/dist/index.d.js'. Please verify that the package.json has a valid "main" entry

Сейчас:
"main": "dist/index.d.js",
дб
"main": "dist/index.js",

The way to programmatic API

Часть 1: заведение пустого проекта в code по API (временно под ?)

  • Залогиниться в студии, достать из local storage access_token и refresh_token
  • С ними можно ходить в REST ручки Graph

Часть 2: походы в ручки кайлы

  • Заводим новый проект через code
  • На странице "Настройки проекта" -> "Классификатор" получаем access_token
  • Доступ до API Caila по access_token
  • Придумать формат для описания интентов + сущностей и из связь
  • Уметь делать import / export данных в и из кайлы (ручки /import и /export)
  • Тренировать модель (/train)

Чусть 3: сценарий

  • Создать проект типа Webhook в студии
  • Поднять необходимую инфраструктуру для локальной разработки проекта
  • Начать писать сценарий
  • Для распознавания интентов/сущностей используем ручку /inference API Caila

Payments support

API Proposal

import { createOrder, registerPayment } from '@salutejs/payments';

handle: ({ req, res }) => {
  const { delivery, items, order } = req.variables;
  
  const order = createOrder({ dilevery, items, order });
  
  const { invoiceId } = async registerPayment(order);
  
  res.askPayment(invoiceId);
}

res.createPayment(invoiceId);

{
    "command": "POLICY_RUN_APP",
    "nodes": {
      "server_action": {
        "app_info": {
          "systemName": "payment_app"
        },
        "parameters": {
          "invoice_id": "XXX",
          "app_info": {
            "projectId": "XXX"
          }
        }
      }
    }
  }

askPayment

curl --location --request POST 'https://smartmarket.online.sberbank.ru/smartpay/v1/invoices' \
--header 'accept: application/json' \
--header 'Authorization: Bearer XXXX'\
--header 'Content-Type: application/json' \
--header 'Content-Type: text/plain' \
--data-raw '{
    "ptype": 0,
    "invoice": {
        "purchaser": {
            "email": string,
            "phone": number,
            "contact": "email"
        },
        "delivery_info": {
            "address": {
                "country": "RU",
                "city": string,
                "address": string
            },
            "delivery_type": "courier",
            "description": "позвонить перед отправкой"
        },
        "invoice_params": [
            {
                "key": "packageName",
                "value": string
            }
        ],
        "order": {
            "order_id": string,
            "order_number": number,
            "order_date": DateTime,
            "service_id": string,
            "amount": number,
            "currency": "RUB",
            "purpose": string,
            "description": string,
            "language": "ru-RU",
            "expiration_date": DateTime,
            "autocompletion_date": DateTime,
            "tax_system": 0,
            "order_bundle": [
                {
                    "position_id": 1,
                    "name": string,
                    "item_params": [
                        {
                            "key": "packageName",
                            "value": string
                        }
                    ],
                    "quantity": {
                        "value": 1,
                        "measure": "кг."
                    },
                    "item_amount": numbrt,
                    "currency": "RUB",
                    "item_code": string,
                    "item_price": number,
                    "discount_type": "percent",
                    "discount_value": number,
                    "interest_type": "agentPercent",
                    "interest_value": number,
                    "tax_type": number,
                    "tax_sum": number
                }
            ]
        }
    }
}'

new System Intent

PAY_DIALOG_FINISHED

NB: Graph reference

Docs https://developer.sberdevices.ru/docs/ru/payment_tools/payment_steps

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.