首页 > 其他分享 >手把手教你使用PySide6搭建AI聊天界面,使用DeepSeek大模型接口

手把手教你使用PySide6搭建AI聊天界面,使用DeepSeek大模型接口

时间:2025-01-18 13:58:40浏览次数:3  
标签:AI DeepSeek current PySide6 消息 message 绘制 self painter

目录


前言

随着深度学习和自然语言处理技术的不断进步,问答系统进入了一个新的发展阶段,能够更加精准地理解复杂问题,支持多种知识形式的表达与多轮对话,从而实现更智能的问答体验。传统的问答方法主要依赖规则库、信息检索技术和浅层机器学习模型,尽管在特定领域中表现较为出色且系统具有较好的解释性,但在处理复杂语义和多轮对话时却显得力不从心。近年来,随着人工智能技术的快速发展,特别是大规模模型的出现,如 chatgpt、DeepSeek 等,迅速火爆整个 AI 圈。本文将使用 PySide6 搭建 AI 聊天界面,模仿 chatgpt 聊天,能实现与 AI 对话,使用 DeepSeek 大模型接口,功能:实现实时聊天,支持流式输出,下文也会教你怎么使用源码,界面如下:

在这里插入图片描述

一、DeepSeek注册与使用

官网地址:
DeepSeek | 深度求索
api接口改到这里了,点击开发平台
在这里插入图片描述
下图应该是旧版本的网页,官网应该更新了
在这里插入图片描述
自行注册
在这里插入图片描述

登录后的样子,有免费的额度,演示应该够用了
在这里插入图片描述

参考官网文档,python 代码感觉没啥用,又不是流式输出,对于新手不是很友好,后面我通过这个接口搭建一个界面:
在这里插入图片描述

二、安装环境

安装 openai 库,命令如下:

pip install openai

在这里插入图片描述
安装 pyside6,在自己创建的虚拟环境安装即可,命令如下

pip install pyside6==6.4.2

在这里插入图片描述

三、界面设计

搭建界面前需要完成 QtDesigner 配置,参考下面的教程:

手把手教你在PyCharm配置PySide6和QtDesigner,实现python程序快速搭建可视化界面

设计好的界面如下:
在这里插入图片描述

之后转成 python 文件即可
在这里插入图片描述

四、后端实现

接下来,将重点介绍如何实现后端逻辑,包括如何处理用户输入、发送 API 请求并响应、以及如何更新 UI 界面。本文的代码实现了一个多轮对话的聊天界面,并结合 API 实现了智能回复功能。

1.QTextEdit 输入控件实现

先说一下用户输入的控件,使用的是 QTextEdit ,原本 QTextEdit 控件键盘回车键是换行,我将其修改成发送信息了,如果按下的是 Shift+Enter,则是换行;如果仅按下 Enter,提交用户输入的消息。
核心代码如下:

    def eventFilter(self, obj, event):
        if obj == self.textEdit_input and event.type() == QEvent.KeyPress:
            if event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return:
                if event.modifiers() & Qt.ShiftModifier:
                    # 按下 Shift+Enter 插入换行
                    cursor = self.textEdit_input.textCursor()
                    cursor.insertText("\n")
                    return True  # 事件被处理,避免传递到其他控件
                else:
                    # 按下 Enter 键发送消息
                    self.on_pushButton_Submit_clicked()
                    return True
        return super().eventFilter(obj, event)

2.API 请求与响应处理

将通过一个自定义的线程类 ApiThread 来实现与后端 API 的交互。用户输入的消息会通过这个线程发送请求,获取响应后再更新到界面上。on_pushButton_Submit_clicked 方法是获取用户输入的消息并启动 API 请求线程。on_api_response 方法会将响应数据显示在聊天窗口中,并根据时间戳处理消息的时间显示。核心代码如下:

    def on_pushButton_Submit_clicked(self):

        message = self.textEdit_input.toPlainText()
        self.textEdit_input.clear()
        time = str(int(QDateTime.currentDateTime().toSecsSinceEpoch()))  # 获取时间戳
        if message != "":  # 确保消息不为空
            self.updateMessageTimeDisplay(time)
            user_window = AIChatMessageWindow(self.listWidget_out.parentWidget())
            user_item = QListWidgetItem(self.listWidget_out)
            self.updateMessageDisplay(user_window, user_item, message, time, RoleType.user)

        self.current_message_window = AIChatMessageWindow(self.listWidget_out.parentWidget())
        self.current_item = QListWidgetItem(self.listWidget_out)
        # 启动API请求线程
        self.api_thread = ApiThread(message)
        self.api_thread.response_signal.connect(self.on_api_response)
        self.api_thread.start()

        self.listWidget_out.setCurrentRow(self.listWidget_out.count() - 1)

    def on_api_response(self, response):
        time = str(int(QDateTime.currentDateTime().toSecsSinceEpoch()))  # 获取时间戳

        if hasattr(self, 'current_item') and self.current_item:
            current_message_window = self.current_message_window
            current_text = current_message_window.message_text  # 获取当前显示的文本
            current_text += response
            # 更新消息显示
            self.updateMessageDisplay(current_message_window, self.current_item, current_text, time, RoleType.system)
            # 将消息列表滚动到最新的消息项
            self.listWidget_out.setCurrentRow(self.listWidget_out.count() - 1)

3.消息显示与时间显示

动态地显示消息,并根据消息的时间间隔决定是否显示时间戳。每当一条消息发送或接收到响应时,都会更新消息显示,并在合适的时机显示时间戳。updateMessageDisplay 方法根据消息的文本内容调整消息项的高度,并将消息显示在聊天窗口中。updateMessageTimeDisplay 方法用来显示时间戳,当两条消息的时间间隔超过 60 秒时,会显示时间戳。核心代码如下:

    def updateMessageDisplay(self, message_window, current_item, text, time, userType):
        message_window.setFixedWidth(self.width())  # 设置消息窗口的宽度为主窗口的宽度
        size = message_window.font_rect(text)  # 获取文本的矩形区域
        current_item.setSizeHint(QSize(self.width(), size.height()))  # 设置列表项的高度为文本高度
        message_window.setText(text, time, size, userType)
        self.listWidget_out.setItemWidget(current_item, message_window)  # 将消息添加到消息列表中

    # 处理消息的时间显示
    def updateMessageTimeDisplay(self, curMsgTime):
        if self.listWidget_out.count() > 0:
            lastItem = self.listWidget_out.item(self.listWidget_out.count() - 1)
            message_window = self.listWidget_out.itemWidget(lastItem)
            lastTime = int(message_window.message_time)  # 获取最后一条消息的时间戳
            curTime = int(curMsgTime)  # 获取当前时间戳
            show_time = (curTime - lastTime) > 60  # 如果两条消息相差超过60秒,显示时间
        else:
            show_time = True

        if show_time:
            messageTime = AIChatMessageWindow(self.listWidget_out.parentWidget())
            itemTime = QListWidgetItem(self.listWidget_out)
            size = QSize(self.width(), 40)
            messageTime.resize(size)
            itemTime.setSizeHint(size)
            messageTime.setText(curMsgTime, curMsgTime, size, RoleType.current_time)
            self.listWidget_out.setItemWidget(itemTime, messageTime)

4.实现头像绘制和文本的绘制

重点是这些代码实现,每个聊天作为一个QWidget窗口,简单来说 QListWidget 可以加载多个QWidget窗口,不过也可以通过其他组件实现,讲一下绘制代码 paintEvent ,paintEvent 是 Qt 框架中窗口和控件的自带方法,它是 QWidget 类的一个事件处理函数。所有继承自 QWidget 的控件(如 QMainWindow、QDialog、QLabel 等)都具有 paintEvent 方法,并且当需要重绘时,Qt 会自动调用这个方法。
在代码中每次窗口重绘时,会根据消息类型绘制不同的内容:

  • RoleType.system:绘制系统消息,包含左侧头像、消息框和文本。
  • RoleType.user:绘制用户消息,包含右侧头像、消息框和文本。
  • RoleType.current_time:绘制时间消息,显示当前时间。

绘制过程中,QPainter 用于绘制图形、文本等,QRect 用于定义矩形区域,QPen 设置画笔颜色。绘制步骤:

  1. 绘制头像:首先根据消息类型选择左侧或右侧的头像,确保其大小与设备的像素比例一致。
  2. 绘制消息框:为每条消息绘制一个背景框,左侧系统消息框背景为浅灰色,右侧用户消息框为蓝色。
  3. 绘制文本:根据消息内容绘制文本,如果有换行,文本会自动换行并适应消息框的宽度。
  4. 绘制时间消息:时间消息居中显示,字体较小且灰色。

paintEvent 方法全部代码如下:

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)

        # 获取 QWidget 的设备像素比(DPI 比例)
        device_pixel_ratio = self.devicePixelRatio()

        if self.message_userType == RoleType.system:  # openai信息
            # 确保头像与设备像素比一致
            pixmap = self.leftPixmap
            if pixmap.devicePixelRatio() != device_pixel_ratio:
                # 将 QPixmap 缩放为正确的 DPI 比例
                pixmap = self.leftPixmap.scaled(self.left_icon_rect.size() * device_pixel_ratio,
                                                Qt.KeepAspectRatio, Qt.SmoothTransformation)
                pixmap.setDevicePixelRatio(device_pixel_ratio)

            # 绘制左侧头像
            painter.drawPixmap(self.left_icon_rect, pixmap)

            # 绘制消息框
            col_KuangB = QColor(234, 234, 234)
            painter.setBrush(col_KuangB)
            painter.drawRoundedRect(self.left_frame_rect.adjusted(-1, -1, 1, 1), 4, 4)

            # 绘制消息框的实际背景
            col_Kuang = QColor(255, 255, 255)
            painter.setBrush(col_Kuang)
            painter.drawRoundedRect(self.left_frame_rect, 4, 4)

            # 绘制文本
            penText = QPen(QColor(51, 51, 51))  # 设置文本颜色
            painter.setPen(penText)
            option = QTextOption(Qt.AlignLeft | Qt.AlignVCenter)
            option.setWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere)  # 设置自动换行
            painter.drawText(self.left_text_rect, self.message_text, option)

        elif self.message_userType == RoleType.user:  # 用户的消息,右侧头像
            # 确保头像与设备像素比一致
            pixmap = self.rightPixmap
            if pixmap.devicePixelRatio() != device_pixel_ratio:
                # 将 QPixmap 缩放为正确的 DPI 比例
                pixmap = self.rightPixmap.scaled(self.right_icon_rect.size() * device_pixel_ratio,
                                                 Qt.KeepAspectRatio, Qt.SmoothTransformation)
                pixmap.setDevicePixelRatio(device_pixel_ratio)  # 设置设备像素比

            # 绘制右侧头像
            painter.drawPixmap(self.right_icon_rect, pixmap)

            # 绘制消息框
            col_Kuang = QColor(75, 164, 242)
            painter.setBrush(col_Kuang)
            painter.drawRoundedRect(self.right_frame_rect, 4, 4)

            # 绘制文本
            penText = QPen(Qt.white)  # 设置文本颜色为白色
            painter.setPen(penText)
            option = QTextOption(Qt.AlignLeft | Qt.AlignVCenter)
            option.setWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere)
            painter.drawText(self.right_text_rect, self.message_text, option)




        elif self.message_userType == RoleType.current_time:  # 时间消息
            penText = QPen(QColor(153, 153, 153))  # 设置时间文本的颜色
            painter.setPen(penText)
            option = QTextOption(Qt.AlignCenter)  # 时间居中显示
            option.setWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere)
            # 设置时间文本的字体
            te_font = self.font()
            te_font.setFamily("Microsoft YaHei")
            te_font.setPointSize(10)
            painter.setFont(te_font)
            painter.drawText(self.rect(), self.current_time, option)

在代码实现过程出现绘制的头像模糊,我电脑设备高分辨率会出现模糊,为了确保在不同显示设备上,使用 devicePixelRatio 方法获取当前显示设备的像素比(DPI比例)之后通过 pixmap.scaled 方法调整图像的大小,这样就可以使图像能够按照正确的设备像素比(DPI)进行缩放和显示,因此能在高分辨率显示器上显示清晰,且不会模糊。核心代码如下:

        # 获取 QWidget 的设备像素比(DPI 比例)
        device_pixel_ratio = self.devicePixelRatio()

        if self.message_userType == RoleType.system:  # openai信息
            # 确保头像与设备像素比一致
            pixmap = self.leftPixmap
            if pixmap.devicePixelRatio() != device_pixel_ratio:
                # 将 QPixmap 缩放为正确的 DPI 比例
                pixmap = self.leftPixmap.scaled(self.left_icon_rect.size() * device_pixel_ratio,
                                                Qt.KeepAspectRatio, Qt.SmoothTransformation)
                pixmap.setDevicePixelRatio(device_pixel_ratio)

            # 绘制左侧头像
            painter.drawPixmap(self.left_icon_rect, pixmap)

5.更换头像

如需更换自己头像也是很简单的,在 leftPixmap 和 rightPixmap 填入图片路径即可。
在这里插入图片描述

五、完整源码下载和使用方法

完整源码发送 AI聊天界面 关键字即可获取,自己配置一下环境即可运行起来,代码需要更换自己的 API keys,在 DeepSeek 平台创建即可,创建时候记住 keys 值,它只会出现一次
在这里插入图片描述

之后在 deepseek.py 文件中的 api_key 处的单引号里面填入你的 keys 就行
在这里插入图片描述


总结

本文到此结束,对你有帮助帮忙点个小爱心呗,完整源码发送 AI聊天界面 关键字即可获取

参考文章: Qt 学习之路】Qt5气泡式聊天框——QListWidget+QPainter实现

标签:AI,DeepSeek,current,PySide6,消息,message,绘制,self,painter
From: https://blog.csdn.net/weixin_44779079/article/details/145226517

相关文章

  • 手把手教你完成YOLOv11 PySide6目标检测界面搭建,使用Qt6设计YOLOv11检测系统,实现图片
    摘要目标检测是计算机视觉中的重要任务,广泛应用于安防监控、自动驾驶、智能家居等领域。YOLO系列模型由于其高效的检测速度和较高的准确率,成为目标检测任务的首选算法之一。本项目结合YOLOv11与PySide6,构建了一个图形化界面,便于用户进行目标检测的操作和展示,实现对图片......
  • AI 音频工具合集
    ......
  • AI 加持下的 arduino ESP32S3 GT30L32S4W 汉字显示
    AI加持下的arduinoESP32S3GT30L32S4W汉字显示程序小白,手上一块中景园1.54寸ST7789显示屏,自带GT30L32S4W汉字字库显示芯片,因为不知道怎么在arduino平台下使用硬字库一直闲置着。在网上翻阅了大量资料针对arduino平台下使用此类硬字库芯片的代码例程没有找到。......
  • 个人如何通过AI大模型变现赚钱
    1.内容创作领域自媒体写作与运营:公众号写作:可利用AI生成文章框架和部分内容,结合自己的观点和风格进行创作,吸引粉丝关注。当粉丝量达到一定规模后,通过流量主广告、品牌合作推广等方式变现。如一些情感类、职场类公众号,通过AI辅助创作优质内容,月收入可达数万元CSDN博客......
  • AI智能推广营销系统怎么用
    一、引言AI智能推广营销系统是现代企业提升营销效率和效果的重要工具。通过利用人工智能技术和大数据分析,该系统能够精准定位目标客户、制定个性化营销策略,并实现自动化营销。本文将详细介绍AI智能推广营销系统的使用方法,并特别介绍万达宝LAIDFU(来福)系统的特点和使用技巧。二、......
  • Nuxt+tailwindcss+element 零帧起手
    文章目录前言一、项目搭建二、全局样式使用(一)、动态样式引入(二)、全局样式引入(三)、tailwindcss引入使用通用引入nuxt3快捷引入三、引入elementplus前言一、项目搭建node版本需要18以上npxnuxi@latestinit<project-name>二、全局样式使用(一)、动态样式引入......
  • 强推未发表!3D图!Transformer-LSTM+NSGAII工艺参数优化、工程设计优化!
    目录效果一览基本介绍程序设计参考资料效果一览基本介绍1.Transformer-LSTM+NSGAII多目标优化算法,工艺参数优化、工程设计优化!(Matlab完整源码和数据)Transformer-LSTM模型的架构:输入层:多个变量作为输入,形成一个多维输入张量。Transformer编码器:该编码器由多个T......
  • 用Mermaid画图
    1、用Mermaid画图mermaid.mdTyporaPortable.rarmermaid.zip目录1Mermaid是什么1.1概述1.2网址官网地址:Github地址:图形图形几种图形名字节点与无名字节点设置样式:style,classDef,class,:::线条图形连线(--)及注释(%%)线条样式实线与虚线箭头实线与粗实线及箭头延长线其......
  • Agent系列(一)——利用OpenAI快速搭建简易Agent
    目录1、Agent 简介1.1Agents的核心组件1.1.1模型(Model):1.1.2工具(Tools):1.1.3编排层(OrchestrationLayer):1.2Agents的运作机制:从输入到输出 2、搭建简易的Agent 2.1模型准备2.1.1获取 api_key2.1.2获取base_url和chat_model2.2搭建Agent2.2.......
  • [ARC108F] Paint Tree
    前言复习什么的就留到下周了,顺便把格式调好现在把每日一练打了差不多今天补了一下午的\(\rm{T2}\),终于还是被码力问题击碎了,不过也还好这道题是模拟赛\(\rm{T3}\)吉司机线段树和左偏树都只能明天搞了,明天把\(\rm{C}\)打了开摆思路首先那几个\(\rm{subtask}\)......