From 2581e529e4d9f940ab3cb16f813d7ddd73e5e435 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Wed, 5 Apr 2017 22:20:11 +0300 Subject: [PATCH] Working on speech rec --- app/Http/Controllers/BotController.php | 26 +++++++-- app/Models/InvoiceStatus.php | 22 ++++++++ app/Ninja/Intents/BaseIntent.php | 54 +++++++++++++++---- app/Ninja/Intents/InvoiceIntent.php | 17 ++++++ .../Intents/WebApp/CreateCreditIntent.php | 2 +- .../Intents/WebApp/CreateInvoiceIntent.php | 3 ++ .../Intents/WebApp/CreateQuoteIntent.php | 3 ++ .../WebApp/CreateRecurringInvoiceIntent.php | 3 ++ app/Ninja/Intents/WebApp/ListClientIntent.php | 2 + app/Ninja/Intents/WebApp/ListCreditIntent.php | 2 + .../Intents/WebApp/ListExpenseIntent.php | 2 + .../Intents/WebApp/ListInvoiceIntent.php | 3 ++ .../Intents/WebApp/ListPaymentIntent.php | 2 + .../Intents/WebApp/ListProductIntent.php | 2 + app/Ninja/Intents/WebApp/ListQuoteIntent.php | 7 ++- .../WebApp/ListRecurringInvoiceIntent.php | 2 + app/Ninja/Intents/WebApp/ListTaskIntent.php | 2 + app/Ninja/Intents/WebApp/ListVendorIntent.php | 2 + .../partials/speech_recognition.blade.php | 7 +-- 19 files changed, 145 insertions(+), 18 deletions(-) diff --git a/app/Http/Controllers/BotController.php b/app/Http/Controllers/BotController.php index 1bd9be85bc55..c6663d0077cf 100644 --- a/app/Http/Controllers/BotController.php +++ b/app/Http/Controllers/BotController.php @@ -6,6 +6,7 @@ use App\Libraries\CurlUtils; use App\Libraries\Skype\SkypeResponse; use App\Models\SecurityCode; use App\Models\User; +use App\Models\Client; use App\Ninja\Intents\BaseIntent; use App\Ninja\Mailers\UserMailer; use Auth; @@ -100,9 +101,28 @@ class BotController extends Controller public function handleCommand() { $data = $this->parseMessage(request()->command); - //dd($data); - $intent = BaseIntent::createIntent(BOT_PLATFORM_WEB_APP, false, $data); - return $intent->process(); + + // If they're viewing a client set it as the current state + $state = false; + $url = url()->previous(); + preg_match('/clients\/(\d*)/', $url, $matches); + if (count($matches) >= 2) { + if ($client = Client::scope($matches[1])->first()) { + $state = BaseIntent::blankState(); + $state->current->client = $client; + } + } + + try { + $intent = BaseIntent::createIntent(BOT_PLATFORM_WEB_APP, $state, $data); + return $intent->process(); + } catch (Exception $exception) { + $message = $exception->getMessage(); + if (env('APP_DEBUG')) { + $message .= '
' . request()->command . ' => ' . json_encode($data); + } + return redirect()->back()->withWarning($message); + } } private function authenticate($input) diff --git a/app/Models/InvoiceStatus.php b/app/Models/InvoiceStatus.php index 4a4dddb5eecb..302b79ca9fc3 100644 --- a/app/Models/InvoiceStatus.php +++ b/app/Models/InvoiceStatus.php @@ -13,4 +13,26 @@ class InvoiceStatus extends Eloquent * @var bool */ public $timestamps = false; + + public static function getIdFromAlias($status) + { + switch ($status) { + case 'draft': + return INVOICE_STATUS_DRAFT; + case 'sent': + return INVOICE_STATUS_SENT; + case 'viewed': + return INVOICE_STATUS_VIEWED; + case 'approved': + return INVOICE_STATUS_APPROVED; + case 'partial': + return INVOICE_STATUS_PARTIAL; + case 'overdue': + return INVOICE_STATUS_OVERDUE; + case 'unpaid': + return INVOICE_STATUS_UNPAID; + default: + return false; + } + } } diff --git a/app/Ninja/Intents/BaseIntent.php b/app/Ninja/Intents/BaseIntent.php index 4c170bba7311..97efae3dae5c 100644 --- a/app/Ninja/Intents/BaseIntent.php +++ b/app/Ninja/Intents/BaseIntent.php @@ -16,14 +16,7 @@ class BaseIntent { //if (true) { if (! $state || is_string($state)) { - $state = new stdClass(); - foreach (['current', 'previous'] as $reference) { - $state->$reference = new stdClass(); - $state->$reference->entityType = false; - foreach ([ENTITY_INVOICE, ENTITY_CLIENT, ENTITY_INVOICE_ITEM] as $entityType) { - $state->$reference->$entityType = []; - } - } + $state = static::blankState(); } $this->state = $state; @@ -32,6 +25,20 @@ class BaseIntent //var_dump($state); } + public static function blankState() + { + $state = new stdClass(); + foreach (['current', 'previous'] as $reference) { + $state->$reference = new stdClass(); + $state->$reference->entityType = false; + foreach ([ENTITY_INVOICE, ENTITY_CLIENT, ENTITY_INVOICE_ITEM] as $entityType) { + $state->$reference->$entityType = []; + } + } + + return $state; + } + public static function createIntent($platform, $state, $data) { if (! count($data->intents)) { @@ -67,7 +74,7 @@ class BaseIntent //echo "Intent: $intent

"; if (! class_exists($className)) { - throw new Exception($intent . ': ' . trans('texts.intent_not_supported')); + throw new Exception($intent . '... ' . trans('texts.intent_not_supported')); } return new $className($state, $data); @@ -84,6 +91,30 @@ class BaseIntent return false; } + protected function getFields($field) + { + $data = []; + + foreach ($this->data->entities as $entity) { + if ($entity->type === $field) { + $data[] = $entity->entity; + } + } + + return $data; + } + + protected function loadStates($entityType) + { + $states = array_filter($this->getFields('State'), function($state) { + return in_array($state, [STATUS_ACTIVE, STATUS_ARCHIVED, STATUS_DELETED]); + }); + + if (count($states)) { + session(['entity_state_filter:' . $entityType => join(',', $states)]); + } + } + protected function hasField($field, $value = false) { $fieldValue = $this->getField($field); @@ -158,10 +189,15 @@ class BaseIntent foreach ($this->data->entities as $param) { if ($param->type == 'Name') { + $param->type = rtrim($param->type, ' \' s'); $client = $clientRepo->findPhonetically($param->entity); } } + if (! $client) { + $client = $this->state->current->client; + } + return $client; } diff --git a/app/Ninja/Intents/InvoiceIntent.php b/app/Ninja/Intents/InvoiceIntent.php index 9421e32e0a4e..ccf6ecb4d8a8 100644 --- a/app/Ninja/Intents/InvoiceIntent.php +++ b/app/Ninja/Intents/InvoiceIntent.php @@ -3,6 +3,7 @@ namespace App\Ninja\Intents; use App\Models\Invoice; +use App\Models\InvoiceStatus; use Auth; use Exception; @@ -104,4 +105,20 @@ class InvoiceIntent extends BaseIntent return $invoiceItems; } + + protected function loadStatuses($entityType) + { + $statusIds = []; + $statuses = $this->getFields('State'); + + foreach ($statuses as $status) { + if ($statusId = InvoiceStatus::getIdFromAlias($status)) { + $statusIds[] = $statusId; + } + } + + if (count($statusIds)) { + session(['entity_status_filter:' . $entityType => join(',', $statusIds)]); + } + } } diff --git a/app/Ninja/Intents/WebApp/CreateCreditIntent.php b/app/Ninja/Intents/WebApp/CreateCreditIntent.php index 147ed99d4491..dc3bec7c0c0c 100644 --- a/app/Ninja/Intents/WebApp/CreateCreditIntent.php +++ b/app/Ninja/Intents/WebApp/CreateCreditIntent.php @@ -13,7 +13,7 @@ class CreateCreditIntent extends BaseIntent //$invoiceItems = $this->requestInvoiceItems(); - $url = '/credits/create/' . $clientPublicId . '?'; + $url = '/credits/create/' . $clientPublicId; //$url .= $this->requestFieldsAsString(Invoice::$requestFields); return redirect($url); diff --git a/app/Ninja/Intents/WebApp/CreateInvoiceIntent.php b/app/Ninja/Intents/WebApp/CreateInvoiceIntent.php index 24982099d251..395b5a78ca08 100644 --- a/app/Ninja/Intents/WebApp/CreateInvoiceIntent.php +++ b/app/Ninja/Intents/WebApp/CreateInvoiceIntent.php @@ -19,6 +19,9 @@ class CreateInvoiceIntent extends InvoiceIntent $url = '/invoices/create/' . $clientPublicId . '?'; $url .= $this->requestFieldsAsString(Invoice::$requestFields); + $url = rtrim($url, '?'); + $url = rtrim($url, '&'); + return redirect($url); } } diff --git a/app/Ninja/Intents/WebApp/CreateQuoteIntent.php b/app/Ninja/Intents/WebApp/CreateQuoteIntent.php index e3a46b0707d5..cd93d4a06d61 100644 --- a/app/Ninja/Intents/WebApp/CreateQuoteIntent.php +++ b/app/Ninja/Intents/WebApp/CreateQuoteIntent.php @@ -17,6 +17,9 @@ class CreateQuoteIntent extends BaseIntent $url = '/quotes/create/' . $clientPublicId . '?'; $url .= $this->requestFieldsAsString(Invoice::$requestFields); + $url = rtrim($url, '?'); + $url = rtrim($url, '&'); + return redirect($url); } } diff --git a/app/Ninja/Intents/WebApp/CreateRecurringInvoiceIntent.php b/app/Ninja/Intents/WebApp/CreateRecurringInvoiceIntent.php index bbf04871696c..db09f8ff4778 100644 --- a/app/Ninja/Intents/WebApp/CreateRecurringInvoiceIntent.php +++ b/app/Ninja/Intents/WebApp/CreateRecurringInvoiceIntent.php @@ -17,6 +17,9 @@ class CreateRecurringInvoiceIntent extends BaseIntent $url = '/recurring_invoices/create/' . $clientPublicId . '?'; $url .= $this->requestFieldsAsString(Invoice::$requestFields); + $url = rtrim($url, '?'); + $url = rtrim($url, '&'); + return redirect($url); } } diff --git a/app/Ninja/Intents/WebApp/ListClientIntent.php b/app/Ninja/Intents/WebApp/ListClientIntent.php index d10e42bf2015..6cb087d2af59 100644 --- a/app/Ninja/Intents/WebApp/ListClientIntent.php +++ b/app/Ninja/Intents/WebApp/ListClientIntent.php @@ -8,6 +8,8 @@ class ListClientIntent extends BaseIntent { public function process() { + $this->loadStates(ENTITY_CLIENT); + return redirect('/clients'); } } diff --git a/app/Ninja/Intents/WebApp/ListCreditIntent.php b/app/Ninja/Intents/WebApp/ListCreditIntent.php index b4f9412cf3c2..dadc36080189 100644 --- a/app/Ninja/Intents/WebApp/ListCreditIntent.php +++ b/app/Ninja/Intents/WebApp/ListCreditIntent.php @@ -8,6 +8,8 @@ class ListCreditIntent extends BaseIntent { public function process() { + $this->loadStates(ENTITY_CREDIT); + if ($client = $this->requestClient()) { $url = $client->present()->url . '#credits'; } else { diff --git a/app/Ninja/Intents/WebApp/ListExpenseIntent.php b/app/Ninja/Intents/WebApp/ListExpenseIntent.php index 03751a97e58d..5b6e6f7dff3c 100644 --- a/app/Ninja/Intents/WebApp/ListExpenseIntent.php +++ b/app/Ninja/Intents/WebApp/ListExpenseIntent.php @@ -8,6 +8,8 @@ class ListExpenseIntent extends BaseIntent { public function process() { + $this->loadStates(ENTITY_EXPENSE); + return redirect('/expenses'); } } diff --git a/app/Ninja/Intents/WebApp/ListInvoiceIntent.php b/app/Ninja/Intents/WebApp/ListInvoiceIntent.php index 477258f94f66..339493bb00f9 100644 --- a/app/Ninja/Intents/WebApp/ListInvoiceIntent.php +++ b/app/Ninja/Intents/WebApp/ListInvoiceIntent.php @@ -8,6 +8,9 @@ class ListInvoiceIntent extends InvoiceIntent { public function process() { + $this->loadStates(ENTITY_INVOICE); + $this->loadStatuses(ENTITY_INVOICE); + if ($client = $this->requestClient()) { $url = $client->present()->url . '#invoices'; } else { diff --git a/app/Ninja/Intents/WebApp/ListPaymentIntent.php b/app/Ninja/Intents/WebApp/ListPaymentIntent.php index 40f2f3688e88..a545bd8559b3 100644 --- a/app/Ninja/Intents/WebApp/ListPaymentIntent.php +++ b/app/Ninja/Intents/WebApp/ListPaymentIntent.php @@ -8,6 +8,8 @@ class ListPaymentIntent extends BaseIntent { public function process() { + $this->loadStates(ENTITY_PAYMENT); + if ($client = $this->requestClient()) { $url = $client->present()->url . '#payments'; } else { diff --git a/app/Ninja/Intents/WebApp/ListProductIntent.php b/app/Ninja/Intents/WebApp/ListProductIntent.php index 613601411228..70bfac9c6703 100644 --- a/app/Ninja/Intents/WebApp/ListProductIntent.php +++ b/app/Ninja/Intents/WebApp/ListProductIntent.php @@ -8,6 +8,8 @@ class ListProductIntent extends BaseIntent { public function process() { + $this->loadStates(ENTITY_PRODUCT); + return redirect('/products'); } } diff --git a/app/Ninja/Intents/WebApp/ListQuoteIntent.php b/app/Ninja/Intents/WebApp/ListQuoteIntent.php index 76bae43d0575..1867d34e0dfe 100644 --- a/app/Ninja/Intents/WebApp/ListQuoteIntent.php +++ b/app/Ninja/Intents/WebApp/ListQuoteIntent.php @@ -2,12 +2,15 @@ namespace App\Ninja\Intents\WebApp; -use App\Ninja\Intents\BaseIntent; +use App\Ninja\Intents\InvoiceIntent; -class ListQuotesIntent extends BaseIntent +class ListQuoteIntent extends InvoiceIntent { public function process() { + $this->loadStates(ENTITY_QUOTE); + $this->loadStatuses(ENTITY_QUOTE); + if ($client = $this->requestClient()) { $url = $client->present()->url . '#quotes'; } else { diff --git a/app/Ninja/Intents/WebApp/ListRecurringInvoiceIntent.php b/app/Ninja/Intents/WebApp/ListRecurringInvoiceIntent.php index d0233c6db7fb..d8823dd7bbcb 100644 --- a/app/Ninja/Intents/WebApp/ListRecurringInvoiceIntent.php +++ b/app/Ninja/Intents/WebApp/ListRecurringInvoiceIntent.php @@ -8,6 +8,8 @@ class ListRecurringInvoiceIntent extends BaseIntent { public function process() { + $this->loadStates(ENTITY_RECURRING_INVOICE); + if ($client = $this->requestClient()) { $url = $client->present()->url . '#recurring_invoices'; } else { diff --git a/app/Ninja/Intents/WebApp/ListTaskIntent.php b/app/Ninja/Intents/WebApp/ListTaskIntent.php index f8c68626cd58..05574761c836 100644 --- a/app/Ninja/Intents/WebApp/ListTaskIntent.php +++ b/app/Ninja/Intents/WebApp/ListTaskIntent.php @@ -8,6 +8,8 @@ class ListTaskIntent extends BaseIntent { public function process() { + $this->loadStates(ENTITY_TASK); + if ($client = $this->requestClient()) { $url = $client->present()->url . '#tasks'; } else { diff --git a/app/Ninja/Intents/WebApp/ListVendorIntent.php b/app/Ninja/Intents/WebApp/ListVendorIntent.php index 2f3f819dec14..0b98d5cbdd3c 100644 --- a/app/Ninja/Intents/WebApp/ListVendorIntent.php +++ b/app/Ninja/Intents/WebApp/ListVendorIntent.php @@ -8,6 +8,8 @@ class ListVendorIntent extends BaseIntent { public function process() { + $this->loadStates(ENTITY_VENDOR); + return redirect('/vendors'); } } diff --git a/resources/views/partials/speech_recognition.blade.php b/resources/views/partials/speech_recognition.blade.php index bc3ffeaca483..d6519905135f 100644 --- a/resources/views/partials/speech_recognition.blade.php +++ b/resources/views/partials/speech_recognition.blade.php @@ -173,9 +173,10 @@ function onMicrophoneClick() { //$('#search').val("show me all of edgar's credits"); - $('#search').val("show me edgar's credits"); - $('#search-form').submit(); - return; + //$('#search').val("new invoice for joe, set the due date to today and the discount to ten percent"); + //$('#search').val("list joe's active and approved quotes"); + //$('#search-form').submit(); + //return; $('.fa-microphone').hide(); $('#search').val("{{ trans('texts.listening') }}");