From 0792027beae236a90920d8f04edac313fb918018 Mon Sep 17 00:00:00 2001 From: wsb1224 Date: Wed, 28 May 2025 16:39:07 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=8E=B7=E5=8F=96=E7=BD=91?= =?UTF-8?q?=E9=A1=B5=E5=86=85=E5=AE=B9=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ArticleReplaceDifyBatchWTT.py | 629 +++++++++++++++++- ArticleReplaceBatch/main_process_wtt.py | 90 ++- 2 files changed, 659 insertions(+), 60 deletions(-) diff --git a/ArticleReplaceBatch/ArticleReplaceDifyBatchWTT.py b/ArticleReplaceBatch/ArticleReplaceDifyBatchWTT.py index 296aca2..e3d2432 100644 --- a/ArticleReplaceBatch/ArticleReplaceDifyBatchWTT.py +++ b/ArticleReplaceBatch/ArticleReplaceDifyBatchWTT.py @@ -1,4 +1,4 @@ - +import json import sys # 导入sys模块 @@ -13,7 +13,7 @@ import tkinter as tk from config import * -from tkinter import ttk, messagebox, filedialog +from tkinter import ttk, messagebox, filedialog, simpledialog from tkinter.scrolledtext import ScrolledText import pymysql @@ -43,16 +43,31 @@ class ArticleReplaceApp(tk.Tk): # 创建配置页面 self.config_frame = ttk.Frame(self.notebook) self.notebook.add(self.config_frame, text="配置") - # 初始化主页面 - self.init_main_frame() - # 初始化配置页面 - self.init_config_frame() + # 初始化变量 self.running = False self.thread = None self.total_links = 0 self.processed_links = 0 + # 初始化Coze配置变量 + self.template_name_var = tk.StringVar() + self.coze_workflow_id_var = tk.StringVar(value=CONFIG['Coze']['workflow_id']) + self.coze_access_token_var = tk.StringVar(value=CONFIG['Coze']['access_token']) + self.coze_is_async_var = tk.StringVar(value=CONFIG['Coze'].get('is_async', 'true')) + self.coze_input_data_template_var = tk.StringVar(value=CONFIG['Coze'].get('input_data_template', '{"article": "{article_text}", "link":"{link}", "weijin":"{weijin}"}')) + + # 初始化模板数据结构 + self.templates = { + "短篇": [], + "文章": [] + } + + # 初始化主页面 + self.init_main_frame() + # 初始化配置页面 + self.init_config_frame() + # 设置关闭窗口事件 self.protocol("WM_DELETE_WINDOW", self.on_close) @@ -82,14 +97,21 @@ class ArticleReplaceApp(tk.Tk): ai_service_combo = ttk.Combobox(control_frame, textvariable=self.ai_service_var, values=["dify", "coze"], width=10, state="readonly") ai_service_combo.grid(row=2, column=1, padx=5, pady=5, sticky=tk.W) + # 生成类型选择 + ttk.Label(control_frame, text="生成类型:").grid(row=3, column=0, padx=5, pady=5, sticky=tk.W) + self.generation_type_var = tk.StringVar(value="短篇") + self.generation_type_combo = ttk.Combobox(control_frame, textvariable=self.generation_type_var, values=["短篇", "文章"], width=10, state="readonly") + self.generation_type_combo.grid(row=3, column=1, padx=5, pady=5, sticky=tk.W) + self.generation_type_combo.bind("<>", self.on_generation_type_changed) + # 开始按钮 self.start_button = ttk.Button(control_frame, text="开始处理", command=self.start_processing) - self.start_button.grid(row=3, column=0, columnspan=3, padx=5, pady=20) + self.start_button.grid(row=4, column=0, columnspan=3, padx=5, pady=20) # 进度条 - ttk.Label(control_frame, text="处理进度:").grid(row=4, column=0, padx=5, pady=5, sticky=tk.W) + ttk.Label(control_frame, text="处理进度:").grid(row=5, column=0, padx=5, pady=5, sticky=tk.W) self.progress_var = tk.DoubleVar() - ttk.Progressbar(control_frame, variable=self.progress_var, maximum=100).grid(row=4, column=1, columnspan=2, + ttk.Progressbar(control_frame, variable=self.progress_var, maximum=100).grid(row=5, column=1, columnspan=2, padx=5, pady=5, sticky=tk.EW) # 创建右侧日志面板 @@ -235,25 +257,77 @@ class ArticleReplaceApp(tk.Tk): ttk.Entry(parent, textvariable=self.dify_input_data_template_var, width=50).grid(row=3, column=1, padx=5, pady=5) def init_coze_config(self, parent): + # 生成类型选择(与主页面联动) + type_frame = ttk.Frame(parent) + type_frame.grid(row=0, column=0, columnspan=3, padx=5, pady=5, sticky=tk.EW) + ttk.Label(type_frame, text="生成类型:").pack(side=tk.LEFT, padx=5) + self.coze_generation_type_var = tk.StringVar(value="短篇") + self.coze_generation_type_combo = ttk.Combobox(type_frame, textvariable=self.coze_generation_type_var, values=["短篇", "文章"], width=10, state="readonly") + self.coze_generation_type_combo.pack(side=tk.LEFT, padx=5) + self.coze_generation_type_combo.bind("<>", self.on_coze_generation_type_changed) + + # 编辑状态标签 + self.edit_status_label = ttk.Label(type_frame, text="", foreground="blue") + self.edit_status_label.pack(side=tk.LEFT, padx=20) + + # 加载已保存的模板 + self.load_templates() + + # 初始化变量跟踪 + self._setup_var_trace() + + # 模板管理框架 + template_frame = ttk.LabelFrame(parent, text="模板管理") + template_frame.grid(row=1, column=0, columnspan=3, padx=5, pady=10, sticky=tk.EW) + + # 模板列表和滚动条 + list_frame = ttk.Frame(template_frame) + list_frame.grid(row=1, column=0, padx=5, pady=5, sticky=tk.W) + ttk.Label(template_frame, text="模板列表:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W) + self.template_listbox = tk.Listbox(list_frame, height=5, width=30) + scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=self.template_listbox.yview) + self.template_listbox.configure(yscrollcommand=scrollbar.set) + self.template_listbox.pack(side=tk.LEFT, fill=tk.Y) + scrollbar.pack(side=tk.RIGHT, fill=tk.Y) + self.template_listbox.bind("<>", self.on_template_selected) + + # 模板操作按钮 + button_frame = ttk.Frame(template_frame) + button_frame.grid(row=1, column=1, padx=10, pady=5, sticky=tk.N) + ttk.Button(button_frame, text="新增模板", command=self.add_template).pack(pady=2) + ttk.Button(button_frame, text="删除模板", command=self.delete_template).pack(pady=2) + ttk.Button(button_frame, text="重命名模板", command=self.rename_template).pack(pady=2) + ttk.Button(button_frame, text="保存模板", command=self.save_template).pack(pady=2) + ttk.Button(button_frame, text="复制模板", command=self.duplicate_template).pack(pady=2) + ttk.Button(button_frame, text="使用模板", command=self.use_template).pack(pady=2) + + # 当前模板配置 + config_frame = ttk.LabelFrame(parent, text="当前模板配置") + config_frame.grid(row=2, column=0, columnspan=3, padx=5, pady=10, sticky=tk.EW) + + # 模板名称 + ttk.Label(config_frame, text="模板名称:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W) + ttk.Entry(config_frame, textvariable=self.template_name_var, width=30).grid(row=0, column=1, padx=5, pady=5) + # Coze Workflow ID - ttk.Label(parent, text="Workflow ID:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W) - self.coze_workflow_id_var = tk.StringVar(value=CONFIG['Coze']['workflow_id']) - ttk.Entry(parent, textvariable=self.coze_workflow_id_var, width=50).grid(row=0, column=1, padx=5, pady=5) + ttk.Label(config_frame, text="Workflow ID:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W) + ttk.Entry(config_frame, textvariable=self.coze_workflow_id_var, width=50).grid(row=1, column=1, padx=5, pady=5) # Coze Access Token - ttk.Label(parent, text="Access Token:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W) - self.coze_access_token_var = tk.StringVar(value=CONFIG['Coze']['access_token']) - ttk.Entry(parent, textvariable=self.coze_access_token_var, width=50).grid(row=1, column=1, padx=5, pady=5) + ttk.Label(config_frame, text="Access Token:").grid(row=2, column=0, padx=5, pady=5, sticky=tk.W) + ttk.Entry(config_frame, textvariable=self.coze_access_token_var, width=50).grid(row=2, column=1, padx=5, pady=5) # Coze Is Async - ttk.Label(parent, text="Is Async:").grid(row=2, column=0, padx=5, pady=5, sticky=tk.W) - self.coze_is_async_var = tk.StringVar(value=CONFIG['Coze']['is_async']) - ttk.Combobox(parent, textvariable=self.coze_is_async_var, values=["true", "false"], width=10, state="readonly").grid(row=2, column=1, padx=5, pady=5, sticky=tk.W) + ttk.Label(config_frame, text="Is Async:").grid(row=3, column=0, padx=5, pady=5, sticky=tk.W) + ttk.Combobox(config_frame, textvariable=self.coze_is_async_var, values=["true", "false"], width=10, state="readonly").grid(row=3, column=1, padx=5, pady=5, sticky=tk.W) # Coze Input Data Template - ttk.Label(parent, text="Input Data模板:").grid(row=3, column=0, padx=5, pady=5, sticky=tk.W) - self.coze_input_data_template_var = tk.StringVar(value=CONFIG['Coze'].get('input_data_template', '{{"article": "{article_text}", "link":"{link}", "weijin":"{weijin}"}}')) # 添加默认值 - ttk.Entry(parent, textvariable=self.coze_input_data_template_var, width=50).grid(row=3, column=1, padx=5, pady=5) + ttk.Label(config_frame, text="Input Data模板:").grid(row=4, column=0, padx=5, pady=5, sticky=tk.W) + # Variable already initialized in __init__ + ttk.Entry(config_frame, textvariable=self.coze_input_data_template_var, width=50).grid(row=4, column=1, padx=5, pady=5) + + # 更新模板列表 + self.update_template_list() def init_baidu_config(self, parent): # 百度 API Key @@ -339,6 +413,468 @@ class ArticleReplaceApp(tk.Tk): CONFIG['Keywords']['banned_words'] = words messagebox.showinfo("保存成功", "违禁词列表已更新") + def on_generation_type_changed(self, event=None): + """主页面生成类型改变时的处理""" + # 同步到coze页面 + self.coze_generation_type_var.set(self.generation_type_var.get()) + self.update_template_list() + + def on_coze_generation_type_changed(self, event=None): + """coze页面生成类型改变时的处理""" + # 同步到主页面 + self.generation_type_var.set(self.coze_generation_type_var.get()) + self.update_template_list() + + def update_template_list(self): + """更新模板列表显示""" + current_type = self.coze_generation_type_var.get() + self.template_listbox.delete(0, tk.END) + + if current_type in self.templates: + for template in self.templates[current_type]: + self.template_listbox.insert(tk.END, template['name']) + + def on_template_selected(self, event=None): + """模板选择时的处理""" + selection = self.template_listbox.curselection() + if selection: + index = selection[0] + current_type = self.coze_generation_type_var.get() + if current_type in self.templates and index < len(self.templates[current_type]): + template = self.templates[current_type][index] + self.load_template_config(template) + + def load_template_config(self, template): + """加载模板配置到界面""" + # 解绑之前的变量跟踪 + self._unbind_var_trace() + + self.template_name_var.set(template['name']) + self.coze_workflow_id_var.set(template.get('workflow_id', '')) + self.coze_access_token_var.set(template.get('access_token', '')) + self.coze_is_async_var.set(template.get('is_async', 'true')) + self.coze_input_data_template_var.set(template.get('input_data_template', '')) + + self.edit_status_label.config(text="已加载", foreground="blue") + self.after(2000, lambda: self.edit_status_label.config(text="")) + + # 重新绑定变量跟踪 + self._setup_var_trace() + + def _setup_var_trace(self): + """设置变量跟踪以显示编辑状态""" + self.var_traces = [] + for var in [self.template_name_var, self.coze_workflow_id_var, + self.coze_access_token_var, self.coze_is_async_var, + self.coze_input_data_template_var]: + trace_id = var.trace_add('write', lambda *args: self._show_edit_status()) + self.var_traces.append((var, trace_id)) + + def _unbind_var_trace(self): + """解绑变量跟踪""" + if hasattr(self, 'var_traces'): + for var, trace_id in self.var_traces: + try: + var.trace_remove('write', trace_id) + except Exception: + pass + self.var_traces = [] + + def _show_edit_status(self): + """显示编辑状态""" + self.edit_status_label.config(text="未保存", foreground="red") + + def add_template(self): + """添加新模板""" + current_type = self.coze_generation_type_var.get() + + # 获取当前模板列表中最大的序号 + max_num = 0 + for template in self.templates[current_type]: + try: + # 尝试将模板名称转换为整数 + if template['name'].isdigit(): + num = int(template['name']) + max_num = max(max_num, num) + except (ValueError, TypeError): + pass + + template_name = f"{max_num + 1}" + + # 获取当前配置作为默认值 + default_workflow_id = CONFIG['Coze'].get('workflow_id', '') + default_access_token = CONFIG['Coze'].get('access_token', '') + default_is_async = CONFIG['Coze'].get('is_async', 'true') + default_template = CONFIG['Coze'].get('input_data_template', + '{"article": "{article_text}", "link":"{link}", "weijin":"{weijin}"}') + + new_template = { + 'name': template_name, + 'type': current_type, + 'workflow_id': default_workflow_id, + 'access_token': default_access_token, + 'is_async': default_is_async, + 'input_data_template': default_template + } + + self.templates[current_type].append(new_template) + self.update_template_list() + self.save_templates() + + # 选中新添加的模板 + self.template_listbox.selection_clear(0, tk.END) + self.template_listbox.selection_set(len(self.templates[current_type]) - 1) + self.load_template_config(new_template) + self.edit_status_label.config(text="已创建", foreground="green") + self.after(2000, lambda: self.edit_status_label.config(text="未保存", foreground="red")) + + def delete_template(self): + """删除选中的模板""" + selection = self.template_listbox.curselection() + if not selection: + messagebox.showwarning("提示", "请先选择要删除的模板") + return + + index = selection[0] + current_type = self.coze_generation_type_var.get() + if current_type not in self.templates or index >= len(self.templates[current_type]): + return + + template_name = self.templates[current_type][index]['name'] + if messagebox.askyesno("确认删除", f"确定要删除模板 '{template_name}' 吗?"): + del self.templates[current_type][index] + self.update_template_list() + self.save_templates() + + # 清除配置并更新状态 + self.clear_template_config() + self.edit_status_label.config(text=f"已删除 '{template_name}'", foreground="red") + self.after(2000, lambda: self.edit_status_label.config(text="")) + + # 如果还有模板,选中最后一个 + if self.templates[current_type]: + last_index = len(self.templates[current_type]) - 1 + self.template_listbox.selection_set(last_index) + self.load_template_config(self.templates[current_type][last_index]) + + def validate_template(self): + """验证模板配置""" + name = self.template_name_var.get().strip() + workflow_id = self.coze_workflow_id_var.get().strip() + access_token = self.coze_access_token_var.get().strip() + input_template = self.coze_input_data_template_var.get().strip() + + if not name: + messagebox.showerror("错误", "模板名称不能为空") + return False + + if not workflow_id: + messagebox.showerror("错误", "Workflow ID不能为空") + return False + + if not access_token: + messagebox.showerror("错误", "Access Token不能为空") + return False + + if not input_template: + messagebox.showerror("错误", "输入数据模板不能为空") + return False + + # 验证输入数据模板的JSON格式 + try: + # 替换占位符以便验证JSON格式 + test_template = input_template.replace('{article_text}', '')\ + .replace('{link}', '')\ + .replace('{weijin}', '') + json.loads(test_template) + except json.JSONDecodeError as e: + messagebox.showerror("错误", f"输入数据模板不是有效的JSON格式:\n{str(e)}") + return False + + return True + + return True + + def save_template(self): + """保存当前模板配置""" + if not self.validate_template(): + return + + selection = self.template_listbox.curselection() + if selection: + index = selection[0] + current_type = self.coze_generation_type_var.get() + if current_type in self.templates and index < len(self.templates[current_type]): + template = self.templates[current_type][index] + template['name'] = self.template_name_var.get().strip() + template['workflow_id'] = self.coze_workflow_id_var.get().strip() + template['access_token'] = self.coze_access_token_var.get().strip() + template['is_async'] = self.coze_is_async_var.get() + template['input_data_template'] = self.coze_input_data_template_var.get().strip() + + self.update_template_list() + self.save_templates() + self.edit_status_label.config(text="已保存", foreground="green") + self.after(2000, lambda: self.edit_status_label.config(text="")) + else: + messagebox.showwarning("未选择模板", "请先选择要保存的模板") + + def rename_template(self): + """重命名当前选中的模板""" + selection = self.template_listbox.curselection() + if not selection: + messagebox.showwarning("未选择模板", "请先选择要重命名的模板") + return + + index = selection[0] + current_type = self.coze_generation_type_var.get() + if current_type not in self.templates or index >= len(self.templates[current_type]): + return + + template = self.templates[current_type][index] + old_name = template['name'] + + # 弹出重命名对话框 + new_name = simpledialog.askstring("重命名模板", "请输入新的模板名称:", initialvalue=old_name) + if new_name and new_name.strip() and new_name != old_name: + template['name'] = new_name.strip() + self.update_template_list() + self.save_templates() + # 重新选中重命名后的模板 + self.template_listbox.selection_set(index) + self.edit_status_label.config(text="已重命名", foreground="green") + self.after(2000, lambda: self.edit_status_label.config(text="")) + + def duplicate_template(self): + """复制当前选中的模板""" + selection = self.template_listbox.curselection() + if not selection: + messagebox.showwarning("提示", "请先选择要复制的模板") + return + + index = selection[0] + current_type = self.coze_generation_type_var.get() + if current_type not in self.templates or index >= len(self.templates[current_type]): + return + + template = self.templates[current_type][index] + new_template = template.copy() + + # 获取当前模板列表中最大的副本序号 + base_name = template['name'] + max_num = 0 + for t in self.templates[current_type]: + if t['name'].startswith(f"{base_name}_副本"): + try: + num = int(t['name'].split('_副本')[-1]) if t['name'].split('_副本')[-1] else 1 + max_num = max(max_num, num) + except (IndexError, ValueError): + pass + + # 设置新的模板名称 + new_name = f"{base_name}_副本{max_num + 1 if max_num > 0 else ''}" + new_template['name'] = new_name + + self.templates[current_type].append(new_template) + self.update_template_list() + self.save_templates() + + # 选中新复制的模板 + new_index = len(self.templates[current_type]) - 1 + self.template_listbox.selection_clear(0, tk.END) + self.template_listbox.selection_set(new_index) + self.load_template_config(new_template) + + # 更新状态提示 + self.edit_status_label.config(text=f"已复制为 '{new_name}'", foreground="green") + self.after(2000, lambda: self.edit_status_label.config(text="未保存", foreground="red")) + + def use_template(self): + """使用模板功能 - 弹出模板选择对话框并应用所选模板配置""" + # 创建模板选择对话框 + dialog = tk.Toplevel(self) + dialog.title("选择模板") + dialog.geometry("400x300") + dialog.transient(self) # 设置为应用程序的子窗口 + dialog.grab_set() # 模态对话框 + dialog.resizable(False, False) + + # 创建说明标签 + ttk.Label(dialog, text="请选择要使用的模板:", font=("Arial", 10)).pack(pady=10) + + # 创建模板类型选择框架 + type_frame = ttk.Frame(dialog) + type_frame.pack(fill=tk.X, padx=10, pady=5) + + ttk.Label(type_frame, text="模板类型:").pack(side=tk.LEFT, padx=5) + dialog_type_var = tk.StringVar(value=self.coze_generation_type_var.get()) + type_combo = ttk.Combobox(type_frame, textvariable=dialog_type_var, values=["短篇", "文章"], width=10, state="readonly") + type_combo.pack(side=tk.LEFT, padx=5) + + # 创建模板列表框架 + list_frame = ttk.Frame(dialog) + list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) + + # 创建模板列表和滚动条 + template_listbox = tk.Listbox(list_frame, height=10, width=40) + scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=template_listbox.yview) + template_listbox.configure(yscrollcommand=scrollbar.set) + template_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + scrollbar.pack(side=tk.RIGHT, fill=tk.Y) + + # 填充模板列表 + def update_dialog_template_list(): + template_listbox.delete(0, tk.END) + current_type = dialog_type_var.get() + if current_type in self.templates: + for template in self.templates[current_type]: + template_listbox.insert(tk.END, template['name']) + + update_dialog_template_list() + + # 绑定类型选择变更事件 + def on_dialog_type_changed(event=None): + update_dialog_template_list() + + type_combo.bind("<>", on_dialog_type_changed) + + # 创建按钮框架 + button_frame = ttk.Frame(dialog) + button_frame.pack(fill=tk.X, padx=10, pady=10) + + # 定义确定按钮功能 + def on_confirm(): + selection = template_listbox.curselection() + if not selection: + messagebox.showwarning("未选择模板", "请先选择要使用的模板", parent=dialog) + return + + index = selection[0] + current_type = dialog_type_var.get() + if current_type not in self.templates or index >= len(self.templates[current_type]): + return + + selected_template = self.templates[current_type][index] + + # 应用所选模板的配置 + self.coze_generation_type_var.set(current_type) # 更新生成类型 + self.generation_type_var.set(current_type) # 同步到主页面 + + # 更新工作流配置 + self.coze_workflow_id_var.set(selected_template.get('workflow_id', '')) + self.coze_access_token_var.set(selected_template.get('access_token', '')) + self.coze_is_async_var.set(selected_template.get('is_async', 'true')) + self.coze_input_data_template_var.set(selected_template.get('input_data_template', '')) + + # 更新CONFIG配置 + CONFIG['Coze']['workflow_id'] = selected_template.get('workflow_id', '') + CONFIG['Coze']['access_token'] = selected_template.get('access_token', '') + CONFIG['Coze']['is_async'] = selected_template.get('is_async', 'true') + CONFIG['Coze']['input_data_template'] = selected_template.get('input_data_template', '') + + # 保存配置 + save_config(CONFIG) + + # 更新模板列表和选中状态 + self.update_template_list() + for i in range(self.template_listbox.size()): + if self.template_listbox.get(i) == selected_template['name']: + self.template_listbox.selection_set(i) + break + + # 显示成功提示 + self.edit_status_label.config(text=f"已应用模板 '{selected_template['name']}'", foreground="green") + self.after(2000, lambda: self.edit_status_label.config(text="")) + + # 关闭对话框 + dialog.destroy() + + # 添加确定和取消按钮 + ttk.Button(button_frame, text="确定", command=on_confirm).pack(side=tk.RIGHT, padx=5) + ttk.Button(button_frame, text="取消", command=dialog.destroy).pack(side=tk.RIGHT, padx=5) + + # 设置默认选中第一个模板 + if template_listbox.size() > 0: + template_listbox.selection_set(0) + + # 等待对话框关闭 + self.wait_window(dialog) + + def clear_template_config(self): + """清空模板配置界面""" + # 解绑变量跟踪 + self._unbind_var_trace() + + # 清空所有配置字段 + self.template_name_var.set('') + self.coze_workflow_id_var.set('') + self.coze_access_token_var.set('') + self.coze_is_async_var.set('true') + self.coze_input_data_template_var.set('') + + # 清空状态提示 + self.edit_status_label.config(text="已清空", foreground="gray") + self.after(2000, lambda: self.edit_status_label.config(text="")) + + # 重新绑定变量跟踪 + self._setup_var_trace() + + def load_templates(self): + """从配置文件加载模板""" + try: + import json + # 检查Templates节是否存在 + if 'Templates' in CONFIG: + templates_section = CONFIG['Templates'] + for key in templates_section: + if key.startswith('templates_'): + template_type = key.replace('templates_', '') + if template_type in self.templates: + value = templates_section[key] + # 确保value是字符串类型 + if isinstance(value, str): + self.templates[template_type] = json.loads(value) + else: + logger.warning(f"模板配置{key}的值不是字符串类型: {type(value)}") + self.templates[template_type] = [] + except Exception as e: + logger.error(f"加载模板配置失败: {e}") + + def save_templates(self): + """保存模板到配置文件""" + try: + import json + # 确保Templates节存在 + if 'Templates' not in CONFIG: + CONFIG.add_section('Templates') + + for template_type, templates in self.templates.items(): + CONFIG['Templates'][f'templates_{template_type}'] = json.dumps(templates, ensure_ascii=False) + + save_config(CONFIG) + except Exception as e: + logger.error(f"保存模板配置失败: {e}") + messagebox.showerror("保存失败", f"保存模板配置时出错:{e}") + + def get_current_template(self): + """获取当前选中的模板配置""" + selection = self.template_listbox.curselection() + if selection: + index = selection[0] + current_type = self.coze_generation_type_var.get() + if current_type in self.templates and index < len(self.templates[current_type]): + return self.templates[current_type][index] + + # 如果没有选中模板,返回当前界面的配置 + return { + 'name': self.template_name_var.get() or '默认模板', + 'type': self.coze_generation_type_var.get(), + 'workflow_id': self.coze_workflow_id_var.get(), + 'access_token': self.coze_access_token_var.get(), + 'is_async': self.coze_is_async_var.get(), + 'input_data_template': self.coze_input_data_template_var.get() + } + def browse_directory(self, var): directory = filedialog.askdirectory() if directory: @@ -490,6 +1026,9 @@ class ArticleReplaceApp(tk.Tk): CONFIG['Coze']['is_async'] = self.coze_is_async_var.get() CONFIG['Coze']['input_data_template'] = self.coze_input_data_template_var.get() # 保存 Coze input data 模板 + # 保存模板配置 + self.save_templates() + # 更新Baidu配置 CONFIG['Baidu']['api_key'] = self.baidu_api_key_var.get() CONFIG['Baidu']['secret_key'] = self.baidu_secret_key_var.get() @@ -559,9 +1098,15 @@ class ArticleReplaceApp(tk.Tk): # 获取AI服务提供商选择 ai_service = self.ai_service_var.get() + + # 获取生成类型 + generation_type = self.generation_type_var.get() + + # 获取当前选中的模板配置 + current_template = self.get_current_template() # 在新线程中运行处理任务 - self.thread = threading.Thread(target=self.run_processing, args=(excel_path, num_threads, ai_service)) + self.thread = threading.Thread(target=self.run_processing, args=(excel_path, num_threads, ai_service, generation_type, current_template)) self.thread.daemon = True self.thread.start() @@ -572,7 +1117,7 @@ class ArticleReplaceApp(tk.Tk): self.start_button.config(state=tk.NORMAL) self.running = False - def run_processing(self, excel_path, num_threads, ai_service): + def run_processing(self, excel_path, num_threads, ai_service, generation_type=None, current_template=None): """在后台线程中运行处理任务""" try: # 更新全局变量 @@ -582,9 +1127,32 @@ class ArticleReplaceApp(tk.Tk): # 记录开始时间 start_time = time.time() + # 如果有模板配置,临时更新CONFIG + original_config = None + if current_template and ai_service == 'coze': + original_config = { + 'workflow_id': CONFIG['Coze']['workflow_id'], + 'access_token': CONFIG['Coze']['access_token'], + 'is_async': CONFIG['Coze']['is_async'], + 'input_data_template': CONFIG['Coze'].get('input_data_template', '') + } + + CONFIG['Coze']['workflow_id'] = current_template.get('workflow_id', '') + CONFIG['Coze']['access_token'] = current_template.get('access_token', '') + CONFIG['Coze']['is_async'] = current_template.get('is_async', 'true') + CONFIG['Coze']['input_data_template'] = current_template.get('input_data_template', '') + + logger.info(f"应用模板配置: {current_template.get('name')}") + logger.info(f"Workflow ID: {CONFIG['Coze']['workflow_id']}") + logger.info(f"Access Token: {'*' * len(CONFIG['Coze']['access_token'])}") + logger.info(f"Is Async: {CONFIG['Coze']['is_async']}") + logger.info(f"Input Template: {CONFIG['Coze']['input_data_template']}") + # 读取链接并处理 - logger.info(f"开始处理链接,使用 {num_threads} 个线程") - results = link_to_text(num_threads=num_threads, ai_service=ai_service) + logger.info(f"开始处理链接,使用 {num_threads} 个线程,生成类型: {generation_type}") + if current_template: + logger.info(f"使用模板: {current_template.get('name', '未命名')}") + results = link_to_text(num_threads=num_threads, ai_service=ai_service, current_template=current_template) # 计算处理结果 total_links = len(results) @@ -595,7 +1163,7 @@ class ArticleReplaceApp(tk.Tk): elapsed_time = end_time - start_time # 记录处理结果 - logger.info( + logger.info( f"处理完成,共处理 {total_links} 个链接,成功 {success_links} 个,失败 {total_links - success_links} 个") logger.info(f"总耗时: {elapsed_time:.2f} 秒") @@ -604,8 +1172,15 @@ class ArticleReplaceApp(tk.Tk): f"共处理 {total_links} 个链接\n成功: {success_links} 个\n失败: {total_links - success_links} 个\n总耗时: {elapsed_time:.2f} 秒")) except Exception as e: logger.error(f"处理任务出错: {e}") - self.after(0, lambda: messagebox.showerror("处理失败", f"处理任务出错:{e}")) + self.after(0, lambda e=e: messagebox.showerror("处理错误", f"处理任务出错: {e}")) finally: + # 恢复原始配置(如果有的话) + if original_config is not None: + CONFIG['Coze']['workflow_id'] = original_config['workflow_id'] + CONFIG['Coze']['access_token'] = original_config['access_token'] + CONFIG['Coze']['is_async'] = original_config['is_async'] + CONFIG['Coze']['input_data_template'] = original_config['input_data_template'] + # 恢复开始按钮状态 self.after(0, lambda: self.start_button.config(state=tk.NORMAL)) self.running = False diff --git a/ArticleReplaceBatch/main_process_wtt.py b/ArticleReplaceBatch/main_process_wtt.py index 18f275d..677c7d7 100644 --- a/ArticleReplaceBatch/main_process_wtt.py +++ b/ArticleReplaceBatch/main_process_wtt.py @@ -12,12 +12,13 @@ from config import * # ==============================主程序=========================== -def process_link(link_info, ai_service): +def process_link(link_info, ai_service, current_template=None): link, article_type = link_info # 解包链接和类型信息 """ 处理单个链接 :param link: 要处理的链接 :param ai_service: AI服务提供商,可选值:dify, coze + :param current_template: 当前选择的模板配置 """ try: if link.startswith("https://www.toutiao.com"): @@ -81,30 +82,52 @@ def process_link(link_info, ai_service): # } message_content = call_dify_workflow(input_data) elif ai_service == "coze": - # logger.info("coze正在处理") - # weijin = "" - # if check_keywords: - # weijin = "违禁" - # # 从配置加载 Coze input_data 模板 - # input_data_template_str = CONFIG['Coze'].get('input_data_template', - # '{{"article": "{article_text}", "link":"{link}", "weijin":"{weijin}"}}') - # try: - # # 解析模板字符串为字典 - # input_data_template = json.loads(input_data_template_str) - # # 使用实际变量格式化模板 - # input_data = {k: v.format(article_text=article_text, link=link, weijin=weijin) for k, v in - # input_data_template.items()} - # except (json.JSONDecodeError, KeyError, AttributeError) as e: - # logger.error(f"处理 Coze input_data 模板时出错: {e}. 使用默认模板.") - # input_data = { - # "article": article_text, - # "link": link, - # "weijin": weijin - # } - input_data = { + logger.info("coze正在处理") + + # 如果有模板配置,临时更新CONFIG + original_config = None + if current_template: + original_config = { + 'workflow_id': CONFIG['Coze']['workflow_id'], + 'access_token': CONFIG['Coze']['access_token'], + 'is_async': CONFIG['Coze']['is_async'], + 'input_data_template': CONFIG['Coze'].get('input_data_template', '') + } + + CONFIG['Coze']['workflow_id'] = current_template.get('workflow_id', '') + CONFIG['Coze']['access_token'] = current_template.get('access_token', '') + CONFIG['Coze']['is_async'] = current_template.get('is_async', 'true') + CONFIG['Coze']['input_data_template'] = current_template.get('input_data_template', '') + + logger.info(f"应用模板配置: {current_template.get('name')}") + logger.info(f"Workflow ID: {CONFIG['Coze']['workflow_id']}") + logger.info(f"Access Token: {'*' * len(CONFIG['Coze']['access_token'])}") + logger.info(f"Is Async: {CONFIG['Coze']['is_async']}") + logger.info(f"Input Template: {CONFIG['Coze']['input_data_template']}") + + try: + # 从配置加载 Coze input_data 模板 + input_data_template_str = CONFIG['Coze'].get('input_data_template', + '{"article": "{article_text}", "link":"{link}", "weijin":"{weijin}"}') + # 解析模板字符串为字典 + input_data_template = json.loads(input_data_template_str) + # 使用实际变量格式化模板 + input_data = input_data_template + except (json.JSONDecodeError, KeyError, AttributeError) as e: + logger.error(f"处理 Coze input_data 模板时出错: {e}. 使用默认模板.") + input_data = { "article": article_text } - message_content = call_coze_article_workflow(input_data) + + try: + message_content = call_coze_article_workflow(input_data) + finally: + # 恢复原始配置(如果有的话) + if original_config is not None: + CONFIG['Coze']['workflow_id'] = original_config['workflow_id'] + CONFIG['Coze']['access_token'] = original_config['access_token'] + CONFIG['Coze']['is_async'] = original_config['is_async'] + CONFIG['Coze']['input_data_template'] = original_config['input_data_template'] # 获取当前时间并格式化 current_time = datetime.now().strftime("%H:%M:%S") @@ -151,7 +174,7 @@ def process_link(link_info, ai_service): if img_urls: # 在类型目录下创建图片目录 - type_picture_dir = os.path.join(PICTURE_BASE_PATH, article_type) + type_picture_dir = os.path.join(IMGS_BASE_PATH, article_type) safe_open_directory(type_picture_dir) download_and_process_images(img_urls, file_name, type_picture_dir) @@ -160,7 +183,7 @@ def process_link(link_info, ai_service): raise -def link_to_text(prompt1=None, prompt2=None, num_threads=None, ai_service="dify"): +def link_to_text(num_threads=None, ai_service="dify", current_template=None): use_link_path = 'use_link_path.txt' # 读取链接 @@ -174,13 +197,14 @@ def link_to_text(prompt1=None, prompt2=None, num_threads=None, ai_service="dify" database = CONFIG['Database']['database'] for link_info in links: - link = link_info[0] # 获取链接 + link = link_info[0].strip() # 获取链接并去除空白字符 + article_type = link_info[1].strip() # 获取类型并去除空白字符 logging.info(f"总共{len(links)}个链接") # if check_link_exists(host, user, password, database, link): # logger.info(f"链接已存在: {link}") # continue # else: - filtered_links.append(link) + filtered_links.append((link, article_type)) # 保存链接和类型的元组 # logger.info(f"链接不存在: {link}") # print("链接不存在,存储到过滤器中:", link) @@ -189,7 +213,7 @@ def link_to_text(prompt1=None, prompt2=None, num_threads=None, ai_service="dify" return [] # 使用多线程处理链接 - results = process_links_with_threads(filtered_links, num_threads, ai_service) + results = process_links_with_threads(filtered_links, num_threads, ai_service, current_template) # 记录已处理的链接 with open(use_link_path, 'a+', encoding='utf-8') as f: @@ -206,7 +230,7 @@ result_queue = queue.Queue() # 工作线程函数 -def worker(ai_service): +def worker(ai_service, current_template=None): while True: try: # 从队列中获取任务 @@ -217,7 +241,7 @@ def worker(ai_service): # 处理链接 try: logger.info(f"开始处理链接:{link}") - process_link(link, ai_service) + process_link(link, ai_service, current_template) result_queue.put((link, True, None)) # 成功 except Exception as e: result_queue.put((link, False, str(e))) # 失败 @@ -230,7 +254,7 @@ def worker(ai_service): # 多线程处理链接 -def process_links_with_threads(links, num_threads=None, ai_service="dify"): +def process_links_with_threads(links, num_threads=None, ai_service="dify", current_template=None): if num_threads is None: num_threads = min(MAX_THREADS, len(links)) else: @@ -245,9 +269,9 @@ def process_links_with_threads(links, num_threads=None, ai_service="dify"): # 创建工作线程 threads = [] - # 将AI服务选择传递给worker函数 + # 将AI服务选择和模板配置传递给worker函数 for _ in range(num_threads): - t = threading.Thread(target=worker, args=(ai_service,)) + t = threading.Thread(target=worker, args=(ai_service, current_template)) t.daemon = True t.start() threads.append(t)