aboutsummaryrefslogtreecommitdiffstats
path: root/agl_service_voiceagent
diff options
context:
space:
mode:
Diffstat (limited to 'agl_service_voiceagent')
-rw-r--r--agl_service_voiceagent/client.py31
-rw-r--r--agl_service_voiceagent/config.ini12
-rw-r--r--agl_service_voiceagent/nlu/rasa_interface.py2
-rw-r--r--agl_service_voiceagent/server.py6
-rw-r--r--agl_service_voiceagent/service.py70
-rw-r--r--agl_service_voiceagent/servicers/voice_agent_servicer.py50
-rw-r--r--agl_service_voiceagent/utils/config.py30
-rw-r--r--agl_service_voiceagent/utils/kuksa_interface.py35
-rw-r--r--agl_service_voiceagent/utils/mapper.py10
9 files changed, 184 insertions, 62 deletions
diff --git a/agl_service_voiceagent/client.py b/agl_service_voiceagent/client.py
index 922e08c..12804e1 100644
--- a/agl_service_voiceagent/client.py
+++ b/agl_service_voiceagent/client.py
@@ -18,11 +18,10 @@ import time
import 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.config import get_config_value
-def run_client(mode, nlu_model):
- SERVER_URL = get_config_value('SERVER_ADDRESS') + ":" + str(get_config_value('SERVER_PORT'))
- nlu_model = voice_agent_pb2.SNIPS if nlu_model == "snips" else voice_agent_pb2.RASA
+def run_client(server_address, server_port, mode, nlu_engine, recording_time):
+ SERVER_URL = server_address + ":" + server_port
+ nlu_engine = voice_agent_pb2.RASA if nlu_engine == "rasa" else voice_agent_pb2.SNIPS
print("Starting Voice Agent Client...")
print(f"Client connecting to URL: {SERVER_URL}")
with grpc.insecure_channel(SERVER_URL) as channel:
@@ -30,7 +29,7 @@ def run_client(mode, nlu_model):
print("Voice Agent Client started!")
if mode == 'wake-word':
stub = voice_agent_pb2_grpc.VoiceAgentServiceStub(channel)
- print("Listening for wake word...")
+ print("[+] Listening for wake word...")
wake_request = voice_agent_pb2.Empty()
wake_results = stub.DetectWakeWord(wake_request)
wake_word_detected = False
@@ -42,18 +41,20 @@ def run_client(mode, nlu_model):
break
elif mode == 'auto':
- raise ValueError("Auto mode is not implemented yet.")
+ raise ValueError("[-] Auto mode is not implemented yet.")
elif mode == 'manual':
stub = voice_agent_pb2_grpc.VoiceAgentServiceStub(channel)
- print("Recording voice command...")
- record_start_request = voice_agent_pb2.RecognizeControl(action=voice_agent_pb2.START, nlu_model=nlu_model, record_mode=voice_agent_pb2.MANUAL)
+ print("[+] Recording voice command in manual mode...")
+ record_start_request = voice_agent_pb2.RecognizeControl(action=voice_agent_pb2.START, nlu_model=nlu_engine, record_mode=voice_agent_pb2.MANUAL)
response = stub.RecognizeVoiceCommand(iter([record_start_request]))
stream_id = response.stream_id
- time.sleep(5) # any arbitrary pause here
- record_stop_request = voice_agent_pb2.RecognizeControl(action=voice_agent_pb2.STOP, nlu_model=nlu_model, record_mode=voice_agent_pb2.MANUAL, stream_id=stream_id)
+
+ time.sleep(recording_time) # pause here for the number of seconds passed by user or default 5 seconds
+
+ record_stop_request = voice_agent_pb2.RecognizeControl(action=voice_agent_pb2.STOP, nlu_model=nlu_engine, record_mode=voice_agent_pb2.MANUAL, stream_id=stream_id)
record_result = stub.RecognizeVoiceCommand(iter([record_stop_request]))
- print("Voice command recorded!")
+ print("[+] Voice command recording ended!")
status = "Uh oh! Status is unknown."
if record_result.status == voice_agent_pb2.REC_SUCCESS:
@@ -64,8 +65,8 @@ def run_client(mode, nlu_model):
status = "Intent not recognized."
# Process the response
- print("Command:", record_result.command)
print("Status:", status)
+ print("Command:", record_result.command)
print("Intent:", record_result.intent)
intent_slots = []
for slot in record_result.intent_slots:
@@ -74,5 +75,7 @@ def run_client(mode, nlu_model):
i_slot = voice_agent_pb2.IntentSlot(name=slot.name, value=slot.value)
intent_slots.append(i_slot)
- exec_voice_command_request = voice_agent_pb2.ExecuteInput(intent=record_result.intent, intent_slots=intent_slots)
- response = stub.ExecuteVoiceCommand(exec_voice_command_request) \ No newline at end of file
+ if record_result.status == voice_agent_pb2.REC_SUCCESS:
+ print("[+] Executing voice command...")
+ exec_voice_command_request = voice_agent_pb2.ExecuteInput(intent=record_result.intent, intent_slots=intent_slots)
+ response = stub.ExecuteVoiceCommand(exec_voice_command_request) \ No newline at end of file
diff --git a/agl_service_voiceagent/config.ini b/agl_service_voiceagent/config.ini
index 074f6a8..81d4e69 100644
--- a/agl_service_voiceagent/config.ini
+++ b/agl_service_voiceagent/config.ini
@@ -1,17 +1,17 @@
[General]
base_audio_dir = /usr/share/nlu/commands/
-stt_model_path = /usr/share/vosk/vosk-model-small-en-us-0.15/
-wake_word_model_path = /usr/share/vosk/vosk-model-small-en-us-0.15/
+stt_model_path = /usr/share/vosk/VOSK_STT_MODEL_NAME/
+wake_word_model_path = /usr/share/vosk/VOSK_WWD_MODEL_NAME/
snips_model_path = /usr/share/nlu/snips/model/
channels = 1
sample_rate = 16000
bits_per_sample = 16
-wake_word = hello auto
+wake_word = WAKE_WORD_VALUE
server_port = 51053
server_address = 127.0.0.1
rasa_model_path = /usr/share/nlu/rasa/models/
rasa_server_port = 51054
-rasa_detached_mode = 0
+rasa_detached_mode = 1
base_log_dir = /usr/share/nlu/logs/
store_voice_commands = 0
@@ -20,8 +20,8 @@ ip = 127.0.0.1
port = 8090
protocol = ws
insecure = True
-token = /usr/lib/python3.10/site-packages/kuksa_certificates/jwt/super-admin.json.token
+token = PYTHON_DIR/kuksa_certificates/jwt/super-admin.json.token
[Mapper]
intents_vss_map = /usr/share/nlu/mappings/intents_vss_map.json
-vss_signals_spec = /usr/share/nlu/mappings/vss_signals_spec.json \ No newline at end of file
+vss_signals_spec = /usr/share/nlu/mappings/vss_signals_spec.json
diff --git a/agl_service_voiceagent/nlu/rasa_interface.py b/agl_service_voiceagent/nlu/rasa_interface.py
index 537a318..350bddf 100644
--- a/agl_service_voiceagent/nlu/rasa_interface.py
+++ b/agl_service_voiceagent/nlu/rasa_interface.py
@@ -40,7 +40,7 @@ class RASAInterface:
self.max_threads = max_threads
self.server_process = None
self.thread_pool = ThreadPoolExecutor(max_workers=max_threads)
- self.log_file = log_dir+"rasa_server_logs.txt"
+ self.log_file = log_dir+"rasa_server.log"
def _start_server(self):
diff --git a/agl_service_voiceagent/server.py b/agl_service_voiceagent/server.py
index d8ce785..aa107dc 100644
--- a/agl_service_voiceagent/server.py
+++ b/agl_service_voiceagent/server.py
@@ -18,12 +18,12 @@ import grpc
from concurrent import futures
from agl_service_voiceagent.generated import voice_agent_pb2_grpc
from agl_service_voiceagent.servicers.voice_agent_servicer import VoiceAgentServicer
-from agl_service_voiceagent.utils.config import get_config_value
+from agl_service_voiceagent.utils.config import get_config_value, get_logger
def run_server():
+ logger = get_logger()
SERVER_URL = get_config_value('SERVER_ADDRESS') + ":" + str(get_config_value('SERVER_PORT'))
print("Starting Voice Agent Service...")
- print(f"Server running at URL: {SERVER_URL}")
print(f"STT Model Path: {get_config_value('STT_MODEL_PATH')}")
print(f"Audio Store Directory: {get_config_value('BASE_AUDIO_DIR')}")
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
@@ -31,5 +31,7 @@ def run_server():
server.add_insecure_port(SERVER_URL)
print("Press Ctrl+C to stop the server.")
print("Voice Agent Server started!")
+ print(f"Server running at URL: {SERVER_URL}")
+ logger.info(f"Voice Agent Service started in server mode! Server running at URL: {SERVER_URL}")
server.start()
server.wait_for_termination() \ No newline at end of file
diff --git a/agl_service_voiceagent/service.py b/agl_service_voiceagent/service.py
index 784d8d9..9682b56 100644
--- a/agl_service_voiceagent/service.py
+++ b/agl_service_voiceagent/service.py
@@ -25,15 +25,14 @@ generated_dir = os.path.join(current_dir, "generated")
sys.path.append(generated_dir)
import argparse
-from agl_service_voiceagent.utils.config import set_config_path, load_config, update_config_value, get_config_value
+from agl_service_voiceagent.utils.config import set_config_path, load_config, update_config_value, get_config_value, get_logger
from agl_service_voiceagent.utils.common import add_trailing_slash
from agl_service_voiceagent.server import run_server
from agl_service_voiceagent.client import run_client
-
def print_version():
print("Automotive Grade Linux (AGL)")
- print(f"Voice Agent Service v0.3.0")
+ print(f"Voice Agent Service v0.4.0")
def main():
@@ -59,8 +58,11 @@ def main():
server_parser.add_argument('--audio-store-dir', required=False, help='Directory to store the generated audio files.')
server_parser.add_argument('--log-store-dir', required=False, help='Directory to store the generated log files.')
+ client_parser.add_argument('--server-address', required=True, help='Address of the gRPC server running the Voice Agent Service.')
+ client_parser.add_argument('--server-port', required=True, help='Port of the gRPC server running the Voice Agent Service.')
client_parser.add_argument('--mode', required=True, help='Mode to run the client in. Supported modes: "wake-word", "auto" and "manual".')
- client_parser.add_argument('--nlu', required=True, help='NLU engine to use. Supported NLU egnines: "snips" and "rasa".')
+ client_parser.add_argument('--nlu', help='NLU engine to use. Supported NLU egnines: "snips" and "rasa".')
+ client_parser.add_argument('--recording-time', help='Number of seconds to continue recording the voice command. Required by the \'manual\' mode. Defaults to 10 seconds.')
args = parser.parse_args()
@@ -70,19 +72,24 @@ def main():
elif args.subcommand == 'run-server':
if not args.default and not args.config:
if not args.stt_model_path:
- raise ValueError("The --stt-model-path is missing. Please provide a value. Use --help to see available options.")
+ print("Error: The --stt-model-path is missing. Please provide a value. Use --help to see available options.")
+ exit(1)
if not args.snips_model_path:
- raise ValueError("The --snips-model-path is missing. Please provide a value. Use --help to see available options.")
+ print("Error: The --snips-model-path is missing. Please provide a value. Use --help to see available options.")
+ exit(1)
if not args.rasa_model_path:
- raise ValueError("The --rasa-model-path is missing. Please provide a value. Use --help to see available options.")
+ print("Error: The --rasa-model-path is missing. Please provide a value. Use --help to see available options.")
+ exit(1)
if not args.intents_vss_map_path:
- raise ValueError("The --intents-vss-map-path is missing. Please provide a value. Use --help to see available options.")
+ print("Error: The --intents-vss-map-path is missing. Please provide a value. Use --help to see available options.")
+ exit(1)
if not args.vss_signals_spec_path:
- raise ValueError("The --vss-signals-spec is missing. Please provide a value. Use --help to see available options.")
+ print("Error: The --vss-signals-spec-path is missing. Please provide a value. Use --help to see available options.")
+ exit(1)
# Contruct the default config file path
config_path = os.path.join(current_dir, "config.ini")
@@ -90,6 +97,9 @@ def main():
# Load the config values from the config file
set_config_path(config_path)
load_config()
+
+ logger = get_logger()
+ logger.info("Starting Voice Agent Service in server mode using CLI provided params...")
# Get the values provided by the user
stt_path = args.stt_model_path
@@ -135,6 +145,9 @@ def main():
print(f"New config file path provided: {cli_config_path}. Overriding the default config file path.")
set_config_path(cli_config_path)
load_config()
+
+ logger = get_logger()
+ logger.info(f"Starting Voice Agent Service in server mode using provided config file at path '{cli_config_path}' ...")
elif args.default:
# Contruct the default config file path
@@ -144,33 +157,40 @@ def main():
set_config_path(config_path)
load_config()
+ logger = get_logger()
+ logger.info(f"Starting Voice Agent Service in server mode using the default config file...")
+
# create the base audio dir if not exists
if not os.path.exists(get_config_value('BASE_AUDIO_DIR')):
os.makedirs(get_config_value('BASE_AUDIO_DIR'))
-
- # create the base log dir if not exists
- if not os.path.exists(get_config_value('BASE_LOG_DIR')):
- os.makedirs(get_config_value('BASE_LOG_DIR'))
run_server()
elif args.subcommand == 'run-client':
- # Contruct the default config file path
- config_path = os.path.join(current_dir, "config.ini")
-
- # Load the config values from the config file
- set_config_path(config_path)
- load_config()
-
+ server_address = args.server_address
+ server_port = args.server_port
+ nlu_engine = ""
mode = args.mode
+ recording_time = 5
+
if mode not in ['wake-word', 'auto', 'manual']:
- raise ValueError("Invalid mode. Supported modes: 'wake-word', 'auto' and 'manual'. Use --help to see available options.")
+ print("Error: Invalid value for --mode. Supported modes: 'wake-word', 'auto' and 'manual'. Use --help to see available options.")
+ exit(1)
- model = args.nlu
- if model not in ['snips', 'rasa']:
- raise ValueError("Invalid NLU engine. Supported NLU engines: 'snips' and 'rasa'. Use --help to see available options.")
+ if mode in ["auto", "manual"]:
+ if not args.nlu:
+ print("Error: The --nlu flag is missing. Please provide a value for intent engine. Supported NLU engines: 'snips' and 'rasa'. Use --help to see available options.")
+ exit(1)
+
+ nlu_engine = args.nlu
+ if nlu_engine not in ['snips', 'rasa']:
+ print("Error: Invalid value for --nlu. Supported NLU engines: 'snips' and 'rasa'. Use --help to see available options.")
+ exit(1)
+
+ if mode == "manual" and args.recording_time:
+ recording_time = int(args.recording_time)
- run_client(mode, model)
+ run_client(server_address, server_port, mode, nlu_engine, recording_time)
else:
print_version()
diff --git a/agl_service_voiceagent/servicers/voice_agent_servicer.py b/agl_service_voiceagent/servicers/voice_agent_servicer.py
index 69af10b..c9b671d 100644
--- a/agl_service_voiceagent/servicers/voice_agent_servicer.py
+++ b/agl_service_voiceagent/servicers/voice_agent_servicer.py
@@ -24,7 +24,7 @@ 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.config import get_config_value, get_logger
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
@@ -40,7 +40,7 @@ class VoiceAgentServicer(voice_agent_pb2_grpc.VoiceAgentServiceServicer):
Constructor for VoiceAgentServicer class.
"""
# Get the config values
- self.service_version = "v0.3.0"
+ self.service_version = "v0.4.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'))
@@ -54,28 +54,48 @@ class VoiceAgentServicer(voice_agent_pb2_grpc.VoiceAgentServiceServicer):
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')))
+ self.logger = get_logger()
# Initialize class methods
+ self.logger.info("Loading Speech to Text and Wake Word Model...")
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.logger.info("Speech to Text and Wake Word Model loaded successfully.")
+
+ self.logger.info("Starting SNIPS intent engine...")
self.snips_interface = SnipsInterface(self.snips_model_path)
+ self.logger.info("SNIPS intent engine started successfully!")
+
self.rasa_interface = RASAInterface(self.rasa_server_port, self.rasa_model_path, self.base_log_dir)
# Only start RASA server if its not in detached mode, else we assume server is already running
if not self.rasa_detached_mode:
+ self.logger.info(f"Starting RASA intent engine server as a subprocess...")
self.rasa_interface.start_server()
+ self.logger.info(f"RASA intent engine server started successfully! RASA server running at URL: 127.0.0.1:{self.rasa_server_port}")
+
+ else:
+ self.logger.info(f"RASA intent engine detached mode detected! Assuming RASA server is running at URL: 127.0.0.1:{self.rasa_server_port}")
self.rvc_stream_uuids = {}
self.kuksa_client = KuksaInterface()
self.kuksa_client.connect_kuksa_client()
self.kuksa_client.authorize_kuksa_client()
+
+ self.logger.info(f"Loading and parsing mapping files...")
self.mapper = Intent2VSSMapper()
+ self.logger.info(f"Successfully loaded and parsed mapping files.")
def CheckServiceStatus(self, request, context):
"""
Check the status of the Voice Agent service including the version.
"""
+ # Log the unique request ID, client's IP address, and the endpoint
+ request_id = generate_unique_uuid(8)
+ client_ip = context.peer()
+ self.logger.info(f"[ReqID#{request_id}] Client {client_ip} made a request to CheckServiceStatus end-point.")
+
response = voice_agent_pb2.ServiceStatus(
version=self.service_version,
status=True
@@ -87,6 +107,11 @@ class VoiceAgentServicer(voice_agent_pb2_grpc.VoiceAgentServiceServicer):
"""
Detect the wake word using the wake word detection model.
"""
+ # Log the unique request ID, client's IP address, and the endpoint
+ request_id = generate_unique_uuid(8)
+ client_ip = context.peer()
+ self.logger.info(f"[ReqID#{request_id}] Client {client_ip} made a request to DetectWakeWord end-point.")
+
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)
@@ -118,6 +143,11 @@ class VoiceAgentServicer(voice_agent_pb2_grpc.VoiceAgentServiceServicer):
if request.action == voice_agent_pb2.START:
status = voice_agent_pb2.REC_PROCESSING
stream_uuid = generate_unique_uuid(8)
+
+ # Log the unique request ID, client's IP address, and the endpoint
+ client_ip = context.peer()
+ self.logger.info(f"[ReqID#{stream_uuid}] Client {client_ip} made a manual START request to RecognizeVoiceCommand end-point.")
+
recorder = AudioRecorder(self.stt_model, self.base_audio_dir, self.channels, self.sample_rate, self.bits_per_sample)
recorder.set_pipeline_mode("manual")
audio_file = recorder.create_pipeline()
@@ -133,6 +163,10 @@ class VoiceAgentServicer(voice_agent_pb2_grpc.VoiceAgentServiceServicer):
stream_uuid = request.stream_id
status = voice_agent_pb2.REC_SUCCESS
+ # Log the unique request ID, client's IP address, and the endpoint
+ client_ip = context.peer()
+ self.logger.info(f"[ReqID#{stream_uuid}] Client {client_ip} made a manual STOP request to RecognizeVoiceCommand end-point.")
+
recorder = self.rvc_stream_uuids[stream_uuid]["recorder"]
audio_file = self.rvc_stream_uuids[stream_uuid]["audio_file"]
del self.rvc_stream_uuids[stream_uuid]
@@ -189,6 +223,11 @@ class VoiceAgentServicer(voice_agent_pb2_grpc.VoiceAgentServiceServicer):
"""
Execute the voice command by sending the intent to Kuksa.
"""
+ # Log the unique request ID, client's IP address, and the endpoint
+ request_id = generate_unique_uuid(8)
+ client_ip = context.peer()
+ self.logger.info(f"[ReqID#{request_id}] Client {client_ip} made a request to ExecuteVoiceCommand end-point.")
+
intent = request.intent
intent_slots = request.intent_slots
processed_slots = []
@@ -203,6 +242,13 @@ class VoiceAgentServicer(voice_agent_pb2_grpc.VoiceAgentServiceServicer):
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
+ # Check for kuksa status, and try re-connecting again if status is False
+ if not self.kuksa_client.get_kuksa_status():
+ self.logger.error(f"[ReqID#{request_id}] Kuksa client found disconnected. Trying to close old instance and re-connecting...")
+ self.kuksa_client.close_kuksa_client()
+ self.kuksa_client.connect_kuksa_client()
+ self.kuksa_client.authorize_kuksa_client()
+
for execution_item in execution_list:
print(execution_item)
action = execution_item["action"]
diff --git a/agl_service_voiceagent/utils/config.py b/agl_service_voiceagent/utils/config.py
index 7295c7f..e0b053e 100644
--- a/agl_service_voiceagent/utils/config.py
+++ b/agl_service_voiceagent/utils/config.py
@@ -14,10 +14,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
+import logging
import configparser
config = configparser.ConfigParser()
config_path = None
+logger = None
def set_config_path(path):
"""
@@ -25,14 +28,25 @@ def set_config_path(path):
"""
global config_path
config_path = path
- config.read(config_path)
def load_config():
"""
- Loads the config file.
+ Loads the config file and initializes the logger.
+
+ Also creates logging directory if it doesn't already exist.
"""
if config_path is not None:
+ global logger
config.read(config_path)
+
+ # create the base log dir if not exists
+ if not os.path.exists(get_config_value('BASE_LOG_DIR')):
+ os.makedirs(get_config_value('BASE_LOG_DIR'))
+
+ logging.basicConfig(filename=get_config_value('BASE_LOG_DIR')+'voiceagent_server.log', level=logging.DEBUG, format='[%(asctime)s] [%(name)s] [%(levelname)s]: (%(filename)s:%(funcName)s) %(message)s', filemode='a')
+ logger = logging.getLogger()
+ logger.info("-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-")
+
else:
raise Exception("Config file path not provided.")
@@ -52,3 +66,15 @@ def get_config_value(key, group="General"):
Gets a value from the config file.
"""
return config.get(group, key)
+
+def get_logger():
+ """
+ Gets the initialized logger.
+ """
+ if logger is not None:
+ return logger
+
+ else:
+ logging.basicConfig(level=logging.DEBUG)
+ print("[-] Error: Failed to get logger. Logger is not initialized!")
+ logging.error("Failed to get logger. Logger is not initialized!")
diff --git a/agl_service_voiceagent/utils/kuksa_interface.py b/agl_service_voiceagent/utils/kuksa_interface.py
index 9270379..0881660 100644
--- a/agl_service_voiceagent/utils/kuksa_interface.py
+++ b/agl_service_voiceagent/utils/kuksa_interface.py
@@ -18,7 +18,7 @@ import time
import json
import threading
from kuksa_client import KuksaClientThread
-from agl_service_voiceagent.utils.config import get_config_value
+from agl_service_voiceagent.utils.config import get_config_value, get_logger
class KuksaInterface:
"""
@@ -55,6 +55,7 @@ class KuksaInterface:
self.insecure = get_config_value("insecure", "Kuksa")
self.protocol = get_config_value("protocol", "Kuksa")
self.token = get_config_value("token", "Kuksa")
+ self.logger = get_logger()
print(self.ip, self.port, self.insecure, self.protocol, self.token)
@@ -102,11 +103,14 @@ class KuksaInterface:
if not self.get_kuksa_status():
print("[-] Error: Connection to Kuksa server failed.")
+ self.logger.error("Connection to Kuksa server failed.")
else:
print("[+] Connection to Kuksa established.")
+ self.logger.info("Connection to Kuksa established.")
except Exception as e:
print("[-] Error: Connection to Kuksa server failed. ", str(e))
+ self.logger.error(f"Connection to Kuksa server failed. {str(e)}")
def authorize_kuksa_client(self):
@@ -119,10 +123,13 @@ class KuksaInterface:
if "error" in response:
error_message = response.get("error", "Unknown error")
print(f"[-] Error: Authorization failed. {error_message}")
+ self.logger.error(f"Authorization failed. {error_message}")
else:
print("[+] Kuksa client authorized successfully.")
+ self.logger.info("Kuksa client authorized successfully.")
else:
print("[-] Error: Kuksa client is not initialized. Call `connect_kuksa_client` first.")
+ self.logger.error("Kuksa client is not initialized. Call `connect_kuksa_client` first.")
def send_values(self, path=None, value=None):
@@ -137,7 +144,8 @@ class KuksaInterface:
"""
result = False
if self.kuksa_client is None:
- print("[-] Error: Kuksa client is not initialized.")
+ print(f"[-] Error: Failed to send value '{value}' to Kuksa. Kuksa client is not initialized.")
+ self.logger.error(f"Failed to send value '{value}' to Kuksa. Kuksa client is not initialized.")
return
if self.get_kuksa_status():
@@ -150,12 +158,15 @@ class KuksaInterface:
else:
error_message = response.get("error", "Unknown error")
print(f"[-] Error: Failed to send value '{value}' to Kuksa. {error_message}")
+ self.logger.error(f"Failed to send value '{value}' to Kuksa. {error_message}")
except Exception as e:
- print("[-] Error: Failed to send values to Kuksa. ", str(e))
+ print(f"[-] Error: Failed to send value '{value}' to Kuksa. ", str(e))
+ self.logger.error(f"Failed to send value '{value}' to Kuksa. {str(e)}")
else:
- print("[-] Error: Connection to Kuksa failed.")
+ print(f"[-] Error: Failed to send value '{value}' to Kuksa. Connection to Kuksa failed.")
+ self.logger.error(f"Failed to send value '{value}' to Kuksa. Connection to Kuksa failed.")
return result
@@ -171,7 +182,8 @@ class KuksaInterface:
"""
result = None
if self.kuksa_client is None:
- print("[-] Error: Kuksa client is not initialized.")
+ print(f"[-] Error: Failed to get value at path '{path}' from Kuksa. Kuksa client is not initialized.")
+ self.logger.error(f"Failed to get value at path '{path}' from Kuksa. Kuksa client is not initialized.")
return
if self.get_kuksa_status():
@@ -185,13 +197,16 @@ class KuksaInterface:
else:
error_message = response.get("error", "Unknown error")
- print(f"[-] Error: Failed to get value from Kuksa. {error_message}")
+ print(f"[-] Error: Failed to get value at path '{path}' from Kuksa. {error_message}")
+ self.logger.error(f"Failed to get value at path '{path}' from Kuksa. {error_message}")
except Exception as e:
- print("[-] Error: Failed to get values from Kuksa. ", str(e))
+ print(f"[-] Error: Failed to get value at path '{path}' from Kuksa. ", str(e))
+ self.logger.error(f"Failed to get value at path '{path}' from Kuksa. {str(e)}")
else:
- print("[-] Error: Connection to Kuksa failed.")
+ print(f"[-] Error: Failed to get value at path '{path}' from Kuksa. Connection to Kuksa failed.")
+ self.logger.error(f"Failed to get value at path '{path}' from Kuksa. Connection to Kuksa failed.")
return result
@@ -206,5 +221,7 @@ class KuksaInterface:
self.kuksa_client.stop()
self.kuksa_client = None
print("[+] Kuksa client stopped.")
+ self.logger.info("Kuksa client stopped.")
except Exception as e:
- print("[-] Error: Failed to close Kuksa client. ", str(e)) \ No newline at end of file
+ print("[-] Error: Failed to close Kuksa client. ", str(e))
+ self.logger.error(f"Failed to close Kuksa client. {str(e)}") \ No newline at end of file
diff --git a/agl_service_voiceagent/utils/mapper.py b/agl_service_voiceagent/utils/mapper.py
index 7529645..f24f44f 100644
--- a/agl_service_voiceagent/utils/mapper.py
+++ b/agl_service_voiceagent/utils/mapper.py
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from agl_service_voiceagent.utils.config import get_config_value
+from agl_service_voiceagent.utils.config import get_config_value, get_logger
from agl_service_voiceagent.utils.common import load_json_file, words_to_number
@@ -33,6 +33,7 @@ class Intent2VSSMapper:
vss_signals_spec_file = get_config_value("vss_signals_spec", "Mapper")
self.intents_vss_map = load_json_file(intents_vss_map_file).get("intents", {})
self.vss_signals_spec = load_json_file(vss_signals_spec_file).get("signals", {})
+ self.logger = get_logger()
if not self.validate_signal_spec_structure():
raise ValueError("[-] Invalid VSS signal specification structure.")
@@ -49,6 +50,7 @@ class Intent2VSSMapper:
# Check if the required keys are present in the signal data
if not all(key in signal_data for key in ['default_value', 'default_change_factor', 'actions', 'values', 'default_fallback', 'value_set_intents']):
print(f"[-] {signal_name}: Missing required keys in signal data.")
+ self.logger.error(f"{signal_name}: Missing required keys in signal data.")
return False
actions = signal_data['actions']
@@ -56,12 +58,14 @@ class Intent2VSSMapper:
# Check if 'actions' is a dictionary with at least one action
if not isinstance(actions, dict) or not actions:
print(f"[-] {signal_name}: Invalid 'actions' key in signal data. Must be an object with at least one action.")
+ self.logger.error(f"{signal_name}: Invalid 'actions' key in signal data. Must be an object with at least one action.")
return False
# Check if the actions match the allowed actions ["set", "increase", "decrease"]
for action in actions.keys():
if action not in ["set", "increase", "decrease"]:
print(f"[-] {signal_name}: Invalid action in signal data. Allowed actions: ['set', 'increase', 'decrease']")
+ self.logger.error(f"{signal_name}: Invalid action in signal data. Allowed actions: ['set', 'increase', 'decrease']")
return False
# Check if the 'synonyms' list is present for each action and is either a list or None
@@ -69,6 +73,7 @@ class Intent2VSSMapper:
synonyms = action_data.get('synonyms')
if synonyms is not None and (not isinstance(synonyms, list) or not all(isinstance(synonym, str) for synonym in synonyms)):
print(f"[-] {signal_name}: Invalid 'synonyms' value in signal data. Must be a list of strings.")
+ self.logger.error(f"{signal_name}: Invalid 'synonyms' value in signal data. Must be a list of strings.")
return False
values = signal_data['values']
@@ -76,11 +81,13 @@ class Intent2VSSMapper:
# Check if 'values' is a dictionary with the required keys
if not isinstance(values, dict) or not all(key in values for key in ['ranged', 'start', 'end', 'ignore', 'additional']):
print(f"[-] {signal_name}: Invalid 'values' key in signal data. Required keys: ['ranged', 'start', 'end', 'ignore', 'additional']")
+ self.logger.error(f"{signal_name}: Invalid 'values' key in signal data. Required keys: ['ranged', 'start', 'end', 'ignore', 'additional']")
return False
# Check if 'ranged' is a boolean
if not isinstance(values['ranged'], bool):
print(f"[-] {signal_name}: Invalid 'ranged' value in signal data. Allowed values: [true, false]")
+ self.logger.error(f"{signal_name}: Invalid 'ranged' value in signal data. Allowed values: [true, false]")
return False
default_fallback = signal_data['default_fallback']
@@ -88,6 +95,7 @@ class Intent2VSSMapper:
# Check if 'default_fallback' is a boolean
if not isinstance(default_fallback, bool):
print(f"[-] {signal_name}: Invalid 'default_fallback' value in signal data. Allowed values: [true, false]")
+ self.logger.error(f"{signal_name}: Invalid 'default_fallback' value in signal data. Allowed values: [true, false]")
return False
# If all checks pass, the self.vss_signals_spec structure is valid