File size: 7,154 Bytes
1dd0e3b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#include "embodied_ai_agent.h"
#include <iostream>
#include <chrono>
#include <sstream>
#include <iomanip>

namespace hhb {
namespace core {

EmbodiedAIAgent::EmbodiedAIAgent()
    : llmClient_(LLMClient::getInstance()),
      toolRegistry_(ToolRegistry::getInstance()),
      state_(EmbodiedAIState::Idle),
      processing_(false) {
}

EmbodiedAIAgent::~EmbodiedAIAgent() {
    if (pendingFuture_.valid()) {
        pendingFuture_.wait();
    }
}

void EmbodiedAIAgent::initialize(const std::string& endpoint, const std::string& api_key,
                                  const std::string& model, GeometryAPI* geometry_api) {
    llmClient_.setEndpoint(endpoint);
    llmClient_.setApiKey(api_key);
    llmClient_.setModel(model);
    llmClient_.setTimeout(60000);

    // 初始化工具注册表,将几何分析能力暴露给 LLM
    toolRegistry_.initialize(geometry_api);

    // 清除旧工具并注册所有工具到 LLMClient
    llmClient_.clearTools();
    toolRegistry_.registerAllToLLM(llmClient_);

    std::cout << "[EmbodiedAIAgent] Initialized with endpoint: " << endpoint
              << " model: " << model << std::endl;
    std::cout << "[EmbodiedAIAgent] Registered tools: ";
    for (const auto& name : llmClient_.getRegisteredToolNames()) {
        std::cout << name << " ";
    }
    std::cout << std::endl;
}

void EmbodiedAIAgent::processInputAsync(const std::string& user_input) {
    if (processing_) {
        std::cout << "[EmbodiedAIAgent] Still processing previous request" << std::endl;
        return;
    }

    processing_ = true;
    setState(EmbodiedAIState::Processing);

    // 添加用户消息到历史
    {
        std::lock_guard<std::mutex> lock(historyMutex_);
        auto now = std::chrono::system_clock::now();
        auto time_t = std::chrono::system_clock::to_time_t(now);
        std::stringstream ss;
        ss << std::put_time(std::localtime(&time_t), "%H:%M:%S");
        chatHistory_.push_back({user_input, true, ss.str()});
    }

    // 异步执行具身智能闭环
    pendingFuture_ = std::async(std::launch::async, [this, user_input]() -> std::string {
        std::cout << "[EmbodiedAIAgent] Starting embodied query for: " << user_input << std::endl;

        setState(EmbodiedAIState::Processing);

        // 调用 LLMClient 的 embodiedQuery 方法
        // 该方法实现了完整的闭环:用户输入 -> LLM 解析 -> 工具执行 -> 结果反馈 -> LLM 总结
        std::string response = llmClient_.embodiedQuery(user_input, 3);

        // 检查工具执行结果,更新高亮
        if (toolRegistry_.hasNewResult()) {
            auto indices = toolRegistry_.getHighlightIndices();
            auto type = toolRegistry_.getHighlightType();
            auto desc = toolRegistry_.getLastAnalysisDesc();

            std::cout << "[EmbodiedAIAgent] Tool result: " << indices.size()
                      << " indices, type=" << static_cast<int>(type) << std::endl;

            // 通知渲染层更新高亮
            if (resultCallback_) {
                resultCallback_(indices, type, desc);
            }

            toolRegistry_.clearNewResult();
        }

        return response;
    });
}

std::string EmbodiedAIAgent::processInput(const std::string& user_input) {
    // 添加用户消息到历史
    {
        std::lock_guard<std::mutex> lock(historyMutex_);
        auto now = std::chrono::system_clock::now();
        auto time_t = std::chrono::system_clock::to_time_t(now);
        std::stringstream ss;
        ss << std::put_time(std::localtime(&time_t), "%H:%M:%S");
        chatHistory_.push_back({user_input, true, ss.str()});
    }

    setState(EmbodiedAIState::Processing);

    std::string response = llmClient_.embodiedQuery(user_input, 3);

    // 检查工具执行结果
    if (toolRegistry_.hasNewResult()) {
        auto indices = toolRegistry_.getHighlightIndices();
        auto type = toolRegistry_.getHighlightType();
        auto desc = toolRegistry_.getLastAnalysisDesc();

        if (resultCallback_) {
            resultCallback_(indices, type, desc);
        }

        toolRegistry_.clearNewResult();
    }

    // 添加 AI 回复到历史
    {
        std::lock_guard<std::mutex> lock(historyMutex_);
        auto now = std::chrono::system_clock::now();
        auto time_t = std::chrono::system_clock::to_time_t(now);
        std::stringstream ss;
        ss << std::put_time(std::localtime(&time_t), "%H:%M:%S");
        chatHistory_.push_back({response, false, ss.str()});
    }

    lastResponse_ = response;

    if (response.find("[Error]") != std::string::npos) {
        lastError_ = response;
        setState(EmbodiedAIState::Error);
    } else {
        setState(EmbodiedAIState::Idle);
    }

    return response;
}

EmbodiedAIState EmbodiedAIAgent::getState() const {
    return state_.load();
}

std::string EmbodiedAIAgent::getStateString() const {
    switch (state_.load()) {
        case EmbodiedAIState::Idle: return "Idle";
        case EmbodiedAIState::Processing: return "Processing...";
        case EmbodiedAIState::ToolExecuting: return "Executing Tool...";
        case EmbodiedAIState::Responding: return "Generating Response...";
        case EmbodiedAIState::Error: return "Error";
        default: return "Unknown";
    }
}

std::vector<ChatMessage> EmbodiedAIAgent::getChatHistory() const {
    std::lock_guard<std::mutex> lock(historyMutex_);
    return chatHistory_;
}

std::string EmbodiedAIAgent::getLastResponse() const {
    return lastResponse_;
}

std::string EmbodiedAIAgent::getLastError() const {
    return lastError_;
}

bool EmbodiedAIAgent::isProcessing() const {
    return processing_.load();
}

void EmbodiedAIAgent::clearHistory() {
    std::lock_guard<std::mutex> lock(historyMutex_);
    chatHistory_.clear();
}

void EmbodiedAIAgent::setStateCallback(StateCallback callback) {
    stateCallback_ = callback;
}

void EmbodiedAIAgent::setResultCallback(ResultCallback callback) {
    resultCallback_ = callback;
}

void EmbodiedAIAgent::setState(EmbodiedAIState state) {
    state_.store(state);
    if (stateCallback_) {
        stateCallback_(state);
    }
}

void EmbodiedAIAgent::checkPendingResult() {
    if (!pendingFuture_.valid()) return;

    auto status = pendingFuture_.wait_for(std::chrono::seconds(0));
    if (status == std::future_status::ready) {
        std::string response = pendingFuture_.get();

        // 添加 AI 回复到历史
        {
            std::lock_guard<std::mutex> lock(historyMutex_);
            auto now = std::chrono::system_clock::now();
            auto time_t = std::chrono::system_clock::to_time_t(now);
            std::stringstream ss;
            ss << std::put_time(std::localtime(&time_t), "%H:%M:%S");
            chatHistory_.push_back({response, false, ss.str()});
        }

        lastResponse_ = response;
        processing_ = false;

        if (response.find("[Error]") != std::string::npos) {
            lastError_ = response;
            setState(EmbodiedAIState::Error);
        } else {
            setState(EmbodiedAIState::Idle);
        }
    }
}

} // namespace core
} // namespace hhb