Ollama 本地GUI客户端:为DeepSeek用户量身定制的智能模型管理与交互工具

news2025/2/24 0:40:13

Ollama 本地GUI客户端:为DeepSeek用户量身定制的智能模型管理与交互工具

相关资源文件已经打包成EXE文件,可双击直接运行程序,且文章末尾已附上相关源码,以供大家学习交流,博主主页还有更多Python相关程序案例,秉着开源精神的想法,望大家喜欢,点个关注不迷路!!!

1. 简介:

在人工智能领域,如何高效地管理、下载和与模型进行交互是每个开发者面临的挑战。DeepSeek:Ollama 本地客户端 是一款专为开发者设计的工具,它使得智能模型的管理和交互变得前所未有的简单与高效。无论是下载本地模型,还是实时与 AI 模型互动,DeepSeek 都能够提供直观、流畅的用户体验,助力开发者在人工智能的世界中快速前行。

为了更便捷地使用DeepSeek-R1并进行本地部署,我安装了官方的ollama软件并通过命令行进行操作。然而,由于命令行操作的使用习惯问题,我决定开发一个简单的图形客户端来简化这一过程。该图形客户端的使用需要先安装官方的ollama软件,安装完成后即可通过该客户端进行操作,从而提供了一个更为直观和易用的图形化界面,减少了对命令行的依赖。

具体来说,用户需要访问ollama官网下载并安装ollama软件,之后运行我开发的图形客户端(ollama_gui)。通过这个客户端,用户可以更加轻松地进行操作,不需要直接通过命令行输入复杂的指令。这一做法大大提升了使用的便捷性和效率。

2. 功能亮点:

1. 简洁直观的用户界面

采用 Tkinter 开发的图形界面,用户可以轻松地管理模型,进行下载、删除等操作,完全不需要依赖复杂的命令行操作。通过简单的点击即可完成所有操作,适合各类开发者使用。

2. 全面的模型管理功能

下载模型: DeepSeek 支持用户从 Ollama API 下载所需的模型,下载进度条会实时更新,用户可以清晰地看到下载进度和速度。
删除模型: 支持一键删除本地模型,保持系统整洁,避免存储空间的浪费。
实时智能对话功能
用户选择模型后,能够直接向模型发送问题并获得实时反馈。对话内容在聊天框中即时显示,支持多轮交互,开发者可以迅速获取所需答案,提升工作效率。

3. 下载速度与进度监控

在下载过程中,DeepSeek 会实时显示下载的速度和总进度。无论模型的大小如何,用户都能实时了解进度,并根据反馈调整操作,提升体验。

4. 代码块高亮与一键复制

响应中的代码块会自动高亮显示,用户可直接复制代码,方便二次使用。无论是复制单段代码,还是复制整个对话记录,DeepSeek 都能提供简洁的操作方式。

5. 灵活的文本交互功能

聊天框和输入框都支持直观的文本操作,用户可以右键点击复制或粘贴内容,提升交互流畅度。此外,聊天内容中的代码块也能轻松复制,方便进行后续处理。

3.运行效果:

原CMD窗口界面:–>>>>

在这里插入图片描述

GUI客户端交互界面–>>>>

在这里插入图片描述

4. 总结:

Ollama 本地客户端 是一款针对开发者的强大工具,它不仅提供了易于操作的图形界面,还集成了强大的模型管理与交互功能。通过这款工具,开发者能够轻松获取、管理并与本地模型进行高效互动。对于那些希望简化 AI 模型操作、提升开发效率的用户来说,这款客户端无疑是一个值得尝试的利器。

随着人工智能技术的不断发展,Ollama 本地客户端将继续更新和优化,带来更多的功能和更好的用户体验。无论是新手开发者,还是资深专家,都能在这款工具中找到适合自己的功能,提升工作效率,专注于更具创意的开发工作。

5. 相关源码:

import tkinter as tk
from tkinter import ttk, messagebox
import requests
import threading
import json
import webbrowser
from tkinter import scrolledtext
import time
import tkinter.font as font
 
# Ollama API 地址
OLLAMA_API_URL = "http://localhost:11434/api"
 
# 定义颜色常量,使用多彩颜色方案
BG_COLOR = "#f5f5f5"  # 背景色
FG_COLOR = "#333333"  # 前景色
BUTTON_BG_COLORS = ["#00C2FE", "#6CE264", "#FF3A48", "#FF8A30","#84BDFE"]  # 按钮背景色数组
BUTTON_HOVER_BG_COLORS = ["#0087B1", "#1E7F18", "#B7000D", "#BE5200","#0059BE"]  # 按钮悬停背景色数组
BUTTON_FG_COLOR = "white"  # 按钮前景色
LABEL_BG_COLOR = "#e0e0e0"  # 标签背景色
CODE_BG_COLOR = "#f8f9fa"  # 代码块背景色
 
 
class OllamaClient:
    def __init__(self, root):
        self.root = root
        self.root.title("Ollama GUI 客户端")
        self.root.configure(bg=BG_COLOR)
         
         
        # 使窗口在桌面居中
        self.center_window()
 
        # 创建界面组件
        self.create_widgets()
        # 初始化模型列表
        self.update_model_list()
 
        # 下载取消标志位
        self.cancel_download = False
 
        # 关闭程序标志位
        self.cancel_APP = False
 
        # 绑定窗口关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)
 
    def center_window(self):
        # 获取屏幕宽度和高度
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
 
        # 窗口宽度和高度
        window_width = 800
        window_height = 600
 
        # 计算窗口左上角的坐标
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
 
        # 设置窗口的位置和大小
        self.root.geometry(f"{window_width}x{window_height}+{x}+{y}")
 
    def create_widgets(self):
        # 使用 grid 布局管理器
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(1, weight=1)
 
        # 顶部框架,用于放置模型选择和下载相关组件
        top_frame = tk.Frame(self.root, bg=BG_COLOR)
        top_frame.grid(row=0, column=0, padx=10, pady=10, sticky="ew")
        top_frame.columnconfigure(0, weight=1)
 
        # 模型选择下拉框
        self.model_combobox = ttk.Combobox(top_frame, background=LABEL_BG_COLOR)
        self.model_combobox.grid(row=0, column=0, padx=10, sticky="w")
 
        # 打开模型库按钮
        open_library_button = tk.Button(top_frame, text="打开模型库", command=self.open_model_library,
                                        bg=BUTTON_BG_COLORS[0], fg=BUTTON_FG_COLOR,width=10, height=1)
        open_library_button.grid(row=0, column=1, padx=10)
        open_library_button.bind("<Enter>", lambda e: e.widget.config(bg=BUTTON_HOVER_BG_COLORS[0]))
        open_library_button.bind("<Leave>", lambda e: e.widget.config(bg=BUTTON_BG_COLORS[0]))
 
        # 下载模型按钮
        self.download_button = tk.Button(top_frame, text="下载模型", command=self.download_model,
                                         bg=BUTTON_BG_COLORS[1], fg=BUTTON_FG_COLOR,width=10, height=1)
        self.download_button.grid(row=0, column=2, padx=10)
        self.download_button.bind("<Enter>", lambda e: e.widget.config(bg=BUTTON_HOVER_BG_COLORS[1]))
        self.download_button.bind("<Leave>", lambda e: e.widget.config(bg=BUTTON_BG_COLORS[1]))
 
        # 删除模型按钮
        self.delete_button = tk.Button(top_frame, text="删除模型", command=self.delete_model,
                                       bg=BUTTON_BG_COLORS[2], fg=BUTTON_FG_COLOR,width=10, height=1)
        self.delete_button.grid(row=0, column=3, padx=10)
        self.delete_button.bind("<Enter>", lambda e: e.widget.config(bg=BUTTON_HOVER_BG_COLORS[2]))
        self.delete_button.bind("<Leave>", lambda e: e.widget.config(bg=BUTTON_BG_COLORS[2]))
 
        # 下载进度条及相关信息框架
        self.download_frame = tk.Frame(self.root, bg=BG_COLOR)
        self.download_frame.grid(row=2, column=0, padx=10, pady=5, sticky="ew")
        self.download_frame.grid_forget()
 
        self.download_progress = ttk.Progressbar(self.download_frame, orient="horizontal", length=300, mode="determinate")
        self.download_progress.pack(side=tk.LEFT, padx=10)
 
        self.download_info_label = tk.Label(self.download_frame, text="", bg=LABEL_BG_COLOR, fg=FG_COLOR)
        self.download_info_label.pack(side=tk.LEFT, padx=10)
 
        # 创建字体对象
        title_font = font.Font(family="黑体", size=12)
 
        # 聊天记录显示框,使用 scrolledtext 增加滚动条
        self.chat_text = scrolledtext.ScrolledText(self.root, width=80, height=20, bg=LABEL_BG_COLOR, fg=FG_COLOR)
        self.chat_text.grid(row=1, column=0, padx=10, pady=10, sticky="nsew")
        self.chat_text.bind("<Button-3>", self.show_chat_context_menu)
        self.chat_text.tag_configure("title", font=title_font)
        self.chat_text.tag_configure("code", background=CODE_BG_COLOR)
 
        # 输入框使用 scrolledtext
        self.input_text = scrolledtext.ScrolledText(self.root, width=80, height=5, bg=LABEL_BG_COLOR, fg=FG_COLOR)
        self.input_text.grid(row=3, column=0, padx=10, pady=10, sticky="ew")
        self.input_text.bind("<Button-3>", self.show_input_context_menu)
         
        # 创建一个新的框架来放置发送按钮和清除按钮
        button_frame = tk.Frame(self.root, bg=BG_COLOR)
        button_frame.grid(row=4, column=0, padx=10, pady=10, sticky="e")
 
        # 发送按钮
        self.send_button = tk.Button(button_frame, text="发送", command=self.send_message,
                                     bg=BUTTON_BG_COLORS[3], fg=BUTTON_FG_COLOR,width=10, height=1)
        self.send_button.grid(row=0, column=0, padx=10)
        self.send_button.bind("<Enter>", lambda e: e.widget.config(bg=BUTTON_HOVER_BG_COLORS[3]))
        self.send_button.bind("<Leave>", lambda e: e.widget.config(bg=BUTTON_BG_COLORS[3]))
 
        # 清空聊天记录按钮
        self.clear_button = tk.Button(button_frame, text="清空聊天", command=self.clear_chat,
                                      bg=BUTTON_BG_COLORS[4], fg=BUTTON_FG_COLOR,width=10, height=1)
        self.clear_button.grid(row=0, column=1, padx=10)
        self.clear_button.bind("<Enter>", lambda e: e.widget.config(bg=BUTTON_HOVER_BG_COLORS[4]))
        self.clear_button.bind("<Leave>", lambda e: e.widget.config(bg=BUTTON_BG_COLORS[4]))
 
    def update_model_list(self):
        try:
            response = requests.get(f"{OLLAMA_API_URL}/tags")
            if response.status_code == 200:
                models = [model["name"] for model in response.json().get("models", [])]
                self.model_combobox['values'] = models
                if models:
                    self.model_combobox.set(models[0])
        except Exception as e:
            messagebox.showerror("错误", f"获取模型列表失败: {str(e)}")
 
    def open_model_library(self):
        webbrowser.open("https://ollama.com/library")
 
    def download_model(self):
        # 创建自定义输入对话框并居中显示
        dialog = tk.Toplevel(self.root)
        dialog.title("下载模型")
        dialog.geometry("300x150")
        dialog.configure(bg=BG_COLOR)
        dialog.attributes("-topmost", True)
        # 使对话框居中
        dialog.update_idletasks()
        width = dialog.winfo_width()
        height = dialog.winfo_height()
        x = (self.root.winfo_screenwidth() // 2) - (width // 2)
        y = (self.root.winfo_screenheight() // 2) - (height // 2)
        dialog.geometry(f"{width}x{height}+{x}+{y}")
 
        tk.Label(dialog, text="请输入要下载的模型名称:", bg=BG_COLOR, fg=FG_COLOR).pack(pady=20)
        model_entry = tk.Entry(dialog, bg=LABEL_BG_COLOR, fg=FG_COLOR)
        model_entry.pack(pady=10)
 
     
 
        def start_download():
            model_name = model_entry.get()
            if model_name:
                dialog.destroy()
                self.download_frame.grid()
                self.cancel_download = False  # 重置取消标志位
                threading.Thread(target=self._download_model_thread, args=(model_name,)).start()
 
        download_btn = tk.Button(dialog, text="开始下载", command=start_download,
                                 bg=BUTTON_BG_COLORS[1], fg=BUTTON_FG_COLOR)
        download_btn.pack(pady=10)
        download_btn.bind("<Enter>", lambda e: e.widget.config(bg=BUTTON_HOVER_BG_COLORS[1]))
        download_btn.bind("<Leave>", lambda e: e.widget.config(bg=BUTTON_BG_COLORS[1]))
 
    def on_close(self):
        # 设置下载取消标志
        self.cancel_download = True
        self.cancel_APP = True
        # 关闭主窗口
        self.root.destroy()
    def _download_model_thread(self, model_name):
        try:
            data = {
                "name": model_name
            }
            response = requests.post(f"{OLLAMA_API_URL}/pull", json=data, stream=True)
            if response.status_code == 200:
                total_size = None
                downloaded_size = 0
                start_time = time.time()
                prev_downloaded = 0
                prev_progress = 0
                prev_time = start_time
                self.download_progress['value'] = 0
                for line in response.iter_lines():
                    if self.cancel_download:  # 检查取消标志位
                        messagebox.showinfo("提示", "下载已取消")
                        break
                    if line:
                        try:
                            chunk = line.decode('utf-8')
                            data = json.loads(chunk)
                            if 'total' in data:
                                total_size = data['total']
                            if 'completed' in data:
                                downloaded_size = data['completed']
                                if total_size:
                                    progress = (downloaded_size / total_size) * 100
                                    current_time = time.time()
                                    # 设置进度更新阈值和时间间隔
                                    if progress - prev_progress >= 1 or current_time - prev_time >= 0.5:
                                        elapsed_time = current_time - start_time
                                        if elapsed_time > 0:
                                            speed = (downloaded_size - prev_downloaded) / elapsed_time / 1024
                                            # 根据文件大小动态调整单位
                                            if total_size / (1024 * 1024 * 1024) >= 1:
                                                total_size_gb = total_size / (1024 * 1024 * 1024)
                                                downloaded_size_gb = downloaded_size / (1024 * 1024 * 1024)
                                                info_text = f"速度: {speed:.2f} KB/s, 已下载: {downloaded_size_gb:.2f} GB, 总大小: {total_size_gb:.2f} GB, 进度: {progress:.2f}%"
                                            else:
                                                total_size_kb = total_size / 1024
                                                downloaded_size_kb = downloaded_size / 1024
                                                info_text = f"速度: {speed:.2f} KB/s, 已下载: {downloaded_size_kb:.2f} KB, 总大小: {total_size_kb:.2f} KB, 进度: {progress:.2f}%"
                                            self.download_info_label.config(text=info_text)
                                            prev_downloaded = downloaded_size
                                        self.download_progress['value'] = progress
                                        self.root.update_idletasks()
                                        prev_progress = progress
                                        prev_time = current_time
                        except Exception as e:
                            messagebox.showerror("错误", f"解析下载进度出错: {str(e)}")
                if not self.cancel_download:
                    messagebox.showinfo("成功", "模型下载成功")
                    self.update_model_list()
            else:
                messagebox.showerror("错误", f"模型下载失败: {response.text}")
        except Exception as e:
            messagebox.showerror("错误", f"发生异常: {str(e)}")
        finally:
            self.download_frame.grid_forget()
 
    def delete_model(self):
        model_name = self.model_combobox.get()
        if model_name:
            try:
                data = {
                    "model": model_name
                }
                print(f"尝试删除模型: {model_name}")  # 打印要删除的模型名称
                response = requests.delete(f"{OLLAMA_API_URL}/delete", json=data)
                print(f"请求响应状态码: {response.status_code}")  # 打印响应状态码
                print(f"请求响应内容: {response.text}")  # 打印响应内容
                if response.status_code == 200:
                    messagebox.showinfo("成功", "模型删除成功")
                    self.update_model_list()
                else:
                    messagebox.showerror("错误", f"模型删除失败: {response.text}")
            except Exception as e:
                messagebox.showerror("错误", f"发生异常: {str(e)}")
        else:
            messagebox.showwarning("警告", "请选择要删除的模型")
 
 
# 在 OllamaClient 类中修改 send_message 方法
    def send_message(self):
        message = self.input_text.get(1.0, tk.END).strip()
        if message:
            model_name = self.model_combobox.get()
            if model_name:
            # 使用线程来执行推理任务
                threading.Thread(target=self._send_message_thread, args=(message, model_name)).start()
            else:
                messagebox.showwarning("警告", "请选择要使用的模型")
 
    def _send_message_thread(self, message, model_name):
        try:
            start_time = time.time()  # 记录开始时间
            data = {
                "model": model_name,
                "prompt": message
            }
        # 使用 stream=True 开启流式响应
            response = requests.post(f"{OLLAMA_API_URL}/generate", json=data, stream=True)
            if response.status_code == 200:
                 
                self.chat_text.insert(tk.END, f"问题: {message}\n","title")
                end_time = time.time()  # 记录结束时间
                inference_time = end_time - start_time  # 计算推理时间
                self.chat_text.insert(tk.END, f"\n思考时间: {inference_time:.2f} 秒\n",)
                self.root.update_idletasks()  # 更新界面
                full_response = ""
                chunk_count = 0
                for line in response.iter_lines():
                    if self.cancel_APP:  # 检查取消标志位
                        break
                    if line:
                        try:
                            chunk = line.decode('utf-8')
                            data = json.loads(chunk)
                            part = data.get("response", "")
                            part = part.replace("<think>", "").replace("</think>", "")
                            full_response += part
                            self.chat_text.insert(tk.END, part)
                            chunk_count += 1
                            if chunk_count % 10 == 0:  # 每接收 10 个数据块更新一次界面
                                self.root.update_idletasks()
                        except Exception as e:
                            messagebox.showerror("错误", f"解析响应数据出错: {str(e)}")
                self.root.update_idletasks()  # 确保最后一次更新界面
                self.input_text.delete(1.0, tk.END)
                self.highlight_code()
            else:
                messagebox.showerror("错误", f"请求失败: {response.text}")
        except Exception as e:
            messagebox.showerror("错误", f"发生异常: {str(e)}")
 
    def clear_chat(self):
        self.chat_text.delete(1.0, tk.END)
 
    def show_chat_context_menu(self, event):
        context_menu = tk.Menu(self.root, tearoff=0)
        context_menu.add_command(label="复制", command=lambda: self.copy_chat_text())
 
        # 获取点击位置的标签
        tags = self.chat_text.tag_names(tk.CURRENT)
        if "code" in tags:
            context_menu.add_command(label="复制当前代码块", command=lambda: self.copy_current_code_block())
 
        context_menu.add_command(label="复制所有代码块", command=lambda: self.copy_code_block())
        context_menu.post(event.x_root, event.y_root)
 
    def copy_chat_text(self):
        selected_text = self.chat_text.get(tk.SEL_FIRST, tk.SEL_LAST)
        if selected_text:
            self.root.clipboard_clear()
            self.root.clipboard_append(selected_text)
 
    def copy_code_block(self):
        tag_ranges = self.chat_text.tag_ranges("code")
        if tag_ranges:
            code_text = ""
            for i in range(0, len(tag_ranges), 2):
                start = tag_ranges[i]
                end = tag_ranges[i + 1]
                code_text += self.chat_text.get(start, end)
            self.root.clipboard_clear()
            self.root.clipboard_append(code_text)
 
    def copy_current_code_block(self):
        tag_ranges = self.chat_text.tag_ranges("code")
        current_pos = self.chat_text.index(tk.CURRENT)
        print(f"当前鼠标位置: {current_pos}")  # 打印当前鼠标位置用于调试
        code_text = None  # 初始化 code_text 为 None
        for i in range(0, len(tag_ranges), 2):
            start = str(tag_ranges[i])  # 将 _tkinter.Tcl_Obj 转换为字符串
            end = str(tag_ranges[i + 1])  # 将 _tkinter.Tcl_Obj 转换为字符串
            print(f"代码块范围: {start} - {end}")  # 打印代码块范围用于调试
            if start <= current_pos <= end:
                code_text = self.chat_text.get(start, end)
                break
        if code_text is not None:
            try:
                self.root.clipboard_clear()
                self.root.clipboard_append(code_text)
                print("代码块复制成功")
            except tk.TclError as e:
                print(f"剪贴板操作失败: {e}")
        else:
            print("未找到包含当前位置的代码块")
 
    def show_input_context_menu(self, event):
        context_menu = tk.Menu(self.root, tearoff=0)
        context_menu.add_command(label="复制", command=lambda: self.copy_input_text())
        context_menu.add_command(label="粘贴", command=lambda: self.paste_input_text())
        context_menu.post(event.x_root, event.y_root)
 
    def copy_input_text(self):
        selected_text = self.input_text.get(tk.SEL_FIRST, tk.SEL_LAST)
        if selected_text:
            self.root.clipboard_clear()
            self.root.clipboard_append(selected_text)
 
    def paste_input_text(self):
        clipboard_text = self.root.clipboard_get()
        if clipboard_text:
            self.input_text.insert(tk.INSERT, clipboard_text)
 
    def highlight_code(self):
        content = self.chat_text.get(1.0, tk.END)
        start_index = 0
        while True:
            start = content.find("===", start_index)
            if start == -1:
                break
            end = content.find("===", start + 3)
            if end == -1:
                break
            start_tag = f"1.0+{start}c"
            end_tag = f"1.0+{end + 3}c"
            self.chat_text.tag_add("code", start_tag, end_tag)
            print(f"代码块范围: {start_tag} - {end_tag}")  # 调试信息,打印代码块范围
            start_index = end + 3
 
 
if __name__ == "__main__":
    root = tk.Tk()
    client = OllamaClient(root)
    root.mainloop()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2304136.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于SSM的《计算机网络》题库管理系统(源码+lw+部署文档+讲解),源码可白嫖!

摘 要 《计算机网络》题库管理系统是一种新颖的考试管理模式&#xff0c;因为系统是用Java技术进行开发。系统分为三个用户进行登录并操作&#xff0c;分别是管理员、教师和学生。教师在系统后台新增试题和试卷&#xff0c;学生进行在线考试&#xff0c;还能对考生记录、错题…

对Revit事务机制的一些推测

什么是事务机制 首先&#xff0c;什么是事务机制。软件事务机制是指一种在软件系统中用于管理一系列操作的方法&#xff0c;这些操作要么全部成功完成&#xff0c;要么全部失败&#xff0c;不会出现部分完成的情况。事务机制确保了数据的一致性和完整性&#xff0c;特别是在并…

《微软量子芯片:开启量子计算新纪元》:此文为AI自动生成

量子计算的神秘面纱 在科技飞速发展的今天,量子计算作为前沿领域,正逐渐走进大众的视野。它宛如一把神秘的钥匙,有望开启未来科技变革的大门,而微软量子芯片则是这把钥匙上一颗璀璨的明珠。 量子计算,简单来说,是一种遵循量子力学规律调控量子信息单元进行计算的新型计算…

SpringBoot+Vue+Mysql苍穹外卖

一.项目介绍 1.项目内容 苍穹外卖是一款为大学学子设计的校园外卖服务软件&#xff0c;旨在提供便捷的食堂外卖送至宿舍的服务。该软件包含系统管理后台和用户端&#xff08;微信小程序&#xff09;两部分&#xff0c;支持在线浏览菜品、添加购物车、下单等功能&#xff0c;并…

网络运维学习笔记 018 HCIA-Datacom综合实验02

文章目录 综合实验2sw3&#xff1a;sw4&#xff1a;gw&#xff1a;core1&#xff08;sw1&#xff09;&#xff1a;core2&#xff08;sw2&#xff09;&#xff1a;ISP 综合实验2 sw3&#xff1a; vlan 2 stp mode stp int e0/0/1 port link-type trunk port trunk allow-pass v…

QT 引入Quazip和Zlib源码工程到项目中,无需编译成库,跨平台,压缩进度

前言 最近在做项目时遇到一个需求&#xff0c;需要将升级的文件压缩成zip&#xff0c;再进行传输&#xff1b; 通过网络调研&#xff0c;有许多方式可以实现&#xff0c;例如QT私有模块的ZipReader、QZipWriter&#xff1b;或者第三方库zlib或者libzip或者quazip等&#xff1…

车载诊断架构 --- LIN节点路由转发注意事项

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…

Eclipse2024中文汉化教程(图文版)

对应Eclipse,部分人需要中文汉化,本章教程,介绍如何对Eclipse进行汉化的具体步骤。 一、汉化前的Eclipse 默认安装Eclipse的时候,默认一般都是English的,我当前版本是使用的是2024-06版本的Eclipse。 二、汉化详细步骤 点击上方菜单选项卡,Hep——Install New Software……

医院安全(不良)事件上报系统源码,基于Laravel8开发,依托其优雅的语法与强大的扩展能力

医院安全&#xff08;不良&#xff09;事件上报系统源码 系统定义&#xff1a; 规范医院安全&#xff08;不良&#xff09;事件的主动报告&#xff0c;增强风险防范意识&#xff0c;及时发现医院不良事件和安全隐患&#xff0c;将获取的医院安全信息进行分析反馈&#xff0c;…

【第一节】C++设计模式(创建型模式)-工厂模式

目录 前言 一、面向对象的两类对象创建问题 二、解决问题 三、工厂模式代码示例 四、工厂模式的核心功能 五、工厂模式的应用场景 六、工厂模式的实现与结构 七、工厂模式的优缺点 八、工厂模式的扩展与优化 九、总结 前言 在面向对象系统设计中&#xff0c;开发者常…

爬虫小案例豆瓣电影top250(json格式)

1.json格式&#xff08;仅供学习参考&#xff09; import requests, json, jsonpathclass Start(object):# 类实例化时会执行def __init__(self):self.headers {user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.…

Spring事务原理 二

在上一篇博文《Spring事务原理 一》中&#xff0c;我们熟悉了Spring声明式事务的AOP原理&#xff0c;以及事务执行的大体流程。 本文中&#xff0c;介绍了Spring事务的核心组件、传播行为的源码实现。下一篇中&#xff0c;我们将结合案例&#xff0c;来讲解实战中有关事务的易…

SpringAI系列 - ToolCalling篇(二) - 如何设置应用侧工具参数ToolContext(有坑)

目录 一、引言二、集成ToolContext示例步骤1: 在`@Tool`标注的工具方法中集成`ToolConext`参数步骤2:`ChatClient`运行时动态设置`ToolContext`参数三、填坑一、引言 在使用AI大模型的工具调用机制时,工具参数都是由大模型解析用户输入上下文获取的,由大模型提供参数给本地…

本地部署MindSearch(开源 AI 搜索引擎框架),然后上传到 hugging face的Spaces——L2G6

部署MindSearch到 hugging face Spaces上——L2G6 任务1 在 官方的MindSearch页面 复制Spaces应用到自己的Spaces下&#xff0c;Space 名称中需要包含 MindSearch 关键词&#xff0c;请在必要的步骤以及成功的对话测试结果当中 实现过程如下&#xff1a; 2.1 MindSearch 简…

MyBatis Plus扩展功能

一、代码生成器 二、逻辑删除 三、枚举处理器 像状态字段我们一般会定义一个枚举&#xff0c;做业务判断的时候就可以直接基于枚举做比较。但是我们数据库采用的是int类型&#xff0c;对应的PO也是Integer。因此业务操作时必须手动把枚举与Integer转换&#xff0c;非常麻烦。 …

深度学习之自然语言处理CBOW预测及模型的保存

自然语言处理CBOW预测及模型的保存 目录 自然语言处理CBOW预测及模型的保存1 自然语言处理1.1 概念1.2 词向量1.2.1 one-hot编码1.2.2 词嵌入1.2.3 常见的词嵌入模型 2 CBOW预测模型搭建2.1 数据及模型确定2.1.1 数据2.1.2 CBOW模型2.1.3 词嵌入降维 2.2 数据预处理2.3 模型搭建…

qt项目配置部署

Test项目: 子项目testFileHelper 1.新建一个test项目的子项目:取名testFileHelper 2.编写测试用例 3.pro文件中引入qosbrowser 4.引入测试对象的cpp和头文件 2.在项目中引入资源文件testfile.txt,在其中输入abc 实现thrid目录复用 移动thrid 将thrild目录统一放在章…

java方法学习

java 方法 在Java中&#xff0c;方法是类&#xff08;或对象&#xff09;的行为或功能的实现。&#xff08;一起实现一个功能&#xff09;java的方法类似于其他语言的函数&#xff0c;是一段用来完成特定功能的代码片段。 方法是解决一类问题步骤的有序结合。 方法包含于类或…

基于vue和微信小程序的校园自助打印系统(springboot论文源码调试讲解)

第3章 系统设计 3.1系统功能结构设计 本系统的结构分为管理员和用户、店长。本系统的功能结构图如下图3.1所示&#xff1a; 图3.1系统功能结构图 3.2数据库设计 本系统为小程序类的预约平台&#xff0c;所以对信息的安全和稳定要求非常高。为了解决本问题&#xff0c;采用前端…

[漏洞篇]文件上传漏洞详解

[漏洞篇]文件上传漏洞详解 一、介绍 1. 概念 文件上传漏洞是指用户上传了一个可执行的脚本文件&#xff0c;并通过此脚本文件获得了执行服务器端命令的能力。这种攻击方式是最为直接和有效的&#xff0c;“文件上传” 本身没有问题&#xff0c;有问题的是文件上传后&#xf…