Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Протестировать методы API можно на странице интерактивного обозревателя API и без написания кода
Некоторые ресурсы, описанные на странице, по умолчанию могут быть не доступны из-за типа приложения (см. Создание и авторизация приложений)

Преобразование речи в текст может быть двух видов:

  1. Правило голосовой навигации (voice_helper) в голосовом меню.

  2. Отправка распознанного текста событиями во время разговора.

Работает только при активированной функции speech_to_text в клиентской конфигурации (эта настройка доступна только администратору платформы)

Table of Contents

Правило голосовой навигации в голосовом меню:

Перед заданием правил голосовой навигации администратором платформы должна быть включена возможность использования правила voice_helper голосового меню. В обратном случае правило не может быть создано, а при отключении функционала правило в настройках голосового меню будет проигнорировано. Права приложения API должны быть all (также включается администратором платформы). Настройка выполняется аналогично другим правилам голосового меню в опциях контекста, количество правил также не ограничено. В ходе распознавания доступен финальный результат распознавания и предположения (предположения доступны в случае прерывания распознавания по набору цифр либо по тайм-ауту).

Описание структур данных

Имя

Тип

Описание

action

string

voice_helper – установить правило голосовой навигации.
Основные параметры для работы этого действия:  sound, voice_helper_digits_max,  voice_helper_rules,  voice_helper_timeout, voice_helper_classic_term, voice_helper_final_count

sound

integer

Идентификатор звукового файла, который необходимо проиграть, можно получить с помощью ресурса: GET /client/{client_id}/sound/
Во время проигрывания файла начинается распознавание речи звонящего, распознавание заканчивается по нажатию кнопки-терминатора #, набору количества цифр донабора (voice_helper_digits_max), либо по тайм-ауту (voice_helper_timeout)

voice_helper_digits_max

integer

Количество цифр донабора, после которого заканчивается распознавание речи. Если на момент до набора нужного количества digits финальный результат распознавания недоступен, мы будем работать с предположениями

voice_helper_rules

string

Список правил переадресации в виде массива { “to_option” : номер_опции, “transcription”: “распознанное слово” }
Опция данного контекста должна быть создана, иначе она пропускается во время звонка. При создании правила опция не проверяется.
Создается опция правилом POST /extension/{extension_id}/ivr/context/{context_id}/options/
Транскрипция может быть вида "привет|здравствуйте” (слова перечислены символом “|”, пробелы вырезаются или должны отсутствовать, регистр символов значения не имеет. Не обязательно указывать слово полностью (если слово или часть слова, указанные в транскрипции, будут содержаться в распознанном слове, это будет считаться совпадением)

voice_helper_timeout 

integer

Время в миллисекундах, по истечении которого заканчивается распознавание речи. Если за это время финальный результат недоступен, мы будем работать с предположениями. Минимальное значение — 3000

voice_helper_classic_term

boolean

Разрешить либо запретить классический донабор с клавиатуры (по умолчанию запрещено и используется только как прерывание распознавания, см. параметр voice_helper_digits_max).
Логика аналогична донабору правила IVR Play sound, но перед переходом в опцию или на внутренний номер проверяются voice_helper_rules и, если там есть совпадения, то переход будет по ним, а не по донабору (приоритет у сказанного, а не набранного, хоть набранное и завершает распознавание сказанного)

voice_helper_final_count

integer

Количество попыток сообщить голосом то, что имеется в voice_helper_rules. Финальное распознавание определяется паузой в речи (до финального распознавания возможны только предположения). Обычно устанавливается от одной до трех попыток final_count

Создание правила голосового меню

К примеру, вызов попадает на внутренний номер с extension_id 204 в контекст 1 на опцию “start“. Будем считать, что контекст пустой и правил в нем еще нет. Добавляем правило, отправляем запрос:

Tabs
[{"content":{"version":1,"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"В разделе "},{"type":"text","text":"authentication","marks":[{"type":"strong"}]},{"type":"text","text":" в поля "},{"type":"text","text":"client_id","marks":[{"type":"strong"}]},{"type":"text","text":" и "},{"type":"text","text":"client_secret","marks":[{"type":"strong"}]},{"type":"text","text":"  требуется ввести полученные при регистрации приложения значения "},{"type":"text","text":"Application_ID","marks":[{"type":"strong"}]},{"type":"text","text":" и "},{"type":"text","text":"Application_Secret","marks":[{"type":"strong"}]},{"type":"text","text":", затем нажать на кнопку \""},{"type":"text","text":"Try it out!","marks":[{"type":"strong"}]},{"type":"text","text":"\". Если данные приложения верны, в ответ вернётся токен доступа ("},{"type":"text","text":"access_token","marks":[{"type":"strong"}]},{"type":"text","text":"). Полученный токен доступа следует ввести в поле \""},{"type":"text","text":"Access Token Field","marks":[{"type":"strong"}]},{"type":"text","text":"\" вверху страницы и сохранить его нажатием кнопки \""},{"type":"text","text":"Set Token","marks":[{"type":"strong"}]},{"type":"text","text":"\"."}]},{"type":"paragraph","content":[{"type":"text","text":"Создание контекста:"}]},{"type":"table","attrs":{"isNumberColumnEnabled":false,"layout":"default"},"content":[{"type":"tableRow","content":[{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"метод","marks":[{"type":"strong"}]}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"ресурс","marks":[{"type":"strong"}]}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"данные","marks":[{"type":"strong"}]}]}]}]},{"type":"tableRow","content":[{"type":"tableCell","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"POST"}]}]},{"type":"tableCell","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"/"},{"type":"text","text":"extension/204/ivr/context/1/options/start/rules/"}]}]},{"type":"tableCell","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"{"},{"type":"hardBreak"},{"type":"text","text":"\"voice_helper_digits_max\": 2,"},{"type":"hardBreak"},{"type":"text","text":"\"voice_helper_rules\": ["},{"type":"hardBreak"},{"type":"text","text":"{"},{"type":"hardBreak"},{"type":"text","text":"\"to_option\": 1,"},{"type":"hardBreak"},{"type":"text","text":"\"transcription\": \"привет|здравствуй|здарова\""},{"type":"hardBreak"},{"type":"text","text":"},"},{"type":"hardBreak"},{"type":"text","text":"{"},{"type":"hardBreak"},{"type":"text","text":"\"to_option\": 2,"},{"type":"hardBreak"},{"type":"text","text":"\"transcription\": \"прощай|пока\""},{"type":"hardBreak"},{"type":"text","text":"},"},{"type":"hardBreak"},{"type":"text","text":"],"},{"type":"hardBreak"},{"type":"text","text":"\"sound\": 52,"},{"type":"hardBreak"},{"type":"text","text":"\"voice_helper_timeout\": 7000"},{"type":"hardBreak"},{"type":"text","text":"}"}]}]}]}]},{"type":"paragraph","content":[{"type":"text","text":"Обновление текущего контекста:"}]},{"type":"table","attrs":{"isNumberColumnEnabled":false,"layout":"default"},"content":[{"type":"tableRow","content":[{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"метод","marks":[{"type":"strong"}]}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"ресурс","marks":[{"type":"strong"}]}]}]},{"type":"tableHeader","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"данные","marks":[{"type":"strong"}]}]}]}]},{"type":"tableRow","content":[{"type":"tableCell","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"PUT"}]}]},{"type":"tableCell","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"/"},{"type":"text","text":"extension/204/ivr/context/1/options/start/rules/1"}]}]},{"type":"tableCell","attrs":{},"content":[{"type":"paragraph","content":[{"type":"text","text":"{"},{"type":"hardBreak"},{"type":"text","text":"\"voice_helper_digits_max\": 2,"},{"type":"hardBreak"},{"type":"text","text":"\"voice_helper_rules\": ["},{"type":"hardBreak"},{"type":"text","text":"{"},{"type":"hardBreak"},{"type":"text","text":"\"to_option\": 1,"},{"type":"hardBreak"},{"type":"text","text":"\"transcription\": \"привет|здравствуй|здарова\""},{"type":"hardBreak"},{"type":"text","text":"},"},{"type":"hardBreak"},{"type":"text","text":"{"},{"type":"hardBreak"},{"type":"text","text":"\"to_option\": 2,"},{"type":"hardBreak"},{"type":"text","text":"\"transcription\": \"прощай|пока\""},{"type":"hardBreak"},{"type":"text","text":"},"},{"type":"hardBreak"},{"type":"text","text":"],"},{"type":"hardBreak"},{"type":"text","text":"\"sound\": 52,"},{"type":"hardBreak"},{"type":"text","text":"\"voice_helper_timeout\": 7000"},{"type":"hardBreak"},{"type":"text","text":"}"}]}]}]}]},{"type":"paragraph","content":[]}]},"id":"19d8553e-48b1-433a-b7b3-ac0f9b6bab25","label":"Интерактивный обозреватель API    ","type":"tab"},{"content":{"version":1,"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Для отправки запросов с помощью программы cURL установим значения переменных "},{"type":"text","text":"url ","marks":[{"type":"strong"}]},{"type":"text","text":"и "},{"type":"text","text":"access_token","marks":[{"type":"strong"}]},{"type":"text","text":":"}]},{"type":"paragraph","content":[{"type":"text","text":"export url=\"https://<hostname>/api/ver1.0\"","marks":[{"type":"code"}]},{"type":"text","text":" "},{"type":"hardBreak"},{"type":"text","text":"(где hostname — hostname API-сервера провайдера IP-телефонии),"}]},{"type":"paragraph","content":[{"type":"text","text":"export access_token=\"8SNsrS0jV35vfmKqKeKtRrHfpbg4UX\"","marks":[{"type":"code"}]},{"type":"text","text":" "},{"type":"hardBreak"},{"type":"text","text":"(полученный токен доступа)."}]},{"type":"paragraph","content":[{"type":"text","text":"Запрос для создания контекста:"}]},{"type":"codeBlock","attrs":{"language":"shell"},"content":[{"type":"text","text":"curl \\\n-H \"Authorization: Bearer ${access_token}\" \\\n-H \"Content-Type: application/json\" \\\r\n-d '{\n  \"voice_helper_digits_max\": 2,\n  \"voice_helper_rules\": [\n  {\n    \"to_option\": 1,\n    \"transcription\": \"привет|здравствуй|здарова\"\n  },\n  {\n    \"to_option\": 2,\n    \"transcription\": \"прощай|пока\"\n  },\n  ],\n  \"sound\": 52,\n  \"voice_helper_timeout\": 7000\n}' \\\n-X POST ${url}/extension/204/ivr/context/1/options/start/rules/"}]},{"type":"paragraph","content":[{"type":"text","text":"Запрос для обновления текущего контекста:"}]},{"type":"codeBlock","attrs":{"language":"shell"},"content":[{"type":"text","text":"curl \\\n-H \"Authorization: Bearer ${access_token}\" \\\n-H \"Content-Type: application/json\" \\\r\n-d '{\n  \"voice_helper_digits_max\": 2,\n  \"voice_helper_rules\": [\n  {\n    \"to_option\": 1,\n    \"transcription\": \"привет|здравствуй|здарова\"\n  },\n  {\n    \"to_option\": 2,\n    \"transcription\": \"прощай|пока\"\n  },\n  ],\n  \"sound\": 52,\n  \"voice_helper_timeout\": 7000\n}' \\\n-X PUT ${url}/extension/204/ivr/context/1/options/start/rules/1"}]}]},"id":"d64cceb4-96ce-4e6d-b799-3e3a83ab410a","label":"Программа cURL    ","type":"tab"},{"content":{"version":1,"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Для отправки запросов на языке Python установим значения переменных URL и ACCESS_TOKEN:"}]},{"type":"paragraph","content":[{"type":"text","text":"URL = \"https://<hostname>/api/ver1.0\"","marks":[{"type":"code"}]},{"type":"hardBreak"},{"type":"text","text":"(где hostname — hostname API-сервера провайдера IP-телефонии),"}]},{"type":"paragraph","content":[{"type":"text","text":"ACCESS_TOKEN = \"8SNsrS0jV35vfmKqKeKtRrHfpbg4UX\"","marks":[{"type":"code"}]},{"type":"hardBreak"},{"type":"text","text":"(полученный токен доступа)."}]},{"type":"paragraph","content":[{"type":"text","text":"Запрос для создания контекста:"}]},{"type":"codeBlock","attrs":{"language":"python"},"content":[{"type":"text","text":"#!/usr/bin/python\n\nimport requests\n\nurl = f'{URL}/extension/204/ivr/context/1/options/start/rules/'\nheaders = {\n    'Authorization': f'Bearer {ACCESS_TOKEN}',\r\n    'Content-Type': 'application/json'\n}\ndata = '''{\n    \"voice_helper_digits_max\": 2,\n    \"voice_helper_rules\": [\n    {\n        \"to_option\": 1,\n        \"transcription\": \"привет|здравствуй|здарова\"\n    },\n    {\n        \"to_option\": 2,\n        \"transcription\": \"прощай|пока\"\n    },\n    ],\n    \"sound\": 52,\n    \"voice_helper_timeout\": 7000\n}'''\nresponse = requests.post(url, headers=headers)\nprint(response.text)"}]},{"type":"paragraph","content":[{"type":"text","text":"Запрос для обновления текущего контекста:"}]},{"type":"codeBlock","attrs":{"language":"python"},"content":[{"type":"text","text":"#!/usr/bin/python\n\nimport requests\n\nurl = f'{URL}/extension/204/ivr/context/1/options/start/rules/1'\nheaders = {\n    'Authorization': f'Bearer {ACCESS_TOKEN}',\r\n    'Content-Type': 'application/json'\n}\ndata = '''{\n    \"voice_helper_digits_max\": 2,\n    \"voice_helper_rules\": [\n    {\n        \"to_option\": 1,\n        \"transcription\": \"привет|здравствуй|здарова\"\n    },\n    {\n        \"to_option\": 2,\n        \"transcription\": \"прощай|пока\"\n    },\n    ],\n    \"sound\": 52,\n    \"voice_helper_timeout\": 7000\n}'''\nresponse = requests.put(url, headers=headers)\nprint(response.text)"}]}]},"id":"330b1ded-3454-41bc-bbd1-f0b38b6d1652","label":"На языке Python3    ","type":"tab"}]

Ответ системы (остальные параметры не имеют значения и исключены из примера):

Code Block
languagejson
{
…
  "voice_helper_sound": 52,
  "voice_helper_timeout": 7000,
  "id": 39,
  "voice_helper_digits_max": "2",
  "voice_helper_rules": [
    { 
      "transcription": "привет|здравствуй|здарова",
      "to_option": 1
    },
    {
      "transcription": "прощай|пока",
      "to_option": 2
    }
  ],
  "final": true,
  "action": "voice_helper",
…
}

В ответе на запрос будет содержаться идентификатор созданного правила: "id": 39. В результате указанного выше запроса будет создано правило голосовой навигации, по которому будет проиграна мелодия по умолчанию.

Опции to_option, куда попадут при сообщении слова из transcription, должны быть созданы (они не создаются автоматически). Параметр transcription может содержать как точное слово, так и часть слова.

Создание звукового приветствия

Если нужно задать конкретное звуковое приветствие, чтобы сообщить в нем, что от звонящего ожидается то или иное слово, нужно заранее подготовить звуковой файл. Ресурс “Звуковые файлы” позволит загрузить файл и узнать идентификатор этого файла. После этого нужно обновить параметры правила голосового помощника, задав идентификатор необходимого звукового файла.

Обновление параметров правила голосового помощника

Обновить любой параметр правила можно с помощью метода
PUT /api/ver1.0/extension/{extension_id}/ivr/context/{context_id}/options/{option_digits}/rules/{rule_id}

К примеру, для задания актуального приветствия с указанием нужного идентификатора файла SOUND_ID нужно отправить вышеуказанный запрос с телом
{"sound": SOUND_ID}

Аналогичным способом обновляется любой параметр правила voice_helper. Например, можно заменить правила voice_helper_rules с помощью запроса
PUT /api/ver1.0/extension/{extension_id}/ivr/context/{context_id}/options/{option_digits}/rules/{rule_id} с телом

Code Block
languagejson
{"voice_helper_rules": [
    {
      "to_option": 1,
      "transcription": "продукты|еда"
    },
    {
      "to_option": 2,
      "transcription": "комиксы|комик|икс"
    }
  ]
}

Не рекомендуется задавать много условий в одном правиле voice_helper_rules (желательно не более 500).

Параметр to_option – это опции контекста (start, invalid, timeout, 1, 2, 3, 4 и т.д.). Правило voice_helper создано в опции start, а навигация голосом будет по опциям 1-10 (либо, к примеру, по 4-40).

Создание опций выполняется запросом
POST /api/ver1.0/extension/{extension_id}/ivr/context/{context_id}/options/ с телом

Code Block
languagejson
{"digits": "string"}

где string – опции контекста start, invalid, timeout, 1, 2, 3, 4 и т.д.

Получение распознанных данных удаленным сервером

Существует возможность получить данные распознавания на своем удаленном сервере.

Функция “Call Interactive” позволяет в качестве действия опции контекста голосового меню (IVR) инициировать HTTP-запрос на заданный URL и обработать ответ на него. С запросом передается постоянный набор параметров, содержащий информацию о вызове в IVR. Для управления действиями после распознавания существуют опциональные параметры запроса функции Call Interactive:

  • voice_navigator_DTMF – донабор с телефонного терминала во время правила голосового меню action='voice_helper';

  • voice_navigator_STT – содержит распознавание голоса во время правила голосового меню action='voice_helper'.

Функция “Call interactive” запросом POST http://mysite.com/myscript?check_number возвращает нужное приветствие с указанием дополнительных параметров, помимо TTS (play_now="false", save_to_var="true"). В таком случае voice_helper c заданным параметром play_sound_from_variable проигнорирует установленное у себя приветствие.

Вызов попадает в стартовый контекст (start), где помимо стандартных опций контекста (start, timeout, invalid) настроены пользовательские опции, например: “1” – ‘call_interactive’, “2” – ‘voice_helper'. Система ожидает, когда звонящий скажет что-то либо донаберет опцию (это объявлено в правиле voice_helper). Например, если звонящий скажет “оператор” – попадет на опцию “0”, а если что-либо из заданных слов (например: "узнать, дату, дата, готовности, готовность, отгрузке, отгрузка, товар, счету, счет") либо наберет 1 – попадет на опцию “1”, где будет работать правило Call Interactive, по которому на сервер будет отправлен запрос POST http://mysite.com/myscript?check_stt_res , после чего сервером будут получены данные:voice_navigator_STT=%D1%85%D0%BE%D1%87%D1%83+%D1%83%D0%B7%D0%BD%D0%B0%D1%82%D1%8C+%D0%B4%D0%B0%D1%82%D1%83+%D0%B3%D0%BE%D1%82%D0%BE%D0%B2%D0%BD%D0%BE%D1%81%D1%82%D0%B8+%D0%BA+%D0%BE%D1%82%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%B5+%D1%82%D0%BE%D0%B2%D0%B0%D1%80%D0%B0
url decode voice_navigator_STT=хочу узнать дату готовности к отгрузке товара
либо voice_navigator_DTMF=1

Если в правиле voice_helper ни одна из опций не отработает (не донаберут или не скажут ни “0”, ни “1”), то в стартовом контексте будет звучать приветствие по умолчанию с предложением соединиться с оператором (“Скажите “оператор” или нажмите “0”). В таком случае можно добавить Call interactive с запросом запрос POST http://mysite.com/myscript?no_option_voice_helper, в котором если и будет voice_navigator_STT, то оно будет содержать значение, альтернативное опциям “0” и “1” (например, если звонящий спросит: "А куда я попал?”), после чего можно задавать другие действия как управлением из Call Interactive, так и статическими правилами в IVR.

События с распознанным текстом

Чтобы получить события с финальным распознанным текстом во время разговора, необходимо воспользоваться следующей схемой. По событию на внутреннем номере (dial-in для входящих вызовов в IVR, anwser для входящих и исходящих с внутреннего номера типа “телефонный терминал”) в зависимости от CallFlow события нужно запомнить extension_id (идентификатор внутреннего номера; если in CalledExtensionID, если out CallerExtensionID)и CallAPIID и воспользоваться ресурсом:
PUT /extension/{extension_id}/speech_to_text/{call_api_id}

Описание структур данных

Имя

Тип

Описание

extension_id

string

Идентификатор внутреннего номера

call_api_id

string

Идентификатор звонка, по которому начнется распознавание речи

action 

string

Действие, может принимать значения start или stop

direction 

string

Направление распознанной речи относительно extension_id: out — если голос идет от внутреннего номера, in — если голос идет к внутреннему номеру

url 

string

URL, куда будут отправляться события с распознанным из речи текстом

Info

При повторной попытке одного и того же action с одним и тем же direction на один и тот же разговор будет выдано сообщение об ошибке!

События выглядят подобным образом:

Code Block
languagehtml
POST / HTTP/1.1
Host: 213.170.66.158:12345
user-agent: Ringme Event Generator
Accept: 
Accept-Encoding: gzip, deflate
Content-Length: 394
Content-Type: application/x-www-form-urlencoded

call_api_id=3232240860-15e67fb4-8f9a-11ea-90b9-05381d8e3a62&extension_id=34414&direction=out&text=%D0%90+%D0%B2%D0%BE%D0%B4%D0%B5+%D0%BC%D0%B8%D0%BC%D0%BE+%D1%81%D0%B5%D0%B9%D1%87%D0%B0%D1%81+%D0%BB%D0%B5%D1%82+%D1%81%D0%B5%D0%B3%D0%BE+%D0%BA%D0%BE%D0%BC%D0%B0%D1%80%D0%B0+%D0%B7%D0%B0%D0%B1%D0%BE%D1%82%D0%B0+%D0%BB%D1%8E%D0%B4%D0%B8+%D1%87%D0%B0%D1%81%D1%83+%D1%81+15+%D0%B3%D0%BE%D0%B4%D0%B0

Длину контента можно считать по Content-Length.
Распознанный текст в читаемом виде – после url decode utf8.

Ресурсы раздела “Внутренний номер”

Expand
titlePUT /extension/{extension_id}/speech_to_text/{call_api_id}

PUT /extension/{extension_id}/speech_to_text/{call_api_id}

Параметры URL

Имя

Тип

extension_id

string

call_api_id

string

Параметры запроса

Имя

Тип

action 

string

direction 

string

url 

string