aboutsummaryrefslogtreecommitdiffstats
path: root/agl_service_voiceagent/servicers/voice_agent_servicer.py
diff options
context:
space:
mode:
Diffstat (limited to 'agl_service_voiceagent/servicers/voice_agent_servicer.py')
-rw-r--r--agl_service_voiceagent/servicers/voice_agent_servicer.py109
1 files changed, 103 insertions, 6 deletions
diff --git a/agl_service_voiceagent/servicers/voice_agent_servicer.py b/agl_service_voiceagent/servicers/voice_agent_servicer.py
index 4038b85..69af10b 100644
--- a/agl_service_voiceagent/servicers/voice_agent_servicer.py
+++ b/agl_service_voiceagent/servicers/voice_agent_servicer.py
@@ -17,42 +17,65 @@
import grpc
import time
import threading
-from generated import voice_agent_pb2
-from generated import voice_agent_pb2_grpc
+from agl_service_voiceagent.generated import voice_agent_pb2
+from agl_service_voiceagent.generated import voice_agent_pb2_grpc
from agl_service_voiceagent.utils.audio_recorder import AudioRecorder
from agl_service_voiceagent.utils.wake_word import WakeWordDetector
from agl_service_voiceagent.utils.stt_model import STTModel
+from agl_service_voiceagent.utils.kuksa_interface import KuksaInterface
+from agl_service_voiceagent.utils.mapper import Intent2VSSMapper
from agl_service_voiceagent.utils.config import get_config_value
+from agl_service_voiceagent.utils.common import generate_unique_uuid, delete_file
from agl_service_voiceagent.nlu.snips_interface import SnipsInterface
from agl_service_voiceagent.nlu.rasa_interface import RASAInterface
-from agl_service_voiceagent.utils.common import generate_unique_uuid, delete_file
class VoiceAgentServicer(voice_agent_pb2_grpc.VoiceAgentServiceServicer):
+ """
+ Voice Agent Servicer class that implements the gRPC service defined in voice_agent.proto.
+ """
+
def __init__(self):
+ """
+ Constructor for VoiceAgentServicer class.
+ """
# Get the config values
- self.service_version = get_config_value('SERVICE_VERSION')
+ self.service_version = "v0.3.0"
self.wake_word = get_config_value('WAKE_WORD')
self.base_audio_dir = get_config_value('BASE_AUDIO_DIR')
self.channels = int(get_config_value('CHANNELS'))
self.sample_rate = int(get_config_value('SAMPLE_RATE'))
self.bits_per_sample = int(get_config_value('BITS_PER_SAMPLE'))
self.stt_model_path = get_config_value('STT_MODEL_PATH')
+ self.wake_word_model_path = get_config_value('WAKE_WORD_MODEL_PATH')
self.snips_model_path = get_config_value('SNIPS_MODEL_PATH')
self.rasa_model_path = get_config_value('RASA_MODEL_PATH')
self.rasa_server_port = int(get_config_value('RASA_SERVER_PORT'))
+ self.rasa_detached_mode = bool(int(get_config_value('RASA_DETACHED_MODE')))
self.base_log_dir = get_config_value('BASE_LOG_DIR')
self.store_voice_command = bool(int(get_config_value('STORE_VOICE_COMMANDS')))
# Initialize class methods
self.stt_model = STTModel(self.stt_model_path, self.sample_rate)
+ self.stt_wake_word_model = STTModel(self.wake_word_model_path, self.sample_rate)
self.snips_interface = SnipsInterface(self.snips_model_path)
self.rasa_interface = RASAInterface(self.rasa_server_port, self.rasa_model_path, self.base_log_dir)
- self.rasa_interface.start_server()
+
+ # Only start RASA server if its not in detached mode, else we assume server is already running
+ if not self.rasa_detached_mode:
+ self.rasa_interface.start_server()
+
self.rvc_stream_uuids = {}
+ self.kuksa_client = KuksaInterface()
+ self.kuksa_client.connect_kuksa_client()
+ self.kuksa_client.authorize_kuksa_client()
+ self.mapper = Intent2VSSMapper()
def CheckServiceStatus(self, request, context):
+ """
+ Check the status of the Voice Agent service including the version.
+ """
response = voice_agent_pb2.ServiceStatus(
version=self.service_version,
status=True
@@ -61,13 +84,16 @@ class VoiceAgentServicer(voice_agent_pb2_grpc.VoiceAgentServiceServicer):
def DetectWakeWord(self, request, context):
+ """
+ Detect the wake word using the wake word detection model.
+ """
wake_word_detector = WakeWordDetector(self.wake_word, self.stt_model, self.channels, self.sample_rate, self.bits_per_sample)
wake_word_detector.create_pipeline()
detection_thread = threading.Thread(target=wake_word_detector.start_listening)
detection_thread.start()
while True:
status = wake_word_detector.get_wake_word_status()
- time.sleep(1)
+ time.sleep(0.5)
if not context.is_active():
wake_word_detector.send_eos()
break
@@ -79,6 +105,9 @@ class VoiceAgentServicer(voice_agent_pb2_grpc.VoiceAgentServiceServicer):
def RecognizeVoiceCommand(self, requests, context):
+ """
+ Recognize the voice command using the STT model and extract the intent using the NLU model.
+ """
stt = ""
intent = ""
intent_slots = []
@@ -154,3 +183,71 @@ class VoiceAgentServicer(voice_agent_pb2_grpc.VoiceAgentServiceServicer):
status=status
)
return response
+
+
+ def ExecuteVoiceCommand(self, request, context):
+ """
+ Execute the voice command by sending the intent to Kuksa.
+ """
+ intent = request.intent
+ intent_slots = request.intent_slots
+ processed_slots = []
+ for slot in intent_slots:
+ slot_name = slot.name
+ slot_value = slot.value
+ processed_slots.append({"name": slot_name, "value": slot_value})
+
+ print(intent)
+ print(processed_slots)
+ execution_list = self.mapper.parse_intent(intent, processed_slots)
+ exec_response = f"Sorry, I failed to execute command against intent '{intent}'. Maybe try again with more specific instructions."
+ exec_status = voice_agent_pb2.EXEC_ERROR
+
+ for execution_item in execution_list:
+ print(execution_item)
+ action = execution_item["action"]
+ signal = execution_item["signal"]
+
+ if self.kuksa_client.get_kuksa_status():
+ if action == "set" and "value" in execution_item:
+ value = execution_item["value"]
+ if self.kuksa_client.send_values(signal, value):
+ exec_response = f"Yay, I successfully updated the intent '{intent}' to value '{value}'."
+ exec_status = voice_agent_pb2.EXEC_SUCCESS
+
+ elif action in ["increase", "decrease"]:
+ if "value" in execution_item:
+ value = execution_item["value"]
+ if self.kuksa_client.send_values(signal, value):
+ exec_response = f"Yay, I successfully updated the intent '{intent}' to value '{value}'."
+ exec_status = voice_agent_pb2.EXEC_SUCCESS
+
+ elif "factor" in execution_item:
+ factor = execution_item["factor"]
+ current_value = self.kuksa_client.get_value(signal)
+ if current_value:
+ current_value = int(current_value)
+ if action == "increase":
+ value = current_value + factor
+ value = str(value)
+ elif action == "decrease":
+ value = current_value - factor
+ value = str(value)
+ if self.kuksa_client.send_values(signal, value):
+ exec_response = f"Yay, I successfully updated the intent '{intent}' to value '{value}'."
+ exec_status = voice_agent_pb2.EXEC_SUCCESS
+
+ else:
+ exec_response = f"Uh oh, there is no value set for intent '{intent}'. Why not try setting a value first?"
+ exec_status = voice_agent_pb2.EXEC_KUKSA_CONN_ERROR
+
+ else:
+ exec_response = "Uh oh, I failed to connect to Kuksa."
+ exec_status = voice_agent_pb2.EXEC_KUKSA_CONN_ERROR
+
+ response = voice_agent_pb2.ExecuteResult(
+ response=exec_response,
+ status=exec_status
+ )
+
+ return response