chore(vault): update Education AI research memory and tools
This commit is contained in:
@@ -73,4 +73,4 @@ type: book-chapter
|
||||
- Python 3.10+
|
||||
- Calibre (ebook-convert)
|
||||
- html2text (recommended)
|
||||
- beautifulsoup4 (optional fallback)
|
||||
- beautifulsoup4 (optional fallback)
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
## 📁 准备工作
|
||||
|
||||
### 1. 应用位置
|
||||
|
||||
- **应用路径**: `D:\Users\hhhh2024\AppData\Local\LLM-Wiki\LLM Wiki.exe`
|
||||
- **测试文件**: `D:\Applications\app\kepano-obsidian-main\raw\呼吸之间_李谨伯\第一编 从身体入手.md`
|
||||
|
||||
### 2. 测试输出目录
|
||||
|
||||
- A 组输出:`D:\Applications\app\kepano-obsidian-main\tools\experiments\wiki-generation-compare\output\llm-wiki-manual-group-a\`
|
||||
- B 组输出:`D:\Applications\app\kepano-obsidian-main\tools\experiments\wiki-generation-compare\output\llm-wiki-manual-group-b\`
|
||||
|
||||
@@ -53,8 +55,8 @@
|
||||
D:\Applications\app\kepano-obsidian-main\raw\呼吸之间_李谨伯\第一编 从身体入手.md
|
||||
```
|
||||
4. 观察左侧 "Activity Panel":
|
||||
- 会看到 "Analyzing..." 进度
|
||||
- 然后看到 "Generating..." 进度
|
||||
- 会看到 "Analyzing…" 进度
|
||||
- 然后看到 "Generating…" 进度
|
||||
|
||||
### 步骤 2A-2:观察 Two-Step 流程
|
||||
|
||||
@@ -63,7 +65,6 @@
|
||||
- 提取结构化信息(概念、方法、实体)
|
||||
- 识别术语关系
|
||||
- 推荐创建页面
|
||||
|
||||
- **Step 2**: LLM 生成 Wiki 页面(约 60-120 秒)
|
||||
- 根据推荐页面生成完整 Markdown
|
||||
- 自动创建目录结构
|
||||
@@ -110,8 +111,8 @@
|
||||
D:\Applications\app\kepano-obsidian-main\raw\呼吸之间_李谨伯\第一编 从身体入手.md
|
||||
```
|
||||
4. 观察左侧 "Activity Panel":
|
||||
- 只会看到 "Generating..." 进度
|
||||
- 没有 "Analyzing..." 阶段
|
||||
- 只会看到 "Generating…" 进度
|
||||
- 没有 "Analyzing…" 阶段
|
||||
|
||||
### 步骤 2B-3:观察 Single-Step 流程
|
||||
|
||||
@@ -150,12 +151,13 @@
|
||||
| 维度 | A 组 | B 组 |
|
||||
|------|------|------|
|
||||
| 生成页面数 | ? 页 | ? 页 |
|
||||
| 常见术语是否覆盖 | 精气神、天人感应... | 精气神、天人感应... |
|
||||
| 常见术语是否覆盖 | 精气神、天人感应… | 精气神、天人感应… |
|
||||
| 未覆盖的术语 | ? | ? |
|
||||
|
||||
### 2. Frontmatter 质量检查
|
||||
|
||||
打开几个生成的页面,检查:
|
||||
|
||||
```yaml
|
||||
---
|
||||
categories:
|
||||
@@ -349,4 +351,4 @@ status: active
|
||||
|
||||
---
|
||||
|
||||
**祝测试顺利!如有问题,请随时反馈。**
|
||||
**祝测试顺利!如有问题,请随时反馈。**
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
真实 B 组实验(Single-Step 模式)- 使用 openai 库
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
import openai
|
||||
|
||||
# 配置
|
||||
base_dir = os.getcwd()
|
||||
experiment_dir = os.path.join(base_dir, "tools", "experiments", "wiki-generation-compare")
|
||||
source_file = os.path.join(base_dir, "raw", "呼吸之间_李谨伯", "第一编 从身体入手.md")
|
||||
output_dir = os.path.join(experiment_dir, "output", "group-b-real")
|
||||
|
||||
# 创建输出目录
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
os.makedirs(os.path.join(output_dir, "wiki", "concepts"), exist_ok=True)
|
||||
os.makedirs(os.path.join(output_dir, "wiki", "methods"), exist_ok=True)
|
||||
os.makedirs(os.path.join(output_dir, "wiki", "entities"), exist_ok=True)
|
||||
|
||||
# 记录开始时间
|
||||
start_time = datetime.now()
|
||||
start_time_str = start_time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
print("=== B 组真实实验开始:Single-Step 模式 ===")
|
||||
print(f"开始时间: {start_time_str}")
|
||||
|
||||
# 检查 API Key
|
||||
api_key = os.environ.get('OPENAI_API_KEY')
|
||||
if not api_key:
|
||||
print("[ERROR] 未找到 OPENAI_API_KEY 环境变量")
|
||||
exit(1)
|
||||
|
||||
print(f"API Key 长度: {len(api_key)}")
|
||||
|
||||
# 初始化 openai 客户端
|
||||
client = openai.OpenAI(api_key=api_key, timeout=300)
|
||||
|
||||
# 直接生成
|
||||
print("\n生成阶段...")
|
||||
|
||||
# 读取源文件
|
||||
with open(source_file, 'r', encoding='utf-8') as f:
|
||||
source_content = f.read()
|
||||
|
||||
# 读取单步 prompt
|
||||
singlestep_prompt_file = os.path.join(experiment_dir, "prompts", "singlestep.md")
|
||||
with open(singlestep_prompt_file, 'r', encoding='utf-8') as f:
|
||||
template = f.read()
|
||||
|
||||
full_prompt = template.replace("{SOURCE_CONTENT}", source_content)
|
||||
|
||||
print(f" Prompt 长度: {len(full_prompt)} 字符")
|
||||
print(" 调用 OpenAI API 生成 Wiki 页面...")
|
||||
|
||||
try:
|
||||
response = client.chat.completions.create(
|
||||
model="reasoning",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "你是一位知识库构建专家。请直接从源文件中提取关键术语并生成 Wiki 页面。"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": full_prompt
|
||||
}
|
||||
],
|
||||
temperature=0.5,
|
||||
max_tokens=16000
|
||||
)
|
||||
|
||||
generation_result = response.choices[0].message.content
|
||||
print(" [OK] LLM 生成完成")
|
||||
print(f" 生成内容长度: {len(generation_result)} 字符")
|
||||
|
||||
# 保存原始生成结果
|
||||
raw_output_file = os.path.join(output_dir, "raw_generation.md")
|
||||
with open(raw_output_file, 'w', encoding='utf-8') as f:
|
||||
f.write(generation_result)
|
||||
print(f" [OK] 原始生成结果已保存到 {raw_output_file}")
|
||||
|
||||
except Exception as e:
|
||||
print(f" [ERROR] LLM API 调用失败: {type(e).__name__}: {e}")
|
||||
exit(1)
|
||||
|
||||
# 解析生成结果
|
||||
sample_pages = []
|
||||
|
||||
# 解析 ---FILE: ... ---END FILE--- 块
|
||||
file_blocks = re.findall(r'---FILE: (.*?)---(.*?)---END FILE---', generation_result, re.DOTALL)
|
||||
|
||||
if not file_blocks:
|
||||
print(" [WARNING] 未找到标准文件块格式,尝试宽松匹配...")
|
||||
# 尝试宽松匹配
|
||||
file_blocks = re.findall(r'FILE: (.*?)\n(.*?)(?=(?:FILE:|$))', generation_result, re.DOTALL)
|
||||
|
||||
print(f"\n 解析到 {len(file_blocks)} 个文件块")
|
||||
|
||||
for i, block in enumerate(file_blocks):
|
||||
if isinstance(block, tuple):
|
||||
file_path = block[0].strip()
|
||||
file_content = block[1].strip()
|
||||
else:
|
||||
# 如果没有匹配,尝试直接提取整个内容
|
||||
continue
|
||||
|
||||
# 创建目录(如果需要)
|
||||
full_path = os.path.join(output_dir, file_path)
|
||||
file_dir = os.path.dirname(full_path)
|
||||
os.makedirs(file_dir, exist_ok=True)
|
||||
|
||||
# 写入文件
|
||||
with open(full_path, 'w', encoding='utf-8') as f:
|
||||
f.write(file_content)
|
||||
sample_pages.append(full_path)
|
||||
print(f" [OK] 生成 [{i+1}/{len(file_blocks)}]: {file_path}")
|
||||
|
||||
# 记录结束时间
|
||||
end_time = datetime.now()
|
||||
end_time_str = end_time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
duration = (end_time - start_time).total_seconds() / 60
|
||||
|
||||
print(f"\n=== B 组实验完成 ===")
|
||||
print(f"结束时间: {end_time_str}")
|
||||
print(f"总耗时: {round(duration, 2)} 分钟")
|
||||
print(f"生成文件数: {len(sample_pages)}")
|
||||
|
||||
# 保存元数据
|
||||
metadata = {
|
||||
"group": "B-real",
|
||||
"mode": "Single-Step (Real API)",
|
||||
"sourceFile": "raw/呼吸之间_李谨伯/第一编 从身体入手.md",
|
||||
"startTime": start_time_str,
|
||||
"endTime": end_time_str,
|
||||
"durationMinutes": round(duration, 2),
|
||||
"pagesGenerated": len(sample_pages),
|
||||
"apiModel": "reasoning",
|
||||
"rawContentLength": len(generation_result),
|
||||
"status": "success"
|
||||
}
|
||||
|
||||
metadata_file = os.path.join(output_dir, "metadata.json")
|
||||
with open(metadata_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(metadata, f, ensure_ascii=False, indent=2)
|
||||
|
||||
print(f"[OK] 元数据已保存到 {metadata_file}")
|
||||
print(f"\n文件输出位置:")
|
||||
print(f" 原始生成: {raw_output_file}")
|
||||
print(f" Wiki 页面: {output_dir}/wiki/")
|
||||
print(f" 元数据: {metadata_file}")
|
||||
@@ -0,0 +1,217 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
使用 singlestep 提示词对测试文件生成 WIKI
|
||||
使用环境变量中的 OPENAI_BASE_URL (阿里云 dashscope)
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
from datetime import datetime
|
||||
import openai
|
||||
|
||||
# 配置
|
||||
base_dir = os.getcwd()
|
||||
experiment_dir = os.path.join(base_dir, "tools", "experiments", "wiki-generation-compare")
|
||||
source_file = os.path.join(base_dir, "raw", "呼吸之间_李谨伯", "第一编 从身体入手.md")
|
||||
output_dir = os.path.join(experiment_dir, "output", "group-b-real")
|
||||
prompt_file = os.path.join(experiment_dir, "prompts", "singlestep.md")
|
||||
|
||||
# 创建输出目录
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
os.makedirs(os.path.join(output_dir, "wiki", "concepts"), exist_ok=True)
|
||||
os.makedirs(os.path.join(output_dir, "wiki", "methods"), exist_ok=True)
|
||||
os.makedirs(os.path.join(output_dir, "wiki", "entities"), exist_ok=True)
|
||||
|
||||
# 记录开始时间
|
||||
start_time = datetime.now()
|
||||
start_time_str = start_time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
print("=== B 组测试:Single-Step 模式 ===")
|
||||
print(f"开始时间: {start_time_str}")
|
||||
|
||||
# 读取源文件
|
||||
print(f"\n读取源文件: {source_file}")
|
||||
with open(source_file, 'r', encoding='utf-8') as f:
|
||||
source_content = f.read()
|
||||
print(f" 源文件长度: {len(source_content)} 字符")
|
||||
|
||||
# 读取 prompt
|
||||
print(f"\n读取 prompt: {prompt_file}")
|
||||
with open(prompt_file, 'r', encoding='utf-8') as f:
|
||||
template = f.read()
|
||||
|
||||
# 替换 {SOURCE_CONTENT}
|
||||
full_prompt = template.replace("{SOURCE_CONTENT}", source_content)
|
||||
print(f" Prompt 长度: {len(full_prompt)} 字符")
|
||||
|
||||
# 检查 API Key 和 Base URL
|
||||
api_key = os.environ.get('OPENAI_API_KEY')
|
||||
base_url = os.environ.get('OPENAI_BASE_URL', 'https://api.openai.com/v1')
|
||||
|
||||
if not api_key:
|
||||
print("[ERROR] 未找到 OPENAI_API_KEY 环境变量")
|
||||
exit(1)
|
||||
|
||||
print(f" API Key 长度: {len(api_key)}")
|
||||
print(f" Base URL: {base_url}")
|
||||
|
||||
# 初始化客户端
|
||||
print("\n初始化 OpenAI 客户端...")
|
||||
client = openai.OpenAI(
|
||||
api_key=api_key,
|
||||
base_url=base_url,
|
||||
timeout=300
|
||||
)
|
||||
|
||||
# 阿里云 dashscope 兼容的模型名称
|
||||
models_to_try = [
|
||||
"qwen-plus", # 通义千问 Plus
|
||||
"qwen-turbo", # 通义千问 Turbo
|
||||
"qwen-max", # 通义千问 Max
|
||||
"qwen-long", # 通义千问 Long
|
||||
"deepseek-r1", # DeepSeek R1
|
||||
"deepseek-v3", # DeepSeek V3
|
||||
"openai/gpt-4o-mini", # 兼容 OpenAI 模型
|
||||
"gpt-4o-mini",
|
||||
"openai/gpt-3.5-turbo",
|
||||
"gpt-3.5-turbo"
|
||||
]
|
||||
|
||||
# 尝试获取可用模型
|
||||
print("\n查找可用模型...")
|
||||
selected_model = None
|
||||
for model_name in models_to_try:
|
||||
try:
|
||||
# 先尝试简单的 chat completion
|
||||
test_response = client.chat.completions.create(
|
||||
model=model_name,
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
max_tokens=5
|
||||
)
|
||||
print(f" [OK] 模型可用: {model_name}")
|
||||
selected_model = model_name
|
||||
break
|
||||
except Exception as e:
|
||||
error_msg = str(e)[:100]
|
||||
print(f" [X] {model_name}: {error_msg}")
|
||||
|
||||
if not selected_model:
|
||||
print("\n[ERROR] 所有模型都不可用,尝试使用 models 端点列出可用模型...")
|
||||
try:
|
||||
models = client.models.list()
|
||||
print(f" 可用模型: {[m.id for m in models.data[:10]]}")
|
||||
if models.data:
|
||||
selected_model = models.data[0].id
|
||||
print(f" 使用第一个模型: {selected_model}")
|
||||
except Exception as e:
|
||||
print(f" [ERROR] 无法列出模型: {e}")
|
||||
exit(1)
|
||||
|
||||
if not selected_model:
|
||||
print("[ERROR] 未找到可用模型")
|
||||
exit(1)
|
||||
|
||||
print(f"\n使用模型: {selected_model}")
|
||||
|
||||
# 调用 LLM 生成
|
||||
print("\n调用 LLM 生成 Wiki 页面...")
|
||||
try:
|
||||
response = client.chat.completions.create(
|
||||
model=selected_model,
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "你是一位知识库构建专家。请直接从源文件中提取关键术语并生成 Wiki 页面。"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": full_prompt
|
||||
}
|
||||
],
|
||||
temperature=0.5,
|
||||
max_tokens=16000
|
||||
)
|
||||
|
||||
generation_result = response.choices[0].message.content
|
||||
print(f" [OK] LLM 生成完成")
|
||||
print(f" 生成内容长度: {len(generation_result)} 字符")
|
||||
|
||||
# 保存原始生成结果
|
||||
raw_output_file = os.path.join(output_dir, "raw_generation.md")
|
||||
with open(raw_output_file, 'w', encoding='utf-8') as f:
|
||||
f.write(generation_result)
|
||||
print(f" [OK] 原始生成结果已保存到: {raw_output_file}")
|
||||
|
||||
except Exception as e:
|
||||
print(f" [ERROR] LLM API 调用失败: {type(e).__name__}: {e}")
|
||||
exit(1)
|
||||
|
||||
# 解析生成结果
|
||||
print("\n解析生成的 Wiki 页面...")
|
||||
sample_pages = []
|
||||
|
||||
# 解析 ---FILE: ... ---END FILE--- 块
|
||||
file_blocks = re.findall(r'---FILE: (.*?)---(.*?)---END FILE---', generation_result, re.DOTALL)
|
||||
|
||||
if not file_blocks:
|
||||
print(" [WARNING] 未找到标准文件块格式,尝试宽松匹配...")
|
||||
file_blocks = re.findall(r'FILE: (.*?)\n(.*?)(?=(?:FILE:|$))', generation_result, re.DOTALL)
|
||||
|
||||
print(f" 解析到 {len(file_blocks)} 个文件块")
|
||||
|
||||
for i, block in enumerate(file_blocks):
|
||||
if isinstance(block, tuple):
|
||||
file_path = block[0].strip()
|
||||
file_content = block[1].strip()
|
||||
else:
|
||||
continue
|
||||
|
||||
# 创建目录(如果需要)
|
||||
full_path = os.path.join(output_dir, file_path)
|
||||
file_dir = os.path.dirname(full_path)
|
||||
os.makedirs(file_dir, exist_ok=True)
|
||||
|
||||
# 写入文件
|
||||
with open(full_path, 'w', encoding='utf-8') as f:
|
||||
f.write(file_content)
|
||||
sample_pages.append(full_path)
|
||||
print(f" [OK] 生成 [{i+1}/{len(file_blocks)}]: {file_path}")
|
||||
|
||||
# 记录结束时间
|
||||
end_time = datetime.now()
|
||||
end_time_str = end_time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
duration = (end_time - start_time).total_seconds() / 60
|
||||
|
||||
print(f"\n=== B 组测试完成 ===")
|
||||
print(f"结束时间: {end_time_str}")
|
||||
print(f"总耗时: {round(duration, 2)} 分钟")
|
||||
print(f"生成文件数: {len(sample_pages)}")
|
||||
|
||||
# 保存元数据
|
||||
metadata = {
|
||||
"group": "B-real",
|
||||
"mode": "Single-Step",
|
||||
"sourceFile": "raw/呼吸之间_李谨伯/第一编 从身体入手.md",
|
||||
"startTime": start_time_str,
|
||||
"endTime": end_time_str,
|
||||
"durationMinutes": round(duration, 2),
|
||||
"pagesGenerated": len(sample_pages),
|
||||
"model": selected_model,
|
||||
"baseUrl": base_url,
|
||||
"rawContentLength": len(generation_result),
|
||||
"status": "success"
|
||||
}
|
||||
|
||||
metadata_file = os.path.join(output_dir, "metadata.json")
|
||||
with open(metadata_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(metadata, f, ensure_ascii=False, indent=2)
|
||||
|
||||
print(f"\n[OK] 元数据已保存到: {metadata_file}")
|
||||
print(f"\n输出文件位置:")
|
||||
print(f" 原始生成: {raw_output_file}")
|
||||
print(f" Wiki 页面: {output_dir}/wiki/")
|
||||
print(f" 元数据: {metadata_file}")
|
||||
print(f"\n接下来可以运行评估脚本对比 A 组和 B 组的结果:")
|
||||
print(f" python tools/experiments/wiki-generation-compare/scripts/evaluate-real.py")
|
||||
@@ -0,0 +1,196 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
使用 singlestep 提示词对测试文件生成 WIKI
|
||||
直接使用当前 opencode 配置的 LLM
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
from datetime import datetime
|
||||
import openai
|
||||
|
||||
# 配置
|
||||
base_dir = os.getcwd()
|
||||
experiment_dir = os.path.join(base_dir, "tools", "experiments", "wiki-generation-compare")
|
||||
source_file = os.path.join(base_dir, "raw", "呼吸之间_李谨伯", "第一编 从身体入手.md")
|
||||
output_dir = os.path.join(experiment_dir, "output", "group-b-real")
|
||||
prompt_file = os.path.join(experiment_dir, "prompts", "singlestep.md")
|
||||
|
||||
# 创建输出目录
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
os.makedirs(os.path.join(output_dir, "wiki", "concepts"), exist_ok=True)
|
||||
os.makedirs(os.path.join(output_dir, "wiki", "methods"), exist_ok=True)
|
||||
os.makedirs(os.path.join(output_dir, "wiki", "entities"), exist_ok=True)
|
||||
|
||||
# 记录开始时间
|
||||
start_time = datetime.now()
|
||||
start_time_str = start_time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
print("=== B 组测试:Single-Step 模式(使用 9router reasoning 模型)===")
|
||||
print(f"开始时间: {start_time_str}")
|
||||
|
||||
# 读取源文件
|
||||
print(f"\n读取源文件: {source_file}")
|
||||
with open(source_file, 'r', encoding='utf-8') as f:
|
||||
source_content = f.read()
|
||||
print(f" 源文件长度: {len(source_content)} 字符")
|
||||
|
||||
# 读取 prompt
|
||||
print(f"\n读取 prompt: {prompt_file}")
|
||||
with open(prompt_file, 'r', encoding='utf-8') as f:
|
||||
template = f.read()
|
||||
|
||||
# 替换 {SOURCE_CONTENT}
|
||||
full_prompt = template.replace("{SOURCE_CONTENT}", source_content)
|
||||
print(f" Prompt 长度: {len(full_prompt)} 字符")
|
||||
|
||||
# 检查 API Key
|
||||
api_key = os.environ.get('OPENAI_API_KEY')
|
||||
if not api_key:
|
||||
print("[ERROR] 未找到 OPENAI_API_KEY 环境变量")
|
||||
exit(1)
|
||||
print(f" API Key 长度: {len(api_key)}")
|
||||
|
||||
# 尝试不同的模型名称
|
||||
models_to_try = [
|
||||
"9router/reasoning",
|
||||
"reasoning",
|
||||
"openai/gpt-4o-mini",
|
||||
"gpt-4o-mini",
|
||||
"openai/gpt-3.5-turbo",
|
||||
"gpt-3.5-turbo"
|
||||
]
|
||||
|
||||
# 尝试连接并获取可用模型
|
||||
print("\n查找可用模型...")
|
||||
available_models = []
|
||||
for model_name in models_to_try:
|
||||
try:
|
||||
client = openai.OpenAI(api_key=api_key, timeout=60)
|
||||
# 先尝试简单的 chat completion
|
||||
test_response = client.chat.completions.create(
|
||||
model=model_name,
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
max_tokens=5
|
||||
)
|
||||
print(f" [OK] 模型可用: {model_name}")
|
||||
available_models.append(model_name)
|
||||
break
|
||||
except Exception as e:
|
||||
print(f" [X] {model_name}: {type(e).__name__}")
|
||||
if "404" not in str(e) and "not exist" not in str(e):
|
||||
# 如果不是 404,可能是网络问题
|
||||
print(f" 错误详情: {str(e)[:200]}")
|
||||
|
||||
if not available_models:
|
||||
print("\n[ERROR] 没有可用的模型")
|
||||
exit(1)
|
||||
|
||||
# 使用第一个可用的模型
|
||||
selected_model = available_models[0]
|
||||
print(f"\n使用模型: {selected_model}")
|
||||
|
||||
# 初始化客户端
|
||||
client = openai.OpenAI(api_key=api_key, timeout=300)
|
||||
|
||||
# 调用 LLM 生成
|
||||
print("\n调用 LLM 生成 Wiki 页面...")
|
||||
try:
|
||||
response = client.chat.completions.create(
|
||||
model=selected_model,
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "你是一位知识库构建专家。请直接从源文件中提取关键术语并生成 Wiki 页面。"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": full_prompt
|
||||
}
|
||||
],
|
||||
temperature=0.5,
|
||||
max_tokens=16000
|
||||
)
|
||||
|
||||
generation_result = response.choices[0].message.content
|
||||
print(f" [OK] LLM 生成完成")
|
||||
print(f" 生成内容长度: {len(generation_result)} 字符")
|
||||
|
||||
# 保存原始生成结果
|
||||
raw_output_file = os.path.join(output_dir, "raw_generation.md")
|
||||
with open(raw_output_file, 'w', encoding='utf-8') as f:
|
||||
f.write(generation_result)
|
||||
print(f" [OK] 原始生成结果已保存到: {raw_output_file}")
|
||||
|
||||
except Exception as e:
|
||||
print(f" [ERROR] LLM API 调用失败: {type(e).__name__}: {e}")
|
||||
exit(1)
|
||||
|
||||
# 解析生成结果
|
||||
print("\n解析生成的 Wiki 页面...")
|
||||
sample_pages = []
|
||||
|
||||
# 解析 ---FILE: ... ---END FILE--- 块
|
||||
file_blocks = re.findall(r'---FILE: (.*?)---(.*?)---END FILE---', generation_result, re.DOTALL)
|
||||
|
||||
if not file_blocks:
|
||||
print(" [WARNING] 未找到标准文件块格式,尝试宽松匹配...")
|
||||
file_blocks = re.findall(r'FILE: (.*?)\n(.*?)(?=(?:FILE:|$))', generation_result, re.DOTALL)
|
||||
|
||||
print(f" 解析到 {len(file_blocks)} 个文件块")
|
||||
|
||||
for i, block in enumerate(file_blocks):
|
||||
if isinstance(block, tuple):
|
||||
file_path = block[0].strip()
|
||||
file_content = block[1].strip()
|
||||
else:
|
||||
continue
|
||||
|
||||
# 创建目录(如果需要)
|
||||
full_path = os.path.join(output_dir, file_path)
|
||||
file_dir = os.path.dirname(full_path)
|
||||
os.makedirs(file_dir, exist_ok=True)
|
||||
|
||||
# 写入文件
|
||||
with open(full_path, 'w', encoding='utf-8') as f:
|
||||
f.write(file_content)
|
||||
sample_pages.append(full_path)
|
||||
print(f" [OK] 生成 [{i+1}/{len(file_blocks)}]: {file_path}")
|
||||
|
||||
# 记录结束时间
|
||||
end_time = datetime.now()
|
||||
end_time_str = end_time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
duration = (end_time - start_time).total_seconds() / 60
|
||||
|
||||
print(f"\n=== B 组测试完成 ===")
|
||||
print(f"结束时间: {end_time_str}")
|
||||
print(f"总耗时: {round(duration, 2)} 分钟")
|
||||
print(f"生成文件数: {len(sample_pages)}")
|
||||
|
||||
# 保存元数据
|
||||
metadata = {
|
||||
"group": "B-real",
|
||||
"mode": "Single-Step",
|
||||
"sourceFile": "raw/呼吸之间_李谨伯/第一编 从身体入手.md",
|
||||
"startTime": start_time_str,
|
||||
"endTime": end_time_str,
|
||||
"durationMinutes": round(duration, 2),
|
||||
"pagesGenerated": len(sample_pages),
|
||||
"model": selected_model,
|
||||
"rawContentLength": len(generation_result),
|
||||
"status": "success"
|
||||
}
|
||||
|
||||
metadata_file = os.path.join(output_dir, "metadata.json")
|
||||
with open(metadata_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(metadata, f, ensure_ascii=False, indent=2)
|
||||
|
||||
print(f"\n[OK] 元数据已保存到: {metadata_file}")
|
||||
print(f"\n输出文件位置:")
|
||||
print(f" 原始生成: {raw_output_file}")
|
||||
print(f" Wiki 页面: {output_dir}/wiki/")
|
||||
print(f" 元数据: {metadata_file}")
|
||||
print(f"\n接下来可以运行评估脚本对比 A 组和 B 组的结果:")
|
||||
print(f" python tools/experiments/wiki-generation-compare/scripts/evaluate-real.py")
|
||||
Reference in New Issue
Block a user