使用C++在Qt框架下调用DeepSeek的API接口实现自己的简易桌面小助手
项目背景
随着DeepSeek的爆火,最近的DeepSeek也进行了新一轮技术的更新,为了拥抱新时代,我们也要不断学习新的知识,难的底层原理我们接触不到,简单的调用还能难住我们?
因为在网络上搜集到的资源都是用Python语言来进行调用,提供C++调用接口的教程较少,所以我就打算出一节关于整个流程的分析,供大家闲暇之余整来玩玩。废话不多说,我们直接开始:
首先:创建一个Qt项目,为项目命名,此时自动生成五个文件。
main.cpp、mainwindow.h、mainwindow.cpp、mainwindow.ui、还有一个.pro项目文件。
此外,我们再额外建一个类:DeepSeekAPI,就需要创建对应的.h和.cpp文件。
完事之后,此时的文件包括:

交互逻辑
我们先来完成页面逻辑的问题,暂不考虑接口调用的事情
在ui文件中,只需要有三个控件即可:QPlainTextEdit、QLineEdit、QPushButton。【我分别命名为:ChatBox、inputBox、btnSend】
ui设计

当然,在这块你怎么喜欢怎么设计,包括设置背景图、改变调色板、大小、布局等的自定义安排。
这不重要,重要的是每个控件的使用,但不要违背事实或习惯。
在MainWindow的主页面初始化时(构造函数中),我们应该将chatBox设置为只读状态。
ui->ChatBox->setReadOnly(true);//对话框只读
点击按钮
分析:点击按钮-》输入框文本清除-》对话框出现我的对话-》AI推理(同时屏蔽按钮的可用属性)-》推理结果显示到对话框上。OK,步骤清晰了,那么剩下的就是完善代码了:
//按钮-发送请求connect(ui->btnSend,&QPushButton::clicked,this,[&](){QString userInput = ui->inputBox->text();if(userInput.isEmpty()) return;ui->inputBox->clear();//输入框清空ui->btnSend->setEnabled(false);//禁用发送按钮,放置频繁发送请求ui->ChatBox->appendPlainText("User: " + userInput);//加入对话框startInference();//开始推理-》推理完成后的任务也交给它了});
主窗体类:
class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();void startInference();
private:Ui::MainWindow *ui;
private:DeepSeekAPI *apiClient = new DeepSeekAPI();// API客户端
};
我们只需要在主窗体添加一个startInference-开始推理的方法,然后添加一个成员:DeepSeekAPI对象指针。然后实现推理方法的逻辑就可以了:
推理逻辑
前端逻辑
推理逻辑的步骤:①采用异步通信方式,调用API的推理接口:inferMessage,将输入框的内容添加进去(如果这块使用控件文本,上面就不要将文本框清空,不然这块就获取不到内容了,不过后面不用这个东西这块知道逻辑就可以了)②异步通信时,使用同类型的监视器监视异步线程,使用setFuture(future)进行绑定监视。③建立信号槽,本次连接是将异步推理线程结束的信号与处理逻辑连接上:
接收异步线程传输的结果-》将结果添加到对话框-》发送按钮重新设置为可使用-》删除监视器
void MainWindow::startInference(){//异步推理QFuture<QString> future = apiClient->inferMessage(ui->inputBox->text());QFutureWatcher<QString> *futureWatcher = new QFutureWatcher<QString>();futureWatcher->setFuture(future);connect(futureWatcher,&QFutureWatcher<QString>::finished,this,[=](){QString result = futureWatcher->result();ui->ChatBox->appendPlainText("AI: "+result);ui->btnSend->setEnabled(true);futureWatcher->deleteLater();});
}
后端逻辑
前面都是从用户与客户端交互的角度完成的逻辑代码,但是真正的推理是后端使用网络通信进行访问DeepSeek官方的API的。
DeepSeekAPI类的定义:
class DeepSeekAPI :QObject {QString apiKey_ = "sk-**********";//这里是API_KEY,需要从DeepSeek创建获取,后面会介绍具体方法
public://Qt提供的网络管理器,方便我们进行网络通信QNetworkAccessManager* networkManager_ = new QNetworkAccessManager();DeepSeekAPI(QObject *parent = nullptr);~DeepSeekAPI();//对话推理QFuture<QString> inferMessage(const QJsonArray& messages);
};
我们看到,这里的对话推理的逻辑中传入的并不是一个单纯的文本信息,而是Json格式的信息的一个数组。那么我们回过头去把这个数组构建出来再使用。
补充一:MainWindow类内添加成员:
//对话信息格式
struct ChatMessage {QString role; // "user" 或 "assistant"QString content;
};class MainWindow{...
private:QList<ChatMessage> chatHistory; // 存储所有对话记录
};
补充二:点击按钮后的操作:
connect(... , ui->ChatBox->appendPlainText("User: " + userInput);chatHistory.append({"user",userInput});//在推理前 新加的内容-{role = "user" , content="...."}startInference(););
补充三:在异步推理之前进行上下文处理:
//上下文处理QJsonArray messageArray;for(const ChatMessage &msg:chatHistory){QJsonObject messageObj;//创建对象messageObj["role"]=msg.role;//设置键值对messageObj["content"]=msg.content;//设置键值对messageArray.append(messageObj);//添加对象}//保留近5轮对话if(chatHistory.size()>20){//由于Token限制,为避免溢出,采用截断旧消息的方式chatHistory = chatHistory.mid(chatHistory.size() - 10);}//异步推理--这时候就可以传入消息数组了QFuture<QString> future = apiClient->inferMessage(messageArray);
这时候,我们就可以进行真正的推理了:
第一步构建 请求体:
//构建请求体QJsonObject content;content["model"] = "deepseek-chat";//选取通用模型//content["model"] = "deepseek-reasoner";//R1模型content["messages"] = messages;QJsonDocument jmsg = QJsonDocument(content);//转换格式
第二步:创建网络请求头:
//异步通信接口QFutureInterface<QString> interface;interface.reportStarted(); // 标记future已开始// 确保networkManager_在主线程创建QNetworkRequest request;request.setUrl(QUrl("https://api.deepseek.com/v1/chat/completions")); //url路由request.setRawHeader("Authorization", ("Bearer " + apiKey_).toUtf8()); //apikeyrequest.setRawHeader("Content-Type", "application/json"); //数据格式 jsonrequest.setRawHeader("max_tokens","500"); //生成最大长度
request.setRawHeader("stream","false");
request.setRawHeader("temperature","1.3"); //控制多样性(0-2)越大越随机,通用对话1.3
request.setRawHeader("top_p","0.9"); /控制生成范围(0-1)不建议与temperature一块使用
request.setRawHeader("stop","\n\n");//连续空行时终止
第三步:从DeepSeek的服务器端接收请求后的反应:
QNetworkReply* reply = networkManager_->post(request, jmsg.toJson());
QObject::connect(reply, &QNetworkReply::finished, ...);
return interface.future();//返回异步通信结果
最后实现接收到请求后的逻辑:
// 连接完成信号QObject::connect(reply, &QNetworkReply::finished, [interface, reply]() mutable {if (reply->error() == QNetworkReply::NoError) {QJsonDocument doc = QJsonDocument::fromJson(reply->readAll());QString result = doc.object()["choices"].toArray().first().toObject()["message"].toObject()["content"].toString();interface.reportResult(result); // 设置结果}reply->deleteLater();interface.reportFinished(); // 标记future完成});
如果有错误,可以使用代码获取:
else {
// 错误处理
qDebug() << "错误:" << reply->errorString();
qDebug() << "HTTP 状态码:" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << "错误详情:" << reply->readAll();
interface.reportResult(QString()); // 返回空字符串表示错误
}
至此,代码模块就完成了,非常简单吧,那么剩下的就是如何获取你的APIKEY:
获取APIKEY

切记:在下面获取玩APIKey之后,必须想办法保存下来,不然后续将无法再次复制。所以复制完就直接保存到安全的位置就可以了。



然后充一块钱试试水。
效果展示

感谢大家!
相关文章:
使用C++在Qt框架下调用DeepSeek的API接口实现自己的简易桌面小助手
项目背景 随着DeepSeek的爆火,最近的DeepSeek也进行了新一轮技术的更新,为了拥抱新时代,我们也要不断学习新的知识,难的底层原理我们接触不到,简单的调用还能难住我们? 因为在网络上搜集到的资源都是用Py…...
Kotlin 协程基础知识汇总(一)
1、协程基础 Kotlin 是一门仅在标准库中提供最基本底层 API 以便其他库能够利用协程的语言。与许多其他具有类似功能的语言不同,async 与 await 在 Kotlin 中并不是关键字,甚至都不是标准库的一部分。此外,Kotlin 的挂起函数概念为异步操作提…...
Deepseek训练成AI图片生成机器人
目录 内容安全层 语义理解层 提示词工程层 图像生成层 交付系统 训练好的指令(复制就可以) 内容安全层 理论支撑:基于深度语义理解的混合过滤系统 敏感词检测:采用BERT+CRF混合模型,建立三级敏感词库(显性/隐性/文化禁忌),通过注意力机制捕捉上下文关联风险 伦…...
关于MTU的使用(TCP/IP网络下载慢可能与此有关)
参考链接:告诉你mtu值怎么设置才能网速最好! -Win7系统之家 出现网络速度被限制,可能与MTU值相关,先查看下本机的MTU winR,然后输入:netsh interface ipv4 show subinterfaces ,查看自己网络中的MTU&…...
【信息系统项目管理师】【高分范文】【历年真题】论信息系统项目的风险管理
【手机端浏览】☞【信息系统项目管理师】【高分范文】【历年真题】论信息系统项目的风险管理 2023年上半年考题 【题目】 论信息系统项目的风险管理 项目风险管理旨在识别和管理未被项目计划及其他过程所管理的风险,如果不妥善管理,这些风险可能导致项…...
Debain-12.9使用vllm部署内嵌模型/embedding
Debain-12.9使用vllm部署内嵌模型/embedding 基础环境准备下载模型部署模型注册dify模型 基础环境准备 基础环境安装 下载模型 modelscope download --model BAAI/bge-m3 --local_dir BAAI/bge-m3部署模型 vllm serve ~/ollama/BAAI/bge-m3 --served-model-name bge-m3 --t…...
香橙派连接摄像头过程
在香橙派上下载NoMachine 在控制电脑上也下载NoMachine sudo nmcli dev wifi connect "你的WiFi名称" password "你的WiFi密码" 连接上wifi后就可以在NoMachine连上香橙派了 (不过前提是香橙派有安装桌面端系统(非仅窗口端&…...
Milvus学习整理
Milvus学习整理 一、度量类型(metric_type) 二、向量字段和适用场景介绍 三、索引字段介绍 (一)、概述总结 (二)、详细说明 四、简单代码示例 (一)、建立集合和索引示例 (二)…...
MySQL事务全解析:从概念到实战
在数据库操作中,事务是一个至关重要的概念,它确保了数据的完整性和一致性。今天,就让我们深入探讨MySQL事务的方方面面,从基础概念到实际应用,全面掌握这一技能。 一、为什么需要事务 假设张三要给李四转账100元&…...
重叠构造函数 、JavaBean模式、建造者模式、Spring的隐性大手
构造函数 重叠构造函数JavaBean模式建造者模式构造Spring看起来为什么简单番外篇为什么在JavaBean中 无参构造函数是必须的呢 小结 构造函数对我来讲是很平常的一个东西,今天来谈谈新的收获。 重叠构造函数 通常我们定义好实体类后,不会特意的去调整构造…...
题单:精挑细选
题目描述 小王是公司的仓库管理员,一天,他接到了这样一个任务:从仓库中找出一根钢管。这听起来不算什么,但是这根钢管的要求可真是让他犯难了,要求如下: 1.1. 这根钢管一定要是仓库中最长的; …...
GGUF 和 llama.cpp 是什么关系
这是个非常关键的问题,咱们来细说下:GGUF 和 llama.cpp 是什么关系,它们各自干什么,如何配合工作。 🔧 一、llama.cpp 是什么? llama.cpp 是 Meta 的开源大语言模型 LLaMA(Language Model from…...
手机怎么换网络IP有什么用?操作指南与场景应用
在数字化时代,手机已经成为我们日常生活中不可或缺的一部分,无论是工作、学习还是娱乐,手机都扮演着至关重要的角色。而在手机的使用过程中,网络IP地址作为设备在互联网上的唯一标识符,其重要性和作用不容忽视。本文将…...
强化学习中的深度卷积神经网络设计与应用实例
I. 引言 强化学习(Reinforcement Learning,RL)是机器学习的一个重要分支,通过与环境的交互来学习最优策略。深度学习,特别是深度卷积神经网络(Deep Convolutional Neural Networks,DCNNs&#…...
软考程序员-操作系统基本知识核心考点和知识重点总结
以下是软考程序员考试中操作系统基本知识章节的核心考点和知识重点总结,结合历年真题和考试大纲整理而成: 一、操作系统基本概念与功能 定义与作用 操作系统是管理计算机软硬件资源的核心系统软件,负责协调程序执行、优化资源利用,…...
思源配置阿里云 OSS 踩坑记
按照正常的配置IAM,赋予OSS权限,思源笔记还是无法使用,缺少ListBuckets权限。 正常配置权限,又无法覆盖,因此需要手动配置权限。 {"Version": "1","Statement": [{"Effect":…...
科技赋能安全:慧通测控的安全带全静态性能测试
汽车的广泛普及给人们的出行带来了极大便利,但交通事故频发也成为严重的社会问题。据世界卫生组织统计,全球每年约有 135 万人死于道路交通事故,而安全带在减少事故伤亡方面起着不可替代的作用。正确使用安全带可使前排驾乘人员的死亡风险降低…...
记录修复一个推拉门滑轮
推拉门有个滑轮的固定螺丝不知什么时候掉了,也找不到,这就导致推拉门卡在轨道上。 这种滑轮在夕夕上很便宜,比哈罗单车还划算,但是现在缺的只是螺丝,如果买就会多出来一个轮… 这种螺丝比较长,大概是m4的…...
压缩壳学习
壳是什么 壳就是软件的一个保护套,防止软件被进行反编译或被轻易地修改。 其作用就是为了保护软件。 常见的大类壳有压缩壳、加密壳、VM 壳的分类。 压缩壳顾名思义就是用来减小软件的文件大小的;加密壳,通过加密软件来保护软件ÿ…...
深入理解 Linux ALSA 音频架构:从入门到驱动开发
文章目录 一、什么是 ALSA?二、ALSA 系统架构全景图核心组件详解:三、用户空间开发实战1. PCM 音频流操作流程2. 高级配置(asound.conf)四、内核驱动开发指南1. 驱动初始化模板2. DMA 缓冲区管理五、高级主题1. 插件系统原理2. 调试技巧3. 实时音频优化六、现代 ALSA 发展七…...
#13【CVPR2024】“不确定性不是敌人”:深入剖析多模态融合中的不确定性
📜 Embracing Unimodal Aleatoric Uncertainty for Robust Multimodal Fusion 本文没有源码,适合基础好的读者 🍞 1:研究背景与问题定义 🍫 1.1 多模态融合的黄金承诺与现实落差 在人工智能的迅猛发展浪潮中,多模态学习(Multimodal Learning)扮演着越来越重要的角…...
使用 QR-Code-Styling 在 Vue 3 中生成二维码
使用 QR-Code-Styling 在 Vue 3 中生成二维码 1. 前言 二维码广泛应用于网站跳转、支付、身份认证等场景。普通的二维码较为单调,而 qr-code-styling 允许我们自定义二维码的颜色、Logo、样式,使其更具个性化。本文将介绍如何在 Vue 3 Element Plus 中…...
CCF-CSP认证 202206-2寻宝!大冒险!
题目描述 思路 有一张绿化图和藏宝图,其中绿化图很大(二维数组在限定的空间内无法存储),而藏宝图是绿化图中的一部分,对于绿化图和藏宝图,左下角的坐标为(0, 0),右上角的坐标是(L, L)、(S, S)&…...
Redis项目:秒杀业务(优化)
当用户发起请求,此时会请求nginx,nginx会访问到tomcat,而tomcat中的程序,会进行串行操作,分成如下几个步骤 1、查询优惠卷 2、判断秒杀库存是否足够 3、查询订单 4、校验是否是一人一单 5、扣减库存 6、创建订单…...
《Gradio Python 客户端入门》
《Gradio Python 客户端入门》 Gradio Python 客户端使将任何 Gradio 应用程序用作 API 变得非常容易。例如,考虑这个 Hugging Face Space,它转录从麦克风录制的音频文件。 使用该库,我们可以轻松地将 Gradio 用作 API 以编程方式转录音频文…...
仿函数 VS 函数指针实现回调
前提: 本博客对比 函数指针实现回调 和 仿函数 ,突出仿函数的优势。 目的: 一个类要能够灵活的调用两个函数,essfc 和 greaterfc,分别用于比较两个整数的大小: ①:lessfc:判断 x …...
MQTT的安装和使用
MQTT的安装和使用 在物联网开发中,mqtt几乎已经成为了广大程序猿必须掌握的技术,这里小编和大家一起学习并记录一下~~ 一、安装 方式1、docker安装 官网地址 https://www.emqx.com/zh/downloads-and-install/broker获取 Docker 镜像 docker pull e…...
网络工程师考试详细介绍,讲解,备考方案
一、考试科目与形式 1. 科目1:基础知识(计算机与网络知识) - 考试形式:机考,75道选择题(含5道英文题),满分75分 - 核心内容: - 计算机系统:硬件组成&…...
ROS melodic 安装 python3 cv_bridge
有时候,我们需要处理这些兼容性问题。此处列举我的过程,以供参考 mkdir -p my_ws_py39/src cd my_ws_py39 catkin_make_isolated-DPYTHON_EXECUTABLE/usr/bin/python3 \-DPYTHON_INCLUDE_DIR/usr/include/python3.8 \-DPYTHON_LIBRARY/usr/lib/x86_64-l…...
SHELL练习01
判断一个数是奇数还是偶数 要求: 编写一个 Shell 脚本,用户输入一个整数,判断该数是奇数还是偶数,并输出结果。 [rootnode test01]# touch Determine parity.sh [rootnode test01]# vim Determine parity.sh 还有 2 个文件等待…...
