先上展示效果:

(这个功能博主是直接加在我的串口助手里面的,想着做一个辅助串口助手的一个AI助手后续等博主更新把完整版的软件发出来)

AI对话实现功能:

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGroupBox>
#include <QFrame>
#include <QComboBox>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QLabel>
#include <QPushButton>
#include <QTextEdit>
#include <QNetworkAccessManager>
#include <QNetworkReply>

#include <QLineEdit>              // 必须添加
#include <QJsonDocument>          // 千帆AI JSON解析
#include <QJsonObject>
#include <QJsonArray>
#include <QDebug>                 // 如果要打印调试日志
#include <QTextEdit>
#include <QLineEdit>              // 👍 QLineEdit 你没有包含!❗ 你必须加上这个




QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private slots:
    //void scanSerialPorts();

private:
    Ui::MainWindow *ui;
    // 声明创建发送区 QGroupBox 的函数
    QGroupBox *createSendGroupBox(QWidget *parent);
    // 声明创建发送区内部 QFrame 的函数
    QFrame *createSendInnerFrame(QWidget *parent);

    QGroupBox *createConfigGroupBox(const QString &title, QWidget *parent);
    QComboBox *createComboBox(const QStringList &items, QWidget *parent);

    QGroupBox *createReceiveGroupBox(QWidget *parent);
    void setupReceiveAreaContent(QGroupBox *groupBox);

    void onDataReceived();
    void clear_Received_data();
    void readData();

    //AI
    void onSendChatClicked();
    void onDeepSeekReplyFinished();

    //AI cleck
    void onApiLoopbackTestClicked();


    QSerialPort *serialPort;
    QTextEdit *sendTextEdit;
    QComboBox *sendModeComboBox;
    QComboBox *sendEncodingComboBox;
    QPushButton *sendButton;
    QPushButton *sendClearButton;
    QGroupBox *recvGroupBox;
    QTextEdit *recvTextEdit;

    //AI
    QLineEdit *chatInput;
    QTextEdit *chatHistory;
    QNetworkAccessManager *networkManager;
    QNetworkReply *currentReply;
    QString deepseekApiKey = "sk-77677a5ba46a4b52b368ef747e2b00f6";  // 替换为你的API Key


  // QString currentPortName; // 当前选择的串口名
};


#endif // MAINWINDOW_H

mainwindow.cpp

函数构建

/*新增AI聊天框针对于解决常见的串口数据传输问题、并将输出的日志进行保存*/
              int chatAreaX = 700; // 距离左边700px开始,1000-700=300px宽
              int chatAreaWidth = 280;
              // 聊天显示框(历史记录)
              chatHistory = new QTextEdit(this);
              chatHistory->setGeometry(chatAreaX, 30, chatAreaWidth, 300);
              chatHistory->setReadOnly(true);
              chatHistory->setStyleSheet("background-color: #F5F5F5; color: black;");

              // 输入框
              chatInput = new QLineEdit(this);
              chatInput->setGeometry(chatAreaX, 340, chatAreaWidth - 80, 30);
              chatInput->setPlaceholderText("请输入问题...");

              // 发送按钮
              QPushButton *sendChatBtn = new QPushButton("发送", this);
              sendChatBtn->setGeometry(chatAreaX + chatAreaWidth - 70, 340, 60, 30);
              sendChatBtn->setStyleSheet("background-color: #2196F3; color: white;");

              networkManager = new QNetworkAccessManager(this);
              connect(sendChatBtn, &QPushButton::clicked, this, &MainWindow::onSendChatClicked);


              QPushButton *btnApiLoopTest = new QPushButton("串口助手AI测试", this);
              btnApiLoopTest->setGeometry(chatAreaX, 380, chatAreaWidth, 30);
              btnApiLoopTest->setStyleSheet("background-color: #4CAF50; color: white;");

              connect(btnApiLoopTest, &QPushButton::clicked, this, &MainWindow::onApiLoopbackTestClicked);

 三个槽函数:

//AI聊天框的槽函数

void MainWindow::onSendChatClicked()
{
    QString userText = chatInput->text().trimmed();
    if (userText.isEmpty()) {
        QMessageBox::warning(this, "提示", "输入不能为空!");
        return;
    }

    chatHistory->append("🧍你:" + userText);
    chatInput->clear();

    QJsonObject body;
    body["model"] = "deepseek-chat";

    QJsonArray messages;
    messages.append(QJsonObject{
        {"role", "user"},
        {"content", userText}
    });
    body["messages"] = messages;

    QNetworkRequest request(QUrl("https://api.deepseek.com/v1/chat/completions"));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    request.setRawHeader("Authorization", "Bearer " + deepseekApiKey.toUtf8());

    currentReply = networkManager->post(request, QJsonDocument(body).toJson());

    connect(currentReply, &QNetworkReply::finished, this, &MainWindow::onDeepSeekReplyFinished);

    qDebug() << "发送内容:" << userText;
}

void MainWindow::onDeepSeekReplyFinished()
{
    if (!currentReply) return;

    QByteArray respData = currentReply->readAll();
    currentReply->deleteLater();
    currentReply = nullptr;

    if (respData.isEmpty()) {
        chatHistory->append("⚠️ 没有返回内容");
        return;
    }

    QJsonParseError parseError;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(respData, &parseError);

    if (parseError.error != QJsonParseError::NoError) {
        chatHistory->append("❌ AI返回格式错误:" + parseError.errorString());
        qDebug() << "原始返回:" << respData;
        return;
    }

    QJsonObject obj = jsonDoc.object();
    if (obj.contains("choices")) {
        QString reply = obj["choices"].toArray()[0].toObject()
                            ["message"].toObject()["content"].toString();
        chatHistory->append("🤖 AI:" + reply);
    } else {
        chatHistory->append("❗ AI返回缺失字段");
        qDebug() << "完整返回:" << jsonDoc.toJson(QJsonDocument::Indented);
    }
}


void MainWindow::onApiLoopbackTestClicked()
{
    QString testText = "你现在叫串口助手AI";

    chatHistory->append("🧪 正在进行测试...");
    chatHistory->append("🧍你:" + testText);

    QJsonObject body;
    body["model"] = "deepseek-chat";

    QJsonArray messages;
    messages.append(QJsonObject{
        {"role", "user"},
        {"content", testText}
    });
    body["messages"] = messages;

    QNetworkRequest request(QUrl("https://api.deepseek.com/v1/chat/completions"));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    request.setRawHeader("Authorization", "Bearer " + deepseekApiKey.toUtf8());

    currentReply = networkManager->post(request, QJsonDocument(body).toJson());
    connect(currentReply, &QNetworkReply::finished, this, [=]() {
        if (!currentReply) return;

        QByteArray respData = currentReply->readAll();
        currentReply->deleteLater();
        currentReply = nullptr;

        QJsonParseError err;
        QJsonDocument jsonDoc = QJsonDocument::fromJson(respData, &err);

        if (err.error != QJsonParseError::NoError) {
            chatHistory->append("❌ 回环失败:API返回格式错误!");
            return;
        }

        QString replyText = jsonDoc["choices"].toArray()[0].toObject()
                                ["message"].toObject()["content"].toString();

        chatHistory->append("🤖 AI:" + replyText);

        if (replyText.contains("loopback", Qt::CaseInsensitive)) {
            QMessageBox::information(this, "测试通过", "✅ API回环成功,AI正常响应!");
        } else {
            QMessageBox::warning(this, "测试通过", "✅ API回环成功,AI正常响应!");
        }
    });
}

特别注意:

当出现这个错误的时候

“qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed”

是因为你使用的 Qt 在尝试与服务器建立 HTTPS 连接时,SSL/TLS 初始化失败,这是一个 环境配置问题,不是代码问题。

原因分析:Qt 使用系统或外部的 OpenSSL 库来处理 HTTPS 请求。如果没有找到合适的 OpenSSL 动态链接库,就无法初始化 TLS,因此 HTTPS 请求失败。

解决办法为:放置 OpenSSL DLL,libcrypto-1_1-x64.dll、libssl-1_1-x64.dll在你构建的工程的.exe文件的同目录下

 本仓库中的资源遵循 OpenSSL 的许可证。请在使用前仔细阅读相关许可证条款。

(因为博主用QT版本为5.14.2,所需的OpenSLL版本为1.1.1)

【下载地址】OpenSLL1.1.1版本下载

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐