Python使用PyQt5实现与DeepSeek聊天的图形化小软件

 更新时间:2025年03月11日 10:35:55   作者:老胖闲聊  
在 PyQt5 中,菜单栏(QMenuBar)、工具栏(QToolBar)和状态栏(QStatusBar)是 QMainWindow 提供的标准控件,用于帮助用户更好地与应用程序交互,所以本文给大家介绍了Python使用PyQt5实现与DeepSeek聊天的图形化小软件,需要的朋友可以参考下

1. 导入依赖库

import sys
import requests
import json
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QTextEdit, QLineEdit, QPushButton, QLabel, QFileDialog
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtGui import QPixmap
  • sys: 用于处理 Python 的系统相关功能,例如退出程序。
  • requests: 用于发送 HTTP 请求,与 DeepSeek API 进行通信。
  • json: 用于处理 JSON 格式的数据。
  • PyQt5: 用于创建图形用户界面(GUI)。
    • QApplication: 管理应用程序的控制流和主要设置。
    • QWidget: 所有用户界面对象的基类。
    • QVBoxLayout: 垂直布局管理器,用于排列控件。
    • QTextEdit: 多行文本输入框,用于显示聊天记录。
    • QLineEdit: 单行文本输入框,用于用户输入消息。
    • QPushButton: 按钮控件,用于触发事件。
    • QLabel: 标签控件,用于显示文本或图像。
    • QFileDialog: 文件选择对话框,用于上传图像。
  • QThread: 用于创建多线程,避免阻塞主线程。
  • pyqtSignal: 用于在线程和主线程之间传递信号。
  • QPixmap: 用于加载和显示图像。

2. DeepSeek API 配置

DEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions"
DEEPSEEK_API_KEY = "your_deepseek_api_key"  # 替换为自己的 DeepSeek API Key
  • DEEPSEEK_API_URL: DeepSeek API 的端点 URL。
  • DEEPSEEK_API_KEY: DeepSeek API 密钥,用于身份验证。

3. ChatThread 类

class ChatThread(QThread):
    response_received = pyqtSignal(str)
    stream_response_received = pyqtSignal(str)

    def __init__(self, messages, stream=False):
        super().__init__()
        self.messages = messages
        self.stream = stream

    def run(self):
        headers = {
            "Authorization": f"Bearer {DEEPSEEK_API_KEY}",
            "Content-Type": "application/json"
        }

        data = {
            "model": "deepseek-chat",
            "messages": self.messages,
            "stream": self.stream
        }

        if self.stream:
            response = requests.post(DEEPSEEK_API_URL, headers=headers, json=data, stream=True)
            for line in response.iter_lines():
                if line:
                    decoded_line = line.decode('utf-8')
                    if decoded_line.startswith("data:"):
                        json_data = json.loads(decoded_line[5:])
                        if "choices" in json_data:
                            content = json_data["choices"][0]["delta"].get("content", "")
                            self.stream_response_received.emit(content)
        else:
            response = requests.post(DEEPSEEK_API_URL, headers=headers, json=data)
            if response.status_code == 200:
                json_data = response.json()
                content = json_data["choices"][0]["message"]["content"]
                self.response_received.emit(content)
            else:
                self.response_received.emit("Error: 无法从DeepSeekAPI获得响应.")

功能说明

  • ChatThread 是一个继承自 QThread 的类,用于在后台与 DeepSeek API 进行通信。
  • response_received 和 stream_response_received: 这两个信号用于将 API 的响应传递回主线程。
  • __init__ 方法:
    • 接受 messages(聊天记录)和 stream(是否启用流式输出)作为参数。
  • run 方法:
    • 发送 HTTP POST 请求到 DeepSeek API。
    • 如果启用流式输出(stream=True),则逐行读取响应并发送信号。
    • 如果禁用流式输出,则等待完整响应后发送信号。

4. ChatApp 类

class ChatApp(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.messages = []

    def initUI(self):
        self.setWindowTitle('DeepSeek Chat')
        self.setGeometry(100, 100, 600, 400)

        layout = QVBoxLayout()

        self.chat_display = QTextEdit()
        self.chat_display.setReadOnly(True)
        layout.addWidget(self.chat_display)

        self.input_box = QLineEdit()
        self.input_box.setPlaceholderText("在此留下你的千言万语...")
        layout.addWidget(self.input_box)

        self.send_button = QPushButton('发送')
        self.send_button.clicked.connect(self.send_message)
        layout.addWidget(self.send_button)

        self.image_label = QLabel()
        layout.addWidget(self.image_label)

        self.upload_image_button = QPushButton('上传图片')
        self.upload_image_button.clicked.connect(self.upload_image)
        layout.addWidget(self.upload_image_button)

        self.setLayout(layout)

功能说明

  • ChatApp 是主应用程序类,继承自 QWidget
  • __init__ 方法:
    • 初始化界面并创建一个空的消息列表 self.messages
  • initUI 方法:
    • 设置窗口标题和大小。
    • 使用 QVBoxLayout 垂直排列控件。
    • chat_display: 用于显示聊天记录的多行文本框。
    • input_box: 用于用户输入消息的单行文本框。
    • send_button: 发送消息的按钮,点击后触发 send_message 方法。
    • image_label: 用于显示上传的图像。
    • upload_image_button: 上传图像的按钮,点击后触发 upload_image 方法。

5. 核心功能方法

5.1 send_message 方法

def send_message(self):
    user_input = self.input_box.text()
    if user_input:
        self.messages.append({"role": "user", "content": user_input})
        self.chat_display.append(f"You: {user_input}")
        self.input_box.clear()

        self.chat_thread = ChatThread(self.messages, stream=True)
        self.chat_thread.stream_response_received.connect(self.update_chat_display_stream)
        self.chat_thread.start()
  • 获取用户输入的消息。
  • 将消息添加到 self.messages 列表中。
  • 在聊天显示区域显示用户的消息。
  • 清空输入框。
  • 启动 ChatThread 线程与 DeepSeek API 通信,并启用流式输出。

5.2 update_chat_display_stream 方法

def update_chat_display_stream(self, content):
    self.chat_display.moveCursor(self.chat_display.textCursor().End)
    self.chat_display.insertPlainText(content)
    self.chat_display.moveCursor(self.chat_display.textCursor().End)
  • 将 DeepSeek API 的流式响应逐字添加到聊天显示区域。
  • 确保光标始终在文本末尾,以便用户可以看到最新的内容。

5.3 upload_image 方法

def upload_image(self):
    options = QFileDialog.Options()
    file_name, _ = QFileDialog.getOpenFileName(self, "上传图片", "", "Images (*.png *.jpg *.jpeg)", options=options)
    if file_name:
        pixmap = QPixmap(file_name)
        self.image_label.setPixmap(pixmap.scaled(200, 200))
        self.messages.append({"role": "user", "content": f"Image: {file_name}"})
  • 打开文件选择对话框,允许用户选择图像文件。
  • 加载图像并显示在 image_label 中。
  • 将图像路径添加到 self.messages 列表中。

6. 主程序入口

if __name__ == '__main__':
    app = QApplication(sys.argv)
    chat_app = ChatApp()
    chat_app.show()
    sys.exit(app.exec_())
  • 创建 QApplication 实例。
  • 创建 ChatApp 实例并显示窗口。
  • 进入主事件循环,等待用户交互。

7、完整代码如下:

需要安装PyQt5和requests

pip install PyQt5 requests
import sys
import requests
import json
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QTextEdit, QLineEdit, QPushButton, QLabel, QFileDialog
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtGui import QPixmap

# DeepSeek API 配置
DEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions"
DEEPSEEK_API_KEY = "your_deepseek_api_key"  # 替换为自己的 DeepSeek API Key,去DeepSeek注册获取

class ChatThread(QThread):
    response_received = pyqtSignal(str)
    stream_response_received = pyqtSignal(str)

    def __init__(self, messages, stream=False):
        super().__init__()
        self.messages = messages
        self.stream = stream

    def run(self):
        headers = {
            "Authorization": f"Bearer {DEEPSEEK_API_KEY}",
            "Content-Type": "application/json"
        }

        data = {
            "model": "deepseek-chat",
            "messages": self.messages,
            "stream": self.stream
        }

        if self.stream:
            response = requests.post(DEEPSEEK_API_URL, headers=headers, json=data, stream=True)
            for line in response.iter_lines():
                if line:
                    decoded_line = line.decode('utf-8')
                    if decoded_line.startswith("data:"):
                        json_data = json.loads(decoded_line[5:])
                        if "choices" in json_data:
                            content = json_data["choices"][0]["delta"].get("content", "")
                            self.stream_response_received.emit(content)
        else:
            response = requests.post(DEEPSEEK_API_URL, headers=headers, json=data)
            if response.status_code == 200:
                json_data = response.json()
                content = json_data["choices"][0]["message"]["content"]
                self.response_received.emit(content)
            else:
                self.response_received.emit("Error: 无法从DeepSeekAPI获得响应.")

class ChatApp(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.messages = []

    def initUI(self):
        self.setWindowTitle('DeepSeek Chat')
        self.setGeometry(100, 100, 600, 400)

        layout = QVBoxLayout()

        self.chat_display = QTextEdit()
        self.chat_display.setReadOnly(True)
        layout.addWidget(self.chat_display)

        self.input_box = QLineEdit()
        self.input_box.setPlaceholderText("在此留下你的千言万语...")
        layout.addWidget(self.input_box)

        self.send_button = QPushButton('发送')
        self.send_button.clicked.connect(self.send_message)
        layout.addWidget(self.send_button)

        self.image_label = QLabel()
        layout.addWidget(self.image_label)

        self.upload_image_button = QPushButton('上传图片')
        self.upload_image_button.clicked.connect(self.upload_image)
        layout.addWidget(self.upload_image_button)

        self.setLayout(layout)

    def send_message(self):
        user_input = self.input_box.text()
        if user_input:
            self.messages.append({"role": "user", "content": user_input})
            self.chat_display.append(f"You: {user_input}")
            self.input_box.clear()

            self.chat_thread = ChatThread(self.messages, stream=True)
            self.chat_thread.stream_response_received.connect(self.update_chat_display_stream)
            self.chat_thread.start()

    def update_chat_display_stream(self, content):
        self.chat_display.moveCursor(self.chat_display.textCursor().End)
        self.chat_display.insertPlainText(content)
        self.chat_display.moveCursor(self.chat_display.textCursor().End)

    def upload_image(self):
        options = QFileDialog.Options()
        file_name, _ = QFileDialog.getOpenFileName(self, "上传图片", "", "Images (*.png *.jpg *.jpeg)", options=options)
        if file_name:
            pixmap = QPixmap(file_name)
            self.image_label.setPixmap(pixmap.scaled(200, 200))
            self.messages.append({"role": "user", "content": f"Image: {file_name}"})

if __name__ == '__main__':
    app = QApplication(sys.argv)
    chat_app = ChatApp()
    chat_app.show()
    sys.exit(app.exec_())

8. 总结

  • 使用 PyQt5 创建了一个简单的图形化聊天界面。
  • 通过 ChatThread 实现了与 DeepSeek API 的异步通信,支持流式和非流式输出。
  • 支持多轮对话和多模态输入(如图像上传)。
  • 代码结构清晰,易于扩展和优化。

以上就是Python使用PyQt5实现与DeepSeek聊天的图形化小软件的详细内容,更多关于Python PyQt5与DeepSeek聊天软件的资料请关注脚本之家其它相关文章!

相关文章

  • 详解Python3注释知识点

    详解Python3注释知识点

    在本篇文章里小编给大家分享了关于Python3注释的相关知识点以及用法,需要的朋友们学习下。
    2019-02-02
  • 用python实现PDF解密打印文件

    用python实现PDF解密打印文件

    大家好,本篇文章主要讲的是用python实现PDF解密打印文件,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-02-02
  • 详解Python设计模式之策略模式

    详解Python设计模式之策略模式

    这篇文章主要介绍了Python设计模式之策略模式的相关知识,文中讲解非常详细,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-06-06
  • python中os.path.exits()的坑

    python中os.path.exits()的坑

    本文主要介绍了python中os.path.exits()的坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • Python绘制多因子柱状图的实现示例

    Python绘制多因子柱状图的实现示例

    本文主要介绍了Python绘制多因子柱状图的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • Python 实现把列表中的偶数变成他的平方

    Python 实现把列表中的偶数变成他的平方

    这篇文章主要介绍了Python 实现把列表中的偶数变成他的平方,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-03-03
  • Python接口自动化测试的实现

    Python接口自动化测试的实现

    这篇文章主要介绍了Python接口自动化测试的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • Python两台电脑实现TCP通信的方法示例

    Python两台电脑实现TCP通信的方法示例

    这篇文章主要介绍了Python两台电脑实现TCP通信的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-05-05
  • 详解python中*号的用法

    详解python中*号的用法

    这篇文章主要介绍了python中*号的用法,文中通过代码给大家介绍了双星号(**)的用法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-10-10
  • 老生常谈Python startswith()函数与endswith函数

    老生常谈Python startswith()函数与endswith函数

    下面小编就为大家带来一篇老生常谈Python startswith()函数与endswith函数。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09

最新评论