make voice assistant toggleable and fix bugs

This commit is contained in:
Nitwel 2024-03-15 19:27:45 +01:00
parent aff66884ca
commit 47c7104d15
9 changed files with 89 additions and 18 deletions

View File

@ -2,6 +2,7 @@ extends Node3D
var sky = preload ("res://assets/materials/sky.material") var sky = preload ("res://assets/materials/sky.material")
var sky_passthrough = preload ("res://assets/materials/sky_passthrough.material") var sky_passthrough = preload ("res://assets/materials/sky_passthrough.material")
const VoiceAssistant = preload ("res://content/system/assist/assist.tscn")
@onready var environment: WorldEnvironment = $WorldEnvironment @onready var environment: WorldEnvironment = $WorldEnvironment
@onready var camera: XRCamera3D = $XROrigin3D/XRCamera3D @onready var camera: XRCamera3D = $XROrigin3D/XRCamera3D
@ -10,6 +11,7 @@ var sky_passthrough = preload ("res://assets/materials/sky_passthrough.material"
@onready var house = $House @onready var house = $House
@onready var menu = $Menu @onready var menu = $Menu
@onready var keyboard = $Keyboard @onready var keyboard = $Keyboard
var voice_assistant = null
func _ready(): func _ready():
# In case we're running on the headset, use the passthrough sky # In case we're running on the headset, use the passthrough sky
@ -20,6 +22,8 @@ func _ready():
else: else:
RenderingServer.set_debug_generate_wireframes(true) RenderingServer.set_debug_generate_wireframes(true)
update_voice_assistant()
controller_left.button_pressed.connect(func(name): controller_left.button_pressed.connect(func(name):
_emit_action(name, true, false) _emit_action(name, true, false)
) )
@ -61,6 +65,17 @@ func _ready():
remove_child(keyboard) remove_child(keyboard)
) )
func update_voice_assistant():
if Store.settings.is_loaded() == false:
await Store.settings.on_loaded
if Store.settings.voice_assistant&&voice_assistant == null:
voice_assistant = VoiceAssistant.instantiate()
add_child(voice_assistant)
elif !Store.settings.voice_assistant&&voice_assistant != null:
remove_child(voice_assistant)
voice_assistant.queue_free()
func toggle_menu(): func toggle_menu():
if menu.show_menu == false: if menu.show_menu == false:
add_child(menu) add_child(menu)

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=17 format=3 uid="uid://eecv28y6jxk4"] [gd_scene load_steps=16 format=3 uid="uid://eecv28y6jxk4"]
[ext_resource type="PackedScene" uid="uid://clc5dre31iskm" path="res://addons/godot-xr-tools/xr/start_xr.tscn" id="1_i4c04"] [ext_resource type="PackedScene" uid="uid://clc5dre31iskm" path="res://addons/godot-xr-tools/xr/start_xr.tscn" id="1_i4c04"]
[ext_resource type="Script" path="res://content/main.gd" id="1_uvrd4"] [ext_resource type="Script" path="res://content/main.gd" id="1_uvrd4"]
@ -11,7 +11,6 @@
[ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://content/ui/menu/menu.tscn" id="8_du83w"] [ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://content/ui/menu/menu.tscn" id="8_du83w"]
[ext_resource type="PackedScene" uid="uid://lrehk38exd5n" path="res://content/system/keyboard/keyboard.tscn" id="9_e5n3p"] [ext_resource type="PackedScene" uid="uid://lrehk38exd5n" path="res://content/system/keyboard/keyboard.tscn" id="9_e5n3p"]
[ext_resource type="PackedScene" uid="uid://cbemihbxkd4ll" path="res://content/system/house/house.tscn" id="9_np6mw"] [ext_resource type="PackedScene" uid="uid://cbemihbxkd4ll" path="res://content/system/house/house.tscn" id="9_np6mw"]
[ext_resource type="PackedScene" uid="uid://oydbwnek6xb4" path="res://content/system/assist/assist.tscn" id="12_8av8q"]
[sub_resource type="Sky" id="Sky_vhymk"] [sub_resource type="Sky" id="Sky_vhymk"]
sky_material = ExtResource("5_wgwf8") sky_material = ExtResource("5_wgwf8")
@ -84,7 +83,4 @@ transform = Transform3D(0.499999, -0.000139169, -6.50204e-05, 5.24307e-05, 0.353
[node name="House" parent="." instance=ExtResource("9_np6mw")] [node name="House" parent="." instance=ExtResource("9_np6mw")]
[node name="Assist" parent="." instance=ExtResource("12_8av8q")]
transform = Transform3D(1, -1.39636e-11, 0, 9.47986e-12, 1, 0, 0, 0, 1, 0.000231838, -4.01369e-06, -0.855612)
[editable path="XROrigin3D/XRControllerLeft"] [editable path="XROrigin3D/XRControllerLeft"]

View File

@ -8,7 +8,7 @@ const target_freq = 16000
const sample_rate_ratio: float = audio_freq / target_freq * 1.5 const sample_rate_ratio: float = audio_freq / target_freq * 1.5
var effect: AudioEffectCapture var effect: AudioEffectCapture
@export var input_threshold: float = 0.1 @export var input_threshold: float = 0.05
@onready var audio_recorder: AudioStreamPlayer = $AudioStreamRecord @onready var audio_recorder: AudioStreamPlayer = $AudioStreamRecord
@onready var audio_timer: Timer = $AudioTimer @onready var audio_timer: Timer = $AudioTimer
@onready var visual_timer: Timer = $VisualTimer @onready var visual_timer: Timer = $VisualTimer
@ -18,7 +18,7 @@ var effect: AudioEffectCapture
@onready var loader: Node3D = $Loader @onready var loader: Node3D = $Loader
@onready var camera = $"/root/Main/XROrigin3D/XRCamera3D" @onready var camera = $"/root/Main/XROrigin3D/XRCamera3D"
var running := true var running := false
func _ready(): func _ready():
var index = AudioServer.get_bus_index("Record") var index = AudioServer.get_bus_index("Record")
@ -51,13 +51,17 @@ func _ready():
) )
HomeApi.api.assist_handler.on_tts_sound.connect(func(audio): HomeApi.api.assist_handler.on_tts_sound.connect(func(audio):
print("Playing TTS ", audio.data.size())
audio_player_3d.stream=audio audio_player_3d.stream=audio
audio_player_3d.play() audio_player_3d.play()
visual_timer.start() visual_timer.start()
running=false running=false
) )
HomeApi.api.assist_handler.on_error.connect(func():
running=false
finish()
)
visual_timer.timeout.connect(func(): visual_timer.timeout.connect(func():
if audio_player_3d.playing == false: if audio_player_3d.playing == false:
finish() finish()

View File

@ -21,7 +21,7 @@ one_shot = true
[node name="AudioStreamPlayer3D" type="AudioStreamPlayer3D" parent="."] [node name="AudioStreamPlayer3D" type="AudioStreamPlayer3D" parent="."]
[node name="VisualTimer" type="Timer" parent="."] [node name="VisualTimer" type="Timer" parent="."]
wait_time = 4.0 wait_time = 5.0
one_shot = true one_shot = true
[node name="ChatUser" parent="." instance=ExtResource("2_laew1")] [node name="ChatUser" parent="." instance=ExtResource("2_laew1")]

View File

@ -3,6 +3,7 @@ extends Node3D
const credits_scene = preload ("./credits.tscn") const credits_scene = preload ("./credits.tscn")
@onready var connection_status = $Content/ConnectionStatus @onready var connection_status = $Content/ConnectionStatus
@onready var main = $"/root/Main"
@onready var input_url = $Content/InputURL @onready var input_url = $Content/InputURL
@onready var input_token = $Content/InputToken @onready var input_token = $Content/InputToken
@ -11,6 +12,7 @@ const credits_scene = preload ("./credits.tscn")
@onready var save = $Content/Save @onready var save = $Content/Save
@onready var clear_save = $Content/ClearSave @onready var clear_save = $Content/ClearSave
@onready var background = $Background @onready var background = $Background
@onready var voice_assist = $Content/VoiceAssist
func _ready(): func _ready():
background.visible = false background.visible = false
@ -53,6 +55,31 @@ func _ready():
House.body.update_house() House.body.update_house()
) )
voice_assist.on_button_down.connect(func():
if Store.settings.is_loaded() == false:
await Store.settings.on_loaded
OS.request_permissions()
voice_assist.label="mic"
Store.settings.voice_assistant=true
main.update_voice_assistant()
Store.settings.save_local()
)
voice_assist.on_button_up.connect(func():
if Store.settings.is_loaded() == false:
await Store.settings.on_loaded
voice_assist.label="mic_off"
Store.settings.voice_assistant=false
main.update_voice_assistant()
Store.settings.save_local()
)
HomeApi.on_connect.connect(func(): HomeApi.on_connect.connect(func():
connection_status.text="Connected" connection_status.text="Connected"
) )
@ -60,3 +87,9 @@ func _ready():
HomeApi.on_disconnect.connect(func(): HomeApi.on_disconnect.connect(func():
connection_status.text="Disconnected" connection_status.text="Disconnected"
) )
if Store.settings.is_loaded() == false:
await Store.settings.on_loaded
voice_assist.label = "mic_off" if Store.settings.voice_assistant == false else "mic"
voice_assist.active = Store.settings.voice_assistant

View File

@ -131,3 +131,18 @@ outline_size = 0
horizontal_alignment = 0 horizontal_alignment = 0
autowrap_mode = 3 autowrap_mode = 3
width = 150.0 width = 150.0
[node name="VoiceAssist" parent="Content" instance=ExtResource("1_faxng")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.1, 0, 0.12)
label = "mic_off"
icon = true
toggleable = true
[node name="LabelVoiceAssist" type="Label3D" parent="Content"]
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0.01, 0, 0.12)
pixel_size = 0.001
text = "Voice-
Assist:"
font_size = 18
outline_size = 0
horizontal_alignment = 0

View File

@ -4,6 +4,7 @@ signal on_wake_word(wake_word: String)
signal on_stt_message(message: String) signal on_stt_message(message: String)
signal on_tts_message(message: String) signal on_tts_message(message: String)
signal on_tts_sound(sound: AudioStreamMP3) signal on_tts_sound(sound: AudioStreamMP3)
signal on_error()
var api: HASS_API var api: HASS_API
var pipe_running := false var pipe_running := false
@ -127,7 +128,9 @@ func handle_message(message: Dictionary):
sound.data = response[3] sound.data = response[3]
tts_sound = sound tts_sound = sound
"error":
if event["data"]["code"] == "stt-no-text-recognized":
on_error.emit()
"run-end": "run-end":
pipe_running = false pipe_running = false
wake_word = null wake_word = null

View File

@ -1,11 +1,11 @@
extends StoreClass extends StoreClass
const StoreClass = preload("./store.gd") const StoreClass = preload ("./store.gd")
var type: String = "HASS_WS" var type: String = "HASS_WS"
var url: String = "" var url: String = ""
var token: String = "" var token: String = ""
var voice_assistant: bool = false
func _init(): func _init():
_save_path = "user://settings.json" _save_path = "user://settings.json"
@ -14,3 +14,4 @@ func clear():
type = "HASS_WS" type = "HASS_WS"
url = "" url = ""
token = "" token = ""
voice_assistant = false

View File

@ -1,6 +1,6 @@
extends RefCounted extends RefCounted
const VariantSerializer = preload("res://lib/utils/variant_serializer.gd") const VariantSerializer = preload ("res://lib/utils/variant_serializer.gd")
signal on_loaded signal on_loaded
signal on_saved signal on_saved
@ -18,7 +18,7 @@ func create_dict():
var data: Dictionary = {} var data: Dictionary = {}
for prop_info in get_property_list(): for prop_info in get_property_list():
if prop_info.name.begins_with("_") || prop_info.hint_string != "": if prop_info.name.begins_with("_")||prop_info.hint_string != "":
continue continue
var prop = get(prop_info.name) var prop = get(prop_info.name)
@ -32,10 +32,14 @@ func create_dict():
func use_dict(dict: Dictionary): func use_dict(dict: Dictionary):
for prop_info in get_property_list(): for prop_info in get_property_list():
if prop_info.name.begins_with("_") || prop_info.hint_string != "": if prop_info.name.begins_with("_")||prop_info.hint_string != "":
continue continue
var prop = get(prop_info.name) var prop = get(prop_info.name)
if dict.has(prop_info.name) == false:
continue
var prop_value = dict[prop_info.name] var prop_value = dict[prop_info.name]
if prop is Store: if prop is Store:
@ -43,7 +47,7 @@ func use_dict(dict: Dictionary):
else: else:
set(prop_info.name, prop_value) set(prop_info.name, prop_value)
func save_local(path = _save_path): func save_local(path=_save_path):
if path == null: if path == null:
return false return false
@ -61,7 +65,7 @@ func save_local(path = _save_path):
return true return true
func load_local(path = _save_path): func load_local(path=_save_path):
if path == null: if path == null:
return false return false