update
This commit is contained in:
@@ -1,21 +1,23 @@
|
||||
package dev.zerozipp
|
||||
|
||||
import dev.zerozipp.assistant.*
|
||||
import dev.zerozipp.assistant.languages.*
|
||||
import javax.sound.sampled.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.vosk.*
|
||||
|
||||
fun main() = runBlocking {
|
||||
fun main() {
|
||||
LibVosk.setLogLevel(LogLevel.WARNINGS)
|
||||
val format = AudioFormat(16000f, 16, 1, true, false)
|
||||
val assistant = System.getenv("HA_URL") ?: error("Set HA_URL env var")
|
||||
val token = System.getenv("HA_TOKEN") ?: error("Set HA_TOKEN env var")
|
||||
val name = System.getenv("COMMAND_NAME") ?: "computer"
|
||||
val name = System.getenv("ASSISTANT_NAME") ?: "computer"
|
||||
val lang = System.getenv("ASSISTANT_LANG") ?: "english"
|
||||
val vosk = System.getenv("VOSK_MODEL") ?: "vosk"
|
||||
|
||||
Home(assistant, token).use { home ->
|
||||
val formatted: String = name.trim().lowercase()
|
||||
Assistant(vosk, formatted, home, format).use {
|
||||
val formatted = name.trim().lowercase()
|
||||
val dict = if(lang == "german") German() else English()
|
||||
Assistant(vosk, home, dict, formatted, format).use {
|
||||
assistant -> assistant.listen()
|
||||
}
|
||||
}
|
||||
|
||||
12
src/main/kotlin/dev/zerozipp/assistant/Action.kt
Normal file
12
src/main/kotlin/dev/zerozipp/assistant/Action.kt
Normal file
@@ -0,0 +1,12 @@
|
||||
package dev.zerozipp.assistant
|
||||
|
||||
abstract class Action {
|
||||
abstract val triggers: Set<String>
|
||||
abstract val options: Map<String, Runnable>
|
||||
|
||||
fun run(command: String) = triggers.forEach {
|
||||
if(!command.startsWith(it)) return@forEach
|
||||
val option = command.replaceFirst(it, "")
|
||||
options[option.trim()]?.run()
|
||||
}
|
||||
}
|
||||
@@ -2,21 +2,26 @@ package dev.zerozipp.assistant
|
||||
|
||||
import org.vosk.Model
|
||||
import org.vosk.Recognizer
|
||||
import dev.zerozipp.assistant.actions.*
|
||||
import javax.sound.sampled.*
|
||||
import com.google.gson.*
|
||||
|
||||
class Assistant(path: String,
|
||||
class Assistant(
|
||||
path: String, home: Home,
|
||||
private val dict: Dictionary,
|
||||
private val name: String,
|
||||
private val home: Home,
|
||||
format: AudioFormat
|
||||
) : AutoCloseable {
|
||||
private val model = Model(path)
|
||||
private val microphone = line(format)
|
||||
private val buffer = ByteArray(4096)
|
||||
private val action = "mach das licht"
|
||||
private val microphone = line(format)
|
||||
private val actions = listOf<Action>(
|
||||
Light(home)
|
||||
)
|
||||
|
||||
private val recognizer = Recognizer(
|
||||
model, format.sampleRate, Gson().toJson(
|
||||
listOf(name, action) + Light.modes.keys
|
||||
listOf(name) + dict.words
|
||||
)
|
||||
)
|
||||
|
||||
@@ -26,19 +31,19 @@ class Assistant(path: String,
|
||||
AudioSystem.getLine(info) as TargetDataLine
|
||||
}.also { it.open(format) }
|
||||
|
||||
private suspend fun process() {
|
||||
private fun process() {
|
||||
val bytes = microphone.read(buffer, 0, buffer.size)
|
||||
if(bytes <= 0 || !recognizer.acceptWaveForm(buffer, bytes)) return
|
||||
val json = Gson().fromJson(recognizer.result, JsonObject::class.java)
|
||||
val text = json.let { it["text"].asString.orEmpty().trim() }.split(action)
|
||||
val text = json.let { it["text"].asString.orEmpty().trim() }
|
||||
|
||||
text.takeIf { it.size == 2 }?.also { (name, key) ->
|
||||
Light.modes[key.trim()]?.takeIf { name.trim() == this.name }
|
||||
?.let { home.light("all", it.state, it.level, it.color) }
|
||||
}
|
||||
if(!text.startsWith(name)) return
|
||||
val command = text.replaceFirst("name", text)
|
||||
val translated = dict.translate(command.trim())
|
||||
actions.forEach { it.run(translated) }
|
||||
}
|
||||
|
||||
suspend fun listen() {
|
||||
fun listen() {
|
||||
microphone.start()
|
||||
while(true) process()
|
||||
}
|
||||
|
||||
8
src/main/kotlin/dev/zerozipp/assistant/Dictionary.kt
Normal file
8
src/main/kotlin/dev/zerozipp/assistant/Dictionary.kt
Normal file
@@ -0,0 +1,8 @@
|
||||
package dev.zerozipp.assistant
|
||||
|
||||
abstract class Dictionary {
|
||||
abstract val mappings: Map<String, String>
|
||||
val words: Set<String> get() = mappings.keys
|
||||
fun translate(text: String) = text.split(" ")
|
||||
.mapNotNull { mappings[it] }.joinToString(" ")
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.zerozipp.assistant
|
||||
|
||||
import com.google.gson.*
|
||||
import kotlinx.coroutines.*
|
||||
import io.ktor.client.engine.cio.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.*
|
||||
@@ -13,8 +14,8 @@ class Home(
|
||||
override fun close() = http.close()
|
||||
private val http = HttpClient(CIO)
|
||||
|
||||
suspend fun light(entity: String,
|
||||
state: Boolean, level: Int?, color: String?) {
|
||||
fun light(entity: String, state: Boolean,
|
||||
level: Int?, color: String?) = runBlocking {
|
||||
val service = if(state) "turn_on" else "turn_off"
|
||||
val url = "$host/api/services/light/$service"
|
||||
val type = ContentType.Application.Json
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package dev.zerozipp.assistant
|
||||
|
||||
object Light {
|
||||
val on = Mode(true, null, null)
|
||||
val off = Mode(false, null, null)
|
||||
fun color(name: String) = Mode(true, name, null)
|
||||
fun level(level: Int) = Mode(true, null, level)
|
||||
|
||||
data class Mode(
|
||||
val state: Boolean,
|
||||
val color: String?,
|
||||
val level: Int?
|
||||
)
|
||||
|
||||
val modes = mapOf(
|
||||
"rot" to color("red"),
|
||||
"grün" to color("green"),
|
||||
"blau" to color("blue"),
|
||||
"weiß" to color("white"),
|
||||
"gelb" to color("yellow"),
|
||||
"orange" to color("orange"),
|
||||
"lila" to color("purple"),
|
||||
"rosa" to color("pink"),
|
||||
"türkis" to color("cyan"),
|
||||
"magenta" to color("magenta"),
|
||||
"braun" to color("brown"),
|
||||
"grau" to color("gray"),
|
||||
"schwarz" to color("black"),
|
||||
"maximal" to level(255),
|
||||
"minimal" to level(0),
|
||||
"dunkel" to level(64),
|
||||
"mittel" to level(128),
|
||||
"hell" to level(191),
|
||||
"aus" to off,
|
||||
"an" to on
|
||||
)
|
||||
}
|
||||
22
src/main/kotlin/dev/zerozipp/assistant/actions/Light.kt
Normal file
22
src/main/kotlin/dev/zerozipp/assistant/actions/Light.kt
Normal file
@@ -0,0 +1,22 @@
|
||||
package dev.zerozipp.assistant.actions
|
||||
|
||||
import dev.zerozipp.assistant.Action
|
||||
import dev.zerozipp.assistant.Home
|
||||
|
||||
class Light(private val home: Home) : Action() {
|
||||
private val on = Runnable { home.light("all", true, null, null) }
|
||||
private val off = Runnable { home.light("all", false, null, null) }
|
||||
private fun color(name: String) = Runnable { home.light("all", true, null, name) }
|
||||
private fun level(level: Int) = Runnable { home.light("all", true, level, null) }
|
||||
override val triggers = setOf("turn the light", "light")
|
||||
|
||||
override val options = mapOf(
|
||||
"maximum" to level(255), "minimum" to level(0),
|
||||
"dark" to level(64), "mid" to level(128), "bright" to level(191),
|
||||
"red" to color("red"), "green" to color("green"), "blue" to color("blue"),
|
||||
"white" to color("white"), "yellow" to color("yellow"), "orange" to color("orange"),
|
||||
"purple" to color("purple"), "pink" to color("pink"), "magenta" to color("magenta"),
|
||||
"cyan" to color("cyan"), "brown" to color("brown"),
|
||||
"on" to on, "off" to off
|
||||
)
|
||||
}
|
||||
16
src/main/kotlin/dev/zerozipp/assistant/languages/English.kt
Normal file
16
src/main/kotlin/dev/zerozipp/assistant/languages/English.kt
Normal file
@@ -0,0 +1,16 @@
|
||||
package dev.zerozipp.assistant.languages
|
||||
|
||||
import dev.zerozipp.assistant.Dictionary
|
||||
|
||||
class English : Dictionary() {
|
||||
override val mappings = mapOf(
|
||||
"turn" to "turn", "the" to "the", "light" to "light",
|
||||
"maximum" to "maximum", "minimum" to "minimum",
|
||||
"dark" to "dark", "mid" to "mid", "bright" to "bright",
|
||||
"red" to "red", "green" to "green", "blue" to "blue",
|
||||
"white" to "white", "yellow" to "yellow", "orange" to "orange",
|
||||
"purple" to "purple", "pink" to "pink", "magenta" to "magenta",
|
||||
"cyan" to "cyan", "brown" to "brown",
|
||||
"on" to "on", "off" to "off"
|
||||
)
|
||||
}
|
||||
16
src/main/kotlin/dev/zerozipp/assistant/languages/German.kt
Normal file
16
src/main/kotlin/dev/zerozipp/assistant/languages/German.kt
Normal file
@@ -0,0 +1,16 @@
|
||||
package dev.zerozipp.assistant.languages
|
||||
|
||||
import dev.zerozipp.assistant.Dictionary
|
||||
|
||||
class German : Dictionary() {
|
||||
override val mappings = mapOf(
|
||||
"mach" to "turn", "the" to "das", "licht" to "light",
|
||||
"maximum" to "maximum", "minimum" to "minimum",
|
||||
"dunkel" to "dark", "mitte" to "mid", "hell" to "bright",
|
||||
"rot" to "red", "grün" to "green", "blau" to "blue",
|
||||
"weiß" to "white", "gelb" to "yellow", "orange" to "orange",
|
||||
"lila" to "purple", "rosa" to "pink", "magenta" to "magenta",
|
||||
"türkis" to "cyan", "braun" to "brown",
|
||||
"an" to "on", "aus" to "off"
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user