Долгое время я терпеть не мог всяческие голосовые помощники для телефонов, по самым разным причинам, но в один прекрасный день все изменилось
Дело в том, что работать на пасеке приходится в перчатках - у меня злые пчелы плюс аллергия на пчелиный яд, ну и в дополнение склероз. Для того чтобы фиксировать действия проделанные с пчелосемьями, вести разнообразную статистику нужно вести журнал. Писать в перчатках я не могу, а по приходу домой напрочь забываю, что и в каком улье я делал
Можно конечно позвать помощника или каждый раз убегать в безопасное место и заносить данные в журнал, но можно использовать для записей смартфон.
Беглый анализ существующих голосовых помощников показал, что у Маруси от ВК есть возможность работать с приватными навыками. То есть вы размещаете код у себя на сервере, настраивате в личном кабинете и спокойно работаете. При этом, кроме вас никто этим навыком воспользоваться не может. Поэтому я решил остановиться на Марусе. К тому же у нее простой апи и сам ассистент ставится как приложение и не работает в фоне на уровне системы, что меня более чем устроило.
Навык для Маруси я назвал просто "Пасечник". Алгоритм работы с пасечником выглядит следующим образом:
Код навыка на 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)
В целом получилось неплохо. Посмотрим насколько это будет удобно в боевых условиях.