OTMovilGasfiter/lib/services/dictation_text_accumulator.dart
2026-08-02 15:50:25 -04:00

89 lines
2.8 KiB
Dart

class DictationTextAccumulator {
String _baseText = '';
String _recognizedText = '';
String get text =>
[_baseText, _recognizedText].where((part) => part.isNotEmpty).join(' ');
void begin(String existingText) {
_baseText = existingText.trimRight();
_recognizedText = '';
}
String addResult(String words) {
final nextText = words.trim().replaceAll(RegExp(r'\s+'), ' ');
if (nextText.isEmpty) return text;
_recognizedText = _mergeWithoutDeleting(_recognizedText, nextText);
return text;
}
String _mergeWithoutDeleting(String previousText, String nextText) {
if (previousText.isEmpty) return nextText;
final previousWords = _words(previousText);
final nextWords = _words(nextText);
if (_startsWith(nextWords, previousWords)) return nextText;
if (_startsWith(previousWords, nextWords)) return previousText;
final commonPrefixLength = _commonPrefixLength(previousWords, nextWords);
if (commonPrefixLength > 0) {
if (nextWords.length > previousWords.length) return nextText;
if (nextWords.length < previousWords.length) return previousText;
return nextText.length >= previousText.length ? nextText : previousText;
}
final overlapLength = _suffixPrefixOverlap(previousWords, nextWords);
if (overlapLength > 0) {
final originalNextWords = nextText.split(' ');
final remainingWords = originalNextWords.skip(overlapLength).join(' ');
return remainingWords.isEmpty
? previousText
: '$previousText $remainingWords';
}
return '$previousText $nextText';
}
List<String> _words(String value) {
return value
.toLowerCase()
.replaceAll(RegExp(r'[.,;:!?¿¡]'), '')
.split(RegExp(r'\s+'))
.where((word) => word.isNotEmpty)
.toList();
}
bool _startsWith(List<String> words, List<String> prefix) {
if (prefix.length > words.length) return false;
for (var index = 0; index < prefix.length; index++) {
if (words[index] != prefix[index]) return false;
}
return true;
}
int _commonPrefixLength(List<String> first, List<String> second) {
final limit = first.length < second.length ? first.length : second.length;
var commonWords = 0;
while (commonWords < limit && first[commonWords] == second[commonWords]) {
commonWords++;
}
return commonWords;
}
int _suffixPrefixOverlap(List<String> previous, List<String> next) {
final limit = previous.length < next.length ? previous.length : next.length;
for (var overlap = limit; overlap > 0; overlap--) {
var matches = true;
for (var index = 0; index < overlap; index++) {
if (previous[previous.length - overlap + index] != next[index]) {
matches = false;
break;
}
}
if (matches) return overlap;
}
return 0;
}
}