data-return/structure_file2.py

345 lines
14 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import openai
from typing import Dict, Any
class DirectoryAnalyzerApp:
def __init__(self, root):
self.root = root
self.root.title("风电叶片目录分析工具")
self.root.geometry("800x600")
# 初始化变量
self.dir_path = tk.StringVar()
self.original_structure = {}
self.ai_structure = {}
self.tree_items = {} # 用于存储树节点ID
# 创建界面组件
self.create_widgets()
def create_widgets(self):
# 顶部框架 - 目录选择和扫描
top_frame = ttk.Frame(self.root, padding="10")
top_frame.pack(fill=tk.X)
ttk.Label(top_frame, text="目录路径:").pack(side=tk.LEFT)
self.dir_entry = ttk.Entry(top_frame, textvariable=self.dir_path, width=50)
self.dir_entry.pack(side=tk.LEFT, padx=5)
browse_btn = ttk.Button(top_frame, text="浏览...", command=self.browse_directory)
browse_btn.pack(side=tk.LEFT, padx=5)
scan_btn = ttk.Button(top_frame, text="扫描目录", command=self.scan_directory)
scan_btn.pack(side=tk.LEFT, padx=5)
# 中间框架 - 目录树显示
mid_frame = ttk.Frame(self.root, padding="10")
mid_frame.pack(fill=tk.BOTH, expand=True)
# 创建Treeview和滚动条
self.tree = ttk.Treeview(mid_frame, columns=("original", "ai"), show="tree")
self.tree.heading("#0", text="原始名称")
self.tree.heading("original", text="原始名称")
self.tree.heading("ai", text="AI建议名称")
y_scroll = ttk.Scrollbar(mid_frame, orient=tk.VERTICAL, command=self.tree.yview)
self.tree.configure(yscrollcommand=y_scroll.set)
x_scroll = ttk.Scrollbar(mid_frame, orient=tk.HORIZONTAL, command=self.tree.xview)
self.tree.configure(xscrollcommand=x_scroll.set)
# 布局
self.tree.grid(row=0, column=0, sticky="nsew")
y_scroll.grid(row=0, column=1, sticky="ns")
x_scroll.grid(row=1, column=0, sticky="ew")
mid_frame.grid_rowconfigure(0, weight=1)
mid_frame.grid_columnconfigure(0, weight=1)
# 底部框架 - 操作按钮
bottom_frame = ttk.Frame(self.root, padding="10")
bottom_frame.pack(fill=tk.X)
ai_btn = ttk.Button(bottom_frame, text="AI分析", command=self.ai_analyze)
ai_btn.pack(side=tk.LEFT, padx=5)
apply_btn = ttk.Button(bottom_frame, text="应用更改", command=self.apply_changes)
apply_btn.pack(side=tk.LEFT, padx=5)
edit_btn = ttk.Button(bottom_frame, text="更改叶片名", command=self.edit_selected)
edit_btn.pack(side=tk.LEFT, padx=5)
# 右键菜单
self.context_menu = tk.Menu(self.root, tearoff=0)
self.context_menu.add_command(label="编辑名称", command=self.edit_selected)
# 绑定右键事件
self.tree.bind("<Button-3>", self.show_context_menu)
def browse_directory(self):
"""打开目录选择对话框"""
dir_path = filedialog.askdirectory()
if dir_path:
self.dir_path.set(dir_path)
def scan_directory(self):
"""扫描选择的目录"""
path = self.dir_path.get()
if not path:
messagebox.showerror("错误", "请先选择目录")
return
try:
self.original_structure = self.scan_dir(path)
self.display_directory(self.original_structure)
messagebox.showinfo("成功", "目录扫描完成")
except Exception as e:
messagebox.showerror("错误", f"扫描目录时出错: {str(e)}")
def scan_dir(self, path):
"""扫描路径结构,递归查找路径并记录路径结构"""
if not os.path.exists(path):
return {}
dir_structure = {}
for item in os.listdir(path):
item_path = os.path.join(path, item)
if os.path.isdir(item_path):
# 如果是目录,递归扫描
dir_structure[item] = self.scan_dir(item_path)
return dir_structure
def display_directory(self, dir_data, parent=""):
"""在Treeview中显示目录结构"""
# 清空现有树
for item in self.tree.get_children():
self.tree.delete(item)
# 递归插入节点
self._insert_nodes("", dir_data)
def _insert_nodes(self, parent, data):
"""递归插入树节点"""
for name, children in data.items():
if isinstance(children, dict): # 目录节点
node_id = self.tree.insert(parent, "end", text=name, values=(name, ""))
self._insert_nodes(node_id, children)
else: # 文件节点
ai_name = ""
if name in self.ai_structure:
ai_name = self.ai_structure[name]
self.tree.insert(parent, "end", text=name, values=(name, ai_name))
def ai_analyze(self):
"""使用AI分析目录结构"""
if not self.original_structure:
messagebox.showerror("错误", "请先扫描目录")
return
try:
# 提取所有文件名(最底层节点)
file_names = self.extract_leaf_folders(self.original_structure)
# 获取AI回复
self.ai_structure = self.get_ai_reply(file_names)
# 更新显示
self.display_directory(self.ai_structure)
messagebox.showinfo("成功", "AI分析完成")
except Exception as e:
messagebox.showerror("错误", f"AI分析时出错: {str(e)}")
def extract_leaf_folders(self, dir_data):
"""从目录结构中提取所有最末端的文件夹名"""
leaf_folders = []
def _extract(data):
for name, children in data.items():
if isinstance(children, dict):
if not children: # 如果子节点为空字典,说明这是最末端的文件夹
leaf_folders.append(name)
else:
_extract(children)
_extract(dir_data)
print(f'获取最底节点:{leaf_folders}')
return leaf_folders
def get_ai_reply(self, file_names: list) -> Dict[str, str]:
"""获取AI的返回信息传入文件名列表让AI返回标准化结构"""
api_config = {
"api_key": "sk-zbytvldaexbdauavbkclbhdcgrlahojvwfchtiqhyvlvryle",
"base_url": "https://api.siliconflow.cn/v1",
"model": "Qwen/Qwen2.5-72B-Instruct",
"prompt": """请根据风电叶片目录命名规则,将以下叶片名称转换为标准格式。标准格式为:叶片号。只需要看第一个字母/数字即可,并且标准的需要用花括号括起来
示例输入1: "A#"
示例输出1: "1" #此处要加花括号
示例输入2: "B#"
示例输出2: "2" #此处要加花括号
示例输入3: "C#"
示例输出3: "3" #此处要加花括号
示例输入1: "1#"
示例输出1: "1" #此处要加花括号
示例输入2: "2#"
示例输出2: "2" #此处要加花括号
示例输入3: "3#"
示例输出3: "3" #此处要加花括号
现在请转换以下名称: {input}"""
}
try:
# 初始化 OpenAI 客户端
client = openai.OpenAI(
api_key=api_config["api_key"],
base_url=api_config["base_url"]
)
print(f"Client initialized: {client}")
except Exception as e:
print(f'初始化client失败:{e}')
return {name: "客户端初始化失败" for name in file_names}
result = {}
for name in file_names:
print(f'发送name{name}')
response = client.chat.completions.create(
model=api_config["model"],
messages=[
{"role": "user", "content": api_config["prompt"].format(input=name)}
],
stream=False # 明确关闭流式传输
)
ai_reply = response.choices[0].message.content
print(f'收到消息:{ai_reply}')
# 使用正则表达式查找花括号内的内容
import re
match = re.search(r'{(.*?)}', ai_reply)
if match:
content_inside_braces = match.group(1)
result[name] = content_inside_braces
else:
result[name] = ai_reply # 如果没有花括号,使用原始内容
print(f'存入:{result[name]}')
return result
def apply_changes(self):
"""应用AI建议的更改到实际文件"""
# 遍历原始结构并应用更改
def find_leaf_directories(directory_dict, current_path=None, result=None):
if result is None:
result = []
if current_path is None:
current_path = []
elif isinstance(current_path, (str, type(self.dir_path))): # 处理 StringVar 或字符串情况
current_path = [current_path]
for name, subdir in directory_dict.items():
new_path = current_path.copy() # 创建列表的副本
new_path.append(name) # 添加当前目录名
if not subdir: # 这是一个最子文件夹
result.append({
'path': os.path.join(*new_path), # 使用os.path.join来构建路径
'name': name
})
else: # 继续递归查找
find_leaf_directories(subdir, new_path, result)
return result
# 确保初始路径是列表形式
initial_path = [self.dir_path.get()] if hasattr(self.dir_path, 'get') else [str(self.dir_path)]
result_to_replace = find_leaf_directories(self.original_structure, initial_path)
for result in result_to_replace:
original_path = result['path'] # 获取原始路径
original_name = result['name'] # 获取原始name
# 从ai_structure中获取要修改的新name值
if original_name in self.ai_structure:
new_name = self.ai_structure[original_name]
# 构造新路径
dir_name = os.path.dirname(original_path)
new_path = os.path.join(dir_name, new_name)
try:
# 确保目标目录不存在
if os.path.exists(new_path):
print(f"Error: Target already exists - {new_path}")
continue
# 重命名文件夹
os.rename(original_path, new_path)
print(f"Renamed: {original_path} -> {new_path}")
except FileNotFoundError:
print(f"Error: Path not found - {original_path}")
except Exception as e:
print(f"Error renaming {original_path}: {str(e)}")
def edit_selected(self):
"""编辑选中的项目名称"""
selected_item = self.tree.selection()
if not selected_item:
messagebox.showerror("错误", "请先选择一个项目")
return
# 获取当前值
item_text = self.tree.item(selected_item, "text")
item_values = self.tree.item(selected_item, "values")
# 创建编辑对话框
edit_dialog = tk.Toplevel(self.root)
edit_dialog.title("编辑名称")
edit_dialog.geometry("400x200")
ttk.Label(edit_dialog, text="原始名称:").pack(pady=5)
original_entry = ttk.Entry(edit_dialog)
original_entry.insert(0, item_text)
original_entry.config(state="readonly")
original_entry.pack(fill=tk.X, padx=10, pady=5)
ttk.Label(edit_dialog, text="AI建议名称:").pack(pady=5)
ai_entry = ttk.Entry(edit_dialog)
ai_entry.insert(0, item_values[1] if len(item_values) > 1 else "")
ai_entry.pack(fill=tk.X, padx=10, pady=5)
def save_changes():
new_name = ai_entry.get()
if new_name:
# 更新树显示
self.tree.item(selected_item, values=(item_text, new_name))
# 更新AI结构字典
if item_text in self.ai_structure:
self.ai_structure[item_text] = new_name
edit_dialog.destroy()
save_btn = ttk.Button(edit_dialog, text="保存", command=save_changes)
save_btn.pack(pady=10)
def show_context_menu(self, event):
"""显示右键上下文菜单"""
item = self.tree.identify_row(event.y)
if item:
self.tree.selection_set(item)
self.context_menu.post(event.x_root, event.y_root)
if __name__ == "__main__":
root = tk.Tk()
app = DirectoryAnalyzerApp(root)
root.mainloop()