Долгое время я терпеть не мог всяческие голосовые помощники для телефонов, по самым разным причинам, но в один прекрасный день все изменилось
Дело в том, что работать на пасеке приходится в перчатках - у меня злые пчелы плюс аллергия на пчелиный яд, ну и в дополнение склероз. Для того чтобы фиксировать действия проделанные с пчелосемьями, вести разнообразную статистику нужно вести журнал. Писать в перчатках я не могу, а по приходу домой напрочь забываю, что и в каком улье я делал
Можно конечно позвать помощника или каждый раз убегать в безопасное место и заносить данные в журнал, но можно использовать для записей смартфон.
Беглый анализ существующих голосовых помощников показал, что у Маруси от ВК есть возможность работать с приватными навыками. То есть вы размещаете код у себя на сервере, настраивате в личном кабинете и спокойно работаете. При этом, кроме вас никто этим навыком воспользоваться не может. Поэтому я решил остановиться на Марусе. К тому же у нее простой апи и сам ассистент ставится как приложение и не работает в фоне на уровне системы, что меня более чем устроило.
Навык для Маруси я назвал просто "Пасечник". Алгоритм работы с пасечником выглядит следующим образом:
Код навыка на php выглядит примерно так:
define('DB_PATH', './marusya.db'); function export_data($request_message=null,$period='curday'){ $res=""; $session_state=""; if($request_message['session']['user_id']){ $user_id =$request_message['session']['user_id']; } if($request_message['state']['session']['hive'] && $session_state=="") { $session_state=$request_message['state']['session']['hive']; } if(file_exists(DB_PATH) && $user_id && $user_id!=""){ $db=new SQLite3(DB_PATH); $curdate = new \DateTime(); $curtime=strtotime($curdate->format("d.m.Y")); if($period=='curday'){ $sql="select * from hives where usr_id='$user_id' and edit_date='$curtime' "; //Если задан номер улья в сессии, то делаем выборку только по нему if($session_state!=""){ $sql.=" and hive_num='$session_state'"; } $q=$db->query($sql); while($row = $q->fetchArray(SQLITE3_ASSOC) ) { $res.=$row['hive_num'].' '.$row['data']."
"; } } else{ //Для экспорта формируем отдельную ссылку $res="Ссылка на загрузку данных localhost/export.php?id=".$user_id; } return $res; } return "Ничего не найдено"; } //Сохраняем данные в базе function save_request_data($request_message){ if(file_exists(DB_PATH)){ $nlu="";$data="";$user_id=""; $db=new SQLite3(DB_PATH); if($request_message['state']['session']['hive']){ //Форматируем число из слов в цифры (один-1) //Для коректной работы должен быть установлен php-intl $fmt = numfmt_create('ru_RU', NumberFormatter::SPELLOUT); $hive_num = numfmt_parse($fmt,$request_message['state']['session']['hive']); } if($request_message['session']['user_id']){ $user_id =$request_message['session']['user_id']; } if($request_message['request']['original_utterance']){ $data = trim(str_replace(["запиши","сохрани"],'',$request_message['request']['original_utterance'])); } if($hive_num!="" && $data!="" && $user_id!=""){ $curdate = new \DateTime(); $curtime=strtotime($curdate->format("d.m.Y")); //Для начала ищем в базе запись для заданного улья. Если дата совпадает, то обновляем текущую запись, добавляя новые данные //Если запись была сделана раньше, то создаем новую запись с текущей датой $sql= "select data from hives where usr_id='$user_id' and hive_num='$hive_num' and edit_date = '$curtime' "; $res = $db->query($sql); $r=$res->fetchArray(SQLITE3_ASSOC); if(is_array($r)){ $data= $r['data'].', '.$data; $d=$db->query("update hives set data='$data' where usr_id='$user_id' and hive_num='$hive_num' and edit_date = '$curtime'"); } else{ $d=$db->query("insert into hives values('$user_id','$hive_num','$data','$curtime')"); } if($d){ return true; } } } return false; } //Формируем ответ для Маруси function create_response($request_message,$text=null,$end_session=false,$session_state="") { if($text && $text!=""){ $response_text=$text; } else if($request_message['request']['original_utterance']) { $response_text=$request_message['request']['original_utterance']; } if($request_message['state']['session']['hive'] && $session_state=="") { $session_state=$request_message['state']['session']['hive']; } return [ 'response' => [ 'text' => $response_text, 'tts' => $response_text, 'end_session' => $end_session, ], 'session' => [ 'user_id' => $request_message['session']['user_id'], 'session_id' => $request_message['session']['session_id'], 'message_id' => $request_message['session']['message_id'], ], 'session_state'=> [ 'hive' => $session_state ], 'version' => $request_message['version'] ]; } $request_message = json_decode(file_get_contents('php://input'), true); $response_message = create_response($request_message,"Пасечник занят",false); //Обрабатываем входящий запрос if($request_message['request']['nlu']['tokens'] && $request_message['request']['command'] && array_key_exists('test',$request_message['request'])==false) { switch(strtolower($request_message['request']['nlu']['tokens'][0])){ case "включи": case "запусти": $response_message=create_response($request_message,"Пасечник на связи"); break; case "спасибо": case "конец": $response_message=create_response($request_message,"Отключаюсь",true); break; case "результат": $res=export_data($request_message); $response_message=create_response($request_message,"Результат за сегодня:
".$res); break; case "экспорт": $res=export_data($request_message,'all'); $response_message=create_response($request_message,$res); break; case "улей": $response_message=create_response($request_message,"Слушаю",false, trim(str_replace('улей','',$request_message['request']['command']))); break; case "запиши": case "сохрани": $s=save_request_data($request_message); if ($s==true){ $response_message = create_response($request_message,"Готово"); } break; } } header('Content-Type: application/json'); echo json_encode($response_message)
В целом получилось неплохо. Посмотрим насколько это будет удобно в боевых условиях.