Статьи

Как использовать новый Dictation API от Pebble

Ранее в этом месяце Pebble выпустил версию 3.6 своего SDK. Мои глаза расширились, когда я обнаружил, что это включает доступ к их Dictation API. Этот API предоставляет всем разработчикам Pebble доступ к диктовке с микрофона Pebble Time. Я с нетерпением открыл редактор CloudPebble и начал экспериментировать!

В этой статье мы рассмотрим API Dictation, собрав приложение watchapp, которое принимает продиктованное сообщение и отправляет его на канал Slack через IFTTT.

Что вам нужно

Чтобы просмотреть это руководство, вам понадобится следующее:

Код

Есть разработчики, которые предпочитают прыгать прямо в код. Если вы разработчик такого типа, весь код доступен на GitHub .

Наш watchapp будет иметь два основных файла:

  • main.c — Наш C-код управляет диктовкой, отображением инструкций и отображением введенного сообщения.
  • pebble-js-app.js — это управляет нашим общением с IFTTT.

IFTTT

Я бы порекомендовал сначала настроить канал IFTTT Maker и правило Slack, просто чтобы настроить код, который мы сделаем после этого, имеет больше смысла.

Ранее я освещал IFTTT в статьях « Подключение лампочек LIFX к IoT с использованием IFTTT и подключение IoT и Node.js к IFTTT» (второй рассказывает о канале «Создатель»). Поэтому, если вы хотите получить более подробное объяснение использования IFTTT и канала Maker, ознакомьтесь с ними.

Вот очень быстрый пример того, что вам нужно настроить:

  • Создайте учетную запись IFTTT, если у вас ее еще нет.
  • Подключите Maker Channel и Slack Channel к своей учетной записи.
  • Создайте новый рецепт с каналом Maker в качестве триггера.
  • Выберите опцию триггера «Получить веб-запрос» и назовите событие «slack_message».
  • Выберите канал Slack, который будет каналом действия для этого правила IFTTT, и выберите действие «Post to channel».
  • Выберите канал Slack, на который вы хотите перейти, и установите в сообщении только {{Value1}} .
  • Вы можете удалить заголовок или выбрать что-то вроде «Pebble Message Received». Я оставил это пустым. Я также оставил URL-адрес эскиза пустым.
  • Создайте свое действие, и вы должны быть готовы к работе! IFTTT готов отправлять любые сообщения, полученные от этого события, на указанный вами канал Slack.

Наш код C

Файл main.c выглядит так:

 #include <pebble.h> static Window *s_main_window; static TextLayer *message_layer; static DictationSession *s_dictation_session; static char display_message[512]; static void handle_message(char *slack_message) { DictionaryIterator *iter; app_message_outbox_begin(&iter); dict_write_cstring(iter, 0, slack_message); app_message_outbox_send(); } static void dictation_session_callback(DictationSession *session, DictationSessionStatus status, char *transcription, void *context) { if(status == DictationSessionStatusSuccess) { snprintf(display_message, sizeof(display_message), "Message sent!\n\n\"%s\"", transcription); text_layer_set_text(message_layer, display_message); handle_message(transcription); } else { static char error_message[128]; snprintf(error_message, sizeof(error_message), "Error code:\n%d", (int)status); text_layer_set_text(message_layer, error_message); } } static void select_click_handler(ClickRecognizerRef recognizer, void *context) { dictation_session_start(s_dictation_session); } static void click_config_provider(void *context) { window_single_click_subscribe(BUTTON_ID_SELECT, select_click_handler); } static void window_load(Window *window) { Layer *window_layer = window_get_root_layer(window); GRect bounds = layer_get_bounds(window_layer); message_layer = text_layer_create(GRect(bounds.origin.x, (bounds.size.h - 72) / 2, bounds.size.w, bounds.size.h)); text_layer_set_text(message_layer, "Press select and tell me your Slack message :)"); text_layer_set_text_alignment(message_layer, GTextAlignmentCenter); text_layer_set_font(message_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD)); layer_add_child(window_layer, text_layer_get_layer(message_layer)); } static void window_unload(Window *window) { text_layer_destroy(message_layer); } static void init() { s_main_window = window_create(); window_set_click_config_provider(s_main_window, click_config_provider); window_set_window_handlers(s_main_window, (WindowHandlers) { .load = window_load, .unload = window_unload, }); window_stack_push(s_main_window, true); app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum()); s_dictation_session = dictation_session_create(sizeof(display_message), dictation_session_callback, NULL); } static void deinit() { dictation_session_destroy(s_dictation_session); window_destroy(s_main_window); } int main() { init(); app_event_loop(); deinit(); } 

Наши диктантные звонки

Первый фрагмент кода, который заметят разработчики Pebble, — это новая строка, которая устанавливает DictationSession . Это то, что мы храним в наших транскрипционных данных и других данных, связанных с Dictation API, в:

 static DictationSession *s_dictation_session; 

Далее мы определяем простой массив char для хранения нашего последнего успешно записанного сообщения:

 static char display_message[512]; 

В нашей функции init() мы настраиваем фактический сеанс диктовки так, чтобы он был готов и ждал, когда мы его запросим. Он предназначен для предоставления места для хранения нашего диктованного сообщения, соответствующего длине display_message . Он также устанавливает функцию обратного вызова, как только мы выполнили диктовку, как dictation_session_callback() .

 s_dictation_session = dictation_session_create(sizeof(display_message), dictation_session_callback, NULL); 

Запуск диктовки по клику

Мы хотим настроить нашу диктовку на запуск, когда пользователь нажимает кнопку выбора на своем Pebble. Мы устанавливаем функциональность window_set_click_config_provider() через window_set_click_config_provider() .

 window_set_click_config_provider(s_main_window, click_config_provider); 

Это говорит нашему Pebble, что наши функции нажатия определены в click_config_provider() . В рамках этого мы инициализируем процесс диктовки нажатием кнопки выбора (определяется как BUTTON_ID_SELECT в SDK Pebble). Это действие кнопки настраивается с помощью функции window_single_click_subscribe() .

 static void click_config_provider(void *context) { window_single_click_subscribe(BUTTON_ID_SELECT, select_click_handler); } 

Наша select_click_handler() имеет только одну задачу — начать наш сеанс dictation_session_start() с помощью dictation_session_start() :

 static void select_click_handler(ClickRecognizerRef recognizer, void *context) { dictation_session_start(s_dictation_session); } 

Когда наш сеанс диктовки закончен, и пользователь передал нам свое сообщение через микрофон, мы сказали Pebble запустить dictation_session_callback() . В этой функции мы начинаем с проверки, была ли диктовка успешной. API предоставляет это нам через переменную DictationSessionStatus status :

 static void dictation_session_callback(DictationSession *session, DictationSessionStatus status, char *transcription, void *context) { if(status == DictationSessionStatusSuccess) { // Dictation worked! } else { // Dictation failed 🙁 } } 

Если диктовка прошла успешно, мы отображаем транскрибированное сообщение в приложении (в основном просто для того, чтобы дать пользователю визуальную обратную связь о том, что приложение имеет его сообщение), а затем мы передаем транскрибированное сообщение в handle_message() (мы рассмотрим, как эта функция работает в ближайшее время ):

 snprintf(display_message, sizeof(display_message), "Message sent!\n\n\"%s\"", transcription); text_layer_set_text(message_layer, display_message); handle_message(transcription); 

Если есть ошибка, мы отображаем код сообщения об ошибке на экране вместо транскрипции:

 static char error_message[128]; snprintf(error_message, sizeof(error_message), "Error code:\n%d", (int)status); text_layer_set_text(message_layer, error_message); 

Передача сообщений в JavaScript

Функция handle_message мы использовали ранее, принимает сообщение и помещает его в словарь нашего приложения. Это позволяет нам отправлять эти данные в код JavaScript с помощью функции Pebble AppMessage. Мы app_message_outbox_begin() доступ к словарю через DictionaryIterator а затем открываем наш почтовый ящик, готовый отправить сообщение в наш JavaScript, используя app_message_outbox_begin() . У нас есть только один ключ в нашем словаре для этого приложения, в котором хранится сообщение диктовки, поэтому, когда мы записываем в наш словарь, мы записываем сообщение в позицию 0 в dict_write_cstring() . Как только сообщение сохранено в этом ключе, мы отправляем его через app_message_outbox_send() .

 static void handle_message(char *slack_message) { DictionaryIterator *iter; app_message_outbox_begin(&iter); dict_write_cstring(iter, 0, slack_message); app_message_outbox_send(); } 

Остальная часть кода на C довольно понятна для всех, кто раньше работал над разработкой приложений для Pebble, поэтому мы продолжим работу с JavaScript!

Наш код JavaScript

Часть JavaScript в уравнении немного короче и выглядит так:

 var host = "https://maker.ifttt.com/trigger/", key = "PUTYOURKEYHERE"; function send_message(message) { console.log(host + "slack_message/with/key/" + key); var url = host + "slack_message/with/key/" + key, data = {"value1": message}; sendPOSTRequest(url, data, function() { console.log("Error!"); }); } function sendPOSTRequest(url, data, fallback) { var req = new XMLHttpRequest(); req.onreadystatechange = function(e) { if (req.readyState == 4 && req.status == 200) { var response = JSON.parse(req.responseText); console.log("Response was ", response); if (response !== undefined && !response.error) { console.log("Message sent successfully."); } else { console.log(response.error); if (fallback) fallback(); } } else if (req.status == 404 || req.status == 500) { console.log("Error " + req.status); if (fallback) fallback(); } }; req.open("POST", url); req.setRequestHeader("Content-Type", "application/json"); req.send(JSON.stringify(data)); } Pebble.addEventListener("appmessage", function(e) { var message = e.payload["0"]; console.log("Received message: " + message); send_message(message); }); 

Начало JavaScript устанавливает начальные настройки URL для URL, который мы хотим вызвать из IFTTT. Этот вызов должен быть в формате https://maker.ifttt.com/trigger/{event}/with/key/{yourkey} . Мы храним начальную часть URL в host а ваш ключ — в key . Вы можете найти свой ключ на странице IFTTT канала Maker . Остальное будет настроено в следующей функции.

 var host = "https://maker.ifttt.com/trigger/", key = "PUTYOURKEYHERE"; 

Функция, которую мы будем вызывать, когда мы хотим отправить сообщение в IFTTT, получила соответствующее имя send_message() . Это помещает наши переменные host и key в наш IFTTT URL вместе с нашим именем события slack_message . Переменная data содержит объект JSON с ключом "value1" который IFTTT ищет, когда решает, как ответить на запрос POST. Если вы хотите передать больше значений, вы также можете передать value2 и value3 .

 function send_message(message) { console.log(host + "slack_message/with/key/" + key); var url = host + "slack_message/with/key/" + key, data = {"value1": message}; ... 

Затем в нашей функции мы передаем этот url и data в функцию sendPOSTRequest() которая будет выполнять магию HTTP-запроса. Он имеет функцию обратного вызова с ошибкой, которая будет запускаться, если что-то пойдет не так (в этом случае мы просто запишем это на консоль).

 sendPOSTRequest(url, data, function() { console.log("Error!"); }); } 

Функция sendPOSTRequest() использует типичный формат JavaScript XMLHttpRequest . Это будет очень похоже на любые запросы POST, содержащие данные JSON. Объяснение деталей того, как это работает, выходит за рамки данной статьи, но довольно распространено в Интернете:

 function sendPOSTRequest(url, data, fallback) { var req = new XMLHttpRequest(); req.onreadystatechange = function(e) { if (req.readyState == 4 && req.status == 200) { var response = JSON.parse(req.responseText); console.log("Response was ", response); if (response !== undefined && !response.error) { console.log("Message sent successfully."); } else { console.log(response.error); if (fallback) fallback(); } } else if (req.status == 404 || req.status == 500) { console.log("Error " + req.status); if (fallback) fallback(); } }; req.open("POST", url); req.setRequestHeader("Content-Type", "application/json"); req.send(JSON.stringify(data)); } 

Наконец, у нас есть фрагмент кода, который запускает наше сообщение. Мы слушаем событие appmessage которое вызывается app_message_outbox_send() в нашем C-коде. Когда это приложение обнаруживает его, оно отправляет данные в формате {"0": "yourmessage"} . Мы фокусируемся на ключе "0" и отправляем его в нашу send_message() .

 Pebble.addEventListener("appmessage", function(e) { var message = e.payload["0"]; console.log("Received message: " + message); send_message(message); }); 

Запуск нашего приложения

Лучше всего запускать приложение на реальных часах Pebble Time. Вы также можете использовать команды Pebble API в терминале для работы с эмулятором через SDK, однако я обнаружил, что гораздо проще просто поговорить с моим Pebble напрямую через CloudPebble! Главное, что нужно иметь в виду при создании приложения, это убедиться, что «Build Aplite» не отмечен в настройках вашего проекта. Наша демонстрационная программа не будет работать с платформой Aplite (это первая платформа Pebble watchface). Ваши настройки должны выглядеть так:

Настройки приложения Pebble с аплитом сняты

Приложение в действии!

Когда мы впервые открываем приложение, оно должно выглядеть так:

Приложение Pebble Slack

Затем, когда вы нажмете кнопку выбора (ту, что посередине с правой стороны), экран диктовки Пеббл должен появиться в ожидании вашего голоса. После того, как вы произнесете речь и получите ваше сообщение, он будет использовать Nuance, стороннюю службу, для расшифровки вашего сообщения. Как только он появится, экран диктовки Pebble попросит вас подтвердить правильность сообщения.

Пекбл Диктант

Если это так, примите его, и он предоставит этот вклад вашему приложению:

Отправлено сообщение о диктанте Pebble

Тогда, если вы посмотрите на свой канал Slack, сообщение также должно появиться там!

Сообщение получено в Slack

Вывод

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

Не стесняйтесь использовать этот код в качестве отправной точки для вашей собственной идеи Pebble Dictation. Попробуйте, это невероятно дает возможность собрать голосовое приложение SmartWatch вместе и увидеть его в действии! Если вы что-то делаете из этого урока, пожалуйста, поделитесь им в комментариях или свяжитесь со мной в Twitter ( @thatpatrickguy ). Я хотел бы услышать об этом.

Если вы ищете дополнительные ссылки по разработке Pebble или API Dictation, в частности, у меня есть несколько ссылок на мое руководство по разработке Dev Diner Pebble . Если у вас есть другие замечательные ресурсы, которых у меня нет в списке, пожалуйста, дайте мне знать!