我给你目前的代码#ifndef COZE_H
#define COZE_H
#include <QWidget>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonArray>
#include <QJsonObject>
#include <QString>
#include <QMap>
class QVBoxLayout;
class QHBoxLayout;
class QLineEdit;
class QTextEdit;
class QPushButton;
class QComboBox;
class QProgressBar;
class QLabel;
class coze : public QWidget
{
Q_OBJECT
public:
explicit coze(QWidget *parent = nullptr);
~coze();
void setApiCredentials(const QString& token, const QString& id);
private slots:
void onSendClicked();
void onInputFinished();
void onClearClicked();
void onHistoryClicked();
void onModelChanged(int index);
void handleCozeResponse(QNetworkReply* reply);
private:
void setupUI();
void loadSettings();
void saveSettings();
void resetInputState();
void showError(const QString& message);
void appendMessage(const QString& sender, const QString& message, bool isError = false);
void sendQueryToCoze(const QString& query);
QJsonArray convertToAdditionalMessages();
void saveConversationHistory();
void loadConversationHistory(const QString& filePath = QString());
void processStreamEvent(const QString& eventName, const QJsonObject& data);
void handleDeltaMessage(const QJsonObject& messageObj);
void handleCompletedMessage(const QJsonObject& messageObj);
void handleChatEvent(const QJsonObject& chatObj);
void loadConversationHistory();
void appendMessage(const QString& sender, const QString& message);
private:
QNetworkAccessManager *networkManager;
QString apiToken;
QString botId;
QString userId;
QString conversationId; // 新增会话ID
QString chatId; // 新增对话ID
// UI Elements
QLabel *titleLabel;
QLabel *statusLabel;
QComboBox *modelComboBox;
QTextEdit *conversationArea;
QLineEdit *inputBox;
QPushButton *sendButton;
QPushButton *clearButton;
QPushButton *historyButton;
QProgressBar *progressBar;
QJsonArray conversationHistory;
// 流式响应处理
QByteArray partialResponse;
QString currentAssistantMessageId;
QString currentAssistantContent;
};
#endif // COZE_H
#include "coze.h"
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QTextEdit>
#include <QPushButton>
#include <QComboBox>
#include <QProgressBar>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QUrl>
#include <QMessageBox>
#include <QDateTime>
#include <QDebug>
#include <QSettings>
#include <QScrollBar>
#include <QShortcut>
#include <QFont>
#include <QFile>
#include <QDir>
#include <QStandardPaths>
#include <QLabel>
#include <QRegularExpression>
#include <QListWidget>
#include <QDialog>
#include <QListWidgetItem>
#include <QUrlQuery>
// ------------------------- 构造函数 -------------------------
coze::coze(QWidget *parent)
: QWidget(parent)
, networkManager(new QNetworkAccessManager(this))
, apiToken("")
, botId("")
, userId("123456789")
, conversationId("")
, chatId("")
{
setupUI();
loadSettings();
connect(networkManager, &QNetworkAccessManager::finished,
this, &coze::handleCozeResponse);
}
// ------------------------- 析构函数 -------------------------
coze::~coze()
{
saveSettings();
}
// ------------------------- 设置API凭证 -------------------------
void coze::setApiCredentials(const QString& token, const QString& id)
{
apiToken = token;
botId = id;
saveSettings();
}
// ------------------------- 创建UI界面 -------------------------
void coze::setupUI()
{
// 主布局
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// 对话区域
conversationArea = new QTextEdit(this);
conversationArea->setReadOnly(true);
conversationArea->setFont(QFont("Arial", 12));
conversationArea->setStyleSheet("background-color: #f9f9f9; border: 1px solid #ddd;");
mainLayout->addWidget(conversationArea);
// 输入区域
QHBoxLayout *inputLayout = new QHBoxLayout();
inputBox = new QLineEdit(this);
inputBox->setPlaceholderText("输入您的问题...");
connect(inputBox, &QLineEdit::returnPressed, this, &coze::onInputFinished);
inputLayout->addWidget(inputBox);
sendButton = new QPushButton("发送", this);
connect(sendButton, &QPushButton::clicked, this, &coze::onSendClicked);
inputLayout->addWidget(sendButton);
clearButton = new QPushButton("清除", this);
connect(clearButton, &QPushButton::clicked, this, &coze::onClearClicked);
inputLayout->addWidget(clearButton);
historyButton = new QPushButton("历史", this);
connect(historyButton, &QPushButton::clicked, this, &coze::onHistoryClicked);
inputLayout->addWidget(historyButton);
mainLayout->addLayout(inputLayout);
// 模型选择
QHBoxLayout *modelLayout = new QHBoxLayout();
modelLayout->addWidget(new QLabel("模型:", this));
modelComboBox = new QComboBox(this);
modelComboBox->addItem("默认", "");
modelComboBox->addItem("GPT-4", "gpt-4");
modelComboBox->addItem("GPT-3.5", "gpt-3.5-turbo");
modelComboBox->addItem("Claude", "claude-2");
connect(modelComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &coze::onModelChanged);
modelLayout->addWidget(modelComboBox);
mainLayout->addLayout(modelLayout);
// 进度条
progressBar = new QProgressBar(this);
progressBar->setRange(0, 0); // 不确定进度
progressBar->setVisible(false);
mainLayout->addWidget(progressBar);
// 状态标签
statusLabel = new QLabel("准备就绪", this);
statusLabel->setAlignment(Qt::AlignCenter);
statusLabel->setStyleSheet("color: #666; font-size: 10pt;");
mainLayout->addWidget(statusLabel);
// 设置布局
setLayout(mainLayout);
setWindowTitle("Coze API 客户端");
resize(800, 600);
}
// ------------------------- 加载设置 -------------------------
void coze::loadSettings()
{
QSettings settings("CozeClient", "Settings");
apiToken = settings.value("apiToken", "").toString();
botId = settings.value("botId", "").toString();
userId = settings.value("userId", "123456789").toString();
conversationId = settings.value("conversationId", "").toString();
// 加载对话历史
loadConversationHistory();
}
// ------------------------- 保存设置 -------------------------
void coze::saveSettings()
{
QSettings settings("CozeClient", "Settings");
settings.setValue("apiToken", apiToken);
settings.setValue("botId", botId);
settings.setValue("userId", userId);
settings.setValue("conversationId", conversationId);
// 保存对话历史
saveConversationHistory();
}
// ------------------------- 加载对话历史 -------------------------
void coze::loadConversationHistory()
{
QSettings settings("CozeClient", "ConversationHistory");
QJsonArray historyArray = QJsonDocument::fromJson(
settings.value("history", "[]").toByteArray()
).array();
conversationHistory = historyArray;
// 在UI中显示历史
for (const QJsonValue &value : historyArray) {
QJsonObject message = value.toObject();
QString role = message["role"].toString();
QString content = message["content"].toString();
if (!content.isEmpty()) {
appendMessage(role == "user" ? "用户" : "AI", content);
}
}
}
// ------------------------- 保存对话历史 -------------------------
void coze::saveConversationHistory()
{
QSettings settings("CozeClient", "ConversationHistory");
QJsonDocument doc(conversationHistory);
settings.setValue("history", doc.toJson(QJsonDocument::Compact));
}
// ------------------------- 发送消息 -------------------------
void coze::onSendClicked()
{
QString query = inputBox->text().trimmed();
if (query.isEmpty()) {
showError("请输入问题内容");
return;
}
// 添加到对话历史(用户消息)
QJsonObject userMessage;
userMessage["role"] = "user";
userMessage["content"] = query;
userMessage["content_type"] = "text";
conversationHistory.append(userMessage);
// 更新UI
appendMessage("用户", query);
inputBox->clear();
appendMessage("AI", "正在思考,请稍候...");
// 禁用输入
inputBox->setEnabled(false);
sendButton->setEnabled(false);
progressBar->setVisible(true);
statusLabel->setText("请求发送中...");
// 发送请求
sendQueryToCoze(query);
}
// ------------------------- 输入完成(回车键) -------------------------
void coze::onInputFinished()
{
onSendClicked();
}
// ------------------------- 清除对话 -------------------------
void coze::onClearClicked()
{
conversationArea->clear();
conversationHistory = QJsonArray();
conversationId = "";
chatId = "";
saveConversationHistory();
statusLabel->setText("对话已清除");
}
// ------------------------- 显示历史记录 -------------------------
void coze::onHistoryClicked()
{
QDialog historyDialog(this);
historyDialog.setWindowTitle("对话历史");
historyDialog.resize(600, 400);
QVBoxLayout *layout = new QVBoxLayout(&historyDialog);
QListWidget *historyList = new QListWidget(&historyDialog);
for (const QJsonValue &value : conversationHistory) {
QJsonObject message = value.toObject();
QString role = message["role"].toString();
QString content = message["content"].toString();
if (!content.isEmpty()) {
QListWidgetItem *item = new QListWidgetItem(
QString("%1: %2").arg(role == "user" ? "用户" : "AI").arg(content)
);
historyList->addItem(item);
}
}
layout->addWidget(historyList);
historyDialog.exec();
}
// ------------------------- 模型改变 -------------------------
void coze::onModelChanged(int index)
{
Q_UNUSED(index);
// 可以添加模型切换后的处理逻辑
}
// ------------------------- 转换对话历史为additional_messages格式 -------------------------
QJsonArray coze::convertToAdditionalMessages()
{
QJsonArray additionalMessages;
// 只保留最近的5条消息(避免上下文过长)
int startIndex = qMax(0, conversationHistory.size() - 5);
for (int i = startIndex; i < conversationHistory.size(); i++) {
QJsonObject message = conversationHistory[i].toObject();
QJsonObject additionalMessage;
additionalMessage["role"] = message["role"];
additionalMessage["content"] = message["content"];
additionalMessage["content_type"] = message["content_type"];
additionalMessages.append(additionalMessage);
}
return additionalMessages;
}
// ------------------------- 发送请求到Coze API -------------------------
void coze::sendQueryToCoze(const QString& query)
{
if (apiToken.isEmpty() || botId.isEmpty()) {
showError("API凭证未设置,请先配置API密钥");
resetInputState();
return;
}
QNetworkRequest request;
QUrl url("https://api.coze.cn/v3/chat");
// 添加会话ID查询参数
if (!conversationId.isEmpty()) {
QUrlQuery urlQuery;
urlQuery.addQueryItem("conversation_id", conversationId);
url.setQuery(urlQuery);
}
request.setUrl(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", ("Bearer " + apiToken).toUtf8());
// 构建请求体
QJsonObject requestBody;
requestBody["bot_id"] = botId;
requestBody["user_id"] = userId;
requestBody["stream"] = false; // 禁用流式响应
requestBody["auto_save_history"] = true;
// 转换对话历史
QJsonArray additionalMessages = convertToAdditionalMessages();
requestBody["additional_messages"] = additionalMessages;
// 添加模型参数
QString model = modelComboBox->currentData().toString();
if (!model.isEmpty()) {
requestBody["model"] = model;
}
// 调试输出请求信息
qDebug() << "Authorization Header:" << ("Bearer " + apiToken);
qDebug() << "Request URL:" << request.url().toString();
QJsonDocument reqDoc(requestBody);
qDebug() << "Request Body:" << reqDoc.toJson(QJsonDocument::Indented);
// 发送POST请求
networkManager->post(request, reqDoc.toJson());
}
// ------------------------- 处理API响应 -------------------------
void coze::handleCozeResponse(QNetworkReply* reply)
{
if (reply->error() != QNetworkReply::NoError) {
showError("网络错误: " + reply->errorString());
resetInputState();
reply->deleteLater();
return;
}
QByteArray responseData = reply->readAll();
reply->deleteLater();
// 调试输出原始响应
qDebug() << "API Response:" << QString(responseData);
// 解析完整响应
QJsonParseError parseError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData, &parseError);
if (parseError.error != QJsonParseError::NoError) {
showError("JSON解析错误: " + parseError.errorString());
resetInputState();
return;
}
if (!jsonDoc.isObject()) {
showError("API返回格式错误");
resetInputState();
return;
}
QJsonObject responseObj = jsonDoc.object();
// 检查API状态码
if (responseObj.contains("code")) {
int code = responseObj["code"].toInt();
if (code != 0) {
QString errorMsg = responseObj["msg"].toString("未知错误");
showError(QString("API错误 [%1]: %2").arg(code).arg(errorMsg));
resetInputState();
return;
}
}
// 检查data字段
if (!responseObj.contains("data")) {
showError("API响应缺少data字段");
resetInputState();
return;
}
QJsonObject dataObj = responseObj["data"].toObject();
// 获取完整消息内容
QString aiResponse = "";
if (dataObj.contains("messages")) {
QJsonArray messages = dataObj["messages"].toArray();
for (const QJsonValue &message : messages) {
QJsonObject msgObj = message.toObject();
if (msgObj["role"].toString() == "assistant" &&
msgObj["type"].toString() == "answer") {
aiResponse = msgObj["content"].toString();
break;
}
}
}
// 更新会话ID
if (dataObj.contains("conversation_id")) {
conversationId = dataObj["conversation_id"].toString();
qDebug() << "更新会话ID:" << conversationId;
}
// 更新对话ID
if (dataObj.contains("id")) {
chatId = dataObj["id"].toString();
qDebug() << "更新对话ID:" << chatId;
}
// 移除"正在思考"消息
QString lastHtml = conversationArea->toHtml();
if (lastHtml.contains("正在思考")) {
lastHtml.replace("<b>AI:</b> 正在思考,请稍候...<br>", "");
conversationArea->setHtml(lastHtml);
}
// 添加完整的AI响应
if (!aiResponse.isEmpty()) {
appendMessage("AI", aiResponse);
// 添加到对话历史
QJsonObject aiMessage;
aiMessage["role"] = "assistant";
aiMessage["content"] = aiResponse;
conversationHistory.append(aiMessage);
// 保存对话历史
saveConversationHistory();
statusLabel->setText("响应接收成功");
} else {
showError("未收到有效的AI响应");
}
resetInputState();
}
// ------------------------- 添加消息到对话区域 -------------------------
void coze::appendMessage(const QString& sender, const QString& message)
{
QString formattedMessage = QString("<b>%1:</b> %2<br>").arg(sender).arg(message);
conversationArea->append(formattedMessage);
// 滚动到底部
QScrollBar *scrollbar = conversationArea->verticalScrollBar();
scrollbar->setValue(scrollbar->maximum());
}
// ------------------------- 显示错误消息 -------------------------
void coze::showError(const QString& error)
{
statusLabel->setText("<span style='color:red;'>错误: " + error + "</span>");
QMessageBox::critical(this, "错误", error);
}
// ------------------------- 重置输入状态 -------------------------
void coze::resetInputState()
{
inputBox->setEnabled(true);
sendButton->setEnabled(true);
progressBar->setVisible(false);
inputBox->setFocus();
}
其中loadConversationHistory(); appendMessage("AI", aiResponse);有问题修改下