- Renamed `check_environment` to `check_api_key_configured` for clarity, simplifying the API key validation logic. - Removed the blocking behavior of the API key check during application startup, allowing the app to run while providing a prompt for configuration. - Updated `LocalAgentApp` to accept an `api_configured` parameter, enabling conditional messaging for API key setup. - Enhanced the `SandboxRunner` to support backup management and improved execution result handling with detailed metrics. - Integrated data governance strategies into the `HistoryManager`, ensuring compliance and improved data management. - Added privacy settings and metrics tracking across various components to enhance user experience and application safety.
322 lines
9.5 KiB
Python
322 lines
9.5 KiB
Python
"""
|
|
复用确认对话框
|
|
显示任务差异并让用户确认是否复用
|
|
"""
|
|
|
|
import tkinter as tk
|
|
from tkinter import ttk
|
|
from typing import List, Callable, Optional
|
|
from history.task_features import TaskDifference
|
|
|
|
|
|
def show_reuse_confirm_dialog(
|
|
parent: tk.Tk,
|
|
task_summary: str,
|
|
timestamp: str,
|
|
similarity_score: float,
|
|
differences: List[TaskDifference],
|
|
on_confirm: Callable,
|
|
on_reject: Callable
|
|
):
|
|
"""
|
|
显示复用确认对话框
|
|
|
|
Args:
|
|
parent: 父窗口
|
|
task_summary: 任务摘要
|
|
timestamp: 任务时间
|
|
similarity_score: 相似度分数
|
|
differences: 差异列表
|
|
on_confirm: 确认回调
|
|
on_reject: 拒绝回调
|
|
"""
|
|
dialog = tk.Toplevel(parent)
|
|
dialog.title("发现相似任务")
|
|
dialog.geometry("700x600")
|
|
dialog.resizable(False, False)
|
|
dialog.configure(bg='#2b2b2b')
|
|
|
|
# 居中显示
|
|
dialog.transient(parent)
|
|
dialog.grab_set()
|
|
|
|
# 主容器
|
|
main_frame = tk.Frame(dialog, bg='#2b2b2b')
|
|
main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
|
|
|
|
# 标题
|
|
title_label = tk.Label(
|
|
main_frame,
|
|
text="🔍 发现相似的成功任务",
|
|
font=('Microsoft YaHei UI', 14, 'bold'),
|
|
bg='#2b2b2b',
|
|
fg='#ffffff'
|
|
)
|
|
title_label.pack(pady=(0, 15))
|
|
|
|
# 任务信息框
|
|
info_frame = tk.Frame(main_frame, bg='#3c3c3c', relief=tk.FLAT, bd=0)
|
|
info_frame.pack(fill=tk.X, pady=(0, 15))
|
|
|
|
# 任务摘要
|
|
task_label = tk.Label(
|
|
info_frame,
|
|
text=f"任务: {task_summary}",
|
|
font=('Microsoft YaHei UI', 10),
|
|
bg='#3c3c3c',
|
|
fg='#e0e0e0',
|
|
anchor='w',
|
|
justify='left'
|
|
)
|
|
task_label.pack(fill=tk.X, padx=15, pady=(10, 5))
|
|
|
|
# 时间
|
|
time_label = tk.Label(
|
|
info_frame,
|
|
text=f"时间: {timestamp}",
|
|
font=('Microsoft YaHei UI', 9),
|
|
bg='#3c3c3c',
|
|
fg='#a0a0a0',
|
|
anchor='w'
|
|
)
|
|
time_label.pack(fill=tk.X, padx=15, pady=(0, 5))
|
|
|
|
# 相似度
|
|
similarity_percent = int(similarity_score * 100)
|
|
similarity_color = '#4caf50' if similarity_score >= 0.8 else '#ff9800' if similarity_score >= 0.6 else '#f44336'
|
|
|
|
similarity_label = tk.Label(
|
|
info_frame,
|
|
text=f"相似度: {similarity_percent}%",
|
|
font=('Microsoft YaHei UI', 9, 'bold'),
|
|
bg='#3c3c3c',
|
|
fg=similarity_color,
|
|
anchor='w'
|
|
)
|
|
similarity_label.pack(fill=tk.X, padx=15, pady=(0, 10))
|
|
|
|
# 差异部分
|
|
if differences:
|
|
# 统计关键差异
|
|
critical_count = sum(1 for d in differences if d.importance == 'critical')
|
|
high_count = sum(1 for d in differences if d.importance == 'high')
|
|
|
|
# 差异标题
|
|
diff_title_frame = tk.Frame(main_frame, bg='#2b2b2b')
|
|
diff_title_frame.pack(fill=tk.X, pady=(0, 10))
|
|
|
|
diff_title = tk.Label(
|
|
diff_title_frame,
|
|
text=f"⚠️ 发现 {len(differences)} 处差异",
|
|
font=('Microsoft YaHei UI', 11, 'bold'),
|
|
bg='#2b2b2b',
|
|
fg='#ff9800'
|
|
)
|
|
diff_title.pack(side=tk.LEFT)
|
|
|
|
if critical_count > 0:
|
|
critical_badge = tk.Label(
|
|
diff_title_frame,
|
|
text=f"{critical_count} 关键",
|
|
font=('Microsoft YaHei UI', 9),
|
|
bg='#f44336',
|
|
fg='#ffffff',
|
|
padx=8,
|
|
pady=2
|
|
)
|
|
critical_badge.pack(side=tk.LEFT, padx=(10, 5))
|
|
|
|
if high_count > 0:
|
|
high_badge = tk.Label(
|
|
diff_title_frame,
|
|
text=f"{high_count} 重要",
|
|
font=('Microsoft YaHei UI', 9),
|
|
bg='#ff9800',
|
|
fg='#ffffff',
|
|
padx=8,
|
|
pady=2
|
|
)
|
|
high_badge.pack(side=tk.LEFT)
|
|
|
|
# 差异列表(可滚动)
|
|
diff_container = tk.Frame(main_frame, bg='#2b2b2b')
|
|
diff_container.pack(fill=tk.BOTH, expand=True, pady=(0, 15))
|
|
|
|
# 创建 Canvas 和 Scrollbar
|
|
canvas = tk.Canvas(diff_container, bg='#2b2b2b', highlightthickness=0)
|
|
scrollbar = ttk.Scrollbar(diff_container, orient="vertical", command=canvas.yview)
|
|
scrollable_frame = tk.Frame(canvas, bg='#2b2b2b')
|
|
|
|
scrollable_frame.bind(
|
|
"<Configure>",
|
|
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
|
|
)
|
|
|
|
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
|
|
canvas.configure(yscrollcommand=scrollbar.set)
|
|
|
|
# 显示差异
|
|
importance_colors = {
|
|
'critical': '#f44336',
|
|
'high': '#ff9800',
|
|
'medium': '#2196f3',
|
|
'low': '#9e9e9e'
|
|
}
|
|
|
|
importance_labels = {
|
|
'critical': '关键',
|
|
'high': '重要',
|
|
'medium': '一般',
|
|
'low': '次要'
|
|
}
|
|
|
|
for i, diff in enumerate(differences):
|
|
diff_frame = tk.Frame(scrollable_frame, bg='#3c3c3c', relief=tk.FLAT, bd=0)
|
|
diff_frame.pack(fill=tk.X, pady=(0, 8), padx=2)
|
|
|
|
# 差异标题行
|
|
header_frame = tk.Frame(diff_frame, bg='#3c3c3c')
|
|
header_frame.pack(fill=tk.X, padx=10, pady=(8, 5))
|
|
|
|
category_label = tk.Label(
|
|
header_frame,
|
|
text=diff.category,
|
|
font=('Microsoft YaHei UI', 9, 'bold'),
|
|
bg='#3c3c3c',
|
|
fg='#ffffff'
|
|
)
|
|
category_label.pack(side=tk.LEFT)
|
|
|
|
importance_badge = tk.Label(
|
|
header_frame,
|
|
text=importance_labels[diff.importance],
|
|
font=('Microsoft YaHei UI', 8),
|
|
bg=importance_colors[diff.importance],
|
|
fg='#ffffff',
|
|
padx=6,
|
|
pady=1
|
|
)
|
|
importance_badge.pack(side=tk.LEFT, padx=(8, 0))
|
|
|
|
# 当前值
|
|
current_frame = tk.Frame(diff_frame, bg='#3c3c3c')
|
|
current_frame.pack(fill=tk.X, padx=10, pady=(0, 3))
|
|
|
|
current_title = tk.Label(
|
|
current_frame,
|
|
text="当前任务:",
|
|
font=('Microsoft YaHei UI', 8),
|
|
bg='#3c3c3c',
|
|
fg='#a0a0a0'
|
|
)
|
|
current_title.pack(side=tk.LEFT)
|
|
|
|
current_value = tk.Label(
|
|
current_frame,
|
|
text=diff.current_value,
|
|
font=('Microsoft YaHei UI', 9),
|
|
bg='#3c3c3c',
|
|
fg='#4caf50',
|
|
wraplength=500,
|
|
justify='left'
|
|
)
|
|
current_value.pack(side=tk.LEFT, padx=(5, 0))
|
|
|
|
# 历史值
|
|
history_frame = tk.Frame(diff_frame, bg='#3c3c3c')
|
|
history_frame.pack(fill=tk.X, padx=10, pady=(0, 8))
|
|
|
|
history_title = tk.Label(
|
|
history_frame,
|
|
text="历史任务:",
|
|
font=('Microsoft YaHei UI', 8),
|
|
bg='#3c3c3c',
|
|
fg='#a0a0a0'
|
|
)
|
|
history_title.pack(side=tk.LEFT)
|
|
|
|
history_value = tk.Label(
|
|
history_frame,
|
|
text=diff.history_value,
|
|
font=('Microsoft YaHei UI', 9),
|
|
bg='#3c3c3c',
|
|
fg='#ff9800',
|
|
wraplength=500,
|
|
justify='left'
|
|
)
|
|
history_value.pack(side=tk.LEFT, padx=(5, 0))
|
|
|
|
canvas.pack(side="left", fill="both", expand=True)
|
|
scrollbar.pack(side="right", fill="y")
|
|
else:
|
|
# 无差异
|
|
no_diff_label = tk.Label(
|
|
main_frame,
|
|
text="✅ 未发现关键差异",
|
|
font=('Microsoft YaHei UI', 10),
|
|
bg='#2b2b2b',
|
|
fg='#4caf50'
|
|
)
|
|
no_diff_label.pack(pady=20)
|
|
|
|
# 提示信息
|
|
hint_label = tk.Label(
|
|
main_frame,
|
|
text="是否直接复用该任务的代码?\n(选择「生成新代码」将根据当前需求重新生成)",
|
|
font=('Microsoft YaHei UI', 9),
|
|
bg='#2b2b2b',
|
|
fg='#a0a0a0',
|
|
justify='center'
|
|
)
|
|
hint_label.pack(pady=(10, 15))
|
|
|
|
# 按钮区域
|
|
button_frame = tk.Frame(main_frame, bg='#2b2b2b')
|
|
button_frame.pack(fill=tk.X)
|
|
|
|
def on_confirm_click():
|
|
dialog.destroy()
|
|
on_confirm()
|
|
|
|
def on_reject_click():
|
|
dialog.destroy()
|
|
on_reject()
|
|
|
|
# 复用按钮
|
|
confirm_btn = tk.Button(
|
|
button_frame,
|
|
text="✓ 复用代码",
|
|
font=('Microsoft YaHei UI', 10, 'bold'),
|
|
bg='#4caf50',
|
|
fg='#ffffff',
|
|
activebackground='#45a049',
|
|
activeforeground='#ffffff',
|
|
relief=tk.FLAT,
|
|
cursor='hand2',
|
|
command=on_confirm_click,
|
|
padx=30,
|
|
pady=10
|
|
)
|
|
confirm_btn.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(0, 5))
|
|
|
|
# 拒绝按钮
|
|
reject_btn = tk.Button(
|
|
button_frame,
|
|
text="✗ 生成新代码",
|
|
font=('Microsoft YaHei UI', 10),
|
|
bg='#555555',
|
|
fg='#ffffff',
|
|
activebackground='#666666',
|
|
activeforeground='#ffffff',
|
|
relief=tk.FLAT,
|
|
cursor='hand2',
|
|
command=on_reject_click,
|
|
padx=30,
|
|
pady=10
|
|
)
|
|
reject_btn.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(5, 0))
|
|
|
|
# 等待对话框关闭
|
|
dialog.wait_window()
|
|
|