1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

update voice

This commit is contained in:
Luke Pulverenti 2016-07-06 14:39:04 -04:00
parent 6e90fe1460
commit aece94029c
13 changed files with 300 additions and 249 deletions

View file

@ -165,7 +165,7 @@
function showVoice() { function showVoice() {
require(['voice/voice'], function (voice) { require(['voice/voice'], function (voice) {
voice.startListening(); voice.showDialog();
}); });
} }

View file

@ -1,5 +1,4 @@
 define([], function () {
define([], function () {
return function (result) { return function (result) {
result.success = true; result.success = true;

View file

@ -1,5 +1,4 @@
 define([], function () {
define([], function () {
return function (result) { return function (result) {
result.success = true; result.success = true;

View file

@ -1,5 +1,4 @@
 define([], function () {
define([], function () {
return function (result) { return function (result) {
result.success = true; result.success = true;

View file

@ -1,12 +1,7 @@
 define([], function () {
define([], function () {
return function (result) { return function (result) {
result.success = true;
switch (result.item.deviceid) { switch (result.item.deviceid) {
case 'displaymirroring':
MediaController.enableDisplayMirroring(false);
break;
default: default:
result.success = false; result.success = false;
return; return;

View file

@ -1,5 +1,4 @@
 define([], function () {
define([], function () {
return function (result) { return function (result) {
result.success = true; result.success = true;

View file

@ -1,5 +1,4 @@
 define([], function () {
define([], function () {
return function (result) { return function (result) {
result.success = true; result.success = true;
@ -12,5 +11,4 @@ define([], function () {
return; return;
} }
} }
}); });

View file

@ -139,7 +139,7 @@
"commandtemplates": [ "commandtemplates": [
"Play music", "Play music",
"Play my music", "Play my music",
"Listen to my music " "Listen to my music"
] ]
}, },
{ {
@ -188,7 +188,7 @@
"commandtemplates": [ "commandtemplates": [
"Play music", "Play music",
"Play my music", "Play my music",
"Listen to my music " "Listen to my music"
] ]
}, },
{ {
@ -200,7 +200,7 @@
"commandtemplates": [ "commandtemplates": [
"Play music", "Play music",
"Play my music", "Play my music",
"Listen to my music ", "Listen to my music",
"shuffle my favorite songs" "shuffle my favorite songs"
] ]
} }

View file

@ -1,5 +1,5 @@
.voiceHelpContent { .voiceHelpContent {
max-width: 600px; max-width: 700px;
margin: auto; margin: auto;
} }

View file

@ -18,9 +18,9 @@ define([], function () {
window.msSpeechRecognition; window.msSpeechRecognition;
}, },
startListening: function () { showDialog: function () {
require(['voice/voicedialog'], function (voicedialog) { require(['voice/voicedialog'], function (voicedialog) {
voicedialog.startListening(); voicedialog.showDialog();
}); });
} }
}; };

View file

@ -1,37 +1,7 @@
define(['dialogHelper', 'jQuery', 'emby-button'], function (dialogHelper, $) { define(['dialogHelper', 'voice/voicereceiver', 'voice/voiceprocessor', 'globalize', 'emby-button', 'css!./voice.css', 'material-icons'], function (dialogHelper, voicereceiver, voiceprocessor, globalize) {
var currentRecognition;
var lang = 'en-US'; var lang = 'en-US';
var commandgroups;
function getCommandGroups() {
if (commandgroups) {
return Promise.resolve(commandgroups);
}
return new Promise(function (resolve, reject) {
var file = "grammar";
//if (language && language.length > 0)
// file = language;
var xhr = new XMLHttpRequest();
xhr.open('GET', "voice/grammar/" + file + ".json", true);
xhr.onload = function (e) {
commandgroups = JSON.parse(this.response);
resolve(commandgroups);
}
xhr.onerror = reject;
xhr.send();
});
}
/// <summary> Shuffle array. </summary> /// <summary> Shuffle array. </summary>
/// <param name="array"> The array. </param> /// <param name="array"> The array. </param>
/// <returns> array </returns> /// <returns> array </returns>
@ -58,7 +28,7 @@ define(['dialogHelper', 'jQuery', 'emby-button'], function (dialogHelper, $) {
/// <returns> The sample commands. </returns> /// <returns> The sample commands. </returns>
function getSampleCommands(groupid) { function getSampleCommands(groupid) {
return getCommandGroups().then(function (commandGroups) { return voiceprocessor.getCommandGroups().then(function (commandGroups) {
groupid = typeof (groupid) !== 'undefined' ? groupid : ''; groupid = typeof (groupid) !== 'undefined' ? groupid : '';
var commands = []; var commands = [];
@ -86,17 +56,20 @@ define(['dialogHelper', 'jQuery', 'emby-button'], function (dialogHelper, $) {
/// <param name="groupid"> The groupid. </param> /// <param name="groupid"> The groupid. </param>
/// <returns> The command group. </returns> /// <returns> The command group. </returns>
function getCommandGroup(groupid) { function getCommandGroup(groupid) {
return voicereceiver.getCommandGroups()
.then(function (commandgroups) {
if (commandgroups) { if (commandgroups) {
var idx = -1; var idx = -1;
idx = commandgroups.map(function (e) { return e.groupid; }).indexOf(groupid); idx = commandgroups.map(function (e) { return e.groupid; }).indexOf(groupid);
if (idx > -1) if (idx > -1)
return commandgroups[idx]; return commandgroups[idx];
else else
return null; return null;
} } else
else
return null; return null;
});
} }
/// <summary> Renders the sample commands. </summary> /// <summary> Renders the sample commands. </summary>
@ -113,7 +86,7 @@ define(['dialogHelper', 'jQuery', 'emby-button'], function (dialogHelper, $) {
}).join(''); }).join('');
$('.exampleCommands', elem).html(commands); elem.querySelector('.exampleCommands').innerHTML = commands;
} }
var currentDialog; var currentDialog;
@ -121,7 +94,16 @@ define(['dialogHelper', 'jQuery', 'emby-button'], function (dialogHelper, $) {
/// <returns> . </returns> /// <returns> . </returns>
function showVoiceHelp(groupid, title) { function showVoiceHelp(groupid, title) {
var dlg = dialogHelper.createDialog({ console.log("Showing Voice Help", groupid, title);
var isNewDialog = false;
var dlg;
if (!currentDialog) {
isNewDialog = true;
dlg = dialogHelper.createDialog({
size: 'medium', size: 'medium',
removeOnClose: true removeOnClose: true
}); });
@ -130,24 +112,21 @@ define(['dialogHelper', 'jQuery', 'emby-button'], function (dialogHelper, $) {
dlg.classList.add('background-theme-b'); dlg.classList.add('background-theme-b');
var html = ''; var html = '';
html += '<h2 class="dialogHeader">'; html += '<div class="dialogHeader" style="margin:0 0 1em;">';
html += '<paper-fab icon="arrow-back" mini class="btnCancelVoiceInput"></paper-fab>'; html += '<button is="paper-icon-button-light" class="btnCancel autoSize btnCancelVoiceInput" tabindex="-1"><i class="md-icon">arrow_back</i></button>';
if (groupid) { html += '<div class="dialogHeaderTitle" id="voiceDialogGroupName">';
var grp = getCommandGroup(groupid); html += '</div>';
if (grp) html += '</div>';
html += ' ' + grp.name;
}
html += '</h2>';
html += '<div>'; html += '<div>';
var getCommandsPromise = getSampleCommands(groupid); html += '<div class="dialogContent smoothScrollY">';
html += '<div class="dialogContentInner centeredContent">';
html += '<div class="voiceHelpContent">'; html += '<div class="voiceHelpContent">';
html += '<div class="defaultVoiceHelp">'; html += '<div class="defaultVoiceHelp">';
html += '<h1 style="margin-bottom:1.25em;">' + Globalize.translate('HeaderSaySomethingLike') + '</h1>'; html += '<h1 style="margin-bottom:1.25em;">' + globalize.translate('HeaderSaySomethingLike') + '</h1>';
html += '<div class="exampleCommands">'; html += '<div class="exampleCommands">';
html += '</div>'; html += '</div>';
@ -155,20 +134,27 @@ define(['dialogHelper', 'jQuery', 'emby-button'], function (dialogHelper, $) {
// defaultVoiceHelp // defaultVoiceHelp
html += '</div>'; html += '</div>';
html += '<div class="unrecognizedCommand" style="display:none;">'; html += '<div class="unrecognizedCommand hide">';
html += '<h1>' + Globalize.translate('HeaderYouSaid') + '</h1>'; html += '<h1>' + globalize.translate('HeaderYouSaid') + '</h1>';
html += '<p class="exampleCommand voiceInputContainer"><i class="fa fa-quote-left"></i><span class="voiceInputText exampleCommandText"></span><i class="fa fa-quote-right"></i></p>'; html +=
html += '<p>' + Globalize.translate('MessageWeDidntRecognizeCommand') + '</p>'; '<p class="exampleCommand voiceInputContainer"><i class="fa fa-quote-left"></i><span class="voiceInputText exampleCommandText"></span><i class="fa fa-quote-right"></i></p>';
html += '<p>' + globalize.translate('MessageWeDidntRecognizeCommand') + '</p>';
html += '<br/>'; html += '<br/>';
html += '<button is="emby-button" type="button" class="raised submit block btnRetry"><iron-icon icon="mic"></iron-icon><span>' + Globalize.translate('ButtonTryAgain') + '</span></button>'; html += '<button is="emby-button" type="button" class="submit block btnRetry raised"><i class="md-icon">mic</i><span>' +
html += '<p class="blockedMessage" style="display:none;">' + Globalize.translate('MessageIfYouBlockedVoice') + '<br/><br/></p>'; globalize.translate('ButtonTryAgain') +
'</span></button>';
html += '<p class="blockedMessage hide">' +
globalize.translate('MessageIfYouBlockedVoice') +
'<br/><br/></p>';
html += '</div>'; html += '</div>';
html += '<button is="emby-button" type="button" class="raised block btnCancelVoiceInput" style="background-color:#444;"><iron-icon icon="close"></iron-icon><span>' + Globalize.translate('ButtonCancel') + '</span></button>'; html +=
'<button is="emby-button" type="button" class="raised block btnCancelVoiceInput cancel"><i class="md-icon">close</i><span>' + globalize.translate('ButtonCancel') + '</span></button>';
// voiceHelpContent html += '</div>';
html += '</div>';
html += '</div>'; html += '</div>';
html += '</div>'; html += '</div>';
@ -183,150 +169,104 @@ define(['dialogHelper', 'jQuery', 'emby-button'], function (dialogHelper, $) {
currentDialog = null; currentDialog = null;
}); });
$('.btnCancelVoiceInput', dlg).on('click', function () { function onCancelClick() {
destroyCurrentRecognition(); voicereceiver.cancel();
dialogHelper.close(dlg); dialogHelper.close(dlg);
}); }
$('.btnRetry', dlg).on('click', function () { var closeButtons = dlg.querySelectorAll('.btnCancelVoiceInput');
$('.unrecognizedCommand').hide(); for (var i = 0, length = closeButtons.length; i < length; i++) {
$('.defaultVoiceHelp').show(); closeButtons[i].addEventListener('click', onCancelClick);
startListening(false); }
});
getCommandsPromise.then(function (commands) { dlg.querySelector('.btnRetry').addEventListener('click', function () {
renderSampleCommands(dlg.querySelector('.voiceHelpContent'), commands); dlg.querySelector('.unrecognizedCommand').classList.add('hide');
dlg.querySelector('.defaultVoiceHelp').classList.remove('hide');
listen();
}); });
} }
/// <summary> Hides the voice help. </summary> dlg = currentDialog;
/// <returns> . </returns>
function hideVoiceHelp() {
$('.voiceInputHelp').remove(); if (groupid) {
getCommandGroup(groupid)
.then(
function (grp) {
dlg.querySelector('#voiceDialogGroupName').innerText = ' ' + grp.name;
});
getSampleCommands(groupid)
.then(function (commands) {
renderSampleCommands(currentDialog, commands);
listen();
})
.catch(function (e) { console.log("Error", e); });
} else if (isNewDialog) {
getSampleCommands()
.then(function (commands) {
renderSampleCommands(currentDialog, commands);
});
}
}
function processInput(input) {
return voiceprocessor.processTranscript(input);
} }
/// <summary> Shows the unrecognized command help. </summary> /// <summary> Shows the unrecognized command help. </summary>
/// <returns> . </returns> /// <returns> . </returns>
function showUnrecognizedCommandHelp() { function showUnrecognizedCommandHelp(command) {
//speak("I don't understend this command"); //speak("I don't understend this command");
$('.unrecognizedCommand').show(); if (command)
$('.defaultVoiceHelp').hide(); currentDialog.querySelector('.voiceInputText').innerText = command;
} currentDialog.querySelector('.unrecognizedCommand').classList.remove('hide');
currentDialog.querySelector('.defaultVoiceHelp').classList.add('hide');
/// <summary> Process the transcript described by text. </summary>
/// <param name="text"> The text. </param>
/// <returns> . </returns>
function processTranscript(text, isCancelled) {
$('.voiceInputText').html(text);
if (text || AppInfo.isNativeApp) {
$('.blockedMessage').hide();
}
else {
$('.blockedMessage').show();
}
if (text) {
require(['voice/voicecommands.js', 'voice/grammarprocessor.js'], function (voicecommands, grammarprocessor) {
var processor = grammarprocessor(commandgroups, text);
if (processor && processor.command) {
voicecommands(processor)
.then(function (result) {
if (result.item.actionid === 'show' && result.item.sourceid === 'group') {
var dlg = currentDialog;
if (dlg)
showCommands(false, result)
else
showCommands(true, result)
}
})
.catch(showUnrecognizedCommandHelp);
}
else
showUnrecognizedCommandHelp();
var dlg = currentDialog;
if (dlg) {
dialogHelper.close(dlg);
}
});
}
else if (!isCancelled) {
showUnrecognizedCommandHelp();
}
}
/// <summary> Starts listening internal. </summary>
/// <returns> . </returns>
function startListening(createUI) {
destroyCurrentRecognition();
var recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.oSpeechRecognition || window.msSpeechRecognition)();
recognition.lang = lang;
var groupid = '';
//recognition.continuous = true;
//recognition.interimResults = true;
recognition.onresult = function (event) {
if (event.results.length > 0) {
processTranscript(event.results[0][0].transcript || '');
}
};
recognition.onerror = function () {
processTranscript('', recognition.cancelled);
};
recognition.onnomatch = function () {
processTranscript('', recognition.cancelled);
};
recognition.start();
currentRecognition = recognition;
showCommands(createUI);
}
/// <summary> Destroys the current recognition. </summary>
/// <returns> . </returns>
function destroyCurrentRecognition() {
var recognition = currentRecognition;
if (recognition) {
recognition.abort();
currentRecognition = null;
}
}
/// <summary> Cancel listener. </summary>
/// <returns> . </returns>
function cancelListener() {
destroyCurrentRecognition();
hideVoiceHelp();
} }
/// <summary> Shows the commands. </summary> /// <summary> Shows the commands. </summary>
/// <param name="createUI"> The create user interface. </param> /// <param name="createUI"> The create user interface. </param>
/// <returns> . </returns> /// <returns> . </returns>
function showCommands(createUI, result) { function showCommands(result) {
if (createUI !== false) {
//speak('Hello, what can I do for you?'); //speak('Hello, what can I do for you?');
require(['paper-fab', 'css!voice/voice.css'], function () {
if (result) if (result)
showVoiceHelp(result.groupid, result.name); showVoiceHelp(result.groupid, result.name);
else else
showVoiceHelp(); showVoiceHelp();
}
function resetDialog() {
if (currentDialog) {
currentDialog.querySelector('.unrecognizedCommand').classList.add('hide');
currentDialog.querySelector('.defaultVoiceHelp').classList.remove('hide');
}
}
function showDialog() {
resetDialog();
showCommands();
listen();
}
function listen() {
voicereceiver.listenForCommand(lang || "en-US").then(processInput).then(function (data) {
closeDialog();
}, function (result) {
if (result.error == 'group') {
showVoiceHelp(result.item.groupid, result.groupName);
return;
}
showUnrecognizedCommandHelp(result.text || '');
}); });
} }
function closeDialog() {
dialogHelper.close(currentDialog);
voicereceiver.cancel();
} }
/// <summary> An enum constant representing the window. voice input manager option. </summary> /// <summary> An enum constant representing the window. voice input manager option. </summary>
return { return {
startListening: startListening showDialog: showDialog
}; };
}); });

View file

@ -0,0 +1,65 @@
define(['voice/voicecommands.js', 'voice/grammarprocessor.js'], function (voicecommands, grammarprocessor) {
var commandgroups;
function getCommandGroups() {
if (commandgroups) {
return Promise.resolve(commandgroups);
}
return new Promise(function (resolve, reject) {
var file = "grammar";
//if (language && language.length > 0)
// file = language;
var xhr = new XMLHttpRequest();
xhr.open('GET', "voice/grammar/" + file + ".json", true);
xhr.onload = function (e) {
commandgroups = JSON.parse(this.response);
resolve(commandgroups);
}
xhr.onerror = reject;
xhr.send();
});
}
/// <summary> Process the transcript described by text. </summary>
/// <param name="text"> The text. </param>
/// <returns> . </returns>
function processTranscript(text) {
if (text) {
var processor = grammarprocessor(commandgroups, text);
if (processor && processor.command) {
console.log("Command from Grammar Processor", processor);
return voicecommands(processor)
.then(function (result) {
console.log("Result of executed command", result);
if (result.item.actionid === 'show' && result.item.sourceid === 'group') {
return Promise.reject({ error: "group", item: result.item, groupName: result.name });
} else {
return Promise.resolve({ item: result.item });
}
}, function () {
return Promise.reject({ error: "unrecognized-command", text: text });
});
} else {
return Promise.reject({ error: "unrecognized-command", text: text });
}
} else {
return Promise.reject({ error: "empty" });
}
}
/// <summary> An enum constant representing the window. voice input manager option. </summary>
return {
processTranscript: processTranscript,
getCommandGroups: getCommandGroups
};
});

View file

@ -0,0 +1,57 @@
define([], function () {
var currentRecognition = null;
/// <summary> Starts listening for voice commands </summary>
/// <returns> . </returns>
function listenForCommand(lang) {
return new Promise(function (resolve, reject) {
cancelListener();
var recognition = new (window.SpeechRecognition ||
window.webkitSpeechRecognition ||
window.mozSpeechRecognition ||
window.oSpeechRecognition ||
window.msSpeechRecognition)();
recognition.lang = lang;
recognition.onresult = function (event) {
console.log(event);
if (event.results.length > 0) {
var resultInput = event.results[0][0].transcript || '';
resolve(resultInput);
}
};
recognition.onerror = function () {
reject({ error: event.error, message: event.message });
};
recognition.onnomatch = function () {
reject({ error: "no-match" });
};
currentRecognition = recognition;
currentRecognition.start();
});
}
/// <summary> Cancel listener. </summary>
/// <returns> . </returns>
function cancelListener() {
if (currentRecognition) {
currentRecognition.abort();
currentRecognition = null;
}
}
/// <summary> An enum constant representing the window. voice input manager option. </summary>
return {
listenForCommand: listenForCommand,
cancel: cancelListener
};
});