|
|
|
@ -0,0 +1,422 @@
|
|
|
|
|
"""
|
|
|
|
|
无人机决策系统 - 主界面模块
|
|
|
|
|
作者:刘宇杰
|
|
|
|
|
日期:2025-07-13
|
|
|
|
|
功能说明:
|
|
|
|
|
本模块实现主界面,支持文件上传、分析、结果展示、历史记录等功能。
|
|
|
|
|
"""
|
|
|
|
|
import tkinter as tk
|
|
|
|
|
import json
|
|
|
|
|
from tkinter import ttk, filedialog, messagebox
|
|
|
|
|
from PIL import Image, ImageTk
|
|
|
|
|
from io import BytesIO
|
|
|
|
|
import base64
|
|
|
|
|
from gui.styles import apply_style
|
|
|
|
|
from core.analysis import AnalysisEngine
|
|
|
|
|
from utils.database import DatabaseManager
|
|
|
|
|
from gui.history_window import HistoryWindow
|
|
|
|
|
|
|
|
|
|
class MainWindow:
|
|
|
|
|
"""
|
|
|
|
|
主界面类,提供文件上传、分析、结果查看等功能。
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, user):
|
|
|
|
|
"""
|
|
|
|
|
初始化主窗口
|
|
|
|
|
:param user: 当前登录的用户信息
|
|
|
|
|
"""
|
|
|
|
|
self.user = user
|
|
|
|
|
self.analysis_engine = AnalysisEngine()
|
|
|
|
|
self.db_manager = DatabaseManager()
|
|
|
|
|
|
|
|
|
|
# 创建主窗口
|
|
|
|
|
self.root = tk.Tk()
|
|
|
|
|
self.root.title(f"无人机决策系统 - 欢迎, {user['username']}")
|
|
|
|
|
self.root.geometry("900x700")
|
|
|
|
|
apply_style(self.root)
|
|
|
|
|
|
|
|
|
|
# 当前显示的分析结果
|
|
|
|
|
self.current_result = None
|
|
|
|
|
|
|
|
|
|
# 创建UI元素
|
|
|
|
|
self._create_widgets()
|
|
|
|
|
|
|
|
|
|
# 运行主循环
|
|
|
|
|
self.root.mainloop()
|
|
|
|
|
|
|
|
|
|
def _create_widgets(self):
|
|
|
|
|
"""创建主窗口的所有UI元素"""
|
|
|
|
|
# 主框架
|
|
|
|
|
main_frame = ttk.Frame(self.root)
|
|
|
|
|
main_frame.pack(expand=True, fill=tk.BOTH, padx=10, pady=10)
|
|
|
|
|
|
|
|
|
|
# 左侧面板(文件上传)
|
|
|
|
|
left_panel = ttk.Frame(main_frame, width=300)
|
|
|
|
|
left_panel.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5)
|
|
|
|
|
left_panel.pack_propagate(False)
|
|
|
|
|
|
|
|
|
|
# 右侧面板(结果显示)
|
|
|
|
|
right_panel = ttk.Frame(main_frame)
|
|
|
|
|
right_panel.pack(side=tk.RIGHT, expand=True, fill=tk.BOTH, padx=5, pady=5)
|
|
|
|
|
|
|
|
|
|
# 左侧面板内容
|
|
|
|
|
self._create_upload_section(left_panel)
|
|
|
|
|
self._create_history_section(left_panel)
|
|
|
|
|
|
|
|
|
|
# 右侧面板内容
|
|
|
|
|
self._create_result_section(right_panel)
|
|
|
|
|
|
|
|
|
|
def _create_upload_section(self, parent):
|
|
|
|
|
"""创建上传文件区域"""
|
|
|
|
|
section_frame = ttk.LabelFrame(parent, text="上传文件", padding=10)
|
|
|
|
|
section_frame.pack(fill=tk.X, pady=5)
|
|
|
|
|
|
|
|
|
|
# 文本上传
|
|
|
|
|
text_frame = ttk.Frame(section_frame)
|
|
|
|
|
text_frame.pack(fill=tk.X, pady=5)
|
|
|
|
|
|
|
|
|
|
ttk.Button(
|
|
|
|
|
text_frame,
|
|
|
|
|
text="上传文本文件",
|
|
|
|
|
command=self._upload_text_file
|
|
|
|
|
).pack(side=tk.LEFT, padx=5)
|
|
|
|
|
|
|
|
|
|
# 或
|
|
|
|
|
ttk.Label(text_frame, text="或").pack(side=tk.LEFT, padx=5)
|
|
|
|
|
|
|
|
|
|
# 文本输入
|
|
|
|
|
self.text_input = tk.Text(
|
|
|
|
|
section_frame,
|
|
|
|
|
height=10,
|
|
|
|
|
wrap=tk.WORD,
|
|
|
|
|
font=("Helvetica", 10)
|
|
|
|
|
)
|
|
|
|
|
self.text_input.pack(fill=tk.X, pady=5)
|
|
|
|
|
|
|
|
|
|
# 图像上传
|
|
|
|
|
image_frame = ttk.Frame(section_frame)
|
|
|
|
|
image_frame.pack(fill=tk.X, pady=5)
|
|
|
|
|
|
|
|
|
|
ttk.Button(
|
|
|
|
|
image_frame,
|
|
|
|
|
text="上传图像",
|
|
|
|
|
command=self._upload_image
|
|
|
|
|
).pack(side=tk.LEFT, padx=5)
|
|
|
|
|
|
|
|
|
|
# 分析按钮
|
|
|
|
|
ttk.Button(
|
|
|
|
|
section_frame,
|
|
|
|
|
text="开始分析",
|
|
|
|
|
command=self._analyze_content,
|
|
|
|
|
style="Accent.TButton"
|
|
|
|
|
).pack(fill=tk.X, pady=10)
|
|
|
|
|
|
|
|
|
|
# 打击计划按钮
|
|
|
|
|
ttk.Button(
|
|
|
|
|
section_frame,
|
|
|
|
|
text="生成打击计划",
|
|
|
|
|
command=self._generate_strike_plan,
|
|
|
|
|
style="Accent.TButton"
|
|
|
|
|
).pack(fill=tk.X, pady=5)
|
|
|
|
|
|
|
|
|
|
def _create_history_section(self, parent):
|
|
|
|
|
"""创建历史记录区域"""
|
|
|
|
|
section_frame = ttk.LabelFrame(parent, text="最近记录", padding=10)
|
|
|
|
|
section_frame.pack(fill=tk.BOTH, expand=True, pady=5)
|
|
|
|
|
|
|
|
|
|
# 历史记录列表
|
|
|
|
|
self.history_listbox = tk.Listbox(
|
|
|
|
|
section_frame,
|
|
|
|
|
height=10,
|
|
|
|
|
selectmode=tk.SINGLE
|
|
|
|
|
)
|
|
|
|
|
self.history_listbox.pack(fill=tk.BOTH, expand=True)
|
|
|
|
|
|
|
|
|
|
# 加载历史记录
|
|
|
|
|
self._load_history()
|
|
|
|
|
|
|
|
|
|
# 查看详情按钮
|
|
|
|
|
ttk.Button(
|
|
|
|
|
section_frame,
|
|
|
|
|
text="查看详情",
|
|
|
|
|
command=self._show_history_detail
|
|
|
|
|
).pack(fill=tk.X, pady=5)
|
|
|
|
|
|
|
|
|
|
# 打开历史窗口按钮
|
|
|
|
|
ttk.Button(
|
|
|
|
|
section_frame,
|
|
|
|
|
text="查看全部历史",
|
|
|
|
|
command=self._open_history_window
|
|
|
|
|
).pack(fill=tk.X, pady=5)
|
|
|
|
|
|
|
|
|
|
def _create_result_section(self, parent):
|
|
|
|
|
"""创建结果显示区域"""
|
|
|
|
|
# 结果标签页
|
|
|
|
|
self.notebook = ttk.Notebook(parent)
|
|
|
|
|
self.notebook.pack(expand=True, fill=tk.BOTH)
|
|
|
|
|
|
|
|
|
|
# 原始结果标签
|
|
|
|
|
raw_frame = ttk.Frame(self.notebook)
|
|
|
|
|
self.raw_text = tk.Text(
|
|
|
|
|
raw_frame,
|
|
|
|
|
wrap=tk.WORD,
|
|
|
|
|
font=("Helvetica", 10)
|
|
|
|
|
)
|
|
|
|
|
self.raw_text.pack(expand=True, fill=tk.BOTH)
|
|
|
|
|
scrollbar = ttk.Scrollbar(raw_frame, command=self.raw_text.yview)
|
|
|
|
|
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
|
|
|
self.raw_text.config(yscrollcommand=scrollbar.set)
|
|
|
|
|
self.notebook.add(raw_frame, text="原始结果")
|
|
|
|
|
|
|
|
|
|
# 格式化结果标签
|
|
|
|
|
formatted_frame = ttk.Frame(self.notebook)
|
|
|
|
|
self.formatted_text = tk.Text(
|
|
|
|
|
formatted_frame,
|
|
|
|
|
wrap=tk.WORD,
|
|
|
|
|
font=("Helvetica", 10)
|
|
|
|
|
)
|
|
|
|
|
self.formatted_text.pack(expand=True, fill=tk.BOTH)
|
|
|
|
|
scrollbar = ttk.Scrollbar(formatted_frame, command=self.formatted_text.yview)
|
|
|
|
|
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
|
|
|
self.formatted_text.config(yscrollcommand=scrollbar.set)
|
|
|
|
|
self.notebook.add(formatted_frame, text="格式化结果")
|
|
|
|
|
|
|
|
|
|
# 图像预览标签(如果有图像)
|
|
|
|
|
self.image_frame = ttk.Frame(self.notebook)
|
|
|
|
|
self.image_label = ttk.Label(self.image_frame)
|
|
|
|
|
self.image_label.pack(expand=True)
|
|
|
|
|
self.notebook.add(self.image_frame, text="图像预览", state="hidden")
|
|
|
|
|
|
|
|
|
|
def _load_history(self):
|
|
|
|
|
"""加载用户的历史记录"""
|
|
|
|
|
self.history_listbox.delete(0, tk.END)
|
|
|
|
|
records = self.db_manager.get_user_records(self.user['id'])
|
|
|
|
|
|
|
|
|
|
for record in records:
|
|
|
|
|
display_text = f"{record['created_at'][:16]} - {record['record_type']}"
|
|
|
|
|
self.history_listbox.insert(tk.END, display_text)
|
|
|
|
|
|
|
|
|
|
def _upload_text_file(self):
|
|
|
|
|
"""上传文本文件"""
|
|
|
|
|
file_path = filedialog.askopenfilename(
|
|
|
|
|
title="选择文本文件",
|
|
|
|
|
filetypes=[("文本文件", "*.txt *.pdf *.docx")]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if file_path:
|
|
|
|
|
try:
|
|
|
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
|
|
|
content = f.read()
|
|
|
|
|
self.text_input.delete(1.0, tk.END)
|
|
|
|
|
self.text_input.insert(tk.END, content)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
messagebox.showerror("错误", f"读取文件失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def _upload_image(self):
|
|
|
|
|
"""上传图像文件"""
|
|
|
|
|
file_path = filedialog.askopenfilename(
|
|
|
|
|
title="选择图像文件",
|
|
|
|
|
filetypes=[("图像文件", "*.png *.jpg *.jpeg *.gif")]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if file_path:
|
|
|
|
|
try:
|
|
|
|
|
with open(file_path, 'rb') as f:
|
|
|
|
|
self.image_data = f.read()
|
|
|
|
|
|
|
|
|
|
# 显示预览
|
|
|
|
|
img = Image.open(BytesIO(self.image_data))
|
|
|
|
|
img.thumbnail((300, 300))
|
|
|
|
|
photo = ImageTk.PhotoImage(img)
|
|
|
|
|
|
|
|
|
|
self.image_label.config(image=photo)
|
|
|
|
|
setattr(self.image_label, 'image', photo)
|
|
|
|
|
self.notebook.tab(self.image_frame, state="normal")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
messagebox.showerror("错误", f"加载图像失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def _analyze_content(self):
|
|
|
|
|
"""分析上传的内容"""
|
|
|
|
|
text_content = self.text_input.get("1.0", tk.END).strip()
|
|
|
|
|
image_data = getattr(self, 'image_data', None)
|
|
|
|
|
|
|
|
|
|
if not text_content and not image_data:
|
|
|
|
|
messagebox.showwarning("警告", "请上传文本或图像内容")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
if text_content:
|
|
|
|
|
# 分析文本
|
|
|
|
|
result = self.analysis_engine.analyze_text(
|
|
|
|
|
text_content,
|
|
|
|
|
"user_input.txt"
|
|
|
|
|
)
|
|
|
|
|
self.db_manager.add_analysis_record(
|
|
|
|
|
"text",
|
|
|
|
|
"user_input.txt",
|
|
|
|
|
result
|
|
|
|
|
)
|
|
|
|
|
elif image_data:
|
|
|
|
|
# 分析图像
|
|
|
|
|
result = self.analysis_engine.analyze_image(
|
|
|
|
|
image_data,
|
|
|
|
|
"uploaded_image.jpg"
|
|
|
|
|
)
|
|
|
|
|
self.db_manager.add_analysis_record(
|
|
|
|
|
"image",
|
|
|
|
|
"uploaded_image.jpg",
|
|
|
|
|
result
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# 显示结果
|
|
|
|
|
self.current_result = result
|
|
|
|
|
self._display_results(result)
|
|
|
|
|
|
|
|
|
|
# 刷新历史记录
|
|
|
|
|
self._load_history()
|
|
|
|
|
|
|
|
|
|
messagebox.showinfo("成功", "分析完成")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
messagebox.showerror("错误", f"分析失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def _display_results(self, result):
|
|
|
|
|
"""显示分析结果"""
|
|
|
|
|
# 显示原始结果
|
|
|
|
|
self.raw_text.delete(1.0, tk.END)
|
|
|
|
|
self.raw_text.insert(tk.END, json.dumps(result, indent=2, ensure_ascii=False))
|
|
|
|
|
|
|
|
|
|
# 显示格式化结果
|
|
|
|
|
self.formatted_text.delete(1.0, tk.END)
|
|
|
|
|
ernie_analysis = result.get('ernie_analysis')
|
|
|
|
|
if isinstance(ernie_analysis, dict):
|
|
|
|
|
formatted = json.dumps(ernie_analysis, indent=2, ensure_ascii=False)
|
|
|
|
|
self.formatted_text.insert(tk.END, formatted)
|
|
|
|
|
else:
|
|
|
|
|
self.formatted_text.insert(tk.END, str(ernie_analysis))
|
|
|
|
|
|
|
|
|
|
# 如果有图像,显示图像预览
|
|
|
|
|
if result.get('type') == 'image' and 'processed_image' in result:
|
|
|
|
|
try:
|
|
|
|
|
img_data = base64.b64decode(result['processed_image'])
|
|
|
|
|
img = Image.open(BytesIO(img_data))
|
|
|
|
|
img.thumbnail((400, 400))
|
|
|
|
|
photo = ImageTk.PhotoImage(img)
|
|
|
|
|
|
|
|
|
|
self.image_label.config(image=photo)
|
|
|
|
|
setattr(self.image_label, 'image', photo)
|
|
|
|
|
self.notebook.tab(self.image_frame, state="normal")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"显示图像失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def _generate_strike_plan(self):
|
|
|
|
|
"""生成打击计划"""
|
|
|
|
|
if not self.current_result:
|
|
|
|
|
messagebox.showwarning("警告", "请先进行分析")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# 在实际应用中,这里可能会使用多个分析结果
|
|
|
|
|
plan = self.analysis_engine.generate_strike_plan([self.current_result])
|
|
|
|
|
|
|
|
|
|
# 保存计划
|
|
|
|
|
self.db_manager.add_strike_plan(self.user['id'], plan)
|
|
|
|
|
|
|
|
|
|
# 显示计划
|
|
|
|
|
self._display_results(plan)
|
|
|
|
|
|
|
|
|
|
messagebox.showinfo("成功", "打击计划生成完成")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
messagebox.showerror("错误", f"生成计划失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
def _show_history_detail(self):
|
|
|
|
|
"""显示选中的历史记录详情"""
|
|
|
|
|
selection = self.history_listbox.curselection()
|
|
|
|
|
if not selection:
|
|
|
|
|
messagebox.showwarning("警告", "请选择一条记录")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
record_index = selection[0]
|
|
|
|
|
records = self.db_manager.get_user_records(self.user['id'])
|
|
|
|
|
|
|
|
|
|
if 0 <= record_index < len(records):
|
|
|
|
|
record = records[record_index]
|
|
|
|
|
try:
|
|
|
|
|
result = json.loads(record['analysis_result'])
|
|
|
|
|
self.current_result = result
|
|
|
|
|
self._display_results(result)
|
|
|
|
|
except json.JSONDecodeError:
|
|
|
|
|
messagebox.showerror("错误", "无法解析记录数据")
|
|
|
|
|
|
|
|
|
|
def _open_history_window(self):
|
|
|
|
|
"""打开历史记录窗口"""
|
|
|
|
|
HistoryWindow(self.user)
|
|
|
|
|
|
|
|
|
|
def unused_function_5():
|
|
|
|
|
s = 0
|
|
|
|
|
for i in range(10):
|
|
|
|
|
s += i
|
|
|
|
|
return s
|
|
|
|
|
|
|
|
|
|
class UnusedClassE:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.name = 'E'
|
|
|
|
|
def get_name(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
unused_var_5 = 'main_window_unused'
|
|
|
|
|
unused_list_5 = list(range(3))
|
|
|
|
|
|
|
|
|
|
def unused_function_15():
|
|
|
|
|
return [i for i in range(40)]
|
|
|
|
|
|
|
|
|
|
def unused_function_16():
|
|
|
|
|
s = 1
|
|
|
|
|
for i in range(1, 10):
|
|
|
|
|
s *= i
|
|
|
|
|
return s
|
|
|
|
|
|
|
|
|
|
class UnusedClassO:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.name = 'O'
|
|
|
|
|
def get_name(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
class UnusedClassP:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.flag = False
|
|
|
|
|
def set_flag(self, val):
|
|
|
|
|
self.flag = val
|
|
|
|
|
def get_flag(self):
|
|
|
|
|
return self.flag
|
|
|
|
|
|
|
|
|
|
unused_var_20 = [str(i) for i in range(10)]
|
|
|
|
|
unused_var_21 = 123456
|
|
|
|
|
unused_var_22 = {'main': True}
|
|
|
|
|
|
|
|
|
|
def unused_function_27():
|
|
|
|
|
return [i for i in range(100)]
|
|
|
|
|
|
|
|
|
|
def unused_function_28():
|
|
|
|
|
s = 1
|
|
|
|
|
for i in range(1, 20):
|
|
|
|
|
s *= i
|
|
|
|
|
return s
|
|
|
|
|
|
|
|
|
|
class UnusedClassAA:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.name = 'AA'
|
|
|
|
|
def get_name(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
class UnusedClassAB:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.flag = False
|
|
|
|
|
def set_flag(self, val):
|
|
|
|
|
self.flag = val
|
|
|
|
|
def get_flag(self):
|
|
|
|
|
return self.flag
|
|
|
|
|
|
|
|
|
|
unused_var_39 = [str(i) for i in range(50)]
|
|
|
|
|
unused_var_40 = 654321
|
|
|
|
|
unused_var_41 = {'main2': False}
|