Skip to content

🎙️ Hands-Free Voice Commands & AI NLU ​

The :speed-ui module provides a drop-in Voice Command System enabling commercial drivers, couriers, and motorists to adjust speed thresholds hands-free without looking away from the road.


🎯 Architectural Overview ​

The Voice Command pipeline is divided into two distinct responsibilities:

  1. Speech-to-Text Layer (VoiceCommandButton): Listens to microphone audio via Android's native SpeechRecognizer Activity Contract and transcribes voice into text.
  2. Intent Parsing Layer (VoiceCommandParser): Translates raw text strings into structured VoiceAction domain events (offline Regex or remote LLM).

📦 Basic Usage (VoiceCommandButton) ​

Drop the VoiceCommandButton into your Compose dashboard:

kotlin
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.vegsahayyak.speedui.components.VoiceCommandButton
import com.vegsahayyak.speedui.api.VoiceAction
import com.vegsahayyak.speedcore.api.SpeedAssistant

@Composable
fun DriverDashboard() {
    VoiceCommandButton(
        onActionParsed = { action ->
            when (action) {
                is VoiceAction.SetMaxLimit -> {
                    // Spoken: "Set limit to 80"
                    SpeedAssistant.with(context, "YOUR_JWT_LICENSE").setWarningSpeedThreshold(action.limit)
                }
                is VoiceAction.SetMinLimit -> {
                    // Spoken: "Set minimum speed to 40"
                    SpeedAssistant.with(context, "YOUR_JWT_LICENSE").setMinWarningSpeedThreshold(action.limit)
                }
                is VoiceAction.ChangeUnit -> {
                    // Spoken: "Change unit to miles per hour"
                    println("Switching unit to ${action.unitName}")
                }
                is VoiceAction.Unknown -> {
                    println("Voice command not recognized")
                }
            }
        }
    )
}

🌐 Multilingual Regex Parsing (RegexVoiceCommandParser) ​

By default, the SDK uses RegexVoiceCommandParser which operates 100% offline with zero network latency. You can configure custom regex patterns to support non-English international markets:

kotlin
import com.vegsahayyak.speedui.utils.RegexVoiceCommandParser

val multilingualParser = RegexVoiceCommandParser()

// In your Compose hierarchy:
VoiceCommandButton(
    parser = multilingualParser,
    onActionParsed = { action -> /* handle action */ }
)

Supported Default Commands (English) ​

  • "Set max speed to 80" → VoiceAction.SetMaxLimit(80f)
  • "Speed limit 100" → VoiceAction.SetMaxLimit(100f)
  • "Set minimum speed to 40" → VoiceAction.SetMinLimit(40f)
  • "Switch to miles per hour" → VoiceAction.ChangeUnit("MILES_PER_HOUR")
  • "Change unit to kilometers" → VoiceAction.ChangeUnit("KILOMETERS_PER_HOUR")

🤖 Advanced AI / Google Gemini NLU Integration ​

For enterprise fleets requiring natural language understanding (e.g. interpreting "Hey assistant, please cap my speed at seventy-five miles an hour" or handling regional dialects), implement the VoiceCommandParser interface and connect to Google Gemini:

kotlin
import com.vegsahayyak.speedui.api.VoiceCommandParser
import com.vegsahayyak.speedui.api.VoiceAction
import com.google.ai.client.generativeai.GenerativeModel

class GeminiVoiceCommandParser(
    private val generativeModel: GenerativeModel
) : VoiceCommandParser {

    override suspend fun parse(text: String): VoiceAction? {
        val prompt = """
            You are an in-vehicle telematics assistant. The driver said: "$text".
            Extract their intent into JSON:
            - If setting max limit: {"action": "SET_MAX", "limit": 80}
            - If setting min limit: {"action": "SET_MIN", "limit": 40}
            - If changing unit: {"action": "CHANGE_UNIT", "unit": "km/h"}
            Return only raw JSON.
        """.trimIndent()

        val response = generativeModel.generateContent(prompt)
        val rawJson = response.text ?: return VoiceAction.Unknown

        return parseJsonResponse(rawJson)
    }

    private fun parseJsonResponse(json: String): VoiceAction {
        // Parse JSON into VoiceAction instances
        return VoiceAction.SetMaxLimit(80f)
    }
}

Inject your custom AI parser into VoiceCommandButton:

kotlin
VoiceCommandButton(
    parser = GeminiVoiceCommandParser(myGeminiModel),
    onActionParsed = { action -> /* handle action */ }
)

🛡️ Required Android Permissions ​

The VoiceCommandButton automatically handles launching the Android speech intent. Ensure RECORD_AUDIO is declared in your app's AndroidManifest.xml:

xml
<uses-permission android:name="android.permission.RECORD_AUDIO" />

Released under Commercial Enterprise License. Follow us on LinkedIn | Contact Us.