Qt结合deepseek实现一个简单的Ai聊天助手

发布于:2025-08-05 ⋅ 阅读:(15) ⋅ 点赞:(0)

搭建界面

界面

在这里插入图片描述
在这里插入图片描述
运行后是这样的
在这里插入图片描述
因为我们要进行网络通信所以在.pro文件我们要加上network模块
在这里插入图片描述

代码

我们首先要根据deepseek的api的官方文档来参考
我们其实就是获取一段文字然后再发送出去 具体的格式是怎样的需要我们阅读官方文档
在这里插入图片描述
在右边有CURL我们根据这个来做参考

curl -L -X POST 'https://api.deepseek.com/chat/completions' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer 这里填写你自己的key' \
--data-raw '{
  "messages": [
    {
      "content": "You are a helpful assistant",
      "role": "system"
    },
    {
      "content": "Hi",
      "role": "user"
    }
  ],
  "model": "deepseek-chat",
  "frequency_penalty": 0,
  "max_tokens": 2048,
  "presence_penalty": 0,
  "response_format": {
    "type": "text"
  },
  "stop": null,
  "stream": false,
  "stream_options": null,
  "temperature": 1,
  "top_p": 1,
  "tools": null,
  "tool_choice": "none",
  "logprobs": false,
  "top_logprobs": null
}'

首先我们要获取这个api Key
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/24796749f380491a89806d364bac526b.png
我们把上面的的位置替换成你自己的Key
在这里插入图片描述
还有一个就是stream这里要把false改成true stream就是流的意思 如果是false服务器可能一下子发送几千字要等好长时间 改成true就会实时发送
在这里插入图片描述
在这里有两个content和role 第一个是告诉服务器的 第一个role表示你是以老师的身份回答问题什么的
下面的content表示我们要说的话 我们只需要替换第二个content里的内容就可以

客户端代码

我们是在点击发送之后呢开始运行的 所以发送按钮我们之间点击转到槽
在这里插入图片描述

接下来我们要把我们刚刚复制的格式全部设置进去

    //获取文本框内容
    QString text=ui->inputEdit->toPlainText();
    
    //发送请求对象
    QNetworkRequest request;
    request.setUrl(QUrl("https://api.deepseek.com/chat/completions"));

设置头

第一个头是本来就有的 第二三个头是自定义的

void MainWindow::on_pushButton_clicked()
{
    //获取文本框内容
    QString text=ui->inputEdit->toPlainText();

    //发送请求对象
    QNetworkRequest request;
    request.setUrl(QUrl("https://api.deepseek.com/chat/completions"));

    //设置固定头
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");
    //设置自定义的头
    request.setRawHeader("Accept","application/json");
    request.setRawHeader("Authorization","自己的密钥");
}

写json文件

我们首先写一个json数组

    QJsonArray messages;

    QJsonObject systemMsg;
    systemMsg["role"]="system";
    systemMsg["content"]="You are a helpful assistant";

    QJsonObject userMsg;
    userMsg["role"]="user";
    userMsg["content"]=text;

    messages.append(systemMsg);
    messages.append(userMsg);

此时整个messages已经完成了 接下来我们还需要实现整个json对象
不用全部添加添加部分即可

    QJsonObject requestBody;
    requestBody["messages"]=messages;
    requestBody["model"]="deepseek-chat";
    requestBody["max_tokens"]=2048;
    requestBody["stream"]=true;
    requestBody["temperature"]=1;

发送请求

在mainwindow.h里添加一个网络管理者
在这里插入图片描述
在构造函数中初始化一下

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    manager=new QNetworkAccessManager();
}

通过这个对象进行发送请求 处理数据等

    //发送请求
    QNetworkReply *reply = manager->post(request,QJsonDocument(requestBody).toJson());

    //处理数据
    connect(reply,&QNetworkReply::readyRead,this,[=]{
        qDebug()<<reply->readAll();
    });

    //接受结束了
    connect(reply,&QNetworkReply::finished,this,[=](){

    });

添加库文件

我们需要把ssleay32.dll和libeay.dll文件放入到debug文件中 这两个库文件在Qt/tool文件中可以搜索到
将 ssleay32.dll和 libeay32.dll放入 Debug 目录是为了确保 Qt 程序在调用 HTTPS 接口(如 AI API)时,能够找到 OpenSSL 库来完成安全通信。缺少这些 DLL 会导致 HTTPS 连接失败,程序无法正常调用 API。
在这里插入图片描述
在这里插入图片描述
析一下这个服务器回复的数据 我们读的时候肯会读到很多数据,我们采用每次读一行的方式 读到换行符就可 触发一次槽函数可能包含多条数据所以只要能读我们就一直读
这是简化后的 我们要提取delta的数据
在这里插入图片描述

//处理数据
    connect(reply,&QNetworkReply::readyRead,this,[=]{
        while(reply->canReadLine())
        {
            QString line=reply->readLine().trimmed();//trimmed可以去除开头和结尾的空格换行符等等
            //我们要读的数据必须是data开头的数据
            if(line.startsWith("data: "))
            {
                line.remove(0,6);//去除前面的data: 一共6个字节
                QJsonParseError error;
                
                QJsonDocument doc=QJsonDocument::fromJson(line.toUtf8(),&error);
                if(error.error==QJsonParseError::NoError)//是个json对象
                {
                    QString content=doc.object()["choices"].toArray().first()
                                        .toObject()["delta"]
                                          .toObject()["content"].toString();
                    if(!content.isEmpty())
                    {
                        ui->outputEdit->moveCursor(QTextCursor::End);
                        ui->outputEdit->insertPlainText(content);
                    }
                }
            }
        }
    });	

读到最后碰到[DONE]代表结束
在这里插入图片描述

 //接受结束了
    connect(reply,&QNetworkReply::finished,this,[=](){
        ui->outputEdit->moveCursor(QTextCursor::End);
        ui->outputEdit->insertPlainText("\n\n\n\n");

        reply->deleteLater();
    });

实现记忆化回复

在这里插入图片描述

// 当网络请求完成时,连接回复完成的信号到处理槽函数
    connect(reply, &QNetworkReply::finished, this, [=] {
        // ==== 获取AI回复内容 ====
        // 获取输出文本框中的完整对话历史
        QString fullText = ui->outputEdit->toPlainText();

        // ==== 定位对话分割位置 ====
        // 查找最后一次用户输入标记的位置(格式:-->用户输入内容)
        int lastUserInputPos = fullText.lastIndexOf("-->" + text); // text应为用户最后输入内容

        // ==== 提取AI回复 ====
        // 从用户输入结束位置开始截取AI回复内容:
        // 1. 起始位置 = 用户输入位置 + 用户输入文本长度 + 2("> "分隔符长度)
        // 2. 使用trimmed()去除首尾空白字符
        QString aiReply = fullText.mid(lastUserInputPos + text.length() + 2).trimmed();

        // ==== 保存到对话历史 ====
        if (!aiReply.isEmpty()) {
            QJsonObject aiMsg;
            aiMsg["role"] = "assistant";    // 标识消息角色为AI助手
            aiMsg["content"] = aiReply;      // 存储AI回复内容
            conversationHistory.append(aiMsg); // 将消息对象添加到对话历史数组
        }

        // ==== UI界面更新 ====
        ui->outputEdit->moveCursor(QTextCursor::End);  // 移动光标到文本框末尾
        ui->outputEdit->insertPlainText("\n\n\n\n");   // 插入换行分隔对话段落

        // ==== 资源清理 ====
        reply->deleteLater();  // 安全释放网络回复对象
    });

测试

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到