listen-agent 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +132 -0
  2. package/dist/commands/create.d.ts +3 -0
  3. package/dist/commands/create.d.ts.map +1 -0
  4. package/dist/commands/create.js +157 -0
  5. package/dist/commands/create.js.map +1 -0
  6. package/dist/commands/init.d.ts +3 -0
  7. package/dist/commands/init.d.ts.map +1 -0
  8. package/dist/commands/init.js +210 -0
  9. package/dist/commands/init.js.map +1 -0
  10. package/dist/commands/list.d.ts +2 -0
  11. package/dist/commands/list.d.ts.map +1 -0
  12. package/dist/commands/list.js +65 -0
  13. package/dist/commands/list.js.map +1 -0
  14. package/dist/commands/setup.d.ts +2 -0
  15. package/dist/commands/setup.d.ts.map +1 -0
  16. package/dist/commands/setup.js +50 -0
  17. package/dist/commands/setup.js.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +53 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/types/index.d.ts +25 -0
  23. package/dist/types/index.d.ts.map +1 -0
  24. package/dist/types/index.js +26 -0
  25. package/dist/types/index.js.map +1 -0
  26. package/dist/utils/detect.d.ts +4 -0
  27. package/dist/utils/detect.d.ts.map +1 -0
  28. package/dist/utils/detect.js +52 -0
  29. package/dist/utils/detect.js.map +1 -0
  30. package/dist/utils/files.d.ts +7 -0
  31. package/dist/utils/files.d.ts.map +1 -0
  32. package/dist/utils/files.js +70 -0
  33. package/dist/utils/files.js.map +1 -0
  34. package/dist/utils/logger.d.ts +9 -0
  35. package/dist/utils/logger.d.ts.map +1 -0
  36. package/dist/utils/logger.js +10 -0
  37. package/dist/utils/logger.js.map +1 -0
  38. package/package.json +66 -0
  39. package/skills/mac-m4-lora-training/README.md +152 -0
  40. package/skills/mac-m4-lora-training/SKILL.md +181 -0
  41. package/skills/mac-m4-lora-training/scripts/auto_lora_train_mps.py +474 -0
  42. package/skills/mac-m4-lora-training/scripts/install_dependencies.sh +226 -0
  43. package/skills/mac-m4-lora-training/scripts/quick_train.sh +88 -0
  44. package/skills/wechat-work-notification/README.md +88 -0
  45. package/skills/wechat-work-notification/SKILL.md +187 -0
  46. package/templates/advanced/README.md +45 -0
  47. package/templates/advanced/SKILL.md +149 -0
  48. package/templates/advanced/scripts/install_dependencies.sh +14 -0
  49. package/templates/advanced/scripts/run_task.sh +48 -0
  50. package/templates/basic/README.md +17 -0
  51. package/templates/basic/SKILL.md +72 -0
@@ -0,0 +1,181 @@
1
+ ---
2
+ name: mac-m4-lora-training
3
+ description: Mac M4芯片专用的无GUI LoRA自动化训练工具,支持参数自调、MPS加速、自然语言反馈优化
4
+ version: 1.0.0
5
+ author: ""
6
+ tags: ["ai", "machine-learning", "lora", "training", "mac-m4", "mps", "pytorch", "stable-diffusion"]
7
+ ---
8
+
9
+ # Mac M4 LoRA自动化训练 Skill
10
+
11
+ 你是一个专门处理Mac M4芯片LoRA模型训练的AI助手,具备完整的自动化训练、参数调优和部署能力。
12
+
13
+ ## 任务概述
14
+
15
+ 本技能用于在Mac M4芯片上进行LoRA(Low-Rank Adaptation)模型的自动化训练,专为ARM架构和MPS加速优化,支持自然语言反馈的参数调优,实现从环境准备到模型部署的完整自动化流程。
16
+
17
+ ## 核心能力
18
+
19
+ - 🚀 **M4芯片优化训练** - 专为ARM架构和MPS加速优化的LoRA训练
20
+ - 🧠 **智能参数调优** - 基于自然语言反馈自动调整训练参数
21
+ - 📊 **自动化流程** - 从环境准备到模型部署的完整自动化
22
+ - 💾 **显存管理** - 针对M4共享内存架构的优化策略
23
+ - 🔄 **ComfyUI集成** - 训练完成自动部署到ComfyUI
24
+ - 📝 **数据处理** - 自动CSV打标和数据预处理
25
+
26
+ ## 系统要求
27
+
28
+ ### 硬件要求
29
+ - **机型**: Mac M4 Pro/Max/Ultra
30
+ - **内存**: ≥16GB(推荐32GB+)
31
+ - **存储**: ≥50GB可用空间
32
+ - **系统**: macOS 13.0+
33
+
34
+ ### 软件依赖
35
+ - Python 3.10+
36
+ - PyTorch (MPS版本)
37
+ - sd-scripts
38
+ - transformers
39
+ - CLIP模型
40
+
41
+ ## 执行步骤
42
+
43
+ ### 第一步:环境安装
44
+
45
+ 使用提供的自动安装脚本:
46
+
47
+ ```bash
48
+ ./scripts/install_dependencies.sh
49
+ ```
50
+
51
+ 这个脚本会自动完成:
52
+ - Homebrew安装
53
+ - Python 3.10安装
54
+ - PyTorch MPS版本安装
55
+ - sd-scripts克隆
56
+ - 所有依赖包安装
57
+ - 目录结构创建
58
+
59
+ ### 第二步:激活环境
60
+
61
+ ```bash
62
+ source activate_env.sh
63
+ ```
64
+
65
+ ### 第三步:准备训练数据
66
+
67
+ 1. 创建训练图片目录
68
+ 2. 放入20-100张训练图片
69
+ 3. 支持格式:PNG, JPG, JPEG, WebP, BMP
70
+
71
+ ### 第四步:开始训练
72
+
73
+ #### 方法1:一键交互式训练
74
+
75
+ ```bash
76
+ ./scripts/quick_train.sh
77
+ ```
78
+
79
+ 脚本会引导你输入:
80
+ - LoRA名称
81
+ - ComfyUI安装目录
82
+ - 训练图片目录
83
+ - 触发词(可选)
84
+ - 训练反馈(可选)
85
+
86
+ #### 方法2:直接使用Python脚本
87
+
88
+ ```bash
89
+ python scripts/auto_lora_train_mps.py \
90
+ --lora_name "my_character" \
91
+ --comfyui_dir "/Users/username/ComfyUI" \
92
+ --train_dir "/path/to/training/images"
93
+ ```
94
+
95
+ ### 第五步:参数调优(可选)
96
+
97
+ 如果训练效果不佳,可以提供反馈进行调优:
98
+
99
+ ```bash
100
+ python scripts/auto_lora_train_mps.py \
101
+ --lora_name "my_character_v2" \
102
+ --comfyui_dir "/Users/username/ComfyUI" \
103
+ --train_dir "/path/to/training/images" \
104
+ --feedback "角色特征不明显"
105
+ ```
106
+
107
+ ## 参数调优映射
108
+
109
+ | 反馈关键词 | 参数调整策略 |
110
+ |------------|--------------|
111
+ | "特征不明显" | 增加network_dim、延长训练轮数、提高学习率 |
112
+ | "风格偏差大" | 降低学习率、减少训练轮数、调整clip_skip |
113
+ | "显存不足" | 减少批次大小、降低network_dim、启用梯度检查点 |
114
+ | "过拟合" | 降低学习率、减少训练轮数、增加批次大小 |
115
+
116
+ ## M4专属优化策略
117
+
118
+ ### 显存优化
119
+ - `network_dim` 最大不超过64
120
+ - `train_batch_size` 建议1-2(M4 Max可尝试3)
121
+ - 必须启用 `--gradient_checkpointing` 和 `--lowram`
122
+ - 训练时关闭其他大型软件
123
+
124
+ ### 性能调优
125
+ - 使用混合精度训练(fp16)
126
+ - 启用梯度检查点节省显存
127
+ - 优化批次大小平衡速度与稳定性
128
+
129
+ ## 故障排除
130
+
131
+ | 问题 | 解决方案 |
132
+ |------|----------|
133
+ | MPS设备未找到 | 确认macOS≥13.0,验证PyTorch MPS支持 |
134
+ | 训练速度慢 | 降低network_dim/批次,启用混合精度 |
135
+ | 模型拷贝失败 | 检查ComfyUI目录权限 |
136
+ | CLIP评估报错 | 降级transformers到4.30.2 |
137
+
138
+ ## 输出文件
139
+
140
+ 训练完成后会生成:
141
+
142
+ 1. **LoRA模型文件**
143
+ - 位置:`{ComfyUI}/models/loras/{lora_name}.safetensors`
144
+ - 可直接在ComfyUI中使用
145
+
146
+ 2. **训练日志**
147
+ - 位置:`{train_dir}/{lora_name}_training_log.json`
148
+ - 包含所有训练参数和结果
149
+
150
+ 3. **标注文件**
151
+ - 位置:`{train_dir}/train.csv`
152
+ - 自动生成的图片标注
153
+
154
+ ## 最佳实践
155
+
156
+ 1. **数据准备**
157
+ - 图片质量要高,避免模糊或低分辨率
158
+ - 保持风格一致性
159
+ - 适当的数据量(20-100张)
160
+
161
+ 2. **参数调优**
162
+ - 从默认参数开始
163
+ - 根据反馈逐步调整
164
+ - 记录每次训练的参数和效果
165
+
166
+ 3. **显存管理**
167
+ - 训练时关闭其他大型应用
168
+ - 使用适当的批次大小
169
+ - 启用显存优化选项
170
+
171
+ 4. **质量评估**
172
+ - 使用参考图进行相似度评估
173
+ - 定期检查训练样本
174
+ - 避免过拟合
175
+
176
+ ## 扩展功能
177
+
178
+ - **批量训练**: 支持多个数据集并行训练
179
+ - **训练监控**: 实时显示loss曲线和训练进度
180
+ - **自动调参**: 基于历史数据自动优化参数
181
+ - **模型管理**: 版本控制和模型比较功能
@@ -0,0 +1,474 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Mac M4 LoRA自动化训练脚本
4
+ 只需提供基本参数即可一键开始训练
5
+
6
+ 使用方法:
7
+ python auto_lora_train_mps.py --lora_name "my_character" --comfyui_dir "/path/to/ComfyUI" --train_dir "/path/to/images"
8
+ """
9
+
10
+ import argparse
11
+ import subprocess
12
+ import shutil
13
+ import os
14
+ import sys
15
+ import json
16
+ import time
17
+ from pathlib import Path
18
+ import torch
19
+ from transformers import CLIPProcessor, CLIPModel
20
+
21
+ # ========================== 核心配置 ==========================
22
+
23
+ # M4专属基础参数配置
24
+ BASE_PARAMS = {
25
+ "network_dim": 32,
26
+ "network_alpha": 32,
27
+ "learning_rate": 2e-4,
28
+ "train_batch_size": 2, # M4推荐批次
29
+ "max_train_epochs": 50,
30
+ "clip_skip": 2,
31
+ "lowram": True,
32
+ "save_every_n_epochs": 10,
33
+ "save_precision": "fp16",
34
+ "resolution": "512,512",
35
+ "device": "mps",
36
+ "gradient_checkpointing": True,
37
+ "mixed_precision": "fp16"
38
+ }
39
+
40
+ # 反馈-参数映射表
41
+ FEEDBACK_PARAM_MAP = {
42
+ "特征不明显": {
43
+ "network_dim": lambda x: min(x+16, 64),
44
+ "max_train_epochs": lambda x: x+20,
45
+ "learning_rate": lambda x: x*1.1
46
+ },
47
+ "风格偏差大": {
48
+ "learning_rate": lambda x: x*0.5,
49
+ "clip_skip": 1,
50
+ "max_train_epochs": lambda x: max(x-10, 30)
51
+ },
52
+ "显存不足": {
53
+ "train_batch_size": lambda x: max(1, x-1),
54
+ "network_dim": lambda x: max(x-16, 16),
55
+ "gradient_checkpointing": True
56
+ },
57
+ "过拟合": {
58
+ "learning_rate": lambda x: x*0.6,
59
+ "max_train_epochs": lambda x: max(x-15, 20),
60
+ "train_batch_size": lambda x: min(x+1, 3)
61
+ }
62
+ }
63
+
64
+ # ========================== 工具函数 ==========================
65
+
66
+ def print_banner():
67
+ """打印启动横幅"""
68
+ banner = """
69
+ ╔══════════════════════════════════════════════════════════════╗
70
+ ║ Mac M4 LoRA 自动化训练工具 ║
71
+ ║ ║
72
+ ║ 🚀 专为Mac M4芯片优化 ║
73
+ ║ 🧠 智能参数调优 ║
74
+ ║ 📊 完整自动化流程 ║
75
+ ║ 💾 显存优化管理 ║
76
+ ╚══════════════════════════════════════════════════════════════╝
77
+ """
78
+ print(banner)
79
+
80
+ def check_system_requirements():
81
+ """检查系统要求"""
82
+ print("🔍 检查系统要求...")
83
+
84
+ # 检查macOS版本
85
+ try:
86
+ result = subprocess.run(['sw_vers', '-productVersion'], capture_output=True, text=True)
87
+ macos_version = result.stdout.strip()
88
+ print(f" macOS版本: {macos_version}")
89
+
90
+ major_version = int(macos_version.split('.')[0])
91
+ if major_version < 13:
92
+ print("❌ 需要macOS 13.0或更高版本以支持MPS")
93
+ return False
94
+ except:
95
+ print("⚠️ 无法检测macOS版本")
96
+
97
+ # 检查MPS支持
98
+ try:
99
+ import torch
100
+ mps_available = torch.backends.mps.is_available()
101
+ print(f" MPS加速: {'✅ 可用' if mps_available else '❌ 不可用'}")
102
+ if not mps_available:
103
+ print("❌ MPS加速不可用,请检查系统配置")
104
+ return False
105
+ except ImportError:
106
+ print("❌ PyTorch未安装")
107
+ return False
108
+
109
+ # 检查内存
110
+ try:
111
+ result = subprocess.run(['system_profiler', 'SPHardwareDataType'], capture_output=True, text=True)
112
+ for line in result.stdout.split('\n'):
113
+ if 'Memory:' in line:
114
+ memory = line.split(':')[1].strip()
115
+ print(f" 系统内存: {memory}")
116
+ break
117
+ except:
118
+ print("⚠️ 无法检测系统内存")
119
+
120
+ print("✅ 系统检查完成")
121
+ return True
122
+
123
+ def setup_environment():
124
+ """设置训练环境"""
125
+ print("🛠️ 设置训练环境...")
126
+
127
+ # 检查sd-scripts目录
128
+ if not os.path.exists('sd-scripts'):
129
+ print("📥 克隆sd-scripts仓库...")
130
+ try:
131
+ subprocess.run(['git', 'clone', 'https://github.com/kohya-ss/sd-scripts.git'], check=True)
132
+ except subprocess.CalledProcessError:
133
+ print("❌ 克隆sd-scripts失败")
134
+ return False
135
+
136
+ # 检查必要的Python包
137
+ required_packages = ['torch', 'transformers', 'accelerate', 'pillow']
138
+ missing_packages = []
139
+
140
+ for package in required_packages:
141
+ try:
142
+ __import__(package)
143
+ except ImportError:
144
+ missing_packages.append(package)
145
+
146
+ if missing_packages:
147
+ print(f"❌ 缺少必要的Python包: {', '.join(missing_packages)}")
148
+ print("请先安装依赖: pip install torch torchvision transformers accelerate pillow")
149
+ return False
150
+
151
+ print("✅ 环境设置完成")
152
+ return True
153
+
154
+ def get_user_inputs():
155
+ """获取用户输入参数"""
156
+ parser = argparse.ArgumentParser(description="Mac M4 LoRA 自动训练工具")
157
+ parser.add_argument("--lora_name", type=str, required=True,
158
+ help="LoRA模型名称(不含后缀)")
159
+ parser.add_argument("--comfyui_dir", type=str, required=True,
160
+ help="ComfyUI安装目录路径")
161
+ parser.add_argument("--train_dir", type=str, required=True,
162
+ help="训练图片目录路径")
163
+ parser.add_argument("--trigger_word", type=str, default="",
164
+ help="LoRA触发词(可选,默认使用lora_name)")
165
+ parser.add_argument("--feedback", type=str, default="",
166
+ help="训练反馈(如'特征不明显')")
167
+ parser.add_argument("--base_model", type=str, default="",
168
+ help="基础模型路径(可选)")
169
+
170
+ args = parser.parse_args()
171
+
172
+ # 设置默认触发词
173
+ if not args.trigger_word:
174
+ args.trigger_word = args.lora_name
175
+
176
+ return args
177
+
178
+ def validate_paths(args):
179
+ """验证路径有效性"""
180
+ print("📁 验证路径...")
181
+
182
+ # 检查训练目录
183
+ if not os.path.exists(args.train_dir):
184
+ print(f"❌ 训练目录不存在: {args.train_dir}")
185
+ return False
186
+
187
+ # 检查训练图片
188
+ img_extensions = ('.png', '.jpg', '.jpeg', '.webp', '.bmp')
189
+ image_files = [f for f in os.listdir(args.train_dir)
190
+ if f.lower().endswith(img_extensions)]
191
+
192
+ if len(image_files) == 0:
193
+ print(f"❌ 训练目录中没有找到图片文件: {args.train_dir}")
194
+ return False
195
+
196
+ print(f" 找到 {len(image_files)} 张训练图片")
197
+
198
+ # 检查ComfyUI目录
199
+ comfyui_lora_dir = os.path.join(args.comfyui_dir, "models", "loras")
200
+ if not os.path.exists(comfyui_lora_dir):
201
+ print(f"❌ ComfyUI LoRA目录不存在: {comfyui_lora_dir}")
202
+ print("请确认ComfyUI安装路径正确")
203
+ return False
204
+
205
+ print(f" ComfyUI LoRA目录: {comfyui_lora_dir}")
206
+
207
+ print("✅ 路径验证完成")
208
+ return True
209
+
210
+ def parse_feedback(feedback_text):
211
+ """解析用户反馈并调整参数"""
212
+ adjusted_params = {}
213
+ if not feedback_text:
214
+ return adjusted_params
215
+
216
+ print(f"🧠 解析训练反馈: {feedback_text}")
217
+
218
+ for keyword, param_rules in FEEDBACK_PARAM_MAP.items():
219
+ if keyword in feedback_text:
220
+ print(f" 检测到关键词: {keyword}")
221
+ for param, rule in param_rules.items():
222
+ if callable(rule):
223
+ adjusted_params[param] = rule(BASE_PARAMS.get(param, 0))
224
+ else:
225
+ adjusted_params[param] = rule
226
+
227
+ if adjusted_params:
228
+ print(f" 调整参数: {adjusted_params}")
229
+
230
+ return adjusted_params
231
+
232
+ def generate_train_csv(train_dir, trigger_word):
233
+ """生成训练CSV文件"""
234
+ print("📝 生成训练标注文件...")
235
+
236
+ csv_path = os.path.join(train_dir, "train.csv")
237
+ img_extensions = ('.png', '.jpg', '.jpeg', '.webp', '.bmp')
238
+
239
+ image_count = 0
240
+ with open(csv_path, "w", encoding="utf-8") as f:
241
+ for img_name in os.listdir(train_dir):
242
+ if img_name.lower().endswith(img_extensions):
243
+ img_path = os.path.join(train_dir, img_name)
244
+ f.write(f"{img_path},{trigger_word}\n")
245
+ image_count += 1
246
+
247
+ print(f" 生成标注文件: {csv_path}")
248
+ print(f" 标注图片数量: {image_count}")
249
+
250
+ return csv_path
251
+
252
+ def create_config_file(train_dir):
253
+ """创建模型配置文件"""
254
+ config_dir = os.path.join("sd-scripts", "configs")
255
+ os.makedirs(config_dir, exist_ok=True)
256
+
257
+ config_path = os.path.join(config_dir, "training_config.yaml")
258
+
259
+ config_content = """
260
+ model:
261
+ model_type: "sd2"
262
+
263
+ training:
264
+ resolution: 512
265
+ clip_skip: 2
266
+ gradient_checkpointing: true
267
+ mixed_precision: "fp16"
268
+ device: "mps"
269
+ """
270
+
271
+ with open(config_path, "w") as f:
272
+ f.write(config_content)
273
+
274
+ return config_path
275
+
276
+ def build_training_command(args, final_params, csv_path, config_path):
277
+ """构建训练命令"""
278
+ print("🔧 构建训练命令...")
279
+
280
+ # 创建输出目录
281
+ output_dir = os.path.join(args.train_dir, "lora_output")
282
+ os.makedirs(output_dir, exist_ok=True)
283
+
284
+ # 基础命令
285
+ cmd = [
286
+ "python", "train_network.py",
287
+ "--train_data_dir", args.train_dir,
288
+ "--output_dir", output_dir,
289
+ "--network_module", "networks.lora",
290
+ "--network_dim", str(final_params["network_dim"]),
291
+ "--network_alpha", str(final_params["network_alpha"]),
292
+ "--learning_rate", str(final_params["learning_rate"]),
293
+ "--train_batch_size", str(final_params["train_batch_size"]),
294
+ "--max_train_epochs", str(final_params["max_train_epochs"]),
295
+ "--save_every_n_epochs", str(final_params["save_every_n_epochs"]),
296
+ "--save_precision", final_params["save_precision"],
297
+ "--resolution", final_params["resolution"],
298
+ "--clip_skip", str(final_params["clip_skip"]),
299
+ "--mixed_precision", final_params["mixed_precision"],
300
+ "--output_name", args.lora_name
301
+ ]
302
+
303
+ # 添加可选参数
304
+ if final_params.get("lowram"):
305
+ cmd.append("--lowram")
306
+
307
+ if final_params.get("gradient_checkpointing"):
308
+ cmd.append("--gradient_checkpointing")
309
+
310
+ # 如果有基础模型
311
+ if args.base_model and os.path.exists(args.base_model):
312
+ cmd.extend(["--pretrained_model_name_or_path", args.base_model])
313
+
314
+ print(f" 输出目录: {output_dir}")
315
+
316
+ return cmd, output_dir
317
+
318
+ def run_training(cmd):
319
+ """执行训练"""
320
+ print("🚀 开始LoRA训练...")
321
+ print(f" 训练命令: {' '.join(cmd)}")
322
+
323
+ # 切换到sd-scripts目录
324
+ original_dir = os.getcwd()
325
+ os.chdir("sd-scripts")
326
+
327
+ try:
328
+ # 执行训练
329
+ process = subprocess.Popen(
330
+ cmd,
331
+ stdout=subprocess.PIPE,
332
+ stderr=subprocess.STDOUT,
333
+ universal_newlines=True,
334
+ bufsize=1
335
+ )
336
+
337
+ # 实时输出训练日志
338
+ for line in process.stdout:
339
+ print(f" {line.rstrip()}")
340
+
341
+ process.wait()
342
+
343
+ if process.returncode != 0:
344
+ raise Exception(f"训练失败,返回码: {process.returncode}")
345
+
346
+ print("✅ 训练完成")
347
+
348
+ finally:
349
+ os.chdir(original_dir)
350
+
351
+ def copy_lora_to_comfyui(output_dir, lora_name, comfyui_dir):
352
+ """拷贝LoRA模型到ComfyUI"""
353
+ print("📦 部署LoRA模型到ComfyUI...")
354
+
355
+ # 查找生成的LoRA文件
356
+ lora_files = []
357
+ for root, dirs, files in os.walk(output_dir):
358
+ for file in files:
359
+ if file.endswith(".safetensors") and lora_name in file:
360
+ lora_files.append(os.path.join(root, file))
361
+
362
+ if not lora_files:
363
+ print("❌ 未找到生成的LoRA模型文件")
364
+ return False
365
+
366
+ # 选择最新的文件
367
+ latest_lora = max(lora_files, key=os.path.getmtime)
368
+ print(f" 找到LoRA文件: {os.path.basename(latest_lora)}")
369
+
370
+ # 拷贝到ComfyUI
371
+ comfyui_lora_dir = os.path.join(comfyui_dir, "models", "loras")
372
+ target_path = os.path.join(comfyui_lora_dir, f"{lora_name}.safetensors")
373
+
374
+ try:
375
+ shutil.copy2(latest_lora, target_path)
376
+ print(f"✅ LoRA模型已部署到: {target_path}")
377
+ return True
378
+ except Exception as e:
379
+ print(f"❌ 拷贝失败: {e}")
380
+ return False
381
+
382
+ def save_training_log(args, final_params, success=True):
383
+ """保存训练日志"""
384
+ log_data = {
385
+ "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
386
+ "lora_name": args.lora_name,
387
+ "train_dir": args.train_dir,
388
+ "trigger_word": args.trigger_word,
389
+ "feedback": args.feedback,
390
+ "parameters": final_params,
391
+ "success": success
392
+ }
393
+
394
+ log_file = os.path.join(args.train_dir, f"{args.lora_name}_training_log.json")
395
+ with open(log_file, "w", encoding="utf-8") as f:
396
+ json.dump(log_data, f, indent=2, ensure_ascii=False)
397
+
398
+ print(f"📋 训练日志已保存: {log_file}")
399
+
400
+ def print_summary(args, success=True):
401
+ """打印训练总结"""
402
+ print("\n" + "="*60)
403
+ if success:
404
+ print("🎉 LoRA训练完成!")
405
+ print(f" 模型名称: {args.lora_name}")
406
+ print(f" 触发词: {args.trigger_word}")
407
+ print(f" ComfyUI路径: {os.path.join(args.comfyui_dir, 'models', 'loras', f'{args.lora_name}.safetensors')}")
408
+ print("\n💡 使用提示:")
409
+ print(f" 在ComfyUI中加载LoRA: {args.lora_name}.safetensors")
410
+ print(f" 在提示词中使用: {args.trigger_word}")
411
+ else:
412
+ print("❌ 训练失败")
413
+ print("请检查错误信息并重试")
414
+ print("="*60)
415
+
416
+ # ========================== 主函数 ==========================
417
+
418
+ def main():
419
+ """主函数"""
420
+ try:
421
+ # 打印启动横幅
422
+ print_banner()
423
+
424
+ # 获取用户输入
425
+ args = get_user_inputs()
426
+
427
+ # 检查系统要求
428
+ if not check_system_requirements():
429
+ sys.exit(1)
430
+
431
+ # 设置环境
432
+ if not setup_environment():
433
+ sys.exit(1)
434
+
435
+ # 验证路径
436
+ if not validate_paths(args):
437
+ sys.exit(1)
438
+
439
+ # 解析反馈并调整参数
440
+ adjusted_params = parse_feedback(args.feedback)
441
+ final_params = {**BASE_PARAMS, **adjusted_params}
442
+
443
+ print(f"🎯 最终训练参数:")
444
+ for key, value in final_params.items():
445
+ print(f" {key}: {value}")
446
+
447
+ # 生成训练文件
448
+ csv_path = generate_train_csv(args.train_dir, args.trigger_word)
449
+ config_path = create_config_file(args.train_dir)
450
+
451
+ # 构建训练命令
452
+ cmd, output_dir = build_training_command(args, final_params, csv_path, config_path)
453
+
454
+ # 执行训练
455
+ run_training(cmd)
456
+
457
+ # 部署到ComfyUI
458
+ copy_success = copy_lora_to_comfyui(output_dir, args.lora_name, args.comfyui_dir)
459
+
460
+ # 保存训练日志
461
+ save_training_log(args, final_params, copy_success)
462
+
463
+ # 打印总结
464
+ print_summary(args, copy_success)
465
+
466
+ except KeyboardInterrupt:
467
+ print("\n⚠️ 训练被用户中断")
468
+ sys.exit(1)
469
+ except Exception as e:
470
+ print(f"\n❌ 训练过程出错: {e}")
471
+ sys.exit(1)
472
+
473
+ if __name__ == "__main__":
474
+ main()