/* * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0/ * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ #include "VshlCoreApi.h" #include #include "afb/AFBApiImpl.h" #include "afb/AFBRequestImpl.h" #include "core/VRRequestProcessor.h" #include "utilities/events/EventRouter.h" #include "utilities/logging/Logger.h" #include "voiceagents/VoiceAgentEventNames.h" #include "voiceagents/VoiceAgentsDataManager.h" #include "json.hpp" using namespace std; CTLP_CAPI_REGISTER("vshl-core-api"); static std::string TAG = "vshlcore::plugins::VshlCoreAPI"; static std::string VA_JSON_ATTR_DEFAULT = "default"; static std::string VA_JSON_ATTR_AGENTS = "agents"; static std::string VA_JSON_ATTR_ID = "id"; static std::string VA_JSON_ATTR_NAME = "name"; static std::string VA_JSON_ATTR_API = "api"; static std::string VA_JSON_ATTR_ACTIVE = "active"; static std::string VA_JSON_ATTR_WWS = "wakewords"; static std::string VA_JSON_ATTR_ACTIVE_WW = "activewakeword"; static std::string VA_JSON_ATTR_DESCRIPTION = "description"; static std::string VA_JSON_ATTR_VENDOR = "vendor"; static std::string STARTLISTENING_JSON_ATTR_REQUEST = "request_id"; static std::string EVENTS_JSON_ATTR_VA_ID = "va_id"; static std::string EVENTS_JSON_ATTR_EVENTS = "events"; static std::shared_ptr sLogger; static std::shared_ptr sAfbApi; static std::unique_ptr sVRRequestProcessor; static std::unique_ptr sVoiceAgentsDataManager; static std::unique_ptr sEventRouter; using json = nlohmann::json; using Level = vshlcore::utilities::logging::Logger::Level; CTLP_ONLOAD(plugin, ret) { if (plugin->api == nullptr) { return -1; } // Logger sLogger = vshlcore::utilities::logging::Logger::create(plugin->api); // sLogger->log(Level::INFO, TAG, "Vshl plugin loaded & initialized."); // AFB Wrapper sAfbApi = vshlcore::afb::AFBApiImpl::create(plugin->api); // VRRequestProcessor auto vrRequestProcessorDelegate = vshlcore::core::VRRequestProcessorDelegate::create(sLogger, sAfbApi); sVRRequestProcessor = vshlcore::core::VRRequestProcessor::create(sLogger, vrRequestProcessorDelegate); if (!sVRRequestProcessor) { sLogger->log(Level::ERROR, TAG, "Failed to create VRRequestProcessor"); return -1; } // VoiceAgentDataManager sVoiceAgentsDataManager = vshlcore::voiceagents::VoiceAgentsDataManager::create(sLogger, sAfbApi); if (!sVoiceAgentsDataManager) { sLogger->log(Level::ERROR, TAG, "Failed to create VoiceAgentsDataManager"); return -1; } sVoiceAgentsDataManager->addVoiceAgentsChangeObserver(sVRRequestProcessor->getVoiceAgentsChangeObserver()); // EventRouter sEventRouter = vshlcore::utilities::events::EventRouter::create(sLogger); if (!sEventRouter) { sLogger->log(Level::ERROR, TAG, "Failed to create EventRouter"); return -1; } sEventRouter->addEventFilter(sVoiceAgentsDataManager->getEventFilter()); return 0; } CTLP_CAPI(onAuthStateEvent, source, argsJ, eventJ) { if (sEventRouter == nullptr) { return -1; } string eventName = vshlcore::voiceagents::VSHL_EVENT_AUTH_STATE_EVENT; json eventJson = json::parse(json_object_to_json_string(eventJ)); if (eventJson.find(EVENTS_JSON_ATTR_VA_ID) == eventJson.end()) { sLogger->log(Level::ERROR, TAG, "onAuthStateEvent: No voiceagent id found."); return -1; } std::string voiceAgentId(eventJson[EVENTS_JSON_ATTR_VA_ID].get()); sEventRouter->handleIncomingEvent(eventName, voiceAgentId, json_object_to_json_string(eventJ)); return 0; } CTLP_CAPI(onConnectionStateEvent, source, argsJ, eventJ) { if (sEventRouter == nullptr) { return -1; } string eventName = vshlcore::voiceagents::VSHL_EVENT_CONNECTION_STATE_EVENT; json eventJson = json::parse(json_object_to_json_string(eventJ)); if (eventJson.find(EVENTS_JSON_ATTR_VA_ID) == eventJson.end()) { sLogger->log(Level::ERROR, TAG, "onConnectionStateEvent: No voiceagent id found."); return -1; } std::string voiceAgentId(eventJson[EVENTS_JSON_ATTR_VA_ID].get()); sEventRouter->handleIncomingEvent(eventName, voiceAgentId, json_object_to_json_string(eventJ)); return 0; } CTLP_CAPI(onDialogStateEvent, source, argsJ, eventJ) { if (sEventRouter == nullptr) { return -1; } string eventName = vshlcore::voiceagents::VSHL_EVENT_DIALOG_STATE_EVENT; json eventJson = json::parse(json_object_to_json_string(eventJ)); if (eventJson.find(EVENTS_JSON_ATTR_VA_ID) == eventJson.end()) { sLogger->log(Level::ERROR, TAG, "onDialogStateEvent: No voiceagent id found."); return -1; } std::string voiceAgentId(eventJson[EVENTS_JSON_ATTR_VA_ID].get()); sEventRouter->handleIncomingEvent(eventName, voiceAgentId, json_object_to_json_string(eventJ)); return 0; } CTLP_CAPI(loadVoiceAgentsConfig, source, argsJ, eventJ) { if (sVoiceAgentsDataManager == nullptr) { sLogger->log(Level::WARNING, TAG, "loadVoiceAgentsConfig: Voice service not initialized."); return -1; } if (argsJ == nullptr) { sLogger->log(Level::WARNING, TAG, "loadVoiceAgentsConfig: No arguments supplied."); return -1; } json agentsConfigJson = json::parse(json_object_to_json_string(argsJ)); if (agentsConfigJson.find(VA_JSON_ATTR_AGENTS) == agentsConfigJson.end()) { sLogger->log(Level::ERROR, TAG, "loadVoiceAgentsConfig: No agents object found in agents json"); return -1; } json agentsJson = agentsConfigJson[VA_JSON_ATTR_AGENTS]; for (auto agentIt = agentsJson.begin(); agentIt != agentsJson.end(); ++agentIt) { json agentJson = *agentIt; if (agentJson.find(VA_JSON_ATTR_ID) == agentJson.end() || agentJson.find(VA_JSON_ATTR_ACTIVE) == agentJson.end() || agentJson.find(VA_JSON_ATTR_NAME) == agentJson.end() || agentJson.find(VA_JSON_ATTR_API) == agentJson.end() || agentJson.find(VA_JSON_ATTR_WWS) == agentJson.end() || agentJson.find(VA_JSON_ATTR_ACTIVE_WW) == agentJson.end() || agentJson.find(VA_JSON_ATTR_DESCRIPTION) == agentJson.end() || agentJson.find(VA_JSON_ATTR_VENDOR) == agentJson.end()) { std::stringstream error; error << "loadVoiceAgentsConfig: One or more missing params in agent " "config " << agentJson.dump(); sLogger->log(Level::WARNING, TAG, error.str().c_str()); continue; } std::string id(agentJson[VA_JSON_ATTR_ID].get()); std::string name(agentJson[VA_JSON_ATTR_NAME].get()); std::string api(agentJson[VA_JSON_ATTR_API].get()); std::string description(agentJson[VA_JSON_ATTR_DESCRIPTION].get()); std::string vendor(agentJson[VA_JSON_ATTR_VENDOR].get()); std::string activeWakeword(agentJson[VA_JSON_ATTR_ACTIVE_WW].get()); bool isActive(agentJson[VA_JSON_ATTR_ACTIVE].get()); shared_ptr> wakewords = std::make_shared>(); json wakewordsJson = agentJson[VA_JSON_ATTR_WWS]; for (auto wwIt = wakewordsJson.begin(); wwIt != wakewordsJson.end(); ++wwIt) { wakewords->insert(wwIt->get()); } sVoiceAgentsDataManager->addNewVoiceAgent( id, name, description, api, vendor, activeWakeword, isActive, wakewords); } // Set the default agent. if (agentsConfigJson.find(VA_JSON_ATTR_DEFAULT) == agentsConfigJson.end()) { sLogger->log(Level::ERROR, TAG, "loadVoiceAgentsConfig: No default agent found in agents json"); return -1; } std::string defaultAgentId(agentsConfigJson[VA_JSON_ATTR_DEFAULT].get()); sVoiceAgentsDataManager->setDefaultVoiceAgent(defaultAgentId); return 0; } CTLP_CAPI(startListening, source, argsJ, eventJ) { if (sVoiceAgentsDataManager == nullptr) { return -1; } if (sVRRequestProcessor == nullptr) { return -1; } int result = 0; string requestId = sVRRequestProcessor->startListening(); if (!requestId.empty()) { json responseJson; responseJson[STARTLISTENING_JSON_ATTR_REQUEST] = requestId; AFB_ReqSuccess(source->request, json_tokener_parse(responseJson.dump().c_str()), NULL); } else { AFB_ReqFail(source->request, NULL, "Failed to startListening..."); } return 0; } CTLP_CAPI(cancelListening, source, argsJ, eventJ) { return 0; } CTLP_CAPI(enumerateVoiceAgents, source, argsJ, eventJ) { if (sVoiceAgentsDataManager == nullptr) { return -1; } auto agents = sVoiceAgentsDataManager->getAllVoiceAgents(); std::string defaultAgentId(sVoiceAgentsDataManager->getDefaultVoiceAgent()); json responseJson; json agentsJson = json::array(); for (auto agent : agents) { json agentJson; agentJson[VA_JSON_ATTR_ID] = agent->getId(); agentJson[VA_JSON_ATTR_NAME] = agent->getName(); agentJson[VA_JSON_ATTR_DESCRIPTION] = agent->getDescription(); agentJson[VA_JSON_ATTR_API] = agent->getApi(); agentJson[VA_JSON_ATTR_VENDOR] = agent->getVendor(); agentJson[VA_JSON_ATTR_ACTIVE] = agent->isActive(); agentJson[VA_JSON_ATTR_ACTIVE_WW] = agent->getActiveWakeword(); auto wakewords = agent->getWakeWords(); if (wakewords != nullptr) { json wakewordsJson; for (auto wakeword : *wakewords) { wakewordsJson.push_back(wakeword); } agentJson[VA_JSON_ATTR_WWS] = wakewordsJson; } agentsJson.push_back(agentJson); } responseJson[VA_JSON_ATTR_AGENTS] = agentsJson; responseJson[VA_JSON_ATTR_DEFAULT] = defaultAgentId; AFB_ReqSuccess(source->request, json_tokener_parse(responseJson.dump().c_str()), NULL); return 0; } CTLP_CAPI(subscribe, source, argsJ, eventJ) { if (sVoiceAgentsDataManager == nullptr) { return -1; } if (eventJ == nullptr) { sLogger->log(Level::WARNING, TAG, "subscribe: No arguments supplied."); return -1; } json subscribeJson = json::parse(json_object_to_json_string(eventJ)); if (subscribeJson.find(EVENTS_JSON_ATTR_VA_ID) == subscribeJson.end()) { sLogger->log(Level::ERROR, TAG, "subscribe: No voiceagent id found in subscribe json"); return -1; } std::string voiceAgentId(subscribeJson[EVENTS_JSON_ATTR_VA_ID].get()); if (subscribeJson.find(EVENTS_JSON_ATTR_EVENTS) == subscribeJson.end()) { sLogger->log(Level::ERROR, TAG, "subscribe: No events array found in subscribe json"); return -1; } list events(subscribeJson[EVENTS_JSON_ATTR_EVENTS].get>()); // Subscribe this client for the listed events. auto request = vshlcore::afb::AFBRequestImpl::create(source->request); for (auto event : events) { if (!sVoiceAgentsDataManager->subscribeToVshlEventFromVoiceAgent(*request, event, voiceAgentId)) { sLogger->log(Level::ERROR, TAG, "subscribe: Failed to subscribe to event: " + event); return -1; } } AFB_ReqSuccess(source->request, json_object_new_string("Subscription to events successfully completed."), NULL); return 0; } CTLP_CAPI(setDefaultVoiceAgent, source, argsJ, eventJ) { if (sVoiceAgentsDataManager == nullptr) { return -1; } if (eventJ == nullptr) { sLogger->log(Level::WARNING, TAG, "setDefaultVoiceAgent: No arguments supplied."); return -1; } json jsonRequest = json::parse(json_object_to_json_string(eventJ)); if (jsonRequest.find(VA_JSON_ATTR_ID) == jsonRequest.end()) { sLogger->log(Level::ERROR, TAG, "setDefaultVoiceAgent: voice agent id not found in request json"); return -1; } std::string voiceAgentId(jsonRequest[VA_JSON_ATTR_ID].get()); if (!sVoiceAgentsDataManager->setDefaultVoiceAgent(voiceAgentId)) { sLogger->log(Level::ERROR, TAG, "setDefaultVoiceAgent: Failed to set default agent"); return -1; } AFB_ReqSuccess(source->request, NULL, NULL); return 0; }