#请核查下面代码中出现“级”字的变量名等名称的正确性,有“极”的全是错的
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
import ollama
import os
import time
import threading
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import pandas as pd
import seaborn as sns
import PyPDF2
import docx
import markdown
from bs4 import BeautifulSoup
import openpyxl
from PIL import Image
import pytesseract
import io
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
class RAGApplication:
def __init__(self, root):
self.root = root
self.root.title("智能RAG应用系统")
self.root.geometry("1200x800")
# 初始化数据
self.documents = []
self.chunks = []
self.embeddings = []
self.qa_history = []
# 模型配置
self.models = {
"llm": "gemma3:27b",
"embedding": "bge-m3:latest"
}
# 默认参数
self.params = {
"temperature": 0.7,
"top_p": 0.9,
"max_length": 2048,
"num_context_docs": 3,
"chunk_size": 500,
"chunk_overlap": 100,
"chunk_strategy": "固定大小",
"separators": "\n\n\n。\n!\n?\n",
"embed_batch_size": 1, # 修复:改为单批次处理
"enable_stream": True,
"show_progress": True,
"show_visualization": True,
"ocr_enabled": True # 是否启用OCR
}
# 创建界面
self.create_ui()
def create_ui(self):
# 主框架
self.main_frame = ttk.Frame(self.root)
self.main_frame.pack(fill=tk.BOTH, expand=True)
# 参数控制面板
self.create_sidebar()
# 主内容区域
self.create_main_content()
def create_sidebar(self):
# 侧边栏框架
self.sidebar = ttk.LabelFrame(self.main_frame, text="参数控制面板", width=300)
self.sidebar.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5)
# 大模型参数
ttk.Label(self.sidebar, text="大模型参数").pack(pady=(10, 0))
self.temperature = tk.DoubleVar(value=self.params["temperature"])
ttk.Label(self.sidebar, text="温度(temperature)").pack()
ttk.Scale(self.sidebar, from_=0.0, to=2.0, variable=self.temperature,
command=lambda v: self.update_param("temperature", float(v))).pack()
ttk.Label(self.sidebar, textvariable=tk.StringVar(value=f"当前值: {self.temperature.get()}")).pack()
self.top_p = tk.DoubleVar(value=self.params["top_p"])
ttk.Label(self.sidebar, text="Top P").pack()
ttk.Scale(self.sidebar, from_=0.0, to=1.0, variable=self.top_p,
command=lambda v: self.update_param("top_p", float(v))).pack()
ttk.Label(self.sidebar, textvariable=tk.StringVar(value=f"当前值: {self.top_p.get()}")).pack()
# RAG参数
ttk.Label(self.sidebar, text="\nRAG参数").pack(pady=(10, 0))
self.chunk_size = tk.IntVar(value=self.params["chunk_size"])
ttk.Label(self.sidebar, text="分块大小(字符)").pack()
ttk.Scale(self.sidebar, from_=100, to=2000, variable=self.chunk_size,
command=lambda v: self.update_param("chunk_size", int(v))).pack()
ttk.Label(self.sidebar, textvariable=tk.StringVar(value=f"当前值: {self.chunk_size.get()}")).pack()
# OCR开关
self.ocr_var = tk.BooleanVar(value=self.params["ocr_enabled"])
ttk.Checkbutton(self.sidebar, text="启用OCR扫描", variable=self.ocr_var,
command=lambda: self.update_param("ocr_enabled", self.ocr_var.get())).pack(pady=(10, 0))
# 使用说明
ttk.Label(self.sidebar, text="\n使用说明").pack(pady=(10, 0))
instructions = """1. 在"文档上传"页上传您的文档
2. 在"文档处理"页对文档进行分块和嵌入
3. 在"问答交互"页提问并获取答案
4. 在"系统监控"页查看系统状态"""
ttk.Label(self.sidebar, text=instructions, justify=tk.LEFT).pack()
def create_main_content(self):
# 主内容框架
self.content_frame = ttk.Frame(self.main_frame)
self.content_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
# 创建选项卡
self.notebook = ttk.Notebook(self.content_frame)
self.notebook.pack(fill=tk.BOTH, expand=True)
# 文档上传页
self.create_upload_tab()
# 文档处理页
self.create_process_tab()
# 问答交互页
self.create_qa_tab()
# 系统监控页
self.create_monitor_tab()
def create_upload_tab(self):
self.upload_tab = ttk.Frame(self.notebook)
self.notebook.add(self.upload_tab, text="文档上传")
ttk.Label(self.upload_tab, text="文档上传与管理", font=('Arial', 14)).pack(pady=10)
# 上传按钮
ttk.Button(self.upload_tab, text="上传文档", command=self.upload_files).pack(pady=10)
# 文档列表
self.doc_list_frame = ttk.LabelFrame(self.upload_tab, text="已上传文档")
self.doc_list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
self.doc_tree = ttk.Treeview(self.doc_list_frame, columns=("name", "size", "time", "type"), show="headings")
self.doc_tree.heading("name", text="文件名")
self.doc_tree.heading("size", text="大小")
self.doc_tree.heading("time", text="上传时间")
self.doc_tree.heading("type", text="类型")
self.doc_tree.pack(fill=tk.BOTH, expand=True)
# 文档统计
self.doc_stats_frame = ttk.Frame(self.upload_tab)
self.doc_stats_frame.pack(fill=tk.X, pady=5)
ttk.Label(self.doc_stats_frame, text="总文档数:").pack(side=tk.LEFT, padx=5)
self.doc_count_label = ttk.Label(self.doc_stats_frame, text="0")
self.doc_count_label.pack(side=tk.LEFT, padx=5)
ttk.Label(self.doc_stats_frame, text="总字符数:").pack(side=tk.LEFT, padx=5)
self.char_count_label = ttk.Label(self.doc_stats_frame, text="0")
self.char_count_label.pack(side=tk.LEFT, padx=5)
# ================== 文件读取函数 ==================
def read_pdf(self, filepath):
"""读取PDF文件内容,支持扫描版OCR"""
content = ""
try:
with open(filepath, 'rb') as f:
reader = PyPDF2.PdfReader(f)
num_pages = len(reader.pages)
for page_num in range(num_pages):
page = reader.pages[page_num]
text = page.extract_text()
# 如果是扫描版PDF,使用OCR识别
if not text.strip() and self.params["ocr_enabled"]:
try:
# 获取页面图像
images = page.images
if images:
for img in images:
image_data = img.data
image = Image.open(io.BytesIO(image_data))
text += pytesseract.image_to_string(image, lang='chi_sim+eng')
except Exception as e:
print(f"OCR处理失败: {str(e)}")
content += text + "\n"
except Exception as e:
print(f"读取PDF失败: {str(e)}")
return content
def read_docx(self, filepath):
"""读取Word文档内容"""
content = ""
try:
doc = docx.Document(filepath)
for para in doc.paragraphs:
content += para.text + "\n"
except Exception as e:
print(f"读取Word文档失败: {str(e)}")
return content
def read_excel(self, filepath):
"""读取Excel文件内容,优化内存使用"""
content = ""
try:
# 使用openpyxl优化大文件读取
wb = openpyxl.load_workbook(filepath, read_only=True)
for sheet_name in wb.sheetnames:
content += f"\n工作表: {sheet_name}\n"
sheet = wb[sheet_name]
for row in sheet.iter_rows(values_only=True):
row_content = " | ".join([str(cell) if cell is not None else "" for cell in row])
content += row_content + "\n"
except Exception as e:
print(f"读取Excel文件失败: {str(e)}")
return content
def read_md(self, filepath):
"""读取Markdown文件内容"""
content = ""
try:
with open(filepath, 'r', encoding='utf-8') as f:
html = markdown.markdown(f.read())
soup = BeautifulSoup(html, 'html.parser')
content = soup.get_text()
except Exception as e:
print(f"读取Markdown文件失败: {str(e)}")
return content
def read_ppt(self, filepath):
"""读取PPT文件内容(简化版)"""
content = ""
try:
# 实际应用中应使用python-pptx库
# 这里仅作演示
content = f"PPT文件内容提取: {os.path.basename(filepath)}"
except Exception as e:
print(f"读取PPT文件失败: {str(e)}")
return content
def upload_files(self):
filetypes = [
("文本文件", "*.txt"),
("PDF文件", "*.pdf"),
("Word文件", "*.docx *.doc"),
("Excel文件", "*.xlsx *.xls"),
("Markdown文件", "*.md"),
("PPT文件", "*.pptx *.ppt"),
("所有文件", "*.*")
]
filenames = filedialog.askopenfilenames(title="选择文档", filetypes=filetypes)
if filenames:
for filename in filenames:
try:
ext = os.path.splitext(filename)[1].lower()
if ext == '.txt':
with open(filename, 'r', encoding='utf-8') as f:
content = f.read()
elif ext == '.pdf':
content = self.read_pdf(filename)
elif ext in ('.docx', '.doc'):
content = self.read_docx(filename)
elif ext in ('.xlsx', '.xls'):
content = self.read_excel(filename)
elif ext == '.md':
content = self.read_md(filename)
elif ext in ('.pptx', '.ppt'):
content = self.read_ppt(filename)
else:
messagebox.showwarning("警告", f"不支持的文件类型: {ext}")
continue
# 处理字符编码问题
if not isinstance(content, str):
try:
content = content.decode('utf-8')
except:
content = content.decode('latin-1', errors='ignore')
self.documents.append({
"name": os.path.basename(filename),
"content": content,
"size": len(content),
"upload_time": time.strftime("%Y-%m-%d %H:%M:%S"),
"type": ext.upper().replace(".", "")
})
# 更新文档列表
self.update_doc_list()
except Exception as e:
messagebox.showerror("错误", f"无法读取文件 {filename}: {str(e)}")
def update_doc_list(self):
# 清空现有列表
for item in self.doc_tree.get_children():
self.doc_tree.delete(item)
# 添加新文档
for doc in self.documents:
self.doc_tree.insert("", tk.END, values=(
doc["name"],
doc["size"],
doc["upload_time"],
doc["type"]
))
# 更新统计信息
self.doc_count_label.config(text=str(len(self.documents)))
self.char_count_label.config(text=str(sum(d['size'] for d in self.documents)))
def create_process_tab(self):
self.process_tab = ttk.Frame(self.notebook)
self.notebook.add(self.process_tab, text="文档处理")
ttk.Label(self.process_tab, text="文档处理与分块", font=('Arial', 14)).pack(pady=10)
# 处理按钮
ttk.Button(self.process_tab, text="处理文档", command=self.process_documents).pack(pady=10)
# 可视化区域
self.visual_frame = ttk.Frame(self.process_tab)
self.visual_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 分块列表
self.chunk_frame = ttk.LabelFrame(self.process_tab, text="分块结果")
self.chunk_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
self.chunk_tree = ttk.Treeview(self.chunk_frame, columns=("doc_name", "start", "end", "content"),
show="headings")
self.chunk_tree.heading("doc_name", text="来源文档")
self.chunk_tree.heading("start", text="起始位置")
self.chunk_tree.heading("end", text="结束位置")
self.chunk_tree.heading("content", text="内容预览")
self.chunk_tree.column("content", width=400)
self.chunk_tree.pack(fill=tk.BOTH, expand=True)
def process_documents(self):
if not self.documents:
messagebox.showwarning("警告", "请先上传文档")
return
# 在新线程中处理文档
threading.Thread(target=self._process_documents_thread, daemon=True).start()
def _process_documents_thread(self):
# 显示进度条
self.progress_window = tk.Toplevel(self.root)
self.progress_window.title("处理进度")
self.progress_window.geometry("400x100")
ttk.Label(self.progress_window, text="正在处理文档...").pack(pady=10)
self.progress_var = tk.DoubleVar()
ttk.Progressbar(self.progress_window, variable=self.progress_var, maximum=100).pack(pady=5, padx=10, fill=tk.X)
try:
# 分块处理
self.chunks = self.chunk_documents(
self.documents,
self.params["chunk_strategy"],
self.params["chunk_size"],
self.params["chunk_overlap"]
)
# 生成嵌入
self.embeddings = self.generate_embeddings(self.chunks)
# 更新UI
self.root.after(0, self.update_chunk_list)
self.root.after(0, self.show_visualizations)
messagebox.showinfo("完成", "文档处理完成!")
except Exception as e:
self.root.after(0, lambda: messagebox.showerror("错误", f"处理文档时出错: {str(e)}"))
finally:
self.root.after(0, self.progress_window.destroy)
def chunk_documents(self, documents, strategy, size, overlap):
chunks = []
total_docs = len(documents)
for doc_idx, doc in enumerate(documents):
content = doc['content']
if strategy == "固定大小":
for i in range(0, len(content), size - overlap):
chunk = content[i:i + size]
chunks.append({
"doc_name": doc['name'],
"content": chunk,
"start": i,
"end": min(i + size, len(content))
})
# 更新进度
progress = (doc_idx + 1) / total_docs * 100
self.progress_var.set(progress)
self.progress_window.update()
return chunks
def generate_embeddings(self, chunks):
"""修复:单批次处理每个分块,避免API参数类型错误"""
embeddings = []
total_chunks = len(chunks)
for idx, chunk in enumerate(chunks):
try:
# 修复:传递单个字符串而不是列表
response = ollama.embeddings(
model=self.models['embedding'],
prompt=chunk['content'] # 单个字符串
)
embeddings.append({
"chunk_id": idx,
"embedding": response['embedding'],
"doc_name": chunk['doc_name']
})
except Exception as e:
print(f"生成嵌入时出错: {str(e)}")
# 添加空嵌入占位符
embeddings.append({
"chunk_id": idx,
"embedding": None,
"doc_name": chunk['doc_name']
})
# 更新进度
progress = (idx + 1) / total_chunks * 100
self.progress_var.set(progress)
self.progress_window.update()
# 添加延迟避免请求过快
time.sleep(0.1)
return embeddings
def update_chunk_list(self):
# 清空现有列表
for item in self.chunk_tree.get_children():
self.chunk_tree.delete(item)
# 添加新分块
for chunk in self.chunks:
preview = chunk['content'][:50] + "..." if len(chunk['content']) > 50 else chunk['content']
self.chunk_tree.insert("", tk.END, values=(
chunk['doc_name'],
chunk['start'],
chunk['end'],
preview
))
def show_visualizations(self):
# 清空可视化区域
for widget in self.visual_frame.winfo_children():
widget.destroy()
if not self.params["show_visualization"] or not self.chunks:
return
# 创建图表
fig = Figure(figsize=(10, 4), dpi=100)
# 分块大小分布
ax1 = fig.add_subplot(121)
chunk_sizes = [len(c['content']) for c in self.chunks]
sns.histplot(chunk_sizes, bins=20, ax=ax1)
ax1.set_title("分块大小分布")
ax1.set_xlabel("字符数")
ax1.set_ylabel("数量")
# 文档分块数量
ax2 = fig.add_subplot(122)
doc_chunk_counts = {}
for chunk in self.chunks:
doc_chunk_counts[chunk['doc_name']] = doc_chunk_counts.get(chunk['doc_name'], 0) + 1
sns.barplot(x=list(doc_chunk_counts.keys()), y=list(doc_chunk_counts.values()), ax=ax2)
ax2.set_title("各文档分块数量")
ax2.set_ylabel = "分块数"
ax2.tick_params(axis='x', rotation=45)
# 在Tkinter中显示图表
canvas = FigureCanvasTkAgg(fig, master=self.visual_frame)
canvas.draw()
canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
def create_qa_tab(self):
self.qa_tab = ttk.Frame(self.notebook)
self.notebook.add(self.qa_tab, text="问答交互")
ttk.Label(self.qa_tab, text="问答交互", font=('Arial', 14)).pack(pady=10)
# 问题输入
self.question_frame = ttk.LabelFrame(self.qa_tab, text="输入问题")
self.question_frame.pack(fill=tk.X, padx=10, pady=5)
self.question_text = scrolledtext.ScrolledText(self.question_frame, height=5)
self.question_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
ttk.Button(self.qa_tab, text="提交问题", command=self.submit_question).pack(pady=5)
# 回答显示
self.answer_frame = ttk.LabelFrame(self.qa_tab, text="回答")
self.answer_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
self.answer_text = scrolledtext.ScrolledText(self.answer_frame, state=tk.DISABLED)
self.answer_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# 问答历史
self.history_frame = ttk.LabelFrame(self.qa_tab, text="问答历史")
self.history_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
self.history_tree = ttk.Treeview(self.history_frame, columns=("question", "time"), show="headings")
self.history_tree.heading("question", text="问题")
self.history_tree.heading("time", text="时间")
self.history_tree.pack(fill=tk.BOTH, expand=True)
# 绑定双击事件查看历史详情
self.history_tree.bind("<Double-1>", self.show_history_detail)
def submit_question(self):
question = self.question_text.get("1.0", tk.END).strip()
if not question:
messagebox.showwarning("警告", "问题不能为空")
return
# 在新线程中处理问题
threading.Thread(target=self._submit_question_thread, args=(question,), daemon=True).start()
def _submit_question_thread(self, question):
try:
# 显示进度窗口
self.progress_window = tk.Toplevel(self.root)
self.progress_window.title("处理中...")
self.progress_window.geometry("400x100")
ttk.Label(self.progress_window, text="正在思考...").pack(pady=10)
self.progress_var = tk.DoubleVar()
ttk.Progressbar(self.progress_window, variable=self.progress_var, maximum=100).pack(pady=5, padx=10,
fill=tk.X)
self.progress_window.update()
# 检索相关文档块
relevant_chunks = self.retrieve_relevant_chunks(question, self.params["num_context_docs"])
# 构建上下文
context = "\n\n".join([
f"文档: {c['doc_name']}\n内容: {c['content']}\n相关性: {c['similarity']:.4f}"
for c in relevant_chunks
])
# 调用大模型生成回答
prompt = f"""基于以下上下文,回答问题。如果答案不在上下文中,请回答"我不知道"。
上下文:
{context}
问题: {question}
回答:"""
# 更新进度
self.progress_var.set(50)
self.progress_window.update()
# 流式输出或一次性输出
if self.params["enable_stream"]:
self.root.after(0, self.answer_text.config, {'state': tk.NORMAL})
self.root.after(0, self.answer_text.delete, "1.0", tk.END)
full_response = ""
for chunk in ollama.generate(
model=self.models['llm'],
prompt=prompt,
stream=True,
options={
'temperature': self.params["temperature"],
'top_p': self.params["top_p"],
'num_ctx': self.params["max_length"]
}
):
full_response += chunk['response']
self.root.after(0, self.answer_text.insert, tk.END, chunk['response'])
self.root.after(0, self.answer_text.see, tk.END)
self.root.after(0, self.answer_text.update)
else:
response = ollama.generate(
model=self.models['llm'],
prompt=prompt,
options={
'temperature': self.params["temperature"],
'top_p': self.params["top_p"],
'num_ctx': self.params["max_length"]
}
)
full_response = response['response']
self.root.after(0, self.answer_text.config, {'state': tk.NORMAL})
self.root.after(0, self.answer_text.delete, "1.0", tk.END)
self.root.after(0, self.answer_text.insert, tk.END, full_response)
self.root.after(0, self.answer_text.config, {'state': tk.DISABLED})
# 记录问答历史
self.qa_history.append({
"question": question,
"answer": full_response,
"context": context,
"time": time.strftime("%Y-%m-%d %H:%M:%S")
})
# 更新历史列表
self.root.after(0, self.update_history_list)
# 完成
self.progress_var.set(100)
self.root.after(1000, self.progress_window.destroy)
except Exception as e:
self.root.after(0, lambda: messagebox.showerror("错误", f"处理问题时出错: {str(e)}"))
self.root.after(0, self.progress_window.destroy)
def retrieve_relevant_chunks(self, query, k):
"""修复:处理嵌入为None的情况"""
# 生成查询的嵌入
query_embedding = ollama.embeddings(
model=self.models['embedding'],
prompt=query
)['embedding'] # 注意:返回的是字典中的'embedding'字段
# 计算相似度
similarities = []
for emb in self.embeddings:
# 跳过无效的嵌入
if emb['embedding'] is None:
continue
# 计算余弦相似度
similarity = np.dot(query_embedding, emb['embedding'])
similarities.append({
'chunk_id': emb['chunk_id'],
'similarity': similarity,
'doc_name': emb['doc_name']
})
# 按相似度排序并返回前k个
top_chunks = sorted(similarities, key=lambda x: x['similarity'], reverse=True)[:k]
return [{
**self.chunks[c['chunk_id']],
'similarity': c['similarity']
} for c in top_chunks]
def update_history_list(self):
# 清空现有列表
for item in self.history_tree.get_children():
self.history_tree.delete(item)
# 添加新历史记录
for i, qa in enumerate(reversed(self.qa_history)):
self.history_tree.insert("", tk.END, values=(qa["question"], qa["time"]))
def show_history_detail(self, event):
selected_item = self.history_tree.selection()
if not selected_item:
return
item = self.history_tree.item(selected_item)
question = item['values'][0]
# 查找对应的问答记录
for qa in reversed(self.qa_history):
if qa["question"] == question:
# 显示详情窗口
detail_window = tk.Toplevel(self.root)
detail_window.title("问答详情")
detail_window.geometry("800x600")
# 问题
ttk.Label(detail_window, text="问题:", font=('Arial', 12, 'bold')).pack(pady=(10, 0), padx=10,
anchor=tk.W)
ttk.Label(detail_window, text=qa["question"], wraplength=780).pack(pady=(0, 10), padx=10, anchor=tk.W)
# 回答
ttk.Label(detail_window, text="回答:", font=('Arial', 12, 'bold')).pack(pady=(10, 0), padx=10,
anchor=tk.W)
answer_text = scrolledtext.ScrolledText(detail_window, wrap=tk.WORD, height=10)
answer_text.insert(tk.INSERT, qa["answer"])
answer_text.config(state=tk.DISABLED)
answer_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10))
# 上下文
ttk.Label(detail_window, text="上下文:", font=('Arial', 12, 'bold')).pack(pady=(10, 0), padx=10,
anchor=tk.W)
context_text = scrolledtext.ScrolledText(detail_window, wrap=tk.WORD, height=15)
context_text.insert(tk.INSERT, qa["context"])
context_text.config(state=tk.DISABLED)
context_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10))
break
def create_monitor_tab(self):
self.monitor_tab = ttk.Frame(self.notebook)
self.notebook.add(self.monitor_tab, text="系统监控")
ttk.Label(self.monitor_tab, text="系统监控", font=('Arial', 14)).pack(pady=10)
# 资源使用
self.resource_frame = ttk.LabelFrame(self.monitor_tab, text="资源使用")
self.resource_frame.pack(fill=tk.BOTH, padx=10, pady=5)
# CPU使用
ttk.Label(self.resource_frame, text="CPU使用率:").pack(pady=(10, 0), padx=10, anchor=tk.W)
self.c极U_usage = ttk.Progressbar(self.resource_frame, length=200)
self.cpu_usage.pack(fill=tk.X, padx=10, pady=(0, 10))
# 内存使用
ttk.Label(self.resource_frame, text="内存使用率:").pack(pady=(10, 0), padx极10, anchor=tk.W)
self.mem_usage = ttk.Progressbar(self.resource_frame, length=200)
self.mem_usage.pack(fill=tk.X, padx=10, pady=(0, 10))
# 磁盘使用
ttk.Label(self.resource_frame, text="磁盘使用率:").pack(pady=(10, 0), padx=10, anchor=tk.W)
self.disk_usage = ttk.Progressbar(self.resource_frame, length=200)
self.disk_usage.pack(fill=tk.X, padx=10, pady=(0, 10))
# 模型状态
self.model_frame = ttk.LabelFrame(self.monitor_tab, text="模型状态")
self.model_frame.pack(fill=tk.BOTH, padx=10, pady=5)
ttk.Button(self.model_frame, text="检查模型状态", command=self.check_model_status).pack(pady=10)
self.model_status_text = scrolledtext.ScrolledText(self.model_frame, height=10, state=tk.DISABLED)
self.model_status_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10))
# 性能统计
self.perf_frame = ttk.LabelFrame(self.monitor_tab, text="性能统计")
self.perf_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
self.update_resource_usage()
def update_resource_usage(self):
# 模拟资源数据
cpu = np.random.randint(50, 90)
mem = np.random.randint(60, 85)
disk = np.random.randint(30, 70)
self.cpu_usage['value'] = cpu
self.mem_usage['value'] = mem
self.disk_usage['value'] = disk
# 10秒后再次更新
self.root.after(10000, self.update_resource_usage)
def check_model_status(self):
try:
llm_info = ollama.show(self.models['llm'])
embed_info = ollama.show(self.models['embedding'])
status_text = f"""大模型信息:
名称: {self.models['llm']}
参数大小: {llm_info.get('size', '未知')}
最后使用时间: {llm_info.get('modified_at', '未知')}
嵌入模型信息:
名称: {self.models['embedding']}
参数大小: {embed_info.get('size', '未知')}
最后使用时间: {embed_info.get('modified_at', '未知')}
"""
self.model_status_text.config(state=tk.NORMAL)
self.model_status_text.delete("1.0", tk.END)
self.model_status_text.insert(tk.INSERT, status_text)
self.model_status_text.config(state=tk.DISABLED)
except Exception as e:
messagebox.showerror("错误", f"检查模型状态时出错: {str(e)}")
def update_param(self, param, value):
self.params[param] = value
# 运行应用程序
if __name__ == "__main__":
root = tk.Tk()
app = RAGApplication(root)
root.mainloop()
最新发布