How to detect speech-to-text support and what is the meaning of mozSpeechRecognition, msSpeechRecognition, oSpeechRecognition? - webspeech-api

The bounty expires tomorrow. Answers to this question are eligible for a +50 reputation bounty.
John Rizzo wants to draw more attention to this question:
I'm convinced that there is someone experienced in Webspeech API who knows, or who has better internet-search skills than I, and could bring a clear answer.
I'm trying to better understand when Webspeech speech-to-text is actually avaialable and operational.
In this process I see these few lines code all over the web, for assessing is speech-to-text is supported by the browser:
const NativeSpeechRecognition = typeof window !== 'undefined' && (
window.SpeechRecognition ||
window.webkitSpeechRecognition ||
window.mozSpeechRecognition ||
window.msSpeechRecognition ||
window.oSpeechRecognition
)
According https://caniuse.com/speech-recognition all actually supporting browsers (chrome, Opera, UC, Samsung, Safari, QQ, Baidu) use the webkit prefix: window.webkitSpeechRecognition.
The caniuse.com table says that speech-to-text does not work on Edge (109 incl), while on my Windows PC, it works with Edge 109.0.1518.78., for my own JS web app (using the react-speech-recognition package and also with https://dictation.io/speech).
My web searches on "oSpeechRecognition" or "mozSpeechRecognition" or "msSpeechRecognition" have not been instructive.
I've run that code sandbox to know which of these is defined.
var recognition = new (window.SpeechRecognition ||
window.webkitSpeechRecognition ||
window.mozSpeechRecognition ||
window.msSpeechRecognition)();
recognition.lang = "en-US";
recognition.interimResults = false;
recognition.maxAlternatives = 5;
recognition.start();
console.log("window.SpeechRecognition", window.SpeechRecognition);
console.log("window.webkitSpeechRecognition", window.webkitSpeechRecognition);
console.log("window.mozSpeechRecognition", window.mozSpeechRecognition);
console.log("window.msSpeechRecognition", window.msSpeechRecognition);
console.log("selected recognition", recognition);
recognition.onresult = function (event) {
console.log("You said: ", event.results[0][0].transcript);
};
On Chrome 109, the console is:
window.SpeechRecognition undefined
window.webkitSpeechRecognition ƒ SpeechRecognition() {}
window.mozSpeechRecognition undefined
window.msSpeechRecognition undefined
selected recognition EventTarget {grammars: Object, lang: "en-US", continuous: false, interimResults: false, maxAlternatives: 5…}
On Edge 109, the console is exactly the same:
window.SpeechRecognition undefined
window.webkitSpeechRecognition ƒ SpeechRecognition() {}
window.mozSpeechRecognition undefined
window.msSpeechRecognition undefined
selected recognition EventTarget {grammars: Object, lang: "en-US", continuous: false, interimResults: false, maxAlternatives: 5…}
On Firefox 109, the sandbox does not run.
TypeError undefined is not a constructor $csb$eval /src/index.js:1:18
var recognition = new (window.SpeechRecognition ||
I'd like to understand:
Why caniuse.com says speech-to-text does not work on Edge?
Why I can't even make the code run on Firefox?
What is the origin/purpose of mozSpeechRecognition, msSpeechRecognition, and oSpeechRecognition that is copied on many code examples and articles with no comment and no explanation. As if it is some 10 years old historical code that no one understands, is not useful anymore but everyone uses.
Many thanks.
John.

Related

Actions-On-Google NodeJS v2 alpha: More than one conv.close()

Will we be able to use conv.close() multiple times within an intent to provide more than just a single element on exit?
Similar to how you can provide multiple conv.ask() in the one intent.
Or can you include more than one 'new element' in a conv.close() tag?
Yes, of course to both ways! At least it's how it works currently during the alpha (which can change depending on feedback).
conv.ask and conv.close are implemented almost identically just that conv.close sets expectUserResponse to false which means you don't expect more responses from the user and the mic will be closed.
This means you can use conv.close just like conv.ask and call it multiple times.
For example, this code:
const { dialogflow } = require('actions-on-google')
const app = dialogflow()
app.intent('Default Welcome Intent', conv => {
conv.close(`Here's a cat image`)
conv.close(new Image({
url: 'https://developers.google.com/web/fundamentals/accessibility/' +
'semantics-builtin/imgs/160204193356-01-cat-500.jpg',
alt: 'A Cat',
}))
})
when the IntentHandler function is done executing (or if it returns a Promise, when the Promise is resolved), constructs a RichResponse based on the response fragments you provided and sends it back to Dialogflow or the Google Assistant.
It closes the mic and shows this as a result in the simulator.
Alternatively, conv.ask and conv.close also allow you to call it with an arbitrary number of response arguments. So this code will also work identical to the example before:
app.intent('Default Welcome Intent', conv => {
conv.close(`Here's a cat image`, new Image({
url: 'https://developers.google.com/web/fundamentals/accessibility/' +
'semantics-builtin/imgs/160204193356-01-cat-500.jpg',
alt: 'A Cat',
}))
})

GtkAppChooser Content type for all applications and/or audio mixers

I'd like to have a GtkAppChooserButton which allows the user to select a program to run which will most likely want to be an audio mixer such as pavucontrol. Despite vague documentation on the matter I gather the app chooser's content type is meant to be a MIME type, however I cannot find a suitable MIME type for an audio mixer, or more generally just "all applications".
Some types such as application/ will give two Other Application... options if Other... items are enabled, both of which are identical and neither of which contain half the applications I have, including any audio mixers. Aside from that, nothing else I do gets me remotely close to what I'm after.
Is there a MIME type and/or GtkAppChooser content type (they seem to be the same thing?) for audio mixers or just all programs in general? (I.e. Any program that would have an icon in the likes of the Gnome app launcher/xfce4-whisker-menu/etc.)
Alright so I've come up with a solution, thought it may not be as clean as you hoped.
This thread mentioned a way to get the GtkAppChooser to "show all", but it doesn't actually show all applications you have installed. However from that I was able to work out how the GtkAppChooser is using Gio.AppInfo, which has Gio.AppInfo.get_all() (this is for PyObject) which returns a full list of Gio.AppInfos for all applications I have installed, provided they have a .desktop file.
So, my "solution" is to write my own app chooser which gets a list of apps from Gio.AppInfo.get_all().
I've cleaned up my previous solution to this and written a class 'AllAppChooser' to inherrit Gtk.Dialog, giving much greater customisation. The completed dialog looks like so:
And the code used:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gio
class AllAppChooser(Gtk.Dialog):
"""Provide a dialog to select an app from all those installed.
The regular Gtk.AppChooserDialog does not seem to provide any way to allow
selection from all installed apps, so this dialog serves as a replacement.
"""
def __init__(self, parent=None):
super().__init__(self)
self.set_default_size(350, 400)
self.set_icon_name('gtk-search')
self.set_title('App Chooser')
if parent:
self.set_parent(parent)
self.content_box = self.get_content_area()
self.content_box.set_margin_left(8)
self.content_box.set_margin_right(8)
self.content_box.set_margin_top(8)
self.content_box.set_margin_bottom(8)
self.content_box.set_spacing(8)
self.button_box = self.get_action_area()
self.button_box.set_margin_left(4)
self.button_box.set_margin_right(4)
self.button_box.set_margin_top(4)
self.button_box.set_margin_bottom(4)
self.label = Gtk.Label('Choose An Application')
self.content_box.pack_start(self.label, False, False, 0)
self.list_store = Gtk.ListStore(str, str, int)
pixbuf_renderer = Gtk.CellRendererPixbuf()
text_renderer = Gtk.CellRendererText()
icon_column = Gtk.TreeViewColumn('icon', pixbuf_renderer, icon_name=1)
text_column = Gtk.TreeViewColumn('text', text_renderer, text=0)
self.tree_view = Gtk.TreeView()
self.tree_view.set_model(self.list_store)
self.tree_view.set_headers_visible(False)
self.tree_view.append_column(icon_column)
self.tree_view.append_column(text_column)
self.view_port = Gtk.Viewport()
self.view_port.add(self.tree_view)
self.scroll_window = Gtk.ScrolledWindow()
self.scroll_window.add(self.view_port)
self.content_box.pack_start(self.scroll_window, True, True, 0)
self.ok_button = self.add_button(Gtk.STOCK_OK, 1)
self.ok_button.connect('clicked', self.on_ok)
self.cancel_button = self.add_button(Gtk.STOCK_CANCEL, 0)
self.selected_app = None
self.app_list = []
def populate_app_list(self):
"""Populate the list of apps with all installed apps.
Icons are provided by icon-name, however some apps may return a full
path to a custom icon rather than a themed-icon name, or even no name
at all. In these cases the generic 'gtk-missing-icon' icon is used.
"""
self.app_list = Gio.AppInfo.get_all()
for i in range(len(self.app_list)):
gio_icon = self.app_list[i].get_icon()
app_icon = 'gtk-missing-icon'
if gio_icon:
app_icon = gio_icon.to_string()
app_name = self.app_list[i].get_display_name()
self.list_store.append([app_name, app_icon, i])
self.list_store.set_sort_column_id(0, Gtk.SortType.ASCENDING)
def run(self):
"""Run the dialog to get a selected app."""
self.populate_app_list()
self.show_all()
super().run()
self.destroy()
return self.selected_app
def set_label(self, text):
"""Set the label text, \"Choose An App\" by default."""
self.label.set_text(text)
def on_ok(self, button):
"""Get Gio.AppInfo of selected app when user presses OK."""
selection = self.tree_view.get_selection()
tree_model, tree_iter = selection.get_selected()
app_index = tree_model.get_value(tree_iter, 2)
self.selected_app = self.app_list[app_index]
This is then run similar to a regular dialog:
app_chooser = AllAppChooser()
application = app_chooser.run()
If the user exits the dialog box or presses cancel then the result will be None, but if they selected an application then run() will return a Gio.AppInfo object for the application which you can then do with as you please. For example, to launch your newly selected application:
application.launch()
I feel this is now a relatively solid solution, but I still welcome additional suggestions. Additionally, if there is a way to do this in Gtk without having to do all this stuff I would still love to hear it.

Same page appears while using ionic native transition plugin?

I am using ionic native transition plugin in my app. I am using slide up transition for pages.It works,but when state changes it shows the same page for a short period of time and then the other page (the page where I want to switch) appears. Here is the github link.I tried with different values for the default options, but it doesn't solve my problem. any help will be appreciated
I'm not sure if your issue is the same that I had (when transition to next/previous state begins the "new state" which it's supposed to transition to is shown in the "old view" before/during animation) but here is what I did. I found a solution which is to add a timeout to the state change in the stateGo() function in the ionic.native-transitions(.min).js which leads to it being run as the last function. The following code works on both iOS and Android devices.
function stateGo() {
var state = arguments.length <= 0 || arguments[0] === undefined ? null : arguments[0];
var stateParams = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
var transitionOptions = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2];
var stateOptions = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3];
if (!state) {
$log.debug('[native transition] cannot change state without a state...');
return;
}
unregisterToStateChangeStartEvent();
transition(transitionOptions);
if (ionic.Platform.isIOS()) {
$timeout(function() {
$state.go(state, stateParams, stateOptions);
});
} else {
$state.go(state, stateParams, stateOptions);
}
}
I decided to add the check for an iOS device and run the timeout only in that case because it was only occurring in iOS devices and the timeout perhaps made Android devices flicker a little on the transition (I could be paranoid and this not really even occurring, or is due to large images on the content on my app).
Same fix probably also works in the case that you are using locationurl instead in which case you just set timeout to the "$location.url(url);" function.
Not sure if this would be the final solution for this problem but it works for now and hopefully the plugin will be fixed soon so this problem won't bother anyone else.
The same issue was on my side as well when using:
$scope.$on('$ionicView.enter', function(event, viewData) {
var transitionDirection = viewData.direction !== "back" ? "left": "right";
var options = {
"direction": transitionDirection,
"duration": 600,
"androiddelay": 75
};
window.plugins.nativepagetransitions.slide(
options,
function () {},
function () {}
);
});
However, when I changed the '$ionicView.enter' event to '$ionicView.beforeEnter', it solved the case for me. Not sure if that is a proper solution though.

Google's autocomplete not activated by pasting with mouse

The Google autocomplete API doesn't seem to be activating by pasting content into a text input with the mouse. It works fine if involving the keyboard at all, but not with just mouse.
I did notice, however, that after you paste your content into the text input it will activate from almost any keypress (tested right arrow key, end key, space).
You can repro it here on their autocomplete demo site.
Is this a bug? or as designed? If it's as designed, how to apply workaround?
I've got this as a workaround so far, but no simulated keypress events seem to work.
$('.txtLocation').bind("paste", function (e)
{
$('.txtLocation').focus();
var e = jQuery.Event("keydown");
e.keyCode = 39; //39=Arrow Right
$('.txtLocation').trigger(e);
});
It seems this impacts not only the context-menu Paste, but also that of Edit|Paste from the browser menu bar as well as the iOS paste functionality. I've opened a bug with Google. You may wish to "Star" that bug report to catch updates.
I found a workaround that, while a bit of a hack, seems to fix the problem. If you store the pasted value, switch focus on a different field, set the value in the Autocomplete field, and finally focus back on the Autocomplete field things work more or less as expected. Also, you have to do this in a setTimeout() callback - the delay time doesn't seem to matter at all, but if you just do this inline you won't see the expected results.
Here's a code sample of what I'm describing above:
$("#address_field").on("paste", googleMapsAutocompletePasteBugFix);
googleMapsAutocompletePasteBugFix = function() {
return setTimeout(function() {
var field, val;
field = $("#address_field");
val = field.val();
$("#price").focus();
field.val(val);
return field.focus();
}, 1);
};
The last focus() is optional, but the UI is a little less surprising than if you just skipped automatically to the next field.
Following solution seems to work for me (existence of field ending with "address_2" is assumed). Tested on IE8, IE9, IE10, Chrome, FF and Safari
if document.addEventListener
$(document).on("paste", "[name*=address_1]", #googleMapsAutocompletePasteBugFix)
$(document).on("onpaste", "[name*=address_1]", #googleMapsAutocompletePasteBugFix)
else
for element in $("input[name*=address_1]")
document.getElementById($(element).attr('id')).onpaste = #googleMapsAutocompletePasteBugFix
googleMapsAutocompletePasteBugFix: (e) ->
unless e
e = window.event
if e.srcElement
target = e.srcElement
else
target = e.target
field = $(target)
fieldId = field.attr('id')
focusSwitchFieldId = fieldId.replace(/(\d)$/, '2')
setTimeout(->
if window.chrome || /Safari/.test(navigator.userAgent)
val = field.val()
$("##{focusSwitchFieldId}").focus()
field.val(val)
field.focus()
else
field = document.getElementById(fieldId)
val = field.value
document.getElementById(focusSwitchFieldId).focus()
setTimeout(->
field.value = val
field.focus()
field.focus()
, 50)
, 10)

Extract image data from camera roll on Android?

Can anyone help me find out if/how you can get image data off of the 'camera roll' in an Android device, using (Appcelorator) Titanium ? I have found a 3rd party module for IOS that does this but I am desperate to find one for Android. Otherwise I'll have to scrap the Titanium and go true native.
What I need is a function that returns an array of data about the images on the device. Although I would love to get 'geolocation' data ( if it exists ), all I really need is a 'create date', and a path to the image, or the actual TiBlob.
Seems simple but i get no responses on the Appcelerator forums, which worries me. There must be at least an Android 'module' that achieves this?
Ti.Media.openPhotoGallery({
allowEditing : true,
success : function(event) {
var image = require('/modules/parts/squarecropper').crop(event.media);
setImage(image);
Ti.Media.hideCamera();
},
cancel : function() {
},
saveToPhotoGallery : false,
mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO],
});
The above method would do your job. Now then either access it directly or get into a file system and encode and decode the data.
var f = Titanium.Filesystem.getFile(currIamge);
var temp = f.read();
var encodeData = Ti.Utils.base64encode(temp);
alert("encodeData = "+encodeData);