forked from xiaozhi/xiaozhi-esp32
Add MCP server
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include "font_awesome_symbols.h"
|
||||
#include "iot/thing_manager.h"
|
||||
#include "assets/lang_config.h"
|
||||
#include "mcp_server.h"
|
||||
|
||||
#if CONFIG_USE_AUDIO_PROCESSOR
|
||||
#include "afe_audio_processor.h"
|
||||
@@ -41,7 +42,7 @@ static const char* const STATE_STRINGS[] = {
|
||||
|
||||
Application::Application() {
|
||||
event_group_ = xEventGroupCreate();
|
||||
background_task_ = new BackgroundTask(4096 * 8);
|
||||
background_task_ = new BackgroundTask(4096 * 7);
|
||||
|
||||
#if CONFIG_USE_AUDIO_PROCESSOR
|
||||
audio_processor_ = std::make_unique<AfeAudioProcessor>();
|
||||
@@ -425,12 +426,15 @@ void Application::Start() {
|
||||
protocol_->server_sample_rate(), codec->output_sample_rate());
|
||||
}
|
||||
SetDecodeSampleRate(protocol_->server_sample_rate(), protocol_->server_frame_duration());
|
||||
|
||||
#if CONFIG_IOT_PROTOCOL_XIAOZHI
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
protocol_->SendIotDescriptors(thing_manager.GetDescriptorsJson());
|
||||
std::string states;
|
||||
if (thing_manager.GetStatesJson(states, false)) {
|
||||
protocol_->SendIotStates(states);
|
||||
}
|
||||
#endif
|
||||
});
|
||||
protocol_->OnAudioChannelClosed([this, &board]() {
|
||||
board.SetPowerSaveMode(true);
|
||||
@@ -465,7 +469,7 @@ void Application::Start() {
|
||||
});
|
||||
} else if (strcmp(state->valuestring, "sentence_start") == 0) {
|
||||
auto text = cJSON_GetObjectItem(root, "text");
|
||||
if (text != NULL) {
|
||||
if (cJSON_IsString(text)) {
|
||||
ESP_LOGI(TAG, "<< %s", text->valuestring);
|
||||
Schedule([this, display, message = std::string(text->valuestring)]() {
|
||||
display->SetChatMessage("assistant", message.c_str());
|
||||
@@ -474,7 +478,7 @@ void Application::Start() {
|
||||
}
|
||||
} else if (strcmp(type->valuestring, "stt") == 0) {
|
||||
auto text = cJSON_GetObjectItem(root, "text");
|
||||
if (text != NULL) {
|
||||
if (cJSON_IsString(text)) {
|
||||
ESP_LOGI(TAG, ">> %s", text->valuestring);
|
||||
Schedule([this, display, message = std::string(text->valuestring)]() {
|
||||
display->SetChatMessage("user", message.c_str());
|
||||
@@ -482,23 +486,32 @@ void Application::Start() {
|
||||
}
|
||||
} else if (strcmp(type->valuestring, "llm") == 0) {
|
||||
auto emotion = cJSON_GetObjectItem(root, "emotion");
|
||||
if (emotion != NULL) {
|
||||
if (cJSON_IsString(emotion)) {
|
||||
Schedule([this, display, emotion_str = std::string(emotion->valuestring)]() {
|
||||
display->SetEmotion(emotion_str.c_str());
|
||||
});
|
||||
}
|
||||
#if CONFIG_IOT_PROTOCOL_MCP
|
||||
} else if (strcmp(type->valuestring, "mcp") == 0) {
|
||||
auto payload = cJSON_GetObjectItem(root, "payload");
|
||||
if (cJSON_IsObject(payload)) {
|
||||
McpServer::GetInstance().ParseMessage(payload);
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_IOT_PROTOCOL_XIAOZHI
|
||||
} else if (strcmp(type->valuestring, "iot") == 0) {
|
||||
auto commands = cJSON_GetObjectItem(root, "commands");
|
||||
if (commands != NULL) {
|
||||
if (cJSON_IsArray(commands)) {
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
for (int i = 0; i < cJSON_GetArraySize(commands); ++i) {
|
||||
auto command = cJSON_GetArrayItem(commands, i);
|
||||
thing_manager.Invoke(command);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else if (strcmp(type->valuestring, "system") == 0) {
|
||||
auto command = cJSON_GetObjectItem(root, "command");
|
||||
if (command != NULL) {
|
||||
if (cJSON_IsString(command)) {
|
||||
ESP_LOGI(TAG, "System command: %s", command->valuestring);
|
||||
if (strcmp(command->valuestring, "reboot") == 0) {
|
||||
// Do a reboot if user requests a OTA update
|
||||
@@ -513,7 +526,7 @@ void Application::Start() {
|
||||
auto status = cJSON_GetObjectItem(root, "status");
|
||||
auto message = cJSON_GetObjectItem(root, "message");
|
||||
auto emotion = cJSON_GetObjectItem(root, "emotion");
|
||||
if (status != NULL && message != NULL && emotion != NULL) {
|
||||
if (cJSON_IsString(status) && cJSON_IsString(message) && cJSON_IsString(emotion)) {
|
||||
Alert(status->valuestring, message->valuestring, emotion->valuestring, Lang::Sounds::P3_VIBRATION);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Alert command requires status, message and emotion");
|
||||
@@ -620,7 +633,10 @@ void Application::OnClockTimer() {
|
||||
clock_ticks_++;
|
||||
|
||||
// Print the debug info every 10 seconds
|
||||
if (clock_ticks_ % 10 == 0) {
|
||||
if (clock_ticks_ % 3 == 0) {
|
||||
// char buffer[500];
|
||||
// vTaskList(buffer);
|
||||
// ESP_LOGI(TAG, "Task list: \n%s", buffer);
|
||||
// SystemInfo::PrintRealTimeStats(pdMS_TO_TICKS(1000));
|
||||
|
||||
int free_sram = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||||
@@ -850,7 +866,9 @@ void Application::SetDeviceState(DeviceState state) {
|
||||
display->SetStatus(Lang::Strings::LISTENING);
|
||||
display->SetEmotion("neutral");
|
||||
// Update the IoT states before sending the start listening command
|
||||
#if CONFIG_IOT_PROTOCOL_XIAOZHI
|
||||
UpdateIotStates();
|
||||
#endif
|
||||
|
||||
// Make sure the audio processor is running
|
||||
if (!audio_processor_->IsRunning()) {
|
||||
@@ -910,11 +928,13 @@ void Application::SetDecodeSampleRate(int sample_rate, int frame_duration) {
|
||||
}
|
||||
|
||||
void Application::UpdateIotStates() {
|
||||
#if CONFIG_IOT_PROTOCOL_XIAOZHI
|
||||
auto& thing_manager = iot::ThingManager::GetInstance();
|
||||
std::string states;
|
||||
if (thing_manager.GetStatesJson(states, true)) {
|
||||
protocol_->SendIotStates(states);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Application::Reboot() {
|
||||
@@ -955,3 +975,11 @@ bool Application::CanEnterSleepMode() {
|
||||
// Now it is safe to enter sleep mode
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::SendMcpMessage(const std::string& payload) {
|
||||
Schedule([this, payload]() {
|
||||
if (protocol_) {
|
||||
protocol_->SendMcpMessage(payload);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user