mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-04 02:47:34 -05:00 
			
		
		
		
	Working on speech rec
This commit is contained in:
		
							parent
							
								
									23e9dd6a97
								
							
						
					
					
						commit
						9dd2ab43c2
					
				@ -325,6 +325,9 @@ if (! defined('APP_NAME')) {
 | 
			
		||||
    define('SKYPE_API_URL', 'https://apis.skype.com/v3');
 | 
			
		||||
    define('MSBOT_STATE_URL', 'https://state.botframework.com/v3');
 | 
			
		||||
 | 
			
		||||
    define('BOT_PLATFORM_WEB_APP', 'WebApp');
 | 
			
		||||
    define('BOT_PLATFORM_SKYPE', 'Skype');
 | 
			
		||||
 | 
			
		||||
    define('BLANK_IMAGE', 'data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=');
 | 
			
		||||
 | 
			
		||||
    define('COUNT_FREE_DESIGNS', 4);
 | 
			
		||||
 | 
			
		||||
@ -80,7 +80,7 @@ class BotController extends Controller
 | 
			
		||||
                        $user->account->loadLocalizationSettings();
 | 
			
		||||
 | 
			
		||||
                        $data = $this->parseMessage($text);
 | 
			
		||||
                        $intent = BaseIntent::createIntent($state, $data);
 | 
			
		||||
                        $intent = BaseIntent::createIntent($platform, $state, $data);
 | 
			
		||||
                        $response = $intent->process();
 | 
			
		||||
                        $state = $intent->getState();
 | 
			
		||||
                    }
 | 
			
		||||
@ -97,6 +97,14 @@ class BotController extends Controller
 | 
			
		||||
        return RESULT_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function handleCommand()
 | 
			
		||||
    {
 | 
			
		||||
        $data = $this->parseMessage(request()->command);
 | 
			
		||||
        $intent = BaseIntent::createIntent(BOT_PLATFORM_WEB_APP, false, $data);
 | 
			
		||||
 | 
			
		||||
        return $intent->process();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function authenticate($input)
 | 
			
		||||
    {
 | 
			
		||||
        $token = isset($_SERVER['HTTP_AUTHORIZATION']) ? $_SERVER['HTTP_AUTHORIZATION'] : false;
 | 
			
		||||
 | 
			
		||||
@ -127,6 +127,7 @@ Route::group(['middleware' => 'auth:user'], function () {
 | 
			
		||||
    Route::get('check_invoice_number/{invoice_id?}', 'InvoiceController@checkInvoiceNumber');
 | 
			
		||||
    Route::post('save_sidebar_state', 'UserController@saveSidebarState');
 | 
			
		||||
    Route::post('contact_us', 'HomeController@contactUs');
 | 
			
		||||
    Route::post('handle_command', 'BotController@handleCommand');
 | 
			
		||||
 | 
			
		||||
    Route::get('settings/user_details', 'AccountController@showUserDetails');
 | 
			
		||||
    Route::post('settings/user_details', 'AccountController@saveUserDetails');
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,7 @@ class BaseIntent
 | 
			
		||||
        //var_dump($state);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function createIntent($state, $data)
 | 
			
		||||
    public static function createIntent($platform, $state, $data)
 | 
			
		||||
    {
 | 
			
		||||
        if (! count($data->intents)) {
 | 
			
		||||
            throw new Exception(trans('texts.intent_not_found'));
 | 
			
		||||
@ -48,13 +48,18 @@ class BaseIntent
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (! $entityType) {
 | 
			
		||||
        if ($state && ! $entityType) {
 | 
			
		||||
            $entityType = $state->current->entityType;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $entityType = ucwords(strtolower($entityType));
 | 
			
		||||
        $intent = str_replace('Entity', $entityType, $intent);
 | 
			
		||||
 | 
			
		||||
        if ($platform == BOT_PLATFORM_WEB_APP) {
 | 
			
		||||
            $className = "App\\Ninja\\Intents\\WebApp\\{$intent}Intent";
 | 
			
		||||
        } else {
 | 
			
		||||
            $className = "App\\Ninja\\Intents\\{$intent}Intent";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //echo "Intent: $intent<p>";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										28
									
								
								app/Ninja/Intents/WebApp/CreateInvoiceIntent.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								app/Ninja/Intents/WebApp/CreateInvoiceIntent.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Ninja\Intents\WebApp;
 | 
			
		||||
 | 
			
		||||
use App\Models\EntityModel;
 | 
			
		||||
use App\Ninja\Intents\InvoiceIntent;
 | 
			
		||||
use Exception;
 | 
			
		||||
 | 
			
		||||
class CreateInvoiceIntent extends InvoiceIntent
 | 
			
		||||
{
 | 
			
		||||
    public function process()
 | 
			
		||||
    {
 | 
			
		||||
        $client = $this->requestClient();
 | 
			
		||||
        $invoiceItems = $this->requestInvoiceItems();
 | 
			
		||||
 | 
			
		||||
        if (! $client) {
 | 
			
		||||
            throw new Exception(trans('texts.client_not_found'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $data = array_merge($this->requestFields(), [
 | 
			
		||||
            'client_id' => $client->public_id,
 | 
			
		||||
            'invoice_items' => $invoiceItems,
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        //var_dump($data);
 | 
			
		||||
        dd($data);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -309,12 +309,15 @@
 | 
			
		||||
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <form id="search-form" class="navbar-form navbar-right" role="search">
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
          <input type="text" id="search" style="width: 240px;padding-top:0px;padding-bottom:0px"
 | 
			
		||||
            class="form-control" placeholder="{{ trans('texts.search') . ': ' . trans('texts.search_hotkey')}}">
 | 
			
		||||
      {!! Former::open('/handle_command')->id('search-form')->addClass('navbar-form navbar-right')->role('search') !!}
 | 
			
		||||
        <div class="form-group has-feedback">
 | 
			
		||||
          <input type="text" name="command" id="search" style="width: 240px;padding-top:0px;padding-bottom:0px;margin-right:12px;"
 | 
			
		||||
            class="form-control" placeholder="{{ trans('texts.search') . ': ' . trans('texts.search_hotkey')}}"/>
 | 
			
		||||
            @if (Utils::isNinja())
 | 
			
		||||
                @include('partials/speech_recognition')
 | 
			
		||||
            @endif
 | 
			
		||||
        </div>
 | 
			
		||||
      </form>
 | 
			
		||||
      {!! Former::close() !!}
 | 
			
		||||
 | 
			
		||||
      @if (false && Utils::isAdmin())
 | 
			
		||||
      <ul class="nav navbar-nav navbar-right">
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										215
									
								
								resources/views/partials/speech_recognition.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								resources/views/partials/speech_recognition.blade.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,215 @@
 | 
			
		||||
<i class="fa fa-microphone form-control-feedback" style="font-size:16px;padding-top:8px" aria-hidden="true"></i>
 | 
			
		||||
 | 
			
		||||
<script type="text/javascript">
 | 
			
		||||
    $(function() {
 | 
			
		||||
        $('#search').keypress(function(event) {
 | 
			
		||||
            if (event.keyCode === 13) {
 | 
			
		||||
                $('#search-form').submit();
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    var langs =
 | 
			
		||||
    [['Afrikaans',       ['af-ZA']],
 | 
			
		||||
     ['Bahasa Indonesia',['id-ID']],
 | 
			
		||||
     ['Bahasa Melayu',   ['ms-MY']],
 | 
			
		||||
     ['Català',          ['ca-ES']],
 | 
			
		||||
     ['Čeština',         ['cs-CZ']],
 | 
			
		||||
     ['Dansk',           ['da-DK']],
 | 
			
		||||
     ['Deutsch',         ['de-DE']],
 | 
			
		||||
     ['English',         ['en-AU', 'Australia'],
 | 
			
		||||
                         ['en-CA', 'Canada'],
 | 
			
		||||
                         ['en-IN', 'India'],
 | 
			
		||||
                         ['en-NZ', 'New Zealand'],
 | 
			
		||||
                         ['en-ZA', 'South Africa'],
 | 
			
		||||
                         ['en-GB', 'United Kingdom'],
 | 
			
		||||
                         ['en-US', 'United States']],
 | 
			
		||||
     ['Español',         ['es-AR', 'Argentina'],
 | 
			
		||||
                         ['es-BO', 'Bolivia'],
 | 
			
		||||
                         ['es-CL', 'Chile'],
 | 
			
		||||
                         ['es-CO', 'Colombia'],
 | 
			
		||||
                         ['es-CR', 'Costa Rica'],
 | 
			
		||||
                         ['es-EC', 'Ecuador'],
 | 
			
		||||
                         ['es-SV', 'El Salvador'],
 | 
			
		||||
                         ['es-ES', 'España'],
 | 
			
		||||
                         ['es-US', 'Estados Unidos'],
 | 
			
		||||
                         ['es-GT', 'Guatemala'],
 | 
			
		||||
                         ['es-HN', 'Honduras'],
 | 
			
		||||
                         ['es-MX', 'México'],
 | 
			
		||||
                         ['es-NI', 'Nicaragua'],
 | 
			
		||||
                         ['es-PA', 'Panamá'],
 | 
			
		||||
                         ['es-PY', 'Paraguay'],
 | 
			
		||||
                         ['es-PE', 'Perú'],
 | 
			
		||||
                         ['es-PR', 'Puerto Rico'],
 | 
			
		||||
                         ['es-DO', 'República Dominicana'],
 | 
			
		||||
                         ['es-UY', 'Uruguay'],
 | 
			
		||||
                         ['es-VE', 'Venezuela']],
 | 
			
		||||
     ['Euskara',         ['eu-ES']],
 | 
			
		||||
     ['Filipino',        ['fil-PH']],
 | 
			
		||||
     ['Français',        ['fr-FR']],
 | 
			
		||||
     ['Galego',          ['gl-ES']],
 | 
			
		||||
     ['Hrvatski',        ['hr_HR']],
 | 
			
		||||
     ['IsiZulu',         ['zu-ZA']],
 | 
			
		||||
     ['Íslenska',        ['is-IS']],
 | 
			
		||||
     ['Italiano',        ['it-IT', 'Italia'],
 | 
			
		||||
                         ['it-CH', 'Svizzera']],
 | 
			
		||||
     ['Lietuvių',        ['lt-LT']],
 | 
			
		||||
     ['Magyar',          ['hu-HU']],
 | 
			
		||||
     ['Nederlands',      ['nl-NL']],
 | 
			
		||||
     ['Norsk bokmål',    ['nb-NO']],
 | 
			
		||||
     ['Polski',          ['pl-PL']],
 | 
			
		||||
     ['Português',       ['pt-BR', 'Brasil'],
 | 
			
		||||
                         ['pt-PT', 'Portugal']],
 | 
			
		||||
     ['Română',          ['ro-RO']],
 | 
			
		||||
     ['Slovenščina',     ['sl-SI']],
 | 
			
		||||
     ['Slovenčina',      ['sk-SK']],
 | 
			
		||||
     ['Suomi',           ['fi-FI']],
 | 
			
		||||
     ['Svenska',         ['sv-SE']],
 | 
			
		||||
     ['Tiếng Việt',      ['vi-VN']],
 | 
			
		||||
     ['Türkçe',          ['tr-TR']],
 | 
			
		||||
     ['Ελληνικά',        ['el-GR']],
 | 
			
		||||
     ['български',       ['bg-BG']],
 | 
			
		||||
     ['Pусский',         ['ru-RU']],
 | 
			
		||||
     ['Српски',          ['sr-RS']],
 | 
			
		||||
     ['Українська',      ['uk-UA']],
 | 
			
		||||
     ['한국어',            ['ko-KR']],
 | 
			
		||||
     ['中文',             ['cmn-Hans-CN', '普通话 (中国大陆)'],
 | 
			
		||||
                         ['cmn-Hans-HK', '普通话 (香港)'],
 | 
			
		||||
                         ['cmn-Hant-TW', '中文 (台灣)'],
 | 
			
		||||
                         ['yue-Hant-HK', '粵語 (香港)']],
 | 
			
		||||
     ['日本語',           ['ja-JP']],
 | 
			
		||||
     ['हिन्दी',            ['hi-IN']],
 | 
			
		||||
     ['ภาษาไทย',         ['th-TH']]];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    var final_transcript = '';
 | 
			
		||||
    var recognizing = false;
 | 
			
		||||
    var ignore_onend;
 | 
			
		||||
    var start_timestamp;
 | 
			
		||||
 | 
			
		||||
    if (!('webkitSpeechRecognition' in window)) {
 | 
			
		||||
      upgrade();
 | 
			
		||||
    } else {
 | 
			
		||||
      //start_button.style.display = 'inline-block';
 | 
			
		||||
      var recognition = new webkitSpeechRecognition();
 | 
			
		||||
      recognition.continuous = true;
 | 
			
		||||
      recognition.interimResults = true;
 | 
			
		||||
 | 
			
		||||
      recognition.onstart = function() {
 | 
			
		||||
        recognizing = true;
 | 
			
		||||
        showInfo('info_speak_now');
 | 
			
		||||
        //start_img.src = '/intl/en/chrome/assets/common/images/content/mic-animate.gif';
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      recognition.onerror = function(event) {
 | 
			
		||||
        if (event.error == 'no-speech') {
 | 
			
		||||
          //start_img.src = '/intl/en/chrome/assets/common/images/content/mic.gif';
 | 
			
		||||
          showInfo('info_no_speech');
 | 
			
		||||
          ignore_onend = true;
 | 
			
		||||
        }
 | 
			
		||||
        if (event.error == 'audio-capture') {
 | 
			
		||||
          //start_img.src = '/intl/en/chrome/assets/common/images/content/mic.gif';
 | 
			
		||||
          showInfo('info_no_microphone');
 | 
			
		||||
          ignore_onend = true;
 | 
			
		||||
        }
 | 
			
		||||
        if (event.error == 'not-allowed') {
 | 
			
		||||
          if (event.timeStamp - start_timestamp < 100) {
 | 
			
		||||
            showInfo('info_blocked');
 | 
			
		||||
          } else {
 | 
			
		||||
            showInfo('info_denied');
 | 
			
		||||
          }
 | 
			
		||||
          ignore_onend = true;
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      recognition.onend = function() {
 | 
			
		||||
        recognizing = false;
 | 
			
		||||
        if (ignore_onend) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        //start_img.src = '/intl/en/chrome/assets/common/images/content/mic.gif';
 | 
			
		||||
        if (!final_transcript) {
 | 
			
		||||
          showInfo('info_start');
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        showInfo('');
 | 
			
		||||
        if (window.getSelection) {
 | 
			
		||||
          window.getSelection().removeAllRanges();
 | 
			
		||||
          var range = document.createRange();
 | 
			
		||||
          range.selectNode(document.getElementById('final_span'));
 | 
			
		||||
          window.getSelection().addRange(range);
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      recognition.onresult = function(event) {
 | 
			
		||||
        var interim_transcript = '';
 | 
			
		||||
        if (typeof(event.results) == 'undefined') {
 | 
			
		||||
          recognition.onend = null;
 | 
			
		||||
          recognition.stop();
 | 
			
		||||
          upgrade();
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        for (var i = event.resultIndex; i < event.results.length; ++i) {
 | 
			
		||||
          if (event.results[i].isFinal) {
 | 
			
		||||
            final_transcript += event.results[i][0].transcript;
 | 
			
		||||
          } else {
 | 
			
		||||
            interim_transcript += event.results[i][0].transcript;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        final_transcript = capitalize(final_transcript);
 | 
			
		||||
        //final_span.innerHTML = linebreak(final_transcript);
 | 
			
		||||
        //interim_span.innerHTML = linebreak(interim_transcript);
 | 
			
		||||
        console.log('final_span: %s', linebreak(final_transcript));
 | 
			
		||||
        console.log('interim_span: %s', linebreak(interim_transcript));
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function upgrade() {
 | 
			
		||||
      start_button.style.visibility = 'hidden';
 | 
			
		||||
      showInfo('info_upgrade');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var two_line = /\n\n/g;
 | 
			
		||||
    var one_line = /\n/g;
 | 
			
		||||
    function linebreak(s) {
 | 
			
		||||
      return s.replace(two_line, '<p></p>').replace(one_line, '<br>');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var first_char = /\S/;
 | 
			
		||||
    function capitalize(s) {
 | 
			
		||||
      return s.replace(first_char, function(m) { return m.toUpperCase(); });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function startButton(event) {
 | 
			
		||||
      if (recognizing) {
 | 
			
		||||
        recognition.stop();
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      final_transcript = '';
 | 
			
		||||
      recognition.lang = select_dialect.value;
 | 
			
		||||
      recognition.start();
 | 
			
		||||
      ignore_onend = false;
 | 
			
		||||
      final_span.innerHTML = '';
 | 
			
		||||
      interim_span.innerHTML = '';
 | 
			
		||||
      //start_img.src = '/intl/en/chrome/assets/common/images/content/mic-slash.gif';
 | 
			
		||||
      showInfo('info_allow');
 | 
			
		||||
      start_timestamp = event.timeStamp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function showInfo(s) {
 | 
			
		||||
      console.log('Info: ' + s);
 | 
			
		||||
      /*
 | 
			
		||||
      if (s) {
 | 
			
		||||
        for (var child = info.firstChild; child; child = child.nextSibling) {
 | 
			
		||||
          if (child.style) {
 | 
			
		||||
            child.style.display = child.id == s ? 'inline' : 'none';
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        info.style.visibility = 'visible';
 | 
			
		||||
      } else {
 | 
			
		||||
        info.style.visibility = 'hidden';
 | 
			
		||||
      }
 | 
			
		||||
      */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user