From 33ded0d13e0b852cda1980d52b277b969ff65402 Mon Sep 17 00:00:00 2001 From: tukuaiai Date: Fri, 24 Apr 2026 17:41:45 +0800 Subject: [PATCH] feat: prompts-library - split jsonl export by sheet --- AGENTS.md | 2 +- README.md | 4 +- assets/repo/prompts-library/README.md | 15 +++++ assets/repo/prompts-library/main.py | 94 +++++++++++++++++++++------ 4 files changed, 91 insertions(+), 24 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8f58748..8de77e3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -72,7 +72,7 @@ git push origin develop 2. Docs → Excel:将 Markdown 文档目录还原为 Excel 工作簿 3. Docs → JSONL:将 Markdown 文档转换为 JSONL 格式 4. JSONL → Excel:将 JSONL 转换为 Excel -5. Excel(JSONL) → JSONL:将内部 JSONL 格式的 Excel 转换为 JSONL 文件 +5. Excel(JSONL) → JSONL:将内部 JSONL 格式的 Excel 转换为 JSONL 目录(每个工作表一个 JSONL 文件) --- diff --git a/README.md b/README.md index 79799a4..d153038 100644 --- a/README.md +++ b/README.md @@ -335,7 +335,7 @@ Canvas方式:**代码 ⇄ 白板 ⇄ AI ⇄ 人类**,白板成为单一真 * [**胶水编程 (Glue Coding)**](./assets/documents/principles/fundamentals/): 软件工程的圣杯与银弹,Vibe Coding 的终极进化形态。 * [**Chat Vault**](./assets/repo/chat-vault/): AI 聊天记录保存工具,支持 Codex/Kiro/Gemini/Claude CLI。 -* [**prompts-library 工具说明**](./assets/repo/prompts-library/): 支持 Excel 与 Markdown 格式互转,包含数百个精选提示词。 +* [**prompts-library 工具说明**](./assets/repo/prompts-library/): 支持 Excel 与 Markdown 格式互转,并支持将内部 JSONL Excel 按工作表拆分导出为 JSONL 目录。 * [**编程提示词集合**](https://docs.google.com/spreadsheets/d/1Ifk_dLF25ULSxcfGem1hXzJsi7_RBUNAki8SBCuvkJA/edit?gid=1254297203#gid=1254297203): 适用于 Vibe Coding 流程的专用提示词(云端表格)。 * [**系统提示词构建原则**](./assets/documents/principles/fundamentals/系统提示词构建原则.md): 构建高效 AI 系统提示词的综合指南。 * [**开发经验总结**](./assets/documents/principles/fundamentals/开发经验.md): 变量命名、文件结构、编码规范、架构原则等。 @@ -411,7 +411,7 @@ Canvas方式:**代码 ⇄ 白板 ⇄ AI ⇄ 人类**,白板成为单一真 │ │ └── canvas-dev/ # Canvas白板驱动开发 │ └── repo/ # 外部工具与依赖镜像(含 Git submodule) │ ├── README.md # 外部工具索引 -│ ├── prompts-library/ # Excel ↔ Markdown 互转工具 +│ ├── prompts-library/ # Excel ↔ Markdown 互转工具,含内部 JSONL Excel 拆分导出 │ ├── chat-vault/ # AI 聊天记录保存工具 │ ├── Skill_Seekers-development/ # Skills 制作器 │ ├── html-tools-main/ # HTML 工具集 diff --git a/assets/repo/prompts-library/README.md b/assets/repo/prompts-library/README.md index d6fc5d5..755898b 100644 --- a/assets/repo/prompts-library/README.md +++ b/assets/repo/prompts-library/README.md @@ -171,6 +171,21 @@ python3 scripts/gemini_jsonl_batch.py --input 2 --output 2/prompts.jsonl --model - 可用 `-v` 查看逐文件处理日志,`--gemini-cmd` 自定义 CLI 可执行路径。 +
+内部 JSONL Excel → JSONL 目录 + +```bash +# 将内部 JSONL 格式的 xlsx 按工作表拆分为多个 jsonl 文件 +python3 main.py --select "prompt_excel/prompt_jsonl.xlsx" --mode jsonl_excel2jsonl +``` + +- 输出目录格式为 `prompt_jsonl/_/` +- 每个工作表输出一个独立的 `.jsonl` 文件 +- 文件名格式为 `<序号>_.jsonl` +- 若工作表中没有标准 JSON 单元格,会对纯文本单元格做 JSONL 兜底转换 +- 自动忽略名为 `说明` 的工作表 +
+ ---
diff --git a/assets/repo/prompts-library/main.py b/assets/repo/prompts-library/main.py index 5f0db1f..38a6ef2 100644 --- a/assets/repo/prompts-library/main.py +++ b/assets/repo/prompts-library/main.py @@ -11,7 +11,7 @@ Unified controller for prompt-library conversions. 2. Docs → Excel : 将 Markdown 文档目录还原为 Excel 工作簿 3. Docs → JSONL : 将 Markdown 文档转换为 JSONL 格式(保留完整元信息) 4. JSONL → Excel : 将 JSONL 转换为 Excel(单元格存储 JSON 对象) -5. Excel(JSONL) → JSONL : 将内部 JSONL 格式的 Excel 转换为 JSONL 文件(自动忽略"说明"工作表) +5. Excel(JSONL) → JSONL : 将内部 JSONL 格式的 Excel 转换为 JSONL 目录(自动忽略"说明"工作表) 数据格式规范 ============ @@ -51,7 +51,7 @@ JSONL → Excel 单元格格式: - Docs→Excel: ./prompt_excel/prompt_excel_YYYY_MMDD_HHMMSS/rebuilt.xlsx - Docs→JSONL: ./prompt_jsonl/{docs_name}.jsonl - JSONL→Excel: ./prompt_excel/{jsonl_name}.xlsx - - Excel(JSONL)→JSONL: ./prompt_jsonl/{excel_name}.jsonl + - Excel(JSONL)→JSONL: ./prompt_jsonl/{excel_name}_{timestamp}/.jsonl 使用示例 ======== @@ -253,9 +253,31 @@ def is_jsonl_excel(excel_path: Path) -> bool: return False +def sanitize_filename(name: str) -> str: + """将工作表名转换为稳定的文件名片段。""" + invalid_chars = '<>:"/\\|?*' + sanitized = "".join("_" if ch in invalid_chars else ch for ch in name).strip() + return sanitized.rstrip(". ") or "sheet" + + +def build_text_record(cat_id: int, cat_name: str, row: int, col: int, text: str) -> dict: + """将纯文本单元格兜底转换为 JSONL 记录。""" + lines = [line.strip() for line in text.splitlines() if line.strip()] + title = lines[0] if lines else text.strip() + return { + "category_id": cat_id, + "category": cat_name, + "row": row, + "col": col, + "title": title[:80], + "content": text, + } + + def run_jsonl_excel_to_jsonl(excel_path: Path, project_root: Path) -> int: - """将内部 JSONL 格式的 Excel 转换为 JSONL 文件(忽略"说明"工作表)""" + """将内部 JSONL 格式的 Excel 转换为 JSONL 目录(忽略"说明"工作表)""" import json + from datetime import datetime try: import pandas as pd except ImportError: @@ -263,16 +285,23 @@ def run_jsonl_excel_to_jsonl(excel_path: Path, project_root: Path) -> int: return 1 xlsx = pd.ExcelFile(excel_path) - output_lines = [] cat_id = 0 + total_records = 0 + written_files = [] - for sheet in xlsx.sheet_names: + timestamp = datetime.now().strftime("%Y_%m%d_%H%M%S") + output_dir = project_root / "prompt_jsonl" / f"{excel_path.stem}_{timestamp}" + output_dir.mkdir(parents=True, exist_ok=True) + + for sheet_index, sheet in enumerate(xlsx.sheet_names, start=1): if sheet == '说明': continue cat_id += 1 cat_name = sheet df = pd.read_excel(xlsx, sheet_name=sheet, header=None) + sheet_lines = [] + fallback_records = [] # 检查列名是否是 JSON 数据 for col_idx, col_name in enumerate(df.columns): @@ -281,7 +310,7 @@ def run_jsonl_excel_to_jsonl(excel_path: Path, project_root: Path) -> int: try: obj = json.loads(col_str) if 'title' in obj and 'content' in obj: - output_lines.append(json.dumps({ + sheet_lines.append(json.dumps({ "category_id": cat_id, "category": cat_name, "row": 1, @@ -298,11 +327,13 @@ def run_jsonl_excel_to_jsonl(excel_path: Path, project_root: Path) -> int: if pd.isna(val): continue val_str = str(val).strip() + if not val_str: + continue if val_str.startswith('{') and val_str.endswith('}'): try: obj = json.loads(val_str) if 'title' in obj and 'content' in obj: - output_lines.append(json.dumps({ + sheet_lines.append(json.dumps({ "category_id": cat_id, "category": cat_name, "row": row_idx + 2, @@ -312,22 +343,43 @@ def run_jsonl_excel_to_jsonl(excel_path: Path, project_root: Path) -> int: }, ensure_ascii=False)) except: pass - - if not output_lines: + else: + # 跳过常见的顶栏广告/元数据噪声,但保留其他纯文本内容作为兜底记录。 + if row_idx == 0 and col_idx == 0 and val_str.startswith("广告位"): + continue + fallback_records.append( + build_text_record( + cat_id=cat_id, + cat_name=cat_name, + row=row_idx + 2, + col=col_idx + 1, + text=val_str, + ) + ) + + if not sheet_lines and fallback_records: + sheet_lines = [ + json.dumps(record, ensure_ascii=False) + for record in fallback_records + ] + + total_records += len(sheet_lines) + file_stem = sanitize_filename(cat_name) + output_file = output_dir / f"{sheet_index:02d}_{file_stem}.jsonl" + with open(output_file, 'w', encoding='utf-8') as f: + if sheet_lines: + f.write('\n'.join(sheet_lines) + '\n') + written_files.append(output_file) + + if not written_files: print(f"❌ 未找到有效的 JSONL 数据: {excel_path}") return 1 - - from datetime import datetime - timestamp = datetime.now().strftime("%Y_%m%d_%H%M%S") - - output_dir = project_root / "prompt_jsonl" - output_dir.mkdir(parents=True, exist_ok=True) - output_file = output_dir / f"{excel_path.stem}_{timestamp}.jsonl" - - with open(output_file, 'w', encoding='utf-8') as f: - f.write('\n'.join(output_lines)) - - print(f"✅ Excel(JSONL)→JSONL OK: {excel_path.name} → {output_file.relative_to(project_root)} ({len(output_lines)} 条记录)") + + print( + f"✅ Excel(JSONL)→JSONL OK: {excel_path.name} → " + f"{output_dir.relative_to(project_root)} " + f"({len(written_files)} 个文件 / {total_records} 条记录)" + ) return 0