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_receivedstream_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_())

7. 总结

  • 使用 PyQt5 创建了一个简单的图形化聊天界面。
  • 通过 ChatThread 实现了与 DeepSeek API 的异步通信,支持流式和非流式输出。
  • 支持多轮对话和多模态输入(如图像上传)。
  • 代码结构清晰,易于扩展和优化。
<think>好的,我现在需要帮助用户找到关于DeepSeek Web图形化界面的实现方式和示例教程。用户提到了几个引用,我需要仔细查看这些引用内容,看看是否有相关的信息。 首先看引用[1],里面提到了启动DeepSeek R1 API服务器和WebUI的命令,比如运行`python -m deepseek.api_server`和`python webui.py`。这说明确实存在一个WebUI的实现,可能用户需要的就是这个。不过需要确认这个webui.py是否是用户所需的图形界面工具。 接下来是引用[2],这里提到使用GUI方式调用Ollama API,并实现完整的GUI对话功能。虽然这里讲的是Ollama,但用户可能想知道是否DeepSeek也有类似的GUI方法。不过引用[2]中的内容主要是关于Ollama的,可能和DeepSeek的直接实现无关,但可以作为参考。 引用[3]主要讨论DeepSeek在自动化测试中的应用,生成测试用例,和图形化界面关系不大,可能暂时不需要关注这部分。 用户的需求是寻找DeepSeek相关的Web图形化工具或实现方法,所以重点应该在引用[1]提到的WebUI。需要进一步确认是否有公开的示例教程或文档。引用[1]中的命令显示可以通过运行webui.py启动Web界面,这可能是一个基于Python的Web应用,比如使用Flask或Streamlit等框架构建的。 可能需要建议用户查看DeepSeek的官方文档或GitHub仓库,寻找webui.py的具体实现。另外,引用[2]提到的GUI方法虽然针对Ollama,但或许用户可以参考其实现思路,比如使用类似的技术栈(如PyQt、Tkinter或Web前端框架)来构建自己的DeepSeek Web界面。 如果用户需要具体的示例代码,可能需要提供一个简单的WebUI实现,比如使用Flask搭建一个前端,调用DeepSeek的API。或者参考引用[1]中的命令,说明如何启动现有的WebUI。 总结,回答应该包括: 1. 引用[1]提到的启动WebUI的方法。 2. 可能的实现方式,如使用Flask、Streamlit等框架。 3. 示例代码或步骤,指导用户如何运行或构建。 4. 相关参考资料或教程链接,帮助用户进一步学习。 需要确保回答结构清晰,分步骤说明,并提供示例代码,同时正确引用提到的来源。</think>根据您的需求,DeepSeek相关Web图形化界面可通过以下两种方式实现: ### 一、基于官方API的WebUI实现(引用[1]) 1. **启动API服务端**: ```bash python -m deepseek.api_server ``` 2. **启动Web图形界面**: ```bash python webui.py ``` 该方式通过Python脚本直接启动Web服务,采用前后端分离架构,前端使用Vue.js框架,后端基于FastAPI实现[^1]。 ### 二、自定义GUI开发方案 1. **技术选型建议**: - 前端框架:Vue.js/React - 后端框架:Flask/FastAPI - 通信协议:WebSocket/HTTP 2. **核心功能实现示例(Flask版)**: ```python from flask import Flask, render_template, request import deepseek app = Flask(__name__) @app.route('/') def index(): return render_template('chat.html') @app.route('/api/chat', methods=['POST']) def chat(): prompt = request.json['prompt'] response = deepseek.generate(prompt) return {'response': response} ``` ### 三、Ollama集成方案(引用[2]) 可通过GUI框架(如PyQt)调用Ollama API: ```python import ollama from PyQt5 import QtWidgets class ChatWindow(QtWidgets.QWidget): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.text_input = QtWidgets.QLineEdit() self.send_btn = QtWidgets.QPushButton('发送') self.send_btn.clicked.connect(self.send_message) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老胖闲聊

创作不易,您的打赏是最大的鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值