csdcorp / speech_to_text

A Flutter plugin that exposes device specific text to speech recognition capability.
BSD 3-Clause "New" or "Revised" License
372 stars 231 forks source link

Workaround when SpeechToTextPlatform.instance.locales() returns duplicates #542

Closed MrCsabaToth closed 1 month ago

MrCsabaToth commented 1 month ago

I'm fiddling with the example to debug #541. The example crashes when I press initialization because it tries to fill the selector for languages and I get:

======== Exception caught by widgets library =======================================================
The following assertion was thrown building SessionOptionsWidget:
There should be exactly one item with [DropdownButton]'s value: en_US. 
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
'package:flutter/src/material/dropdown.dart':
Failed assertion: line 942 pos 15: 'items == null || items.isEmpty || value == null ||
              items.where((DropdownMenuItem<T> item) {
                return item.value == value;
              }).length == 1'

The relevant error-causing widget was: 
  SessionOptionsWidget SessionOptionsWidget:file:///home/csaba/repos/flutter/speech_to_text/speech_to_text/example/lib/main.dart:91:15
When the exception was thrown, this was the stack: 
#2      new DropdownButton (package:flutter/src/material/dropdown.dart:942:15)
#3      SessionOptionsWidget.build (package:speech_to_text_example/main.dart:405:15)

The reason for this is because the

  Future<List<LocaleName>> locales() async {
    final locales = await SpeechToTextPlatform.instance.locales();

call in the plugin returns duplicates. In my case:

locales = {_List} size = 9
 0 = "en_US:English (United States)"
 1 = "en_AU:English (Australia)"
 2 = "en_SG:English (Singapore)"
 3 = "ja_JP:Japanese (Japan)"
 4 = "it_IT:Italian (Italy)"
 5 = "en_IE:English (Ireland)"
 6 = "fr_FR:French (France)"
 7 = "en_US:English (United States)"
 8 = "en_GB:English (United Kingdom)"

As we can see the "en_US:English (United States)" is duplicated. I'm not 100% sure if this meant to be handled in the plugin, but if not, then at least it should be handled in the example to deduplicate that array.

MrCsabaToth commented 1 month ago

The tersest fix is adding an extra .toSet() at https://github.com/csdcorp/speech_to_text/blob/1a40e483bfc30f4be9e9f542a8d0b823284b438a/speech_to_text/lib/speech_to_text.dart#L571 like so: var filteredLocales = locales.toSet()

One downside of this approach, that the toSet may disturb the original order of items, so maybe an extra ordering needed. If the deduplication is done at the application level (instead of the plugin), then objects need to be compared, more code is needed.

sowens-csd commented 1 month ago

Yes, duplicates should be removed by the plugin, I'll have a look at that.

sowens-csd commented 1 month ago

I can't reproduce this and can't see how it could happen given the de-duplication that happens in the Android implementation. However, it's pretty simple to add another layer into the plugin so I'll do that for the next release.

7.0.0-beta.2 is in pub.dev now with this change.

MrCsabaToth commented 1 month ago

I also was not able to reproduce it with most of my devices (phones and FAWs), only one did that.

sowens-csd commented 1 month ago

Now available in 7.0.0 on pub.dev