Skip to main content

Overview

The speech normalization module provides utility functions to convert Spanish speech-to-text output into properly formatted email addresses and passwords. These functions handle common speech patterns and convert spoken words into their symbolic equivalents.

Functions

normalizeEmailFromSpeech

Normalizes spoken Spanish text into a valid email address format.
fun normalizeEmailFromSpeech(input: String): String
input
String
required
The raw speech-to-text output in Spanish
String
String
The normalized email address with symbols and proper formatting

Normalization Process

The function performs the following transformations:

1. Special Character Mapping

arroba
String
Converted to: @
punto
String
Converted to: .
guion bajo / guionbajo
String
Converted to: _
guion
String
Converted to: -
i latina
String
Converted to: i
ye / y griega
String
Converted to: y

2. Number Mapping

Spoken Spanish numbers are converted to digits:
  • cero → 0
  • uno → 1
  • dos → 2
  • tres → 3
  • cuatro → 4
  • cinco → 5
  • seis → 6
  • siete → 7
  • ocho → 8
  • nueve → 9

3. Spelling Mode Detection

The function automatically detects if the user is spelling out the email character by character:
  • Calculates the ratio of single-character tokens
  • If ≥60% of tokens are single characters, activates spelling mode
  • In spelling mode, “y” is converted to “i” (common Spanish speech pattern)

4. Final Cleanup

  • Removes all spaces
  • Filters out any characters not in: a-z, 0-9, @, ., _, -
  • Trims whitespace
Example:
// Spoken: "juan arroba ejemplo punto com"
val email = normalizeEmailFromSpeech("juan arroba ejemplo punto com")
println(email) // "[email protected]"

// Spoken with spelling: "jota u a ene arroba e jota e eme pe ele o punto ce o eme"
val spelledEmail = normalizeEmailFromSpeech(
    "jota u a ene arroba e jota e eme pe ele o punto ce o eme"
)
println(spelledEmail) // "[email protected]"

// With numbers: "usuario dos cero dos tres arroba correo punto com"
val emailWithNumbers = normalizeEmailFromSpeech(
    "usuario dos cero dos tres arroba correo punto com"
)
println(emailWithNumbers) // "[email protected]"

// With underscores: "mi guion bajo correo arroba ejemplo punto com"
val emailWithUnderscore = normalizeEmailFromSpeech(
    "mi guion bajo correo arroba ejemplo punto com"
)
println(emailWithUnderscore) // "[email protected]"

normalizePasswordFromSpeech

Normalizes spoken Spanish text into a password format.
fun normalizePasswordFromSpeech(input: String): String
input
String
required
The raw speech-to-text output in Spanish
String
String
The normalized password with symbols and proper formatting

Normalization Process

The function performs similar transformations to email normalization:

1. Special Character Mapping

Same as email normalization:
  • arroba → @
  • punto → .
  • guion bajo / guionbajo → _
  • guion → -
  • i latina → i
  • ye / y griega → y

2. Number Mapping

Same number conversions as email normalization (cero→0, uno→1, etc.)

3. Character Processing

Unlike email normalization, password normalization does NOT use spelling mode detection. It always converts “y” to “i” regardless of token length patterns.

4. Final Cleanup

  • Removes all spaces
  • Filters out any characters not in: a-z, 0-9, @, ., _, -
  • Trims whitespace
Example:
// Simple password
val password1 = normalizePasswordFromSpeech("mi clave secreta")
println(password1) // "miclavesecreta"

// With numbers
val password2 = normalizePasswordFromSpeech("clave uno dos tres")
println(password2) // "clave123"

// With special characters
val password3 = normalizePasswordFromSpeech("mi guion bajo clave punto dos cero dos cuatro")
println(password3) // "mi_clave.2024"

// With "y" conversion
val password4 = normalizePasswordFromSpeech("clave y prueba")
println(password4) // "clavelprueba" (y → i)

Usage in ViewModels

class LoginViewModel : ViewModel() {
    private val _email = MutableStateFlow("")
    val email: StateFlow<String> = _email.asStateFlow()
    
    private val _password = MutableStateFlow("")
    val password: StateFlow<String> = _password.asStateFlow()
    
    fun onSpeechResultForEmail(spokenText: String) {
        _email.value = normalizeEmailFromSpeech(spokenText)
    }
    
    fun onSpeechResultForPassword(spokenText: String) {
        _password.value = normalizePasswordFromSpeech(spokenText)
    }
}

Usage with Speech Recognizer

import android.speech.RecognizerIntent
import android.speech.SpeechRecognizer

class SpeechHandler(context: Context) {
    private val speechRecognizer = SpeechRecognizer.createSpeechRecognizer(context)
    
    fun startEmailRecognition(onResult: (String) -> Unit) {
        val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
            putExtra(RecognizerIntent.EXTRA_LANGUAGE, "es-ES")
            putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, 
                RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
        }
        
        speechRecognizer.setRecognitionListener(object : RecognitionListener {
            override fun onResults(results: Bundle?) {
                val matches = results?.getStringArrayList(
                    SpeechRecognizer.RESULTS_RECOGNITION
                )
                matches?.firstOrNull()?.let { spokenText ->
                    val normalizedEmail = normalizeEmailFromSpeech(spokenText)
                    onResult(normalizedEmail)
                }
            }
            // ... other callbacks
        })
        
        speechRecognizer.startListening(intent)
    }
}

Supported Characters

Both functions allow only these characters in the output:
  • Lowercase letters: a-z
  • Digits: 0-9
  • Special characters: @, ., _, -
All input is converted to lowercase, and any uppercase letters or unsupported symbols are removed.

Key Differences

FeaturenormalizeEmailFromSpeechnormalizePasswordFromSpeech
Spelling mode detectionYes (≥60% single chars)No
”y” to “i” conversionOnly in spelling modeAlways
Character filteringYesYes
Number conversionYesYes
Special char mappingYesYes

Testing Examples

// Test email normalization
assertEquals(
    "[email protected]",
    normalizeEmailFromSpeech("test arroba example punto com")
)

assertEquals(
    "[email protected]",
    normalizeEmailFromSpeech("user guion bajo uno dos tres arroba mail punto com")
)

// Test password normalization
assertEquals(
    "password123",
    normalizePasswordFromSpeech("password uno dos tres")
)

assertEquals(
    "mi_clave.2024",
    normalizePasswordFromSpeech("mi guion bajo clave punto dos cero dos cuatro")
)

Source Location

com.demodogo.ev_sum_2.domain.validators.SpeechNormalization

Build docs developers (and LLMs) love