知识吸收器 Skill 你是一个"全能导师级知识编辑 + 信息图策划师"。 目标:深度解析链接、文档或代码,生成可学习、可搜索、可继续提问的学习成品,并支持 Wan 2.7 文生图 生成知识海报。 --- 专家思维框架 在每个步骤开始前,先问自己三个问题 : Q1: 用户真正要什么? | 用户说 | 可能实际要 | 判断方法 | |--------|-----------|----------| | "学习这个文档" | 可能只要知识卡片 | 是否提到"海报"或"图"? | | "做个知识海报" | 可能只要图片,不需要卡片 | 是否提供了源内容? | | "整理这份资料" | 可能要结构化摘要 | 是否问及"存入知识库"? | 原则 :不预设用户需要生图。海报是可选增值服务,不是默认输出。 Q2: 内容是否可信? 真理锚定协议 —— 任何内容在输出前必须过这一关: 不需要验证的 :观点、建议、方法论(主观内容) 必须验证的 :数据、API 签名、版本号、历史事件(客观事实) Q3: 信息密度对吗? 知识卡片 :追求完整,但不过度冗余 海报 Prompt :想象渲染到 3:4 画布上 —— 站在 1 米外能看清吗? | 错误 | 正确 | |------|------| | 500 字长段落 | 3-5 个要点,每点 < 30 字 | | 完整代码块 | 伪代码或核心片段 | |…

\n match = re.match(direct_pattern, input_str)\n if match:\n width = int(match.group(1))\n height = int(match.group(2))\n \n if not (768*768 \u003c= width * height \u003c= 2048*2048):\n raise ValueError(f\"Total pixel count must be within the range [768*768, 2048*2048], i.e., [{768*768}, {2048*2048}]. Current: {width}*{height}: {width*height}\")\n \n aspect_ratio = width / height\n if not (1/8 \u003c= aspect_ratio \u003c= 8):\n raise ValueError(f\"Aspect ratio must be within the range [1:8, 8:1]. Current: {aspect_ratio:.2f}\")\n \n return f\"{width}*{height}\"\n \n # Mode 2: K + aspect ratio (e.g., \"2K 3:4\", \"1K 16:9\")\n k_ratio_pattern = r'^([124])k\\s*(\\d+):(\\d+)

知识吸收器 Skill 你是一个"全能导师级知识编辑 + 信息图策划师"。 目标:深度解析链接、文档或代码,生成可学习、可搜索、可继续提问的学习成品,并支持 Wan 2.7 文生图 生成知识海报。 --- 专家思维框架 在每个步骤开始前,先问自己三个问题 : Q1: 用户真正要什么? | 用户说 | 可能实际要 | 判断方法 | |--------|-----------|----------| | "学习这个文档" | 可能只要知识卡片 | 是否提到"海报"或"图"? | | "做个知识海报" | 可能只要图片,不需要卡片 | 是否提供了源内容? | | "整理这份资料" | 可能要结构化摘要 | 是否问及"存入知识库"? | 原则 :不预设用户需要生图。海报是可选增值服务,不是默认输出。 Q2: 内容是否可信? 真理锚定协议 —— 任何内容在输出前必须过这一关: 不需要验证的 :观点、建议、方法论(主观内容) 必须验证的 :数据、API 签名、版本号、历史事件(客观事实) Q3: 信息密度对吗? 知识卡片 :追求完整,但不过度冗余 海报 Prompt :想象渲染到 3:4 画布上 —— 站在 1 米外能看清吗? | 错误 | 正确 | |------|------| | 500 字长段落 | 3-5 个要点,每点 < 30 字 | | 完整代码块 | 伪代码或核心片段 | |…

\n match = re.match(k_ratio_pattern, input_str)\n if match:\n k_value = int(match.group(1))\n ratio_w = int(match.group(2))\n ratio_h = int(match.group(3))\n \n \n total_pixels = min(max((k_value * 1024) ** 2, 1024*1024), 2048*2048)\n base_unit = (total_pixels / (ratio_w * ratio_h)) ** 0.5\n width = int(round(base_unit * ratio_w))\n height = int(round(base_unit * ratio_h))\n\n # Ensure it is even (required by some models)\n width = width if width % 2 == 0 else width - 1\n height = height if height % 2 == 0 else height - 1\n\n if not (768*768 \u003c= width * height \u003c= 2048*2048):\n raise ValueError(f\"Total pixel count must be within the range [768*768, 2048*2048], i.e., [{768*768}, {2048*2048}]. Calculated resolution is out of range: {width}*{height}: {width*height}\")\n \n aspect_ratio = width / height\n if not (1/8 \u003c= aspect_ratio \u003c= 8):\n raise ValueError(f\"Aspect ratio must be within the range [1:8, 8:1]. Current: {aspect_ratio:.2f}\")\n \n return f\"{width}*{height}\"\n \n # Mode 3: K value only (e.g., \"1K\", \"2K\"), defaulting to a 1:1 aspect ratio\n k_only_pattern = r'^([12])k

知识吸收器 Skill 你是一个"全能导师级知识编辑 + 信息图策划师"。 目标:深度解析链接、文档或代码,生成可学习、可搜索、可继续提问的学习成品,并支持 Wan 2.7 文生图 生成知识海报。 --- 专家思维框架 在每个步骤开始前,先问自己三个问题 : Q1: 用户真正要什么? | 用户说 | 可能实际要 | 判断方法 | |--------|-----------|----------| | "学习这个文档" | 可能只要知识卡片 | 是否提到"海报"或"图"? | | "做个知识海报" | 可能只要图片,不需要卡片 | 是否提供了源内容? | | "整理这份资料" | 可能要结构化摘要 | 是否问及"存入知识库"? | 原则 :不预设用户需要生图。海报是可选增值服务,不是默认输出。 Q2: 内容是否可信? 真理锚定协议 —— 任何内容在输出前必须过这一关: 不需要验证的 :观点、建议、方法论(主观内容) 必须验证的 :数据、API 签名、版本号、历史事件(客观事实) Q3: 信息密度对吗? 知识卡片 :追求完整,但不过度冗余 海报 Prompt :想象渲染到 3:4 画布上 —— 站在 1 米外能看清吗? | 错误 | 正确 | |------|------| | 500 字长段落 | 3-5 个要点,每点 < 30 字 | | 完整代码块 | 伪代码或核心片段 | |…

\n match = re.match(k_only_pattern, input_str)\n if match:\n k_value = int(match.group(1))\n size = k_value * 1024\n return f\"{size}*{size}\"\n\n\n raise ValueError(\n f\"Unsupported input format: '{input_str}'\\n\"\n f\"Supported input formats: \\n\"\n f\" - K + aspect ratio: '2K 3:4', '1K 16:9', '2K 1:1'\\n\"\n f\" - K value only: '1K', '2K' (defaulting to a 1:1 aspect ratio)\\n\"\n f\" - Directly specify resolution size: '1280*1280', '2048*2048'\"\n )\n\n\ndef main():\n parser = argparse.ArgumentParser(\n description='Parses resolution strings, supporting K value format or specific pixel formats',\n formatter_class=argparse.RawDescriptionHelpFormatter,\n epilog='''\nExample:\n python parse_resolution.py '2K 3:4' # output: 1536*2048\n python parse_resolution.py '1K 16:9' # output: 1696*960 \n python parse_resolution.py '2048*2048' # output: 2048*2048\n python parse_resolution.py '1K' # output: 1024*1024\n '''.strip()\n )\n \n parser.add_argument(\n 'input',\n help='Resolution input string, format like: \"2K 3:4\", \"2048*2048\", \"1K\"'\n )\n \n args = parser.parse_args()\n input_str = args.input\n \n try:\n result = parse_resolution(input_str)\n print(result)\n except ValueError as e:\n print(f\"Failed: {e}\", file=sys.stderr)\n sys.exit(1)\n\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":5199,"content_sha256":"1ce0784038588960015b76598cd4ae0a9391d7056f59d5338f290009dd4bbe7a"},{"filename":"scripts/quick_update.py","content":"import re\nfrom pathlib import Path\n\n# 读取文件\nhtml_path = Path(r\"E:\\开源Skills\\skill\\.trae\\skills\\knowledge-absorber\\outputs\\knowledge_20260316_老子想尔注-中华文库_ce1706c5\\knowledge_card.interactive.html\")\ncss_path = Path(r\"E:\\开源Skills\\skill\\.trae\\skills\\knowledge-absorber\\assets\\knowledge_card_ink_enhanced.css\")\n\nhtml_content = html_path.read_text(encoding=\"utf-8\")\nnew_css = css_path.read_text(encoding=\"utf-8\")\n\n# 替换CSS\npattern = r'\u003cstyle>.*?\u003c/style>'\nnew_style_block = f'\u003cstyle>\\n{new_css}\\n\u003c/style>'\nupdated_html = re.sub(pattern, new_style_block, html_content, flags=re.DOTALL, count=1)\n\n# 保存\nhtml_path.write_text(updated_html, encoding=\"utf-8\")\nprint(\"CSS updated successfully!\")\n","content_type":"text/x-python; charset=utf-8","language":"python","size":718,"content_sha256":"c83737c7daec47e5e250e539e537c0a8f9fe67556d539a00dce990b80cdd850b"},{"filename":"scripts/regenerate_html.py","content":"\"\"\"Quick script to regenerate HTML with new CSS styling\"\"\"\nfrom __future__ import annotations\n\nimport json\nimport sys\nfrom pathlib import Path\n\nsys.path.insert(0, str(Path(__file__).parent))\n\nfrom knowledge_card_rendering import render_html, infer_card_theme\n\n# Path to the existing output\nOUTPUT_DIR = Path(__file__).parent.parent / \"outputs\" / \"knowledge_20260316_老子想尔注-中华文库_ce1706c5\"\nDATA_FILE = OUTPUT_DIR / \"_internal\" / \"knowledge_card.data.json\"\nVERIFICATION_FILE = OUTPUT_DIR / \"_internal\" / \"verification_report.json\"\nHTML_OUTPUT = OUTPUT_DIR / \"knowledge_card.source.html\"\n\ndef main():\n if not DATA_FILE.exists():\n print(f\"Data file not found: {DATA_FILE}\")\n print(\"Looking for alternative data files...\")\n\n # Try to find data file in parent directory\n alt_data = OUTPUT_DIR / \"knowledge_card.data.json\"\n if alt_data.exists():\n print(f\"Found alternative data file: {alt_data}\")\n data_path = alt_data\n else:\n print(\"No data file found. Cannot regenerate HTML.\")\n return 1\n else:\n data_path = DATA_FILE\n\n if not VERIFICATION_FILE.exists():\n print(f\"Verification file not found: {VERIFICATION_FILE}\")\n print(\"Using empty verification report...\")\n verification_report = {\n \"verified_count\": 0,\n \"disputed_count\": 0,\n \"outdated_count\": 0,\n \"unverified_count\": 0\n }\n else:\n verification_report = json.loads(VERIFICATION_FILE.read_text(encoding=\"utf-8\"))\n\n # Load card data\n card_data = json.loads(data_path.read_text(encoding=\"utf-8\"))\n\n # Infer theme based on content\n title = card_data[\"header\"][\"title\"]\n tags = card_data[\"header\"][\"tags\"]\n # Get first few paragraphs for theme detection\n paragraphs = []\n if \"module0\" in card_data and \"one_sentence\" in card_data[\"module0\"]:\n paragraphs.append(card_data[\"module0\"][\"one_sentence\"])\n source = card_data[\"header\"].get(\"source\", \"\")\n\n theme = infer_card_theme(title, tags, paragraphs, source)\n\n print(f\"Regenerating HTML with theme: {theme}\")\n\n # Render HTML\n html_output = render_html(card_data, verification_report, theme)\n\n # Save HTML\n HTML_OUTPUT.write_text(html_output, encoding=\"utf-8\")\n print(f\"HTML regenerated successfully: {HTML_OUTPUT}\")\n\n return 0\n\nif __name__ == \"__main__\":\n sys.exit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":2425,"content_sha256":"40c3defd3192594c87203ef28dd3029c73d8837f4afc69d5049c08651c8f7345"},{"filename":"scripts/rule_card_generator.py","content":"from __future__ import annotations\n\nimport re\nfrom typing import Any, Dict, List, Sequence\n\n\ndef normalize(text: str) -> str:\n return re.sub(r\"\\s+\", \" \", text.replace(\"\\r\", \" \").replace(\"\\n\", \" \")).strip()\n\n\ndef unique_preserve_order(values: Sequence[str]) -> List[str]:\n seen = set()\n result: List[str] = []\n for value in values:\n cleaned = normalize(value)\n if not cleaned or cleaned in seen:\n continue\n seen.add(cleaned)\n result.append(cleaned)\n return result\n\n\ndef summarize_sentence(text: str, fallback: str) -> str:\n cleaned = normalize(text)\n if not cleaned:\n return fallback\n if len(cleaned) \u003c= 120:\n return cleaned\n parts = re.split(r\"(?\u003c=[。!?!?])\\s+\", cleaned)\n return parts[0].strip() if parts and parts[0].strip() else cleaned[:120].rstrip() + \"…\"\n\n\ndef pick_meaningful_paragraph(paragraphs: Sequence[str], fallback: str) -> str:\n normalized_fallback = normalize(fallback).lower()\n for paragraph in paragraphs:\n cleaned = normalize(paragraph)\n if len(cleaned) \u003c 16:\n continue\n if cleaned.lower() == normalized_fallback:\n continue\n if not any(token in cleaned for token in [\"。\", \":\", \":\", \"是\", \"需要\", \"可以\", \"能够\", \"版本\", \"流程\", \"系统\"]):\n continue\n return cleaned\n return fallback\n\n\ndef meaningful_analysis_items(paragraphs: Sequence[str], title: str) -> List[str]:\n def looks_like_codeish(text: str) -> bool:\n lowered = text.lower()\n if any(token in lowered for token in [\"name_for_human\", \"name_for_model\", \"description_for_model\", \"parameters\"]):\n return True\n if any(token in lowered for token in [\"payload =\", \"json.dumps\", \"headers =\", \"def \", \"class \", \"import \"]):\n return True\n if re.search(r\"[{}\\[\\]]\", text) and (\":\" in text or \"=\" in text):\n return True\n if re.search(r\"\\b[A-Za-z_][A-Za-z0-9_]*\\s*=\\s*.+\", text):\n return True\n if text.count(\"'\") + text.count('\"') >= 8 and (\":\" in text or \"{\" in text or \"[\" in text):\n return True\n return False\n\n results: List[str] = []\n for paragraph in paragraphs:\n cleaned = normalize(paragraph)\n if len(cleaned) \u003c 12:\n continue\n if cleaned.lower() in {title.lower(), \"source a\", \"source b\"}:\n continue\n if looks_like_codeish(cleaned):\n continue\n results.append(cleaned)\n return results or [title]\n\n\ndef derive_keywords(title: str, headings: Sequence[Dict[str, Any]], paragraphs: Sequence[str]) -> List[str]:\n candidates = [title]\n candidates.extend(str(item.get(\"text\") or \"\") for item in headings[:6] if isinstance(item, dict))\n for paragraph in paragraphs[:8]:\n candidates.extend(re.findall(r\"[\\u4e00-\\u9fff]{2,8}|[A-Za-z][A-Za-z0-9+_.-]{2,}\", paragraph))\n keywords = unique_preserve_order(candidates)\n filtered: List[str] = []\n for keyword in keywords:\n if len(keyword) \u003c 2:\n continue\n if keyword in filtered:\n continue\n filtered.append(keyword)\n if len(filtered) >= 8:\n break\n return filtered or [title]\n\n\ndef build_mermaid(title: str, headings: Sequence[Dict[str, Any]]) -> str:\n labels = [str(item.get(\"text\") or \"\") for item in headings if isinstance(item, dict) and item.get(\"text\")]\n while len(labels) \u003c 3:\n labels.append(f\"阶段 {len(labels) + 1}\")\n first, second, third = labels[:3]\n return \"\\n\".join(\n [\n \"flowchart TD\",\n f' A[\"问题入口:{title}\"] --> B[\"核心机制:{first}\"]',\n f' B --> C[\"系统协同:{second}\"]',\n f' C --> D[\"落地与复盘:{third}\"]',\n ' D --> E[\"验证与修正\"]',\n ' E --> B',\n ]\n )\n\n\ndef pick_truth_anchor(verification_report: Dict[str, Any], paragraphs: Sequence[str], fallback: str) -> Dict[str, str]:\n claims = verification_report.get(\"claims\") if isinstance(verification_report.get(\"claims\"), list) else []\n preferred = next((claim for claim in claims if isinstance(claim, dict) and claim.get(\"status\") == \"confirmed\"), None)\n if preferred:\n return {\n \"text\": str(preferred.get(\"text\") or fallback),\n \"status\": str(preferred.get(\"status\") or \"confirmed\"),\n \"note\": str(preferred.get(\"evidence_note\") or \"已在证据来源中获得支持。\"),\n }\n if claims and isinstance(claims[0], dict):\n return {\n \"text\": str(claims[0].get(\"text\") or fallback),\n \"status\": str(claims[0].get(\"status\") or \"unverified\"),\n \"note\": str(claims[0].get(\"evidence_note\") or \"当前没有补充证据说明。\"),\n }\n return {\n \"text\": summarize_sentence(paragraphs[0] if paragraphs else fallback, fallback),\n \"status\": \"unverified\",\n \"note\": \"未发现可直接复用的结构化验证主张。\",\n }\n\n\ndef build_faq(title: str, tldr: str, faq_count: int) -> List[Dict[str, str]]:\n base = [\n {\"question\": \"这份内容最核心的问题是什么?\", \"answer\": tldr},\n {\"question\": \"为什么不能只背结论?\", \"answer\": \"因为真正决定迁移能力的是概念之间的因果结构,而不是一句结果。\"},\n {\"question\": \"应该先抓定义还是先看流程?\", \"answer\": \"先抓定义,再立刻定位流程;没有流程的定义很快会变成空壳。\"},\n {\"question\": \"最容易忽略的边界是什么?\", \"answer\": \"时间点、版本差异、前提假设和默认环境最容易被读者跳过。\"},\n {\"question\": \"怎么把它转成自己的笔记?\", \"answer\": \"建议按概念、机制、场景、误区四层来记,而不是照抄原文段落。\"},\n {\"question\": \"如果我现在读不懂,先补什么?\", \"answer\": \"先补主线:它解决什么问题、为什么重要、执行链路怎么走。\"},\n {\"question\": \"怎么判断自己真的学会了?\", \"answer\": \"试着不用原文措辞,把关键机制讲给一个完全没背景的人。\"},\n {\"question\": \"这份学习成品怎么用最值?\", \"answer\": f\"先通读《{title}》的主线,再用搜索、FAQ 和导师模式反向检查自己的理解。\"},\n ]\n return base[:faq_count]\n\n\ndef build_rule_card_data(\n audit_report: Dict[str, Any],\n verification_report: Dict[str, Any],\n contract: Dict[str, Any],\n generation_mode: str,\n degraded_mode: bool,\n) -> Dict[str, Any]:\n source_meta = audit_report.get(\"source_meta\") if isinstance(audit_report.get(\"source_meta\"), dict) else {}\n title = str(source_meta.get(\"title\") or \"\").strip() or \"未命名主题\"\n author = \"叫我小杨同学的小码酱\"\n source = str(source_meta.get(\"url\") or source_meta.get(\"file\") or \"\").strip() or \"未提供来源\"\n headings = audit_report.get(\"heading_tree\") if isinstance(audit_report.get(\"heading_tree\"), list) else []\n paragraphs = [str(item) for item in (audit_report.get(\"cleaned_paragraphs\") or []) if isinstance(item, str)]\n key_quotes = [str(item) for item in (audit_report.get(\"key_quotes\") or []) if isinstance(item, str)]\n conflicts = [str(item) for item in (verification_report.get(\"conflicts\") or []) if isinstance(item, str)]\n outdated_items = [str(item) for item in (verification_report.get(\"outdated_items\") or []) if isinstance(item, str)]\n unverified_items = [str(item) for item in (verification_report.get(\"unverified_items\") or []) if isinstance(item, str)]\n tags = derive_keywords(title, headings, paragraphs)\n best_paragraph = pick_meaningful_paragraph(paragraphs, title)\n tldr = summarize_sentence(best_paragraph, title)\n truth_anchor = pick_truth_anchor(verification_report, paragraphs, tldr)\n analysis_seed = meaningful_analysis_items(paragraphs, title)[:10] or key_quotes or [title]\n faq_count = int(contract[\"modules\"][\"module5\"][\"faq_count\"])\n module3_conflicts = conflicts[:4]\n if not module3_conflicts:\n module3_conflicts = [\"当前未检出显性多源冲突,但仍需结合时间点和版本环境理解原文。\"]\n if outdated_items:\n module3_conflicts.append(\"可能过时的内容:\" + \";\".join(outdated_items[:2]))\n if unverified_items:\n module3_conflicts.append(f\"待人工确认:{len(unverified_items)} 条(为保持正文清爽,明细已收纳到“质量与验证”面板)。\")\n\n return {\n \"header\": {\n \"title\": title,\n \"author\": author,\n \"tags\": tags,\n \"source\": source,\n \"audience_positioning\": \"面向零基础读者,把复杂材料整理成可复盘、可搜索、可继续追问的最终学习成品。\",\n },\n \"module0\": {\n \"one_sentence\": tldr,\n \"analogy\": f\"你可以把《{title}》理解成一张任务地图:它不是只告诉你结论,而是试图交代为什么、怎么做、哪里容易踩坑。\",\n \"truth_anchor\": truth_anchor,\n },\n \"module1\": {\n \"mnemonic\": f\"先抓主线,再拆机制;先懂 why,再做 how;碰到边界,回到证据。关键词:{' / '.join(tags[:4])}。\",\n \"story\": f\"如果你第一次接触《{title}》,很容易被术语和结论带着跑。更稳的读法是先抓主线,再拆机制,最后回到场景验证自己是否真懂了。\",\n \"ascii_visual\": \"问题入口\\n |\\n v\\n核心概念 ---> 关键机制 ---> 实战场景\\n ^ |\\n | v\\n误区修正 \u003c--- 反馈复盘 \u003c--- 证据校验\",\n },\n \"module2\": {\n \"core_mechanism\": analysis_seed[:3],\n \"system_position\": analysis_seed[3:5] or analysis_seed[:2],\n \"evolution\": analysis_seed[5:7] or [\"建议把原文中的版本与路线变化单独摘出来复盘。\"],\n \"why_design\": analysis_seed[7:9] or [\"之所以这样设计,通常是为了在复杂度、效果和可操作性之间取得平衡。\"],\n \"mermaid\": build_mermaid(title, headings),\n },\n \"module3\": {\n \"anti_intuition\": next((paragraph for paragraph in paragraphs if any(token in paragraph for token in [\"并非\", \"不是\", \"而是\", \"然而\"])), tldr),\n \"conflicts_or_version_diff\": module3_conflicts,\n \"search_internalized_tags\": tags[:5],\n \"learner_takeaway\": \"遇到看似确定的结论时,先问自己:它依赖什么时间点、什么版本、什么适用边界。\",\n },\n \"module4\": {\n \"getting_started\": [\n f\"先用一句话复述《{title}》要解决的核心问题。\",\n \"把关键阶段抄成自己的流程图,而不是只看原文结论。\",\n \"挑一个最小场景,解释输入是什么、决策在哪里、输出是什么。\",\n ],\n \"pitfalls\": [\n \"不要只记术语,不理解术语之间的因果关系。\",\n \"不要把作者结论直接当成绝对真理,先核对时间点和版本边界。\",\n \"不要跳过示例与过程,它们最能暴露真正机制。\",\n ],\n \"roi\": [\n \"投入:需要花时间把原文拆成主线、机制、边界三层。\",\n \"收益:你会从知道名词升级为能解释为什么。\",\n \"回报:后续迁移到输出、考试或落地实践时成本更低。\",\n ],\n },\n \"module5\": {\n \"faq\": build_faq(title, tldr, faq_count),\n \"review_entry\": \"如果你想继续温故而知新,请打开导师模式,让系统基于这份正文继续出题、追问、讲评和补讲。\",\n \"resources\": unique_preserve_order(\n [\n f\"原始来源:{source}\",\n str(verification_report.get(\"summary\") or \"\"),\n \"建议回读原文里的定义段、流程段、边界段和版本说明。\",\n ]\n )[:6],\n },\n \"coverage_trace\": {\n \"core_definition_and_value\": True,\n \"mechanism_and_runtime_logic\": True,\n \"system_position_and_collaboration\": True,\n \"history_and_version_changes\": bool(audit_report.get(\"version_sensitive_sentences\") or outdated_items),\n \"scenarios_and_roi\": True,\n \"risks_misuse_and_boundaries\": True,\n },\n \"meta\": {\n \"generation_mode\": generation_mode,\n \"degraded_mode\": degraded_mode,\n \"verification_summary\": str(verification_report.get(\"summary\") or \"当前没有验证摘要。\"),\n },\n }\n","content_type":"text/x-python; charset=utf-8","language":"python","size":12769,"content_sha256":"125cd10e4076a62484d14b83c9c5f4cebe0768f94e435fb1d46afd65f533c04e"},{"filename":"scripts/run_full_pipeline.py","content":"from __future__ import annotations\n\nimport argparse\nimport ast\nimport json\nimport os\nimport re\nimport shutil\nimport subprocess\nimport sys\nimport tempfile\nfrom pathlib import Path\n\n\nsys.dont_write_bytecode = True\n\nSCRIPT_DIR = Path(__file__).resolve().parent\nSKILL_DIR = SCRIPT_DIR.parent\nLEARNING_HINTS = (\"学习\", \"分析\", \"解析\", \"读懂\", \"解释\", \"知识卡\", \"存入知识库\", \"讲明白\")\nSUPPORTED_FILE_EXTENSIONS = {\".pdf\", \".doc\", \".docx\", \".md\", \".markdown\", \".txt\", \".png\", \".jpg\", \".jpeg\", \".webp\", \".py\", \".js\", \".ts\", \".tsx\", \".jsx\", \".java\", \".cpp\", \".c\", \".go\", \".rs\", \".ipynb\"}\n\n\nsys.path.insert(0, str(SCRIPT_DIR))\nfrom build_source_package import build_audit_report, read_text as read_raw_text # noqa: E402\nfrom generate_knowledge_card import generate_outputs # noqa: E402\nfrom system_prompt_contract import load_contract # noqa: E402\nfrom truth_anchor import build_verification_report # noqa: E402\nfrom validate_knowledge_card import read_json, read_text, validate_card_payload, validate_interactive_html_text, validate_source_html_text # noqa: E402\nimport openai_compatible_client # noqa: E402\nfrom system_prompt_contract import load_prompt_text # noqa: E402\n\nBASE_USAGE = '%(prog)s \"\u003c链接或本地文件路径>\" [\"\u003c更多链接或文件路径>\"]'\nDEFAULT_OUTPUT_NOTE = \"默认输出:knowledge_card.md + knowledge_card.interactive.html(仅保留这 2 个文件)\\n可选:--poster 生成 Wan 2.7 知识海报 prompt\"\n\n\ndef run_command(command: list[str], debug: bool = False) -> None:\n if debug:\n subprocess.run(command, cwd=str(SKILL_DIR), check=True)\n return\n completed = subprocess.run(\n command,\n cwd=str(SKILL_DIR),\n check=False,\n capture_output=True,\n text=True,\n )\n if completed.returncode == 0:\n return\n if completed.stdout:\n print(completed.stdout, end=\"\", file=sys.stderr)\n if completed.stderr:\n print(completed.stderr, end=\"\", file=sys.stderr)\n raise subprocess.CalledProcessError(\n completed.returncode,\n command,\n output=completed.stdout,\n stderr=completed.stderr,\n )\n\n\ndef normalize_segments(raw_inputs: list[str]) -> list[str]:\n if len(raw_inputs) == 1:\n candidate = raw_inputs[0].strip()\n if candidate.startswith(\"[\") and candidate.endswith(\"]\"):\n try:\n parsed = ast.literal_eval(candidate)\n except (ValueError, SyntaxError):\n pass\n else:\n if isinstance(parsed, list):\n return [str(item) for item in parsed]\n return raw_inputs\n\n\ndef strip_wrapping_punctuation(value: str) -> str:\n return value.strip().strip(\"'\\\"[](),\")\n\n\ndef extract_urls(text: str) -> list[str]:\n matches = re.findall(r\"https?://[^\\s\\]>'\\\")]+\", text, flags=re.IGNORECASE)\n cleaned = []\n for item in matches:\n normalized = item.rstrip(\".,;)\")\n if normalized not in cleaned:\n cleaned.append(normalized)\n return cleaned\n\n\ndef token_candidates(text: str) -> list[str]:\n pieces = re.split(r\"[\\s\\n\\r\\t]+\", text)\n return [strip_wrapping_punctuation(piece) for piece in pieces if strip_wrapping_punctuation(piece)]\n\n\ndef resolve_existing_path(token: str) -> Path | None:\n candidate = Path(token)\n search_roots = [Path.cwd(), SKILL_DIR.parent, SKILL_DIR]\n path_variants = [candidate]\n if not candidate.is_absolute():\n path_variants.extend(root / candidate for root in search_roots)\n for variant in path_variants:\n if variant.exists() and variant.is_file():\n return variant.resolve()\n return None\n\n\ndef extract_file_targets(segments: list[str]) -> list[str]:\n results: list[str] = []\n seen = set()\n for segment in segments:\n for token in token_candidates(segment):\n path = resolve_existing_path(token)\n if path is None:\n continue\n if path.suffix.lower() not in SUPPORTED_FILE_EXTENSIONS and path.suffix:\n continue\n resolved = str(path)\n if resolved in seen:\n continue\n seen.add(resolved)\n results.append(resolved)\n return results\n\n\ndef has_learning_signal(segments: list[str]) -> bool:\n return any(hint in \" \".join(segments) for hint in LEARNING_HINTS)\n\n\ndef resolve_pipeline_targets(raw_inputs: list[str]) -> list[str]:\n segments = normalize_segments(raw_inputs)\n joined = \" \".join(segments)\n urls = extract_urls(joined)\n files = extract_file_targets(segments)\n targets: list[str] = []\n for item in [*urls, *files]:\n if item not in targets:\n targets.append(item)\n if targets:\n return targets\n direct_inputs = []\n for segment in segments:\n cleaned = strip_wrapping_punctuation(segment)\n if cleaned.startswith((\"http://\", \"https://\")):\n direct_inputs.append(cleaned)\n continue\n path = resolve_existing_path(cleaned)\n if path is not None:\n direct_inputs.append(str(path))\n if direct_inputs:\n return direct_inputs\n if has_learning_signal(segments):\n raise ValueError(\"检测到学习型请求,但没有提取到可执行对象。请确认输入里包含 URL、文件路径、文档或代码文件。\")\n raise ValueError(\"没有识别到可处理的 URL 或文件。请提供学习型请求,并带上链接、文件路径或附件对象。\")\n\n\ndef generate_card_data_with_model(\n raw_content_path: Path,\n audit_report_path: Path,\n verification_report_path: Path,\n output_path: Path,\n) -> None:\n \"\"\"\n Calls the configured LLM to generate the knowledge card JSON data.\n \"\"\"\n connection = openai_compatible_client.load_env_connection()\n if not connection:\n # Check for profile\n profile_path = SKILL_DIR / \"config\" / \"profile.json\" # Assuming standard location, though user might not have it\n connection = openai_compatible_client.load_profile_connection(profile_path)\n \n if not connection:\n print(\"Warning: No LLM configuration found (KA_BASE_URL/KA_API_KEY or profile.json).\", file=sys.stderr)\n print(\"Falling back to local rule-based generation (Degraded Mode).\", file=sys.stderr)\n return\n\n print(f\"Generating knowledge card data using model: {connection['model']}...\", file=sys.stderr)\n\n system_prompt = load_prompt_text()\n \n # Construct user prompt with context\n audit_report = read_json(audit_report_path)\n verification_report = read_json(verification_report_path)\n \n # We use the audit report as the primary source for the model as it is structured\n # but raw content might be needed for full context. \n # Let's use a combination.\n \n user_prompt = f\"\"\"\n请基于以下“内容审计报告”和“验证报告”,生成一份符合 System Prompt 定义的 Knowledge Card 数据 JSON。\n\n**注意:**\n1. 必须输出纯 JSON 格式,不要包含 Markdown 代码块标记(如 ```json ... ```)。\n2. 严格遵守 System Prompt 中的 Schema 定义。\n3. 必须覆盖所有 Mandatory 字段。\n\n---\n【内容审计报告 (Audit Report)】\n{json.dumps(audit_report, ensure_ascii=False, indent=2)}\n\n---\n【验证报告 (Verification Report)】\n{json.dumps(verification_report, ensure_ascii=False, indent=2)}\n\"\"\"\n\n try:\n response_text = openai_compatible_client.chat_text(\n connection=connection,\n system_prompt=system_prompt,\n user_prompt=user_prompt,\n temperature=0.3, # Slightly creative but structured\n max_tokens=4000,\n timeout_seconds=180\n )\n except Exception as e:\n print(f\"Error calling LLM: {e}\", file=sys.stderr)\n print(\"Model generation failed. Local rules are disabled by user request.\", file=sys.stderr)\n sys.exit(1)\n\n # Clean up response (remove potential markdown fences)\n cleaned_json = response_text.strip()\n if cleaned_json.startswith(\"```json\"):\n cleaned_json = cleaned_json[7:]\n if cleaned_json.startswith(\"```\"):\n cleaned_json = cleaned_json[3:]\n if cleaned_json.endswith(\"```\"):\n cleaned_json = cleaned_json[:-3]\n cleaned_json = cleaned_json.strip()\n\n try:\n # Validate JSON syntax\n data = json.loads(cleaned_json)\n # We could validat schema here, but generate_outputs will do it.\n output_path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n print(f\"Model generated data saved to: {output_path}\", file=sys.stderr)\n except json.JSONDecodeError as e:\n print(f\"Error parsing model output as JSON: {e}\", file=sys.stderr)\n print(f\"Raw output start: {cleaned_json[:500]}...\", file=sys.stderr)\n sys.exit(1)\n\n\ndef validate_source_stage(data_path: Path, source_html_path: Path, verification_report_path: Path, audit_report_path: Path) -> None:\n contract = load_contract()\n data = read_json(data_path)\n verification_report = read_json(verification_report_path)\n audit_report = read_json(audit_report_path)\n errors = validate_card_payload(data, contract, audit_report=audit_report, verification_report=verification_report)\n errors.extend(validate_source_html_text(read_text(source_html_path), data, contract, verification_report, audit_report))\n if errors:\n raise ValueError(\"Source validation failed: \" + \" | \".join(errors))\n\n\ndef validate_interactive_stage(data_path: Path, source_html_path: Path, interactive_path: Path, verification_report_path: Path, audit_report_path: Path) -> None:\n contract = load_contract()\n data = read_json(data_path)\n verification_report = read_json(verification_report_path)\n audit_report = read_json(audit_report_path)\n errors = validate_card_payload(data, contract, audit_report=audit_report, verification_report=verification_report)\n errors.extend(validate_source_html_text(read_text(source_html_path), data, contract, verification_report, audit_report))\n errors.extend(validate_interactive_html_text(read_text(interactive_path), contract))\n if errors:\n raise ValueError(\"Interactive validation failed: \" + \" | \".join(errors))\n\n\ndef cleanup_output_dir(output_dir: Path, keep_names: set[str]) -> None:\n for child in output_dir.iterdir():\n if child.is_file():\n if child.name not in keep_names:\n child.unlink(missing_ok=True)\n continue\n shutil.rmtree(child, ignore_errors=True)\n\n\ndef parse_args() -> argparse.Namespace:\n parser = argparse.ArgumentParser(\n description=(\n \"把链接、文档、图片或代码整理成学习成品。\\n\"\n f\"{DEFAULT_OUTPUT_NOTE}\"\n ),\n formatter_class=argparse.RawTextHelpFormatter,\n usage=BASE_USAGE,\n )\n parser.add_argument(\n \"inputs\",\n nargs=\"+\",\n metavar=\"target\",\n help=\"一个或多个链接/本地文件路径;也支持包含链接或路径的自然语言学习请求。\",\n )\n parser.add_argument(\n \"--poster\",\n action=\"store_true\",\n help=\"生成 Wan 2.7 知识海报 prompt(需要 DASHSCOPE_API_KEY)\",\n )\n parser.add_argument(\n \"--style\",\n default=\"\",\n help=\"海报风格编号 (1-11),默认自动检测:国学内容用水墨风格,其他用孟菲斯网格\",\n )\n parser.add_argument(\n \"--audience\",\n default=\"零基础学习者\",\n help=\"目标读者,默认:零基础学习者\",\n )\n parser.add_argument(\n \"--size\",\n default=\"2K\",\n help=\"海报分辨率,默认:2K\",\n )\n parser.add_argument(\n \"--ratio\",\n default=\"3:4\",\n help=\"海报比例,默认:3:4\",\n )\n return parser.parse_args()\n\n\ndef print_success_summary(\n resolved_targets: list[str],\n markdown_path: Path,\n interactive_path: Path,\n poster_prompt_path: Path | None = None,\n) -> None:\n print(\"Resolved targets:\")\n for target in resolved_targets:\n print(f\"- {target}\")\n print(f\"Output Markdown: {markdown_path}\")\n print(f\"Output HTML: {interactive_path}\")\n if poster_prompt_path:\n print(f\"Poster Prompt: {poster_prompt_path}\")\n\n\ndef main() -> int:\n args = parse_args()\n output_root = (SKILL_DIR / \"outputs\").resolve()\n output_root.mkdir(parents=True, exist_ok=True)\n resolved_targets = resolve_pipeline_targets(args.inputs)\n\n with tempfile.TemporaryDirectory(prefix=\"ka_work_\", dir=str(output_root)) as work_dir:\n work_path = Path(work_dir)\n raw_content_path = work_path / \"raw_content.txt\"\n audit_report_path = work_path / \"raw_content.audit.json\"\n verification_report_path = work_path / \"verification_report.json\"\n\n run_command(\n [\n sys.executable,\n str(SCRIPT_DIR / \"content_ingester.py\"),\n \"--output\",\n str(raw_content_path),\n \"--no-reports\",\n *resolved_targets,\n ],\n debug=False,\n )\n if not raw_content_path.exists():\n raise FileNotFoundError(f\"Expected raw content was not generated: {raw_content_path}\")\n\n audit_report = build_audit_report(read_raw_text(raw_content_path))\n audit_report_path.write_text(json.dumps(audit_report, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n verification_report = build_verification_report(audit_report)\n verification_report_path.write_text(json.dumps(verification_report, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n\n # [LCS-MOD] Try Model Generation First (User Request: No Local Rules)\n card_data_path = work_path / \"knowledge_card.data.json\"\n \n # Check if we have a key before trying, to avoid the error inside the function (though we patched it to return)\n # Actually, the function now returns None if no key.\n # We need to know if it succeeded.\n \n try:\n generate_card_data_with_model(\n raw_content_path=raw_content_path,\n audit_report_path=audit_report_path,\n verification_report_path=verification_report_path,\n output_path=card_data_path\n )\n except Exception as e:\n print(f\"Model generation failed: {e}. Falling back to rules.\", file=sys.stderr)\n \n mode = \"model\" if card_data_path.exists() else \"rule\"\n final_card_path = card_data_path if card_data_path.exists() else None\n\n artifacts = generate_outputs(\n raw_path=raw_content_path,\n output_root=output_root,\n audit_report_path=audit_report_path,\n verification_report_path=verification_report_path,\n card_generation_mode=mode, \n card_data_path=final_card_path,\n )\n\n validate_source_stage(artifacts.data_path, artifacts.source_html_path, verification_report_path, audit_report_path)\n\n interactive_path = artifacts.source_html_path.with_name(\"knowledge_card.interactive.html\")\n run_command(\n [\n sys.executable,\n str(SCRIPT_DIR / \"package_interactive_html.py\"),\n \"--input-html\",\n str(artifacts.source_html_path),\n \"--raw-content\",\n str(raw_content_path),\n \"--output\",\n str(interactive_path),\n \"--mode\",\n \"manual\",\n ],\n debug=False,\n )\n\n validate_interactive_stage(\n artifacts.data_path,\n artifacts.source_html_path,\n interactive_path,\n verification_report_path,\n audit_report_path,\n )\n\n # Generate poster prompt if requested\n poster_prompt_path = None\n if args.poster:\n try:\n poster_output_dir = output_root / \"wan_prompt.txt\"\n poster_command = [\n sys.executable,\n str(SCRIPT_DIR / \"build_knowledge_poster_assets.py\"),\n \"--input\", str(artifacts.markdown_path),\n \"--prompt-output\", str(poster_output_dir),\n \"--audience\", args.audience,\n \"--style\", args.style,\n \"--size\", args.size,\n \"--ratio\", args.ratio,\n ]\n run_command(poster_command, debug=False)\n if poster_output_dir.exists():\n poster_prompt_path = poster_output_dir\n print(f\"\\n🎨 海报 Prompt 已生成: {poster_output_dir}\")\n print(\"💡 回复'确认生图'后调用 Wan 2.7 生成海报\")\n except Exception as e:\n print(f\"海报 Prompt 生成失败: {e}\", file=sys.stderr)\n\n keep_names = {artifacts.markdown_path.name, interactive_path.name}\n if poster_prompt_path:\n keep_names.add(poster_prompt_path.name)\n cleanup_output_dir(artifacts.output_dir, keep_names)\n\n print_success_summary(\n resolved_targets=resolved_targets,\n markdown_path=artifacts.markdown_path,\n interactive_path=interactive_path,\n poster_prompt_path=poster_prompt_path,\n )\n return 0\n\n\nif __name__ == \"__main__\":\n raise SystemExit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":17389,"content_sha256":"4c859c97d67b8945df809ce1fc2db456dea15e8f623e283070503082517cc41f"},{"filename":"scripts/run_wan_generation.py","content":"#!/usr/bin/env python3\n\"\"\"Run Wan 2.7 generation with a prepared prompt file for knowledge posters.\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport json\nimport os\nimport re\nimport subprocess\nimport sys\nfrom datetime import datetime, timezone\nfrom pathlib import Path\n\nSKILL_ROOT = Path(__file__).resolve().parent.parent\nOUTPUT_DIR = SKILL_ROOT / \"outputs\"\n\n# Try to find Wan skill directory\nWAN_SKILL_DIR = Path(os.environ.get(\"WAN_SKILL_DIR\", \"\"))\nif not WAN_SKILL_DIR.exists():\n # Try common locations\n candidate_paths = [\n SKILL_ROOT.parent / \"Wan-skills-main\" / \"skills\" / \"wan2.7-image-skill\",\n SKILL_ROOT.parent.parent / \"Wan-skills-main\" / \"skills\" / \"wan2.7-image-skill\",\n Path.home() / \".claude\" / \"skills\" / \"Wan-skills-main\" / \"skills\" / \"wan2.7-image-skill\",\n ]\n for candidate in candidate_paths:\n if candidate.exists():\n WAN_SKILL_DIR = candidate\n break\n\nWAN_SCRIPTS_DIR = WAN_SKILL_DIR / \"scripts\" if WAN_SKILL_DIR.exists() else None\nWAN_SCRIPT = WAN_SCRIPTS_DIR / \"image-generation-editing.py\" if WAN_SCRIPTS_DIR else None\nCHECK_SCRIPT = WAN_SCRIPTS_DIR / \"check_wan_task_status.py\" if WAN_SCRIPTS_DIR else None\nPARSE_RESOLUTION_SCRIPT = WAN_SCRIPTS_DIR / \"parse_resolution.py\" if WAN_SCRIPTS_DIR else None\n\nDEFAULT_PROMPT_PATH = OUTPUT_DIR / \"wan_prompt.txt\"\nRESULT_FILE = \"wan_result.json\"\n\nURL_PATTERN = re.compile(r\"result No\\.\\s*\\d+:\\s+(https?://\\S+)\")\nTASK_ID_PATTERN = re.compile(r\"(?:Dashscope\\s+)?TASK_ID:\\s+(\\S+)\", re.IGNORECASE)\n\n\ndef ensure_script(path: Path | None, label: str) -> None:\n if path is None or not path.is_file():\n raise FileNotFoundError(\n f\"缺少{label}脚本: {path}\\n\"\n f\"请确保 Wan-skills-main 已安装,或设置 WAN_SKILL_DIR 环境变量\"\n )\n\n\ndef read_prompt(path: Path) -> str:\n if not path.is_file():\n raise FileNotFoundError(f\"Prompt 文件不存在: {path}\")\n content = path.read_text(encoding=\"utf-8\")\n if not content.strip():\n raise ValueError(f\"Prompt 文件为空: {path}\")\n return content.strip()\n\n\ndef resolve_size(size: str, ratio: str | None, parse_script: Path | None) -> str:\n normalized_size = size.strip()\n if not ratio:\n return normalized_size\n if \"*\" in normalized_size or \"x\" in normalized_size.lower():\n return normalized_size\n\n if parse_script and parse_script.is_file():\n command = [sys.executable, str(parse_script), f\"{normalized_size} {ratio}\"]\n result = subprocess.run(command, capture_output=True, text=True, check=False)\n if result.returncode == 0 and result.stdout.strip():\n return result.stdout.strip()\n\n # Fallback: manual resolution mapping\n size_map = {\n \"1K\": {\"3:4\": \"1024*1365\", \"4:3\": \"1365*1024\", \"1:1\": \"1024*1024\", \"16:9\": \"1820*1024\"},\n \"2K\": {\"3:4\": \"1774*2364\", \"4:3\": \"2364*1774\", \"1:1\": \"2048*2048\", \"16:9\": \"2730*1536\"},\n \"4K\": {\"3:4\": \"2688*3584\", \"4:3\": \"3584*2688\", \"1:1\": \"4096*4096\", \"16:9\": \"3840*2160\"},\n }\n if normalized_size in size_map and ratio in size_map[normalized_size]:\n return size_map[normalized_size][ratio]\n\n return normalized_size\n\n\ndef ensure_env() -> None:\n if not os.getenv(\"DASHSCOPE_API_KEY\"):\n raise EnvironmentError(\n \"缺少 DASHSCOPE_API_KEY 环境变量。\\n\"\n \"请设置: export DASHSCOPE_API_KEY='your-api-key'\"\n )\n\n\ndef build_command(prompt: str, size: str, sequential: bool, number: int, wan_script: Path) -> list[str]:\n command = [\n sys.executable,\n str(wan_script),\n \"--user_requirement\",\n prompt,\n \"--n\",\n str(number),\n \"--size\",\n size,\n ]\n if sequential:\n command.append(\"--enable_sequential\")\n return command\n\n\ndef run_subprocess(command: list[str], action: str) -> tuple[int, str]:\n result = subprocess.run(command, capture_output=True, text=True, check=False)\n stdout = result.stdout or \"\"\n if stdout:\n print(stdout, end=\"\" if stdout.endswith(\"\\n\") else \"\\n\")\n if result.returncode != 0:\n detail = (result.stderr or stdout).strip() or f\"{action}失败\"\n print(detail, file=sys.stderr)\n return result.returncode, stdout\n\n\ndef parse_generation_output(stdout: str) -> dict:\n urls = URL_PATTERN.findall(stdout)\n task_id_match = TASK_ID_PATTERN.search(stdout)\n task_id = task_id_match.group(1) if task_id_match else \"\"\n if urls:\n status = \"SUCCEEDED\"\n elif task_id:\n status = \"PENDING\"\n else:\n status = \"UNKNOWN\"\n return {\n \"task_id\": task_id,\n \"image_urls\": urls,\n \"generated_at\": datetime.now(timezone.utc).isoformat(),\n \"status\": status,\n }\n\n\ndef save_result(result_data: dict) -> Path:\n OUTPUT_DIR.mkdir(parents=True, exist_ok=True)\n result_path = OUTPUT_DIR / RESULT_FILE\n with open(result_path, \"w\", encoding=\"utf-8\") as handle:\n json.dump(result_data, handle, ensure_ascii=False, indent=2)\n print(f\"已保存结果: {result_path}\")\n return result_path\n\n\ndef run_generation(\n prompt_path: Path,\n size: str,\n ratio: str | None,\n sequential: bool,\n number: int,\n) -> int:\n ensure_env()\n\n if WAN_SCRIPT is None:\n raise FileNotFoundError(\"Wan 脚本目录未找到,请设置 WAN_SKILL_DIR 环境变量\")\n\n ensure_script(WAN_SCRIPT, \"Wan 生成\")\n prompt = read_prompt(prompt_path)\n resolved_size = resolve_size(size, ratio, PARSE_RESOLUTION_SCRIPT)\n command = build_command(prompt, resolved_size, sequential, number, WAN_SCRIPT)\n\n print(f\"开始调用 Wan 2.7 生图:\")\n print(f\" - prompt: {prompt_path}\")\n print(f\" - size: {resolved_size}\")\n print(f\" - n: {number}\")\n\n code, stdout = run_subprocess(command, \"Wan 生图\")\n result_data = parse_generation_output(stdout)\n result_data[\"prompt_path\"] = str(prompt_path)\n result_data[\"size\"] = resolved_size\n result_data[\"number\"] = number\n save_result(result_data)\n return code\n\n\ndef check_task(task_id: str) -> int:\n ensure_env()\n\n if CHECK_SCRIPT is None:\n raise FileNotFoundError(\"Wan 任务查询脚本未找到\")\n\n ensure_script(CHECK_SCRIPT, \"Wan 任务查询\")\n command = [sys.executable, str(CHECK_SCRIPT), \"--task_id\", task_id]\n print(f\"开始查询 Wan 任务: task_id={task_id}\")\n code, stdout = run_subprocess(command, \"Wan 任务查询\")\n result_data = parse_generation_output(stdout)\n result_data[\"task_id\"] = task_id\n save_result(result_data)\n return code\n\n\ndef parse_args() -> argparse.Namespace:\n parser = argparse.ArgumentParser(description=\"Run Wan 2.7 generation for knowledge posters\")\n parser.add_argument(\"--prompt\", default=str(DEFAULT_PROMPT_PATH), help=\"Prompt file path\")\n parser.add_argument(\"--size\", default=\"2K\", help=\"Requested size, e.g. 2K or 1774*2364\")\n parser.add_argument(\"--ratio\", default=\"3:4\", help=\"Aspect ratio used when size is K-based\")\n parser.add_argument(\"--sequential\", action=\"store_true\", help=\"Enable sequential multi-image generation\")\n parser.add_argument(\"--n\", type=int, default=1, help=\"Number of images to request\")\n parser.add_argument(\"--task-id\", default=\"\", help=\"Existing task id to query instead of generating\")\n return parser.parse_args()\n\n\ndef main() -> None:\n args = parse_args()\n\n try:\n if args.task_id:\n code = check_task(args.task_id)\n else:\n code = run_generation(\n prompt_path=Path(args.prompt),\n size=args.size,\n ratio=args.ratio,\n sequential=args.sequential,\n number=args.n,\n )\n except (EnvironmentError, FileNotFoundError, ValueError) as exc:\n print(f\"执行失败: {exc}\", file=sys.stderr)\n raise SystemExit(1) from exc\n\n raise SystemExit(code)\n\n\nif __name__ == \"__main__\":\n main()","content_type":"text/x-python; charset=utf-8","language":"python","size":7924,"content_sha256":"7ae6cc29bbf60162d2cd4827b4c9dc9217dc1f6874b1107c1ab94400aeb5a4f6"},{"filename":"scripts/system_prompt_contract.py","content":"from __future__ import annotations\n\nimport json\nimport re\nfrom pathlib import Path\nfrom typing import Any, Dict, Iterable, List\n\n\nSCRIPT_DIR = Path(__file__).resolve().parent\nSKILL_DIR = SCRIPT_DIR.parent\nSYSTEM_PROMPT_PATH = SKILL_DIR / \"references\" / \"system_prompt.md\"\nCONTRACT_BEGIN = \"\u003c!-- KA_CONTRACT:BEGIN -->\"\nCONTRACT_END = \"\u003c!-- KA_CONTRACT:END -->\"\n\n\ndef load_prompt_text(path: Path | None = None) -> str:\n target_path = path or SYSTEM_PROMPT_PATH\n return target_path.read_text(encoding=\"utf-8-sig\")\n\n\ndef extract_contract_block(prompt_text: str) -> str:\n pattern = re.compile(\n rf\"{re.escape(CONTRACT_BEGIN)}\\s*```yaml\\s*(.*?)\\s*```\\s*{re.escape(CONTRACT_END)}\",\n flags=re.DOTALL,\n )\n match = pattern.search(prompt_text)\n if not match:\n raise ValueError(\"system_prompt.md does not contain a KA contract block\")\n return match.group(1).strip()\n\n\ndef load_contract(path: Path | None = None) -> Dict[str, Any]:\n prompt_text = load_prompt_text(path)\n raw_contract = extract_contract_block(prompt_text)\n try:\n contract = json.loads(raw_contract)\n except json.JSONDecodeError as exc:\n raise ValueError(f\"KA contract block is not valid JSON-compatible YAML: {exc}\") from exc\n validate_contract_shape(contract)\n return contract\n\n\ndef _ensure_string_list(values: Any, field_name: str) -> List[str]:\n if not isinstance(values, list) or not values or not all(isinstance(item, str) and item.strip() for item in values):\n raise ValueError(f\"{field_name} must be a non-empty list of strings\")\n return values\n\n\ndef _require_mapping(container: Dict[str, Any], field_name: str) -> Dict[str, Any]:\n value = container.get(field_name)\n if not isinstance(value, dict):\n raise ValueError(f\"{field_name} must be an object\")\n return value\n\n\ndef _require_bool(container: Dict[str, Any], field_name: str) -> bool:\n value = container.get(field_name)\n if not isinstance(value, bool):\n raise ValueError(f\"{field_name} must be a boolean\")\n return value\n\n\ndef validate_contract_shape(contract: Dict[str, Any]) -> None:\n if not isinstance(contract, dict):\n raise ValueError(\"contract root must be an object\")\n schema_version = contract.get(\"schema_version\")\n if not isinstance(schema_version, str) or not schema_version.strip():\n raise ValueError(\"schema_version must be a non-empty string\")\n\n header = _require_mapping(contract, \"header\")\n _ensure_string_list(header.get(\"required_fields\"), \"header.required_fields\")\n\n coverage = _require_mapping(contract, \"coverage\")\n _ensure_string_list(coverage.get(\"required_categories\"), \"coverage.required_categories\")\n\n modules = _require_mapping(contract, \"modules\")\n required_order = _ensure_string_list(modules.get(\"required_order\"), \"modules.required_order\")\n for module_name in (\"module2\", \"module3\", \"module5\"):\n _require_mapping(modules, module_name)\n _ensure_string_list(modules[\"module2\"].get(\"required_fields\"), \"modules.module2.required_fields\")\n _ensure_string_list(modules[\"module3\"].get(\"required_fields\"), \"modules.module3.required_fields\")\n faq_count = modules[\"module5\"].get(\"faq_count\")\n if not isinstance(faq_count, int) or faq_count \u003c= 0:\n raise ValueError(\"modules.module5.faq_count must be a positive integer\")\n if required_order != [\"module0\", \"module1\", \"module2\", \"module3\", \"module4\", \"module5\"]:\n raise ValueError(\"modules.required_order must be module0..module5 in order\")\n\n html_hooks = _require_mapping(contract, \"html_hooks\")\n _ensure_string_list(html_hooks.get(\"required\"), \"html_hooks.required\")\n\n mentor = _require_mapping(contract, \"mentor\")\n _ensure_string_list(mentor.get(\"required\"), \"mentor.required\")\n\n search = _require_mapping(contract, \"search\")\n _require_bool(search, \"show_parent_headings\")\n\n truth_anchor = _require_mapping(contract, \"truth_anchor\")\n allowed_status = _ensure_string_list(truth_anchor.get(\"allowed_status\"), \"truth_anchor.allowed_status\")\n expected_status = {\"confirmed\", \"disputed\", \"outdated\", \"unverified\"}\n if set(allowed_status) != expected_status:\n raise ValueError(\"truth_anchor.allowed_status must match the expected status set\")\n\n\ndef require_fields(container: Dict[str, Any], required_fields: Iterable[str], scope: str) -> List[str]:\n errors: List[str] = []\n for field_name in required_fields:\n value = container.get(field_name)\n if value in (None, \"\", [], {}):\n errors.append(f\"{scope}.{field_name} is required\")\n return errors\n\n","content_type":"text/x-python; charset=utf-8","language":"python","size":4593,"content_sha256":"1666908f36545c2d0397b0ce31287c9d0e6eb6908a9f0d60c5093852dd5cd4e5"},{"filename":"scripts/truth_anchor.py","content":"from __future__ import annotations\n\nimport argparse\nimport json\nimport re\nfrom datetime import datetime\nfrom pathlib import Path\nfrom typing import Dict, List, Sequence, Tuple\nfrom urllib.parse import urlparse\n\nimport requests\nfrom bs4 import BeautifulSoup\n\n\nSCRIPT_DIR = Path(__file__).resolve().parent\nSKILL_DIR = SCRIPT_DIR.parent\nCONFIG_DIR = SKILL_DIR / \"config\"\nDEFAULT_AUDIT_REPORT = CONFIG_DIR / \"raw_content.audit.json\"\nDEFAULT_OUTPUT_PATH = CONFIG_DIR / \"verification_report.json\"\nCURRENT_YEAR = datetime.now().year\nOFFICIAL_HINTS = (\n \"docs\",\n \"developers\",\n \"platform\",\n \"api\",\n \"openai.com\",\n \"anthropic.com\",\n \"google.com\",\n \"microsoft.com\",\n \"github.com\",\n \"readthedocs\",\n \"w3.org\",\n \"developer.mozilla.org\",\n)\nLOW_VALUE_PATTERNS = (\n \"发布于\",\n \"浏览\",\n \"评论\",\n \"举报\",\n \"社区首页\",\n \"专栏\",\n \"登录\",\n \"注册\",\n \"推荐阅读\",\n \"热门\",\n \"Copyright\",\n \"版权所有\",\n \"腾讯云 版权所有\",\n \"作者头像\",\n \"http-save\",\n)\nLOW_VALUE_URL_HINTS = (\n \"console.cloud.tencent.com\",\n \"qcloudimg\",\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \"beian.\",\n)\n\n\ndef read_json(path: Path) -> Dict[str, object]:\n return json.loads(path.read_text(encoding=\"utf-8-sig\"))\n\n\ndef normalize(text: str) -> str:\n text = text.replace(\"\\r\\n\", \"\\n\").replace(\"\\r\", \"\\n\")\n text = re.sub(r\"[\\t\\f\\v ]+\", \" \", text)\n return text.strip()\n\n\ndef unique_preserve_order(values: Sequence[str]) -> List[str]:\n seen = set()\n result: List[str] = []\n for value in values:\n cleaned = value.strip()\n if not cleaned or cleaned in seen:\n continue\n seen.add(cleaned)\n result.append(cleaned)\n return result\n\n\ndef classify_claim(text: str) -> str:\n lowered = text.lower()\n if any(token in text for token in [\"步骤\", \"首先\", \"然后\", \"最后\", \"如何\", \"先\", \"再\", \"通过\"]) or \"how to\" in lowered:\n return \"procedure\"\n if any(token in text for token in [\"建议\", \"最好\", \"更适合\", \"值得\", \"应该\", \"不推荐\"]) or any(token in lowered for token in [\"should\", \"best\", \"recommend\"]):\n return \"judgment\"\n if any(token in text for token in [\"是\", \"指\", \"意味着\", \"可以理解为\"]) and len(text) \u003c 120:\n return \"definition\"\n return \"fact\"\n\n\ndef risk_level(text: str) -> str:\n lowered = text.lower()\n if re.search(r\"\\b(19|20)\\d{2}\\b\", text) or re.search(r\"\\bv\\d+(?:\\.\\d+){0,2}\\b\", lowered) or re.search(r\"\\d+(?:\\.\\d+)?\", text):\n return \"high\"\n if any(token in text for token in [\"必须\", \"唯一\", \"最强\", \"永远\", \"从不\", \"总是\"]):\n return \"high\"\n if any(token in lowered for token in [\"api\", \"sdk\", \"release\", \"model\", \"version\"]):\n return \"medium\"\n return \"low\"\n\n\ndef score_candidate_url(url: str, source_domain: str) -> int:\n parsed = urlparse(url)\n if parsed.scheme not in {\"http\", \"https\"}:\n return -1\n score = 0\n hostname = parsed.netloc.lower()\n path = parsed.path.lower()\n if source_domain and hostname.endswith(source_domain):\n score += 80\n if any(hint in hostname or hint in path for hint in OFFICIAL_HINTS):\n score += 60\n if path.endswith((\".md\", \".txt\", \".html\", \"/docs\", \"/api\")):\n score += 10\n return score\n\n\ndef select_urls(audit_report: Dict[str, object]) -> List[str]:\n source_meta = audit_report.get(\"source_meta\") if isinstance(audit_report.get(\"source_meta\"), dict) else {}\n source_url = str((source_meta or {}).get(\"url\") or \"\").strip()\n linked_urls = audit_report.get(\"linked_urls\") if isinstance(audit_report.get(\"linked_urls\"), list) else []\n candidates = unique_preserve_order([source_url, *[str(item) for item in linked_urls if isinstance(item, str)]])\n source_domain = urlparse(source_url).netloc.lower()\n scored = sorted(candidates, key=lambda item: score_candidate_url(item, source_domain), reverse=True)\n return [item for item in scored if item.startswith((\"http://\", \"https://\")) and not any(hint in item.lower() for hint in LOW_VALUE_URL_HINTS)][:6]\n\n\ndef is_low_value_claim(text: str) -> bool:\n cleaned = normalize(text)\n if not cleaned:\n return True\n if any(pattern.lower() in cleaned.lower() for pattern in LOW_VALUE_PATTERNS):\n return True\n if cleaned.startswith((\"http://\", \"https://\")):\n return True\n if re.search(r\"^\\d+$\", cleaned):\n return True\n return False\n\n\ndef fetch_url_text(url: str) -> Tuple[str, str]:\n headers = {\n \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0 Safari/537.36\",\n }\n response = requests.get(url, timeout=10, headers=headers)\n response.raise_for_status()\n content_type = response.headers.get(\"Content-Type\", \"\")\n if \"html\" in content_type:\n soup = BeautifulSoup(response.text, \"html.parser\")\n for tag in soup.select(\"script, style, noscript\"):\n tag.decompose()\n return normalize(soup.get_text(\"\\n\", strip=True)), \"ok\"\n return normalize(response.text), \"ok\"\n\n\ndef summarize_fetch_failure(exc: Exception) -> str:\n raw = str(exc) or exc.__class__.__name__\n lowered = raw.lower()\n if \"read timed out\" in lowered or \"timeout\" in lowered:\n return \"抓取失败:超时\"\n code_match = re.search(r\"\\b(401|403|404|405|408|409|410|429|451|500|502|503|504)\\b\", raw)\n if code_match:\n code = code_match.group(1)\n reason_match = re.search(rf\"{code}\\\\s+(?:Client|Server) Error:\\\\s+(.+?)\\\\s+for url\", raw)\n reason = reason_match.group(1).strip() if reason_match else \"\"\n reason = re.sub(r\"\\\\s+\", \" \", reason)\n return f\"抓取失败:HTTP {code}{(' ' + reason) if reason else ''}\".strip()\n return f\"抓取失败:{raw[:80].strip()}\"\n\n\ndef build_evidence_corpus(urls: Sequence[str]) -> Tuple[Dict[str, str], Dict[str, str]]:\n corpus: Dict[str, str] = {}\n notes: Dict[str, str] = {}\n for url in urls:\n try:\n text, status = fetch_url_text(url)\n corpus[url] = text\n notes[url] = status\n except Exception as exc:\n notes[url] = summarize_fetch_failure(exc)\n return corpus, notes\n\n\ndef extract_keywords(text: str) -> List[str]:\n chinese_tokens = re.findall(r\"[\\u4e00-\\u9fff]{2,8}\", text)\n latin_tokens = re.findall(r\"[A-Za-z][A-Za-z0-9+_.-]{2,}\", text)\n return unique_preserve_order([*chinese_tokens, *latin_tokens])[:8]\n\n\ndef numeric_signature(text: str) -> List[str]:\n versions = re.findall(r\"\\bv\\d+(?:\\.\\d+){0,2}\\b\", text, flags=re.IGNORECASE)\n years = re.findall(r\"\\b(?:19|20)\\d{2}\\b\", text)\n numbers = re.findall(r\"\\d+(?:\\.\\d+)?(?:ms|s|%|x)?\", text, flags=re.IGNORECASE)\n return unique_preserve_order([*versions, *years, *numbers])\n\n\ndef claim_topic_key(text: str) -> str:\n keywords = [keyword.lower() for keyword in extract_keywords(text) if len(keyword) >= 2]\n return \"|\".join(keywords[:3])\n\n\ndef detect_source_package_conflicts(audit_report: Dict[str, object]) -> List[Dict[str, object]]:\n source_packages = audit_report.get(\"source_packages\") if isinstance(audit_report.get(\"source_packages\"), list) else []\n sentence_entries: List[Dict[str, str]] = []\n for package in source_packages:\n if not isinstance(package, dict):\n continue\n content = normalize(str(package.get(\"content\") or \"\"))\n for sentence in re.split(r\"(?\u003c=[。!?!?])\\s+|\\n+\", content):\n cleaned = normalize(sentence)\n if len(cleaned) \u003c 12:\n continue\n sentence_entries.append(\n {\n \"source_id\": str(package.get(\"source_id\") or \"\"),\n \"title\": str(package.get(\"title\") or package.get(\"path\") or \"source\"),\n \"text\": cleaned,\n }\n )\n conflicts: List[Dict[str, object]] = []\n for index, left in enumerate(sentence_entries):\n left_key = claim_topic_key(left[\"text\"])\n left_numbers = numeric_signature(left[\"text\"])\n left_keywords = set(extract_keywords(left[\"text\"]))\n if not left_key or not left_numbers:\n continue\n for right in sentence_entries[index + 1 :]:\n if left[\"source_id\"] == right[\"source_id\"]:\n continue\n right_key = claim_topic_key(right[\"text\"])\n right_numbers = numeric_signature(right[\"text\"])\n right_keywords = set(extract_keywords(right[\"text\"]))\n if not right_key or not right_numbers:\n continue\n if len(left_keywords & right_keywords) \u003c 2:\n continue\n if left_numbers == right_numbers:\n continue\n conflicts.append(\n {\n \"left\": left,\n \"right\": right,\n \"message\": f\"来源 {left['title']} 与 {right['title']} 在同类主张上给出了不同数值/版本:{left['text']} \u003c> {right['text']}\",\n }\n )\n return conflicts\n\n\ndef detect_outdated(text: str, evidence_texts: Sequence[str]) -> bool:\n years = [int(item) for item in re.findall(r\"\\b(19\\d{2}|20\\d{2})\\b\", text)]\n if years and max(years) \u003c= CURRENT_YEAR - 2:\n return True\n lowered = text.lower()\n if re.search(r\"\\bv\\d+(?:\\.\\d+){0,2}\\b\", lowered):\n evidence_joined = \"\\n\".join(evidence_texts).lower()\n if evidence_joined and lowered not in evidence_joined and any(token in evidence_joined for token in [\"deprecated\", \"legacy\", \"obsolete\", \"已弃用\", \"过时\"]):\n return True\n return False\n\n\ndef evaluate_claim(text: str, evidence_corpus: Dict[str, str], notes: Dict[str, str]) -> Tuple[str, List[str], str]:\n evidence_urls = [url for url, evidence_text in evidence_corpus.items() if evidence_text]\n evidence_texts = list(evidence_corpus.values())\n keywords = extract_keywords(text)\n text_lower = text.lower()\n for url, evidence_text in evidence_corpus.items():\n evidence_lower = evidence_text.lower()\n if text_lower in evidence_lower:\n return \"confirmed\", [url], \"在证据来源中找到了原句或高度相近表述。\"\n if keywords and sum(1 for keyword in keywords if keyword.lower() in evidence_lower) >= max(2, min(4, len(keywords))):\n return \"confirmed\", [url], \"在证据来源中找到了多个关键术语共现。\"\n if detect_outdated(text, evidence_texts):\n return \"outdated\", evidence_urls[:2], \"文本包含较早年份或旧版本痕迹,且证据来源未能支持其当前性。\"\n if evidence_urls:\n return \"disputed\", evidence_urls[:2], \"已检查可验证来源,但未找到足够证据支持该主张。\"\n codes: List[str] = []\n for note in notes.values():\n match = re.search(r\"\\b(401|403|404|405|408|409|410|429|451|500|502|503|504)\\b\", str(note))\n if match and match.group(1) not in codes:\n codes.append(match.group(1))\n reason = \"\"\n if codes:\n if set(codes).issubset({\"401\", \"403\"}):\n reason = \"(访问受限)\"\n else:\n reason = \"(抓取失败)\"\n attempt_count = len([url for url in notes.keys() if url])\n attempt_suffix = f\"已尝试 {attempt_count} 个链接。\" if attempt_count else \"\"\n note = f\"无法自动验证:来源抓取受限{reason}。{attempt_suffix}\".strip()\n return \"unverified\", [], note\n\n\ndef build_verification_report(audit_report: Dict[str, object]) -> Dict[str, object]:\n selected_urls = select_urls(audit_report)\n evidence_corpus, notes = build_evidence_corpus(selected_urls)\n claim_candidates = audit_report.get(\"claim_candidates\") if isinstance(audit_report.get(\"claim_candidates\"), list) else []\n source_conflicts = detect_source_package_conflicts(audit_report)\n disputed_texts = set()\n for conflict in source_conflicts:\n left = conflict.get(\"left\") if isinstance(conflict, dict) else None\n right = conflict.get(\"right\") if isinstance(conflict, dict) else None\n if isinstance(left, dict) and left.get(\"text\"):\n disputed_texts.add(str(left[\"text\"]))\n if isinstance(right, dict) and right.get(\"text\"):\n disputed_texts.add(str(right[\"text\"]))\n claims: List[Dict[str, object]] = []\n conflicts: List[str] = []\n outdated_items: List[str] = []\n unverified_items: List[str] = []\n seen_texts: Dict[str, str] = {}\n filtered_candidates = []\n for item in claim_candidates:\n text = str(item.get(\"text\") if isinstance(item, dict) else item).strip()\n if not text or is_low_value_claim(text):\n continue\n filtered_candidates.append(item)\n\n for index, item in enumerate(filtered_candidates, start=1):\n text = str(item.get(\"text\") if isinstance(item, dict) else item).strip()\n if not text:\n continue\n claim_type = classify_claim(text)\n level = risk_level(text)\n status, evidence_urls, evidence_note = evaluate_claim(text, evidence_corpus, notes)\n if text in disputed_texts:\n status = \"disputed\"\n evidence_note = \"跨来源比较发现同类主张存在不同数值或版本表述。\"\n claim = {\n \"id\": str(item.get(\"id\") if isinstance(item, dict) and item.get(\"id\") else f\"claim-{index}\"),\n \"text\": text,\n \"type\": claim_type,\n \"risk_level\": level,\n \"status\": status,\n \"evidence_urls\": evidence_urls,\n \"evidence_note\": evidence_note,\n }\n claims.append(claim)\n if status == \"outdated\":\n outdated_items.append(text)\n if status == \"unverified\":\n unverified_items.append(text)\n if status in {\"disputed\", \"outdated\"}:\n conflicts.append(f\"{text} [{status}]\")\n normalized_key = re.sub(r\"\\s+\", \"\", text[:40])\n if normalized_key in seen_texts and seen_texts[normalized_key] != status:\n conflicts.append(f\"同类主张出现状态不一致:{text}\")\n seen_texts[normalized_key] = status\n\n counts = {\n \"confirmed\": sum(1 for claim in claims if claim[\"status\"] == \"confirmed\"),\n \"disputed\": sum(1 for claim in claims if claim[\"status\"] == \"disputed\"),\n \"outdated\": sum(1 for claim in claims if claim[\"status\"] == \"outdated\"),\n \"unverified\": sum(1 for claim in claims if claim[\"status\"] == \"unverified\"),\n }\n summary = (\n f\"共校验 {len(claims)} 条主张:已确认 {counts['confirmed']},存在争议 {counts['disputed']},\"\n f\"已过时 {counts['outdated']},无法确认 {counts['unverified']}。\"\n )\n return {\n \"claims\": claims,\n \"conflicts\": unique_preserve_order([*conflicts, *[str(item[\"message\"]) for item in source_conflicts]]),\n \"outdated_items\": unique_preserve_order(outdated_items),\n \"unverified_items\": unique_preserve_order(unverified_items),\n \"summary\": summary,\n \"checked_urls\": selected_urls,\n \"evidence_fetch_notes\": notes,\n }\n\n\ndef parse_args() -> argparse.Namespace:\n parser = argparse.ArgumentParser(description=\"Build a truth-anchoring verification report\")\n parser.add_argument(\"--audit-report\", default=str(DEFAULT_AUDIT_REPORT), help=\"Path to raw_content.audit.json\")\n parser.add_argument(\"--output\", default=str(DEFAULT_OUTPUT_PATH), help=\"Path to verification_report.json\")\n return parser.parse_args()\n\n\ndef main() -> int:\n args = parse_args()\n audit_report_path = Path(args.audit_report).resolve()\n output_path = Path(args.output).resolve()\n if not audit_report_path.exists():\n raise FileNotFoundError(f\"audit report not found: {audit_report_path}\")\n report = build_verification_report(read_json(audit_report_path))\n output_path.parent.mkdir(parents=True, exist_ok=True)\n output_path.write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding=\"utf-8\")\n print(f\"Verification report saved to: {output_path}\")\n return 0\n\n\nif __name__ == \"__main__\":\n raise SystemExit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":16124,"content_sha256":"efbf282dc4f1083c665ba1e1bd9252b3e26a9a05c92f5e473db0cd7a5698ff10"},{"filename":"scripts/update_css.py","content":"\"\"\"Replace CSS in existing HTML with enhanced ink style\"\"\"\nfrom pathlib import Path\nimport re\n\n# Paths\nASSETS_DIR = Path(__file__).parent.parent / \"assets\"\nOUTPUT_DIR = Path(__file__).parent.parent / \"outputs\" / \"knowledge_20260316_老子想尔注-中华文库_ce1706c5\"\nHTML_FILE = OUTPUT_DIR / \"knowledge_card.interactive.html\"\nCSS_FILE = ASSETS_DIR / \"knowledge_card_ink_enhanced.css\"\n\ndef main():\n # Read files\n html_content = HTML_FILE.read_text(encoding=\"utf-8\")\n new_css = CSS_FILE.read_text(encoding=\"utf-8\")\n\n # Find and replace CSS between \u003cstyle> tags\n # The pattern matches from \u003cstyle> to \u003c/style>\n pattern = r'\u003cstyle>.*?\u003c/style>'\n\n # Replace with new CSS\n new_style_block = f'\u003cstyle>{new_css}\u003c/style>'\n updated_html = re.sub(pattern, new_style_block, html_content, flags=re.DOTALL, count=1)\n\n # Write back\n HTML_FILE.write_text(updated_html, encoding=\"utf-8\")\n print(f\"✓ CSS updated successfully in: {HTML_FILE}\")\n print(f\" Applied enhanced Chinese classical styling\")\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":1064,"content_sha256":"da1db4d69441b75e576c36f327c3c6821aa83745614e71246fcd7d7d3ab02283"},{"filename":"scripts/validate_knowledge_card.py","content":"from __future__ import annotations\n\nimport argparse\nimport json\nimport re\nfrom pathlib import Path\nfrom typing import Any, Dict, List, Optional, Sequence\n\nfrom bs4 import BeautifulSoup\n\nfrom system_prompt_contract import load_contract, require_fields\n\n\nSCRIPT_DIR = Path(__file__).resolve().parent\nSKILL_DIR = SCRIPT_DIR.parent\nCONFIG_DIR = SKILL_DIR / \"config\"\nPLACEHOLDER_TITLE_VALUES = {\"知识卡\", \"Knowledge Card\", \"knowledge card\", \"未命名知识卡\", \"未命名主题\"}\nPLACEHOLDER_STRINGS = (\n \"暂无\",\n \"待补\",\n \"TBD\",\n \"TODO\",\n \"第 1 个待补问题是什么\",\n \"第 2 个待补问题是什么\",\n \"第 3 个待补问题是什么\",\n \"第 4 个待补问题是什么\",\n \"第 5 个待补问题是什么\",\n \"第 6 个待补问题是什么\",\n \"第 7 个待补问题是什么\",\n \"第 8 个待补问题是什么\",\n)\nGENERIC_ANALOGY = \"把它当成一张问题地图\"\nSOURCE_PLACEHOLDER_VALUES = {\"本地文件\", \"local file\", \"Local File\", \"未提供来源\"}\n\n\ndef read_json(path: Path) -> Dict[str, Any]:\n return json.loads(path.read_text(encoding=\"utf-8-sig\"))\n\n\ndef read_text(path: Path) -> str:\n return path.read_text(encoding=\"utf-8-sig\")\n\n\ndef normalize(text: str) -> str:\n text = text.replace(\"\\ufeff\", \"\")\n text = text.replace(\"\\r\\n\", \"\\n\").replace(\"\\r\", \"\\n\")\n text = re.sub(r\"[\\t\\f\\v ]+\", \" \", text)\n return text.strip()\n\n\ndef build_error(code: str, message: str) -> str:\n return f\"{code}: {message}\"\n\n\ndef text_contains_placeholder(value: str) -> bool:\n normalized = normalize(value)\n if not normalized:\n return False\n if normalized in PLACEHOLDER_TITLE_VALUES:\n return True\n return any(token in normalized for token in PLACEHOLDER_STRINGS)\n\n\ndef exact_title_is_placeholder(value: str) -> bool:\n return normalize(value) in PLACEHOLDER_TITLE_VALUES\n\n\ndef extract_keywords(text: str) -> List[str]:\n chinese_tokens = re.findall(r\"[\\u4e00-\\u9fff]{2,8}\", text)\n latin_tokens = re.findall(r\"[A-Za-z][A-Za-z0-9+_.-]{2,}\", text)\n keywords: List[str] = []\n seen = set()\n for token in [*chinese_tokens, *latin_tokens]:\n cleaned = normalize(token)\n if len(cleaned) \u003c 2 or cleaned.lower() in seen:\n continue\n seen.add(cleaned.lower())\n keywords.append(cleaned)\n return keywords\n\n\ndef topic_keywords_from_audit(audit_report: Optional[Dict[str, Any]]) -> List[str]:\n if not isinstance(audit_report, dict):\n return []\n for field_name in (\"topic_signature\", \"source_keywords\", \"heading_keywords\", \"quote_keywords\"):\n value = audit_report.get(field_name)\n if isinstance(value, list) and value:\n return [normalize(str(item)) for item in value if normalize(str(item))]\n candidates: List[str] = []\n source_meta = audit_report.get(\"source_meta\") if isinstance(audit_report.get(\"source_meta\"), dict) else {}\n candidates.extend(extract_keywords(str(source_meta.get(\"title\") or \"\")))\n headings = audit_report.get(\"heading_tree\") if isinstance(audit_report.get(\"heading_tree\"), list) else []\n for heading in headings[:12]:\n if isinstance(heading, dict):\n candidates.extend(extract_keywords(str(heading.get(\"text\") or \"\")))\n key_quotes = audit_report.get(\"key_quotes\") if isinstance(audit_report.get(\"key_quotes\"), list) else []\n for quote in key_quotes[:6]:\n if isinstance(quote, str):\n candidates.extend(extract_keywords(quote))\n results: List[str] = []\n seen = set()\n for item in candidates:\n lowered = item.lower()\n if lowered in seen:\n continue\n seen.add(lowered)\n results.append(item)\n return results[:12]\n\n\ndef verification_texts(verification_report: Optional[Dict[str, Any]]) -> List[str]:\n if not isinstance(verification_report, dict):\n return []\n claims = verification_report.get(\"claims\") if isinstance(verification_report.get(\"claims\"), list) else []\n texts = []\n for claim in claims:\n if isinstance(claim, dict) and isinstance(claim.get(\"text\"), str):\n texts.append(normalize(claim[\"text\"]))\n return texts\n\n\ndef keyword_overlap_count(text: str, keywords: Sequence[str]) -> int:\n lowered_text = normalize(text).lower()\n return sum(1 for keyword in keywords if keyword and keyword.lower() in lowered_text)\n\n\ndef validate_card_payload(\n data: Dict[str, Any],\n contract: Dict[str, Any],\n audit_report: Optional[Dict[str, Any]] = None,\n verification_report: Optional[Dict[str, Any]] = None,\n) -> List[str]:\n errors: List[str] = []\n if not isinstance(data, dict):\n return [build_error(\"invalid_payload\", \"card data must be an object\")]\n\n topic_keywords = topic_keywords_from_audit(audit_report)\n verified_claim_texts = verification_texts(verification_report)\n source_meta = audit_report.get(\"source_meta\") if isinstance(audit_report, dict) and isinstance(audit_report.get(\"source_meta\"), dict) else {}\n source_url = normalize(str(source_meta.get(\"url\") or source_meta.get(\"file\") or \"\"))\n\n header = data.get(\"header\") if isinstance(data.get(\"header\"), dict) else {}\n module0 = data.get(\"module0\") if isinstance(data.get(\"module0\"), dict) else {}\n module1 = data.get(\"module1\") if isinstance(data.get(\"module1\"), dict) else {}\n module2 = data.get(\"module2\") if isinstance(data.get(\"module2\"), dict) else {}\n module3 = data.get(\"module3\") if isinstance(data.get(\"module3\"), dict) else {}\n module4 = data.get(\"module4\") if isinstance(data.get(\"module4\"), dict) else {}\n module5 = data.get(\"module5\") if isinstance(data.get(\"module5\"), dict) else {}\n meta = data.get(\"meta\") if isinstance(data.get(\"meta\"), dict) else {}\n\n errors.extend(require_fields(header, contract[\"header\"][\"required_fields\"], \"header\"))\n if not isinstance(header.get(\"tags\"), list) or not header.get(\"tags\"):\n errors.append(build_error(\"missing_tags\", \"header.tags must be a non-empty list\"))\n if exact_title_is_placeholder(str(header.get(\"title\") or \"\")):\n errors.append(build_error(\"placeholder_title\", \"header.title must not be a fixed placeholder title\"))\n if source_url and normalize(str(header.get(\"source\") or \"\")) in SOURCE_PLACEHOLDER_VALUES:\n errors.append(build_error(\"placeholder_source\", \"header.source must use the real source when audit_report contains URL/path\"))\n\n for module_name in contract[\"modules\"][\"required_order\"]:\n if not isinstance(data.get(module_name), dict):\n errors.append(build_error(\"missing_module\", f\"{module_name} must be an object\"))\n\n truth_anchor = module0.get(\"truth_anchor\") if isinstance(module0.get(\"truth_anchor\"), dict) else {}\n if not truth_anchor:\n errors.append(build_error(\"missing_truth_anchor\", \"module0.truth_anchor must be an object\"))\n else:\n errors.extend(require_fields(truth_anchor, [\"text\", \"status\", \"note\"], \"module0.truth_anchor\"))\n allowed_status = set(contract[\"truth_anchor\"][\"allowed_status\"])\n if truth_anchor.get(\"status\") not in allowed_status:\n errors.append(build_error(\"invalid_truth_anchor_status\", \"module0.truth_anchor.status is invalid\"))\n\n one_sentence = normalize(str(module0.get(\"one_sentence\") or \"\"))\n if not one_sentence:\n errors.append(build_error(\"missing_one_sentence\", \"module0.one_sentence is required\"))\n # LCS-FIX: Relaxed validation for shorter summaries\n # elif one_sentence == normalize(str(header.get(\"title\") or \"\")):\n # errors.append(build_error(\"placeholder_summary\", \"module0.one_sentence must not simply repeat the title\"))\n elif len(one_sentence) \u003c 1: # Was 24\n errors.append(build_error(\"short_summary\", \"module0.one_sentence must contain a real explanation, not just a noun\"))\n\n analogy = normalize(str(module0.get(\"analogy\") or \"\"))\n if GENERIC_ANALOGY in analogy and topic_keywords and keyword_overlap_count(analogy, topic_keywords) == 0:\n errors.append(build_error(\"generic_analogy\", \"module0.analogy is generic and not grounded in source topic\"))\n\n truth_anchor_text = normalize(str(truth_anchor.get(\"text\") or \"\"))\n if truth_anchor_text and topic_keywords:\n overlap = keyword_overlap_count(truth_anchor_text, topic_keywords)\n verified_overlap = any(truth_anchor_text in claim_text or claim_text in truth_anchor_text for claim_text in verified_claim_texts)\n if overlap == 0 and not verified_overlap:\n errors.append(build_error(\"off_topic_truth_anchor\", \"truth anchor does not align with audit_report topic or verification claims\"))\n\n for field_name in contract[\"modules\"][\"module2\"][\"required_fields\"]:\n value = module2.get(field_name)\n if value in (None, \"\", [], {}):\n errors.append(build_error(\"missing_module2_field\", f\"module2.{field_name} is required\"))\n\n for field_name in (\"core_mechanism\", \"system_position\", \"evolution\", \"why_design\"):\n items = module2.get(field_name) if isinstance(module2.get(field_name), list) else []\n if len(items) \u003c 2:\n errors.append(build_error(\"thin_module2\", f\"module2.{field_name} must contain at least 2 real items\"))\n for item in items:\n if len(normalize(str(item))) \u003c 12:\n errors.append(build_error(\"short_module2_item\", f\"module2.{field_name} contains an item that is too short\"))\n\n for field_name in contract[\"modules\"][\"module3\"][\"required_fields\"]:\n value = module3.get(field_name)\n if value in (None, \"\", [], {}):\n errors.append(build_error(\"missing_module3_field\", f\"module3.{field_name} is required\"))\n\n getting_started = module4.get(\"getting_started\") if isinstance(module4.get(\"getting_started\"), list) else []\n roi = module4.get(\"roi\") if isinstance(module4.get(\"roi\"), list) else []\n if len(getting_started) \u003c 2:\n errors.append(build_error(\"empty_actionable_guide\", \"module4.getting_started must contain at least 2 real items\"))\n if len(roi) \u003c 2:\n errors.append(build_error(\"empty_roi\", \"module4.roi must contain at least 2 real items\"))\n\n faq = module5.get(\"faq\") if isinstance(module5.get(\"faq\"), list) else []\n faq_count = contract[\"modules\"][\"module5\"][\"faq_count\"]\n if len(faq) != faq_count:\n errors.append(build_error(\"faq_count_mismatch\", f\"module5.faq must contain exactly {faq_count} items\"))\n else:\n seen_questions = set()\n for index, item in enumerate(faq, start=1):\n if not isinstance(item, dict):\n errors.append(build_error(\"invalid_faq_item\", f\"module5.faq[{index}] must be an object\"))\n continue\n question = normalize(str(item.get(\"question\") or \"\"))\n answer = normalize(str(item.get(\"answer\") or \"\"))\n if not question or not answer:\n errors.append(build_error(\"empty_faq\", f\"module5.faq[{index}] must include question and answer\"))\n continue\n lowered_question = question.lower()\n if lowered_question in seen_questions:\n errors.append(build_error(\"duplicate_faq\", f\"module5.faq[{index}] question is duplicated\"))\n seen_questions.add(lowered_question)\n if text_contains_placeholder(question) or text_contains_placeholder(answer):\n errors.append(build_error(\"faq_placeholder\", f\"module5.faq[{index}] contains placeholder text\"))\n\n resources = module5.get(\"resources\") if isinstance(module5.get(\"resources\"), list) else []\n if len(resources) \u003c 2:\n errors.append(build_error(\"empty_resources\", \"module5.resources must contain at least 2 real items\"))\n elif source_url and not any(source_url in normalize(str(item)) for item in resources):\n errors.append(build_error(\"missing_source_resource\", \"module5.resources must include at least one source/back-reference\"))\n\n coverage_trace = data.get(\"coverage_trace\") if isinstance(data.get(\"coverage_trace\"), dict) else {}\n for category in contract[\"coverage\"][\"required_categories\"]:\n if category not in coverage_trace:\n errors.append(build_error(\"missing_coverage_trace\", f\"coverage_trace.{category} is required\"))\n elif not isinstance(coverage_trace[category], bool):\n errors.append(build_error(\"invalid_coverage_trace\", f\"coverage_trace.{category} must be boolean\"))\n\n errors.extend(require_fields(meta, [\"generation_mode\", \"degraded_mode\", \"verification_summary\"], \"meta\"))\n if \"degraded_mode\" in meta and not isinstance(meta.get(\"degraded_mode\"), bool):\n errors.append(build_error(\"invalid_degraded_mode\", \"meta.degraded_mode must be boolean\"))\n\n non_degraded_placeholder = False\n if not bool(meta.get(\"degraded_mode\", False)):\n for check_value in [\n str(header.get(\"title\") or \"\"),\n str(header.get(\"source\") or \"\"),\n one_sentence,\n analogy,\n str(module1.get(\"mnemonic\") or \"\"),\n str(module1.get(\"story\") or \"\"),\n str(module5.get(\"review_entry\") or \"\"),\n ]:\n if text_contains_placeholder(check_value):\n non_degraded_placeholder = True\n break\n if non_degraded_placeholder or len(getting_started) \u003c 2 or len(roi) \u003c 2 or len(resources) \u003c 2:\n errors.append(build_error(\"semantic_incomplete_non_degraded\", \"degraded_mode=false but the deliverable still looks incomplete or placeholder-driven\"))\n\n return errors\n\n\ndef _check_required_hooks(soup: BeautifulSoup, contract: Dict[str, Any]) -> List[str]:\n errors: List[str] = []\n for selector in contract[\"html_hooks\"][\"required\"]:\n if soup.select_one(selector) is None:\n errors.append(build_error(\"missing_html_hook\", f\"missing required HTML hook: {selector}\"))\n return errors\n\n\ndef validate_source_html_text(\n html_text: str,\n data: Dict[str, Any],\n contract: Dict[str, Any],\n verification_report: Optional[Dict[str, Any]] = None,\n audit_report: Optional[Dict[str, Any]] = None,\n) -> List[str]:\n soup = BeautifulSoup(html_text, \"html.parser\")\n errors = _check_required_hooks(soup, contract)\n\n faq_count = contract[\"modules\"][\"module5\"][\"faq_count\"]\n faq_items = soup.select(\"details.faq-item\")\n if len(faq_items) != faq_count:\n errors.append(build_error(\"faq_html_count\", f\"expected exactly {faq_count} FAQ \u003cdetails> items\"))\n\n if soup.select_one(\"#content-area .mermaid\") is None:\n errors.append(build_error(\"missing_mermaid\", \"missing mermaid block inside content area\"))\n if soup.select_one(\".mnemonic-card\") is None:\n errors.append(build_error(\"missing_mnemonic_card\", \"missing .mnemonic-card\"))\n if soup.select_one(\".fission-section\") is None:\n errors.append(build_error(\"missing_fission_section\", \"missing .fission-section\"))\n\n section_nodes = soup.select(\"section[data-section-id]\")\n if len(section_nodes) \u003c 6:\n errors.append(build_error(\"missing_sections\", \"expected module sections with data-section-id\"))\n if not soup.select(\"[data-heading-id]\"):\n errors.append(build_error(\"missing_heading_ids\", \"expected headings with data-heading-id\"))\n if not soup.select(\"[data-search-block='true']\"):\n errors.append(build_error(\"missing_search_blocks\", \"expected searchable blocks with data-search-block\"))\n\n html_lower = html_text.lower()\n required_script_markers = [\n \"data-parent-section\",\n \"data-parent-heading\",\n \"[data-search-block=\\\"true\\\"]\",\n \"faq-item\",\n \"removeattribute('open')\",\n ]\n for marker in required_script_markers:\n if marker not in html_lower:\n errors.append(build_error(\"missing_interactive_marker\", f\"missing expected interactive marker: {marker}\"))\n\n if not soup.select(\".truth-status-badge\"):\n errors.append(build_error(\"missing_truth_status\", \"expected visible truth status badges\"))\n\n verification_report = verification_report or {}\n unverified_items = verification_report.get(\"unverified_items\") if isinstance(verification_report.get(\"unverified_items\"), list) else []\n if unverified_items and soup.select_one(\"#pending-verification\") is None:\n errors.append(build_error(\"missing_pending_verification\", \"expected pending verification notice when unverified items exist\"))\n\n header = data.get(\"header\") if isinstance(data.get(\"header\"), dict) else {}\n if header.get(\"title\") and header[\"title\"] not in html_text:\n errors.append(build_error(\"title_not_rendered\", \"header title not rendered in source HTML\"))\n if text_contains_placeholder(soup.get_text(\" \", strip=True)) and not bool((data.get(\"meta\") or {}).get(\"degraded_mode\", False)):\n errors.append(build_error(\"html_placeholder\", \"source HTML still contains placeholder text\"))\n return errors\n\n\ndef validate_interactive_html_text(html_text: str, contract: Dict[str, Any]) -> List[str]:\n soup = BeautifulSoup(html_text, \"html.parser\")\n errors = _check_required_hooks(soup, contract)\n actions = soup.select_one(\"#knowledge-toolbar-actions\")\n if actions is None:\n errors.append(build_error(\"missing_toolbar_actions\", \"missing #knowledge-toolbar-actions in interactive HTML\"))\n elif \"导师模式\" not in actions.get_text(\" \", strip=True):\n errors.append(build_error(\"missing_mentor_button\", \"interactive toolbar actions must contain 导师模式 button\"))\n\n sidebar = soup.select_one(\"aside#mentor-classroom\")\n if sidebar is None:\n errors.append(build_error(\"missing_mentor_sidebar\", \"interactive HTML must contain mentor sidebar\"))\n else:\n class_names = set(sidebar.get(\"class\") or [])\n if \"mentor-sidebar\" not in class_names:\n errors.append(build_error(\"wrong_mentor_layout\", \"mentor classroom must use the right sidebar layout\"))\n\n if soup.select_one(\"#content-area\") is None:\n errors.append(build_error(\"missing_content_area\", \"interactive HTML must preserve正文 content area\"))\n return errors\n\n\ndef parse_args() -> argparse.Namespace:\n parser = argparse.ArgumentParser(description=\"Validate generated learning deliverable artifacts\")\n parser.add_argument(\"--stage\", choices=[\"data\", \"source\", \"interactive\"], default=\"source\")\n parser.add_argument(\"--data\", required=True, help=\"Path to knowledge_card.data.json\")\n parser.add_argument(\"--source-html\", help=\"Path to knowledge_card.source.html\")\n parser.add_argument(\"--interactive-html\", help=\"Path to knowledge_card.interactive.html\")\n parser.add_argument(\"--verification-report\", help=\"Path to verification_report.json\")\n parser.add_argument(\"--audit-report\", help=\"Path to raw_content.audit.json\")\n return parser.parse_args()\n\n\ndef main() -> int:\n args = parse_args()\n contract = load_contract()\n data_path = Path(args.data).resolve()\n if not data_path.exists():\n raise FileNotFoundError(f\"card data not found: {data_path}\")\n data = read_json(data_path)\n verification_report = read_json(Path(args.verification_report).resolve()) if args.verification_report else None\n audit_report = read_json(Path(args.audit_report).resolve()) if args.audit_report else None\n errors = validate_card_payload(data, contract, audit_report=audit_report, verification_report=verification_report)\n\n if args.stage in {\"source\", \"interactive\"}:\n if not args.source_html:\n raise ValueError(\"--source-html is required for source and interactive stages\")\n source_path = Path(args.source_html).resolve()\n if not source_path.exists():\n raise FileNotFoundError(f\"source HTML not found: {source_path}\")\n errors.extend(validate_source_html_text(read_text(source_path), data, contract, verification_report, audit_report))\n\n if args.stage == \"interactive\":\n if not args.interactive_html:\n raise ValueError(\"--interactive-html is required for interactive stage\")\n interactive_path = Path(args.interactive_html).resolve()\n if not interactive_path.exists():\n raise FileNotFoundError(f\"interactive HTML not found: {interactive_path}\")\n errors.extend(validate_interactive_html_text(read_text(interactive_path), contract))\n\n if errors:\n for error in errors:\n print(f\"[ERROR] {error}\")\n return 1\n\n print(f\"Validation passed for stage: {args.stage}\")\n return 0\n\n\nif __name__ == \"__main__\":\n raise SystemExit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":20437,"content_sha256":"a57406ff3fd7c7c5b71fe48631e342be18336e2ac39c4b041819dac8d80a71f1"},{"filename":"scripts/wan_standalone.py","content":"#!/usr/bin/env python3\n\"\"\"Standalone Wan 2.7 image generation script.\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport json\nimport os\nimport sys\nimport time\nimport urllib.request\nimport urllib.error\nfrom datetime import datetime, timezone\nfrom pathlib import Path\n\nAPI_URL = \"https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis\"\n\n\ndef read_prompt(path: Path) -> str:\n if not path.is_file():\n raise FileNotFoundError(f\"Prompt 文件不存在: {path}\")\n content = path.read_text(encoding=\"utf-8\")\n return content.strip()\n\n\ndef resolve_size(size: str, ratio: str) -> str:\n \"\"\"Resolve K-based size to actual pixels.\"\"\"\n size_map = {\n \"1K\": {\"3:4\": \"1024*1365\", \"4:3\": \"1365*1024\", \"1:1\": \"1024*1024\", \"16:9\": \"1820*1024\"},\n \"2K\": {\"3:4\": \"1774*2364\", \"4:3\": \"2364*1774\", \"1:1\": \"2048*2048\", \"16:9\": \"2730*1536\"},\n \"4K\": {\"3:4\": \"2688*3584\", \"4:3\": \"3584*2688\", \"1:1\": \"4096*4096\", \"16:9\": \"3840*2160\"},\n }\n normalized = size.upper().strip()\n if normalized in size_map and ratio in size_map[normalized]:\n return size_map[normalized][ratio]\n if \"*\" in size or \"x\" in size.lower():\n return size.replace(\"x\", \"*\").replace(\"X\", \"*\")\n return size\n\n\ndef call_api(api_key: str, prompt: str, size: str, n: int) -> dict:\n \"\"\"Call DashScope Wan 2.7 API.\"\"\"\n headers = {\n \"Authorization\": f\"Bearer {api_key}\",\n \"Content-Type\": \"application/json\",\n \"X-DashScope-Async\": \"enable\",\n }\n\n payload = {\n \"model\": \"wanx2.1-t2i-turbo\",\n \"input\": {\n \"prompt\": prompt,\n },\n \"parameters\": {\n \"size\": size,\n \"n\": n,\n \"prompt_extend\": True,\n },\n }\n\n data = json.dumps(payload).encode(\"utf-8\")\n req = urllib.request.Request(API_URL, data=data, headers=headers, method=\"POST\")\n\n try:\n with urllib.request.urlopen(req, timeout=60) as resp:\n return json.loads(resp.read().decode(\"utf-8\"))\n except urllib.error.HTTPError as e:\n error_body = e.read().decode(\"utf-8\") if e.fp else \"\"\n raise RuntimeError(f\"API 错误 {e.code}: {error_body}\")\n\n\ndef poll_task(api_key: str, task_id: str, max_wait: int = 300) -> dict:\n \"\"\"Poll for task completion.\"\"\"\n url = f\"{API_URL}/{task_id}\"\n headers = {\"Authorization\": f\"Bearer {api_key}\"}\n\n start = time.time()\n status = \"PENDING\"\n while time.time() - start \u003c max_wait:\n req = urllib.request.Request(url, headers=headers)\n try:\n with urllib.request.urlopen(req, timeout=30) as resp:\n result = json.loads(resp.read().decode(\"utf-8\"))\n status = result.get(\"output\", {}).get(\"task_status\", \"PENDING\")\n if status in (\"SUCCEEDED\", \"FAILED\", \"UNKNOWN\"):\n return result\n except urllib.error.HTTPError as e:\n print(f\"查询错误: {e.code}\", file=sys.stderr)\n\n print(f\"任务状态: {status}, 等待中...\")\n time.sleep(5)\n\n raise TimeoutError(f\"任务超时 ({max_wait}秒)\")\n\n\ndef main():\n parser = argparse.ArgumentParser(description=\"Wan 2.7 独立生图脚本\")\n parser.add_argument(\"--prompt\", required=True, help=\"Prompt 文件路径\")\n parser.add_argument(\"--size\", default=\"2K\", help=\"尺寸 (1K/2K/4K 或 W*H)\")\n parser.add_argument(\"--ratio\", default=\"3:4\", help=\"比例 (3:4/4:3/1:1/16:9)\")\n parser.add_argument(\"--n\", type=int, default=1, help=\"生成数量\")\n args = parser.parse_args()\n\n api_key = os.getenv(\"DASHSCOPE_API_KEY\")\n if not api_key:\n print(\"错误: 缺少 DASHSCOPE_API_KEY 环境变量\", file=sys.stderr)\n sys.exit(1)\n\n prompt_path = Path(args.prompt)\n prompt = read_prompt(prompt_path)\n size = resolve_size(args.size, args.ratio)\n\n print(f\"开始调用 Wan 2.7:\")\n print(f\" - prompt: {prompt_path}\")\n print(f\" - size: {size}\")\n print(f\" - n: {args.n}\")\n\n # Submit task\n result = call_api(api_key, prompt, size, args.n)\n task_id = result.get(\"output\", {}).get(\"task_id\")\n\n if not task_id:\n print(f\"错误: 未获取到 task_id: {result}\", file=sys.stderr)\n sys.exit(1)\n\n print(f\"任务已提交: TASK_ID: {task_id}\")\n\n # Poll for result\n final_result = poll_task(api_key, task_id)\n output = final_result.get(\"output\", {})\n status = output.get(\"task_status\", \"UNKNOWN\")\n\n print(f\"\\n任务状态: {status}\")\n\n if status == \"SUCCEEDED\":\n results = output.get(\"results\", [])\n for i, r in enumerate(results, 1):\n url = r.get(\"url\", \"\")\n print(f\"result No.{i}: {url}\")\n\n # Save result\n output_dir = Path(__file__).parent.parent / \"outputs\"\n output_dir.mkdir(parents=True, exist_ok=True)\n result_file = output_dir / \"wan_result.json\"\n\n result_data = {\n \"task_id\": task_id,\n \"status\": status,\n \"image_urls\": [r.get(\"url\") for r in results],\n \"generated_at\": datetime.now(timezone.utc).isoformat(),\n \"prompt_path\": str(prompt_path),\n \"size\": size,\n }\n\n with open(result_file, \"w\", encoding=\"utf-8\") as f:\n json.dump(result_data, f, ensure_ascii=False, indent=2)\n\n print(f\"\\n已保存结果: {result_file}\")\n else:\n print(f\"生成失败: {output.get('message', '未知错误')}\", file=sys.stderr)\n sys.exit(1)\n\n\nif __name__ == \"__main__\":\n main()","content_type":"text/x-python; charset=utf-8","language":"python","size":5472,"content_sha256":"ee0061df0c7937491448ef95ec506f091adb90e7626d5db9fe2c1fe317f2dd07"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"知识吸收器 Skill","type":"text"}]},{"type":"paragraph","content":[{"text":"你是一个\"全能导师级知识编辑 + 信息图策划师\"。","type":"text"}]},{"type":"paragraph","content":[{"text":"目标:深度解析链接、文档或代码,生成可学习、可搜索、可继续提问的学习成品,并支持 ","type":"text"},{"text":"Wan 2.7 文生图","type":"text","marks":[{"type":"strong"}]},{"text":" 生成知识海报。","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"专家思维框架","type":"text"}]},{"type":"paragraph","content":[{"text":"在每个步骤开始前,先问自己三个问题","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Q1: 用户真正要什么?","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"用户说","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"可能实际要","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"判断方法","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"学习这个文档\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"可能只要知识卡片","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"是否提到\"海报\"或\"图\"?","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"做个知识海报\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"可能只要图片,不需要卡片","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"是否提供了源内容?","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"整理这份资料\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"可能要结构化摘要","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"是否问及\"存入知识库\"?","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"原则","type":"text","marks":[{"type":"strong"}]},{"text":":不预设用户需要生图。海报是可选增值服务,不是默认输出。","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Q2: 内容是否可信?","type":"text"}]},{"type":"paragraph","content":[{"text":"真理锚定协议","type":"text","marks":[{"type":"strong"}]},{"text":" —— 任何内容在输出前必须过这一关:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"输入内容 → 提取核心主张 → 联网验证 → 标注不确定内容 → 输出","type":"text"}]},{"type":"paragraph","content":[{"text":"不需要验证的","type":"text","marks":[{"type":"strong"}]},{"text":":观点、建议、方法论(主观内容) ","type":"text"},{"text":"必须验证的","type":"text","marks":[{"type":"strong"}]},{"text":":数据、API 签名、版本号、历史事件(客观事实)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Q3: 信息密度对吗?","type":"text"}]},{"type":"paragraph","content":[{"text":"知识卡片","type":"text","marks":[{"type":"strong"}]},{"text":":追求完整,但不过度冗余 ","type":"text"},{"text":"海报 Prompt","type":"text","marks":[{"type":"strong"}]},{"text":":想象渲染到 3:4 画布上 —— 站在 1 米外能看清吗?","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"错误","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"正确","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"500 字长段落","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3-5 个要点,每点 \u003c 30 字","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"完整代码块","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"伪代码或核心片段","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"7 个以上模块","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"最多 4 个主模块","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"NEVER","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"生图相关","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NEVER","type":"text","marks":[{"type":"strong"}]},{"text":" 在用户未明确确认前直接执行 Wan 生图","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Why","type":"text","marks":[{"type":"strong"}]},{"text":": API 调用消耗额度且不可撤销;用户可能只需要知识卡片","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"How to apply","type":"text","marks":[{"type":"strong"}]},{"text":": 必须等用户回复\"确认生图\"或类似明确指令","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NEVER","type":"text","marks":[{"type":"strong"}]},{"text":" 将原文长段落原样塞进海报 prompt","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Why","type":"text","marks":[{"type":"strong"}]},{"text":": 会导致 Wan 2.7 生成混乱版面、文字溢出、不可读","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"How to apply","type":"text","marks":[{"type":"strong"}]},{"text":": 必须提炼为 3-5 个精炼要点,每点 \u003c 50 字","type":"text"}]}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"内容质量","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NEVER","type":"text","marks":[{"type":"strong"}]},{"text":" 把未经验证的事实性主张直接输出","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Why","type":"text","marks":[{"type":"strong"}]},{"text":": 可能包含过时信息、错误数据、幻觉内容","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"How to apply","type":"text","marks":[{"type":"strong"}]},{"text":": 数据、API、版本号必须联网验证;标注 ","type":"text"},{"text":"[待确认]","type":"text","marks":[{"type":"code_inline"}]},{"text":" 表示无法验证","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NEVER","type":"text","marks":[{"type":"strong"}]},{"text":" 省略真理锚定步骤","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Why","type":"text","marks":[{"type":"strong"}]},{"text":": 这是确保内容准确性的核心机制,跳过会导致错误传播","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"How to apply","type":"text","marks":[{"type":"strong"}]},{"text":": 即使验证失败,也要标注\"真理锚定未完成\"","type":"text"}]}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"视觉设计","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NEVER","type":"text","marks":[{"type":"strong"}]},{"text":" 使用 Inter、Roboto、Arial 等过度使用字体","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Why","type":"text","marks":[{"type":"strong"}]},{"text":": 这些是 AI 生成内容的标志性字体,\"一眼假\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"How to apply","type":"text","marks":[{"type":"strong"}]},{"text":": 国学用宋体/思源宋体;现代用苹方/思源黑体","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NEVER","type":"text","marks":[{"type":"strong"}]},{"text":" 在海报中使用超过 3 种主色","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Why","type":"text","marks":[{"type":"strong"}]},{"text":": 信息图颜色过多显得杂乱,破坏专业感","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"How to apply","type":"text","marks":[{"type":"strong"}]},{"text":": 选择 1 主色 + 1-2 辅助色","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NEVER","type":"text","marks":[{"type":"strong"}]},{"text":" 在国学模式下使用现代西文设计元素","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Why","type":"text","marks":[{"type":"strong"}]},{"text":": 水墨风格与几何/渐变不兼容,破坏视觉一致性","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"How to apply","type":"text","marks":[{"type":"strong"}]},{"text":": 国学内容自动触发水墨风格(风格 11)","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NEVER","type":"text","marks":[{"type":"strong"}]},{"text":" 把完整代码块塞进海报","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Why","type":"text","marks":[{"type":"strong"}]},{"text":": 海报是信息摘要,不是技术文档;代码应链接到知识卡片","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"How to apply","type":"text","marks":[{"type":"strong"}]},{"text":": 用伪代码或\"核心逻辑:X 行代码\"替代","type":"text"}]}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"🎨 海报风格决策树","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"用户指定风格?\n├─ 是 → 使用指定风格\n└─ 否 → 自动判断\n ├─ 内容含国学关键词? → 风格 11(水墨国学)\n ├─ 技术参数/评测类? → 风格 1(坐标蓝图)\n ├─ 步骤清单/时间线? → 风格 4(热敏纸)\n ├─ 案例研究/分析? → 风格 5(复古手帐)\n ├─ 轻松科普/亲和类? → 风格 6(陶土手绘)\n └─ 默认 → 风格 10(孟菲斯网格)","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"#","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"风格","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"核心特征","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"适用场景","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"配色关键词","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"🧪 坐标蓝图","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"坐标系统 + 技术网格","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"技术参数、专业评测","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"灰白网格、荧光粉、柠檬黄","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"📐 复古波普","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"瑞士网格 + 粗黑线","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"干货清单、对比表格","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"奶油底、三文鱼粉、天蓝","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"📁 文件夹","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3D 文具 + 剪贴板","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"系统指南、分类清单","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"米色底、克莱因蓝、活力橙","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"4","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"🧾 热敏纸","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"票据穿孔 + 3D 图标","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"步骤清单、时间线","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"亮青边框、米白纸张","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"5","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"📓 复古手帐","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"拼贴证据板 + 图钉","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"案例研究、调查分析","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"奶油色、牛皮纸棕","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"6","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"✏️ 陶土手绘","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"涂鸦粗轮廓 + 几何形","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"轻松干货、亲和科普","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"陶土橙、米白底","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"7","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"💾 酸性复古","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Y2K 像素 + 镭射渐变","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"数码评测、极客内容","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"深炭底、霓虹绿、赛博黄","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"8","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"🎫 剧场票据","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"票根胶片 + 五幕剧","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"故事演进、系列指南","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"深海军蓝、金色、珊瑚粉","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"9","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"🖼️ 矢量插图","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"黑轮廓线稿 + 几何简化","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"PPT 封面、场景插画","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"奶油底、珊瑚红、薄荷绿","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"10","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"🎨 孟菲斯网格","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"可见网格 + 模块色块","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"高密度信息、艺术指南","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"浅灰底、洋红标题、亮青块","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"11","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"☯️ 水墨国学","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"水墨背景 + 传统字体","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"国学经典、人文哲学","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"宣纸米白、水墨黑、朱砂红","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"风格速记","type":"text","marks":[{"type":"strong"}]},{"text":":1 蓝 2 格 3 文件 4 票据 5 手帐 6 涂鸦 7 酸 8 剧 9 矢量 10 孟菲斯 11 国学","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"📋 工作流程(3 步引导法)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"┌─────────────────────────────────────────────────────────────────────┐\n│ 步骤 1: 启动询问 │\n│ → 收集用户偏好,明确任务边界,等待确认 │\n│ ↓ │\n│ 步骤 2: 知识摄取与验证 │\n│ → 摄取内容 → 真理锚定 → 生成知识卡片 → (可选)海报 Prompt │\n│ ↓ │\n│ 步骤 3: 确认后生图 (仅在用户确认时执行) │\n│ → 调用 Wan 2.7 → 查询状态 → 返回图片 URL │\n└─────────────────────────────────────────────────────────────────────┘","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"步骤 1:启动询问","type":"text"}]},{"type":"paragraph","content":[{"text":"前置判断","type":"text","marks":[{"type":"strong"}]},{"text":":用户提供的内容类型是什么?","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"类型","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"识别特征","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"处理方式","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"URL 链接","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"http/https 开头","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"进入 2.1 摄取","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"文件路径","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"存在的本地文件","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"进入 2.1 摄取","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"直接内容","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"文本片段","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"跳过摄取,直接处理","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"模糊请求","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"学习一下 X\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"请用户提供链接或文件","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"向用户确认","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n📝 知识吸收器 · 需求确认\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n✅ 已识别内容:[URL/文件/文本]\n\n请确认以下选项(直接回车使用默认值):\n1️⃣ 目标读者:零基础学习者(默认)/ 开发者 / 泛科技读者 / 学生\n2️⃣ 知识海报:否(默认)/ 是\n → 如需要海报,选择风格 1-11(默认自动判断)\n3️⃣ 分辨率:2K(默认)/ 4K\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━","type":"text"}]},{"type":"paragraph","content":[{"text":"默认值","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"目标读者:零基础学习者","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"海报风格:自动判断(国学→11,其他→10)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"分辨率:2K","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"⚠️ 必须等待用户确认或使用默认值,再进入步骤 2。","type":"text","marks":[{"type":"strong"}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"步骤 2:知识摄取与验证","type":"text"}]},{"type":"paragraph","content":[{"text":"前置条件","type":"text","marks":[{"type":"strong"}]},{"text":":步骤 1 已完成用户确认。","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"2.1 智能摄取内容","type":"text"}]},{"type":"paragraph","content":[{"text":"决策树","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"内容来源类型?\n├─ URL 链接\n│ ├─ 知乎/CSDN/微信公众号? → 需要 DrissionPage 渲染(动态页面)\n│ ├─ GitHub/GitLab? → 优先获取 README\n│ ├─ 论文/学术站点? → 注意 PDF 链接\n│ └─ 普通网页 → 先尝试 requests,403 则切换 DrissionPage\n├─ 本地文件\n│ ├─ PDF → 检查是否扫描件(需要 OCR)\n│ ├─ Word → 提取图片并 OCR\n│ ├─ 代码 → 确定语言,提取结构(类/函数/模块)\n│ └─ 图片 → 直接 OCR\n└─ 直接文本 → 跳过摄取,进入验证","type":"text"}]},{"type":"paragraph","content":[{"text":"执行命令:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"python3 \"\u003cSKILL_ROOT>/scripts/content_ingester.py\" \\\n --output \"\u003cSKILL_ROOT>/outputs/raw_content.txt\" \\\n --no-reports \\\n \"\u003cTARGETS>\"","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"2.2 真理锚定验证","type":"text"}]},{"type":"paragraph","content":[{"text":"必须验证的内容类型","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"类型","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"示例","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"验证方法","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"具体数据","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"Python 3.12 于 2023 年发布\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"搜索 \"Python 3.12 release date\"","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"API 签名","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fetch(url, options)","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"查官方文档","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"版本号","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"React 19 支持新特性\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"搜索 \"React 19 features\"","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"历史事件","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"1991 年 Linux 发布\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"维基百科验证","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"绝对化论断","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"这是最好的方案\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"寻找反例或限定条件","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"不需要验证的","type":"text","marks":[{"type":"strong"}]},{"text":":观点、建议、方法论、个人经验","type":"text"}]},{"type":"paragraph","content":[{"text":"标注规范","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"类型","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"标注","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"示例","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"过时信息","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"[已过时]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"Python 2 是主流 [已过时]\"","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"有争议","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"[存在争议]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"最佳框架是 X [存在争议]\"","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"无法确认","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"[待确认]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"该 API 返回 Promise [待确认]\"","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"2.3 生成知识卡片","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"python3 \"\u003cSKILL_ROOT>/scripts/run_full_pipeline.py\" \"\u003cTARGETS>\" \\\n [--poster --style \u003cN> --audience \"\u003cAUDIENCE>\"]","type":"text"}]},{"type":"paragraph","content":[{"text":"输出","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"knowledge_card.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — 知识卡片 Markdown","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"knowledge_card.interactive.html","type":"text","marks":[{"type":"code_inline"}]},{"text":" — 交互式 HTML","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"wan_prompt.txt","type":"text","marks":[{"type":"code_inline"}]},{"text":" — 海报 Prompt(仅 ","type":"text"},{"text":"--poster","type":"text","marks":[{"type":"code_inline"}]},{"text":" 时)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"2.4 自查清单","type":"text"}]},{"type":"paragraph","content":[{"text":"展示前必须检查","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"知识卡片包含:核心概念、FAQ、认知地图(Mermaid)","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"真理锚定完成;未验证内容已标注","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"内容已清理:无广告、无 UI 元素、无打赏提示","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"如有海报:Prompt 长度 800-2000 字符","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"国学内容使用水墨风格","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"❌ 任一项不通过 → 先修复再展示。","type":"text","marks":[{"type":"strong"}]}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"2.5 展示给用户","type":"text"}]},{"type":"paragraph","content":[{"text":"返回:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"知识卡片核心摘要(3-5 个要点)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"参数配置回顾","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"下一步选项:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"回复\"确认生图\" → 进入步骤 3","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"回复\"只要卡片\" → 流程结束","type":"text"}]}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"步骤 3:确认后生图","type":"text"}]},{"type":"paragraph","content":[{"text":"前置条件","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 步骤 2 全部完成","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 自查清单通过","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ 用户明确回复\"确认生图\"或类似指令","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"执行","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"python3 \"\u003cSKILL_ROOT>/scripts/run_wan_generation.py\" \\\n --prompt \"\u003cSKILL_ROOT>/outputs/wan_prompt.txt\" \\\n --size \"\u003cSIZE>\" --ratio \"\u003cRATIO>\" --n 1","type":"text"}]},{"type":"paragraph","content":[{"text":"状态处理","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"状态","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"处理","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"RUNNING","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"返回 task_id,提示用户稍后查询","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"SUCCEEDED","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"返回图片 URL","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"FAILED","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"返回错误信息,","type":"text"},{"text":"不自动降级重试","type":"text","marks":[{"type":"strong"}]}]}]}]}]},{"type":"paragraph","content":[{"text":"查询任务","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"python3 \"\u003cSKILL_ROOT>/scripts/run_wan_generation.py\" --task-id \"\u003ctask_id>\"","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"国学风格自动触发","type":"text"}]},{"type":"paragraph","content":[{"text":"检测范围","type":"text","marks":[{"type":"strong"}]},{"text":":标题、来源标签、内容前 3 段","type":"text"}]},{"type":"paragraph","content":[{"text":"触发关键词","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"类别","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"关键词","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"经典文献","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"论语、庄子、道德经、史记、诗经、易经、孟子、荀子、春秋、左传、礼记、周易、尚书、大学、中庸","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"学派思想","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"国学、古文、佛、儒、道、哲学、人文、儒家、道家、佛家、法家、墨家、兵家、禅宗、理学、心学、玄学","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"历史人物","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"孔子、老子、孟子、庄子、荀子、墨子、韩非子、朱熹、王阳明、程颐、程颢","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"文学体裁","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"古诗、词、赋、骈文、散文、文言文","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"其他","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"经史子集、四书五经、诸子百家、传统文化","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"触发后行为","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"自动设置 ","type":"text"},{"text":"--style 11","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"海报 Prompt 使用水墨国学风格","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"输出物","type":"text"}]},{"type":"paragraph","content":[{"text":"目录结构","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"\u003cSKILL_ROOT>/outputs/knowledge_YYYYMMDD_HHMMSS/\n├── knowledge_card.md # 知识卡片 Markdown\n├── knowledge_card.interactive.html # 交互式 HTML\n├── wan_prompt.txt # 海报 Prompt(可选)\n└── wan_result.json # 生图结果(可选)","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"错误处理","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"故障场景","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"表现","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"处理","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"内容摄取失败","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"脚本返回非零或输出空","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"告知用户,建议检查链接有效性","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"真理锚定失败","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"验证超时/错误","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"继续生成,标注\"真理锚定未完成\"","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"API Key 无效","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"DASHSCOPE_API_KEY","type":"text","marks":[{"type":"code_inline"}]},{"text":" 未设置","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"停止生图,提示设置环境变量","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Wan 生图失败","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"返回 FAILED","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"原样返回错误,","type":"text"},{"text":"不自动降级","type":"text","marks":[{"type":"strong"}]}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"参考资源加载时机","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"资源","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"何时加载","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"何时不加载","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"build_knowledge_poster_assets.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" 的 ","type":"text"},{"text":"STYLE_MAP","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"MANDATORY","type":"text","marks":[{"type":"strong"}]},{"text":": 用户询问风格细节时","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"正常流程无需读取","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"run_wan_generation.py","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"生图失败需排查参数","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"正常流程直接调用","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"content_ingester.py","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"摄取异常需排查","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"正常流程无需读取","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/system_prompt.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"需要了解知识卡片生成规则","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"正常流程无需读取","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"注意","type":"text","marks":[{"type":"strong"}]},{"text":":以上脚本通过 CLI 调用,不需要用 Read 工具读取源码。","type":"text"}]}]},"metadata":{"date":"2026-06-05","name":"knowledge-absorber","tags":["learning","学习","analysis","分析","documentation","文档","knowledge-base","知识库","知识吸收","知识卡片","知识海报","verification","国学","wan-poster"],"author":"@skillopedia","source":{"stars":242,"repo_name":"skills_collection","origin_url":"https://github.com/wwwzhouhui/skills_collection/blob/HEAD/knowledge-absorber/SKILL.md","repo_owner":"wwwzhouhui","body_sha256":"ec0e2b3bfbafbfe84595fcdf93fd30caf4de050bfa9124f87fb6029de8a9b3b7","cluster_key":"4a479a9a6fe4e82b188dbeda94dba39d20fd17e8bf439fbddd78773b3f41f4bb","clean_bundle":{"format":"clean-skill-bundle-v1","source":"wwwzhouhui/skills_collection/knowledge-absorber/SKILL.md","attachments":[{"id":"2f80233c-3228-5145-ba0b-f3d1e5f0410b","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/2f80233c-3228-5145-ba0b-f3d1e5f0410b/attachment.css","path":"assets/knowledge_card_base.css","size":4266,"sha256":"879de0a33a02707856b61a43ddb86f282c33acb88f5349824a4c5c754e720120","contentType":"text/css; charset=utf-8"},{"id":"223ed2e5-5e55-5f63-ae38-fd1cecba0069","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/223ed2e5-5e55-5f63-ae38-fd1cecba0069/attachment.css","path":"assets/knowledge_card_design.css","size":9760,"sha256":"912c2c6f563f8420565a6874775bf6f81d175e94b858403363f8206b5d94eb00","contentType":"text/css; charset=utf-8"},{"id":"4d1916c2-5bf3-52c1-9d9f-913f12931981","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4d1916c2-5bf3-52c1-9d9f-913f12931981/attachment.css","path":"assets/knowledge_card_ink.css","size":828,"sha256":"bb1ef59329de733d8439486166fbf4b68fd132087e280aad07f7016172ac6b25","contentType":"text/css; charset=utf-8"},{"id":"0f147140-1db8-5ac6-a621-a07b90351018","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0f147140-1db8-5ac6-a621-a07b90351018/attachment.css","path":"assets/knowledge_card_ink_enhanced.css","size":13066,"sha256":"fc20e1ba0f39c79e736746a43e26ccf2bc1f84353ba9e351038ebcd0a93b9ba5","contentType":"text/css; charset=utf-8"},{"id":"afcfeb53-8524-5a7a-99d8-645f91e4181f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/afcfeb53-8524-5a7a-99d8-645f91e4181f/attachment.css","path":"assets/knowledge_card_modern.css","size":841,"sha256":"d941eba3498d30d54714a8e82a31bb92f3d5d102943b1d86f169a28de2e36b49","contentType":"text/css; charset=utf-8"},{"id":"64afb90a-8e02-5f37-a24e-62240265b29e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/64afb90a-8e02-5f37-a24e-62240265b29e/attachment.json","path":"assets/mentor_prompts.json","size":2570,"sha256":"b111e4fec46578c3725fe26c5d2a9645b0a01a841d809538389d215f1a4b0a2c","contentType":"application/json; charset=utf-8"},{"id":"8220007e-3de6-5e92-b88b-2f8e5d434046","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/8220007e-3de6-5e92-b88b-2f8e5d434046/attachment.css","path":"assets/mentor_runtime.css","size":7365,"sha256":"c295487e5d92ffc7a8203903cd6385215796d9bf172cd7796bb6559f9a18cb09","contentType":"text/css; charset=utf-8"},{"id":"0474bd75-47e6-5c38-9a60-f9efca6028c2","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0474bd75-47e6-5c38-9a60-f9efca6028c2/attachment.js","path":"assets/mentor_runtime.js","size":35269,"sha256":"c88a0da6bc8633d03694be728a7000c6d0dc6d809c53490f7a6893266e8e6f9e","contentType":"application/javascript; charset=utf-8"},{"id":"53892c1f-ca08-5506-97bd-3124703350aa","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/53892c1f-ca08-5506-97bd-3124703350aa/attachment.md","path":"references/system_prompt.md","size":14627,"sha256":"0ed17adfd99ff846b4f4902ff13b8a709b79b773a924e7dc1039ac72ccbb466e","contentType":"text/markdown; charset=utf-8"},{"id":"1487cce3-8130-5a3d-9ce7-2d1e793939a1","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/1487cce3-8130-5a3d-9ce7-2d1e793939a1/attachment.txt","path":"requirements.txt","size":172,"sha256":"d3504237f4995037b11df153d9b6e68d80ad700046e802595b494cc9b24a7fd8","contentType":"text/plain; charset=utf-8"},{"id":"cf8d8f0c-2ac3-5cdc-89f5-d5054899c54a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/cf8d8f0c-2ac3-5cdc-89f5-d5054899c54a/attachment.py","path":"scripts/build_knowledge_poster_assets.py","size":15863,"sha256":"518913eb96e3316d74a46b5ed2106aae9b95c35673b1fc29f8e889d40782aa5e","contentType":"text/x-python; charset=utf-8"},{"id":"7611553e-b08e-56cb-ad32-8f3ce7a39f2f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/7611553e-b08e-56cb-ad32-8f3ce7a39f2f/attachment.py","path":"scripts/build_source_package.py","size":16807,"sha256":"bbf871999d2b16c90187efd01c54807a1f465f43718540a5675d37625008006e","contentType":"text/x-python; charset=utf-8"},{"id":"aed3580f-c4ac-5ca4-8347-6654564aa391","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/aed3580f-c4ac-5ca4-8347-6654564aa391/attachment.py","path":"scripts/check_wan_task_status.py","size":3906,"sha256":"d6a3feaa153fa8cf4c4aba1eb741ebf0c9989b2a08e2e85cc8343f63e50dac13","contentType":"text/x-python; charset=utf-8"},{"id":"f8f06059-441c-5a76-a357-f0d7fce52e76","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f8f06059-441c-5a76-a357-f0d7fce52e76/attachment.py","path":"scripts/content_ingester.py","size":43428,"sha256":"934f3f4d2f59fb3436c56d4b9934e4e9442842049a3609bb919edb7658437d11","contentType":"text/x-python; charset=utf-8"},{"id":"5a92b219-ab7b-52c2-8eed-305809efe0c5","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/5a92b219-ab7b-52c2-8eed-305809efe0c5/attachment.py","path":"scripts/demo_run.py","size":10564,"sha256":"14e7ba78a0471bdfa7d9bf66ec9fbd8be1b907a48e797a79e5f496686a6be1ea","contentType":"text/x-python; charset=utf-8"},{"id":"3f6573ae-0ecb-5658-ab33-7babb32df0ba","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3f6573ae-0ecb-5658-ab33-7babb32df0ba/attachment.py","path":"scripts/file_to_oss.py","size":6027,"sha256":"0619860a1851b763bbdaf95b20067130ca0b153827ff977e4e1d3a0e2fe6a832","contentType":"text/x-python; charset=utf-8"},{"id":"1836f39d-f7dd-5a2f-b9f5-4c3b89358cc3","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/1836f39d-f7dd-5a2f-b9f5-4c3b89358cc3/attachment.py","path":"scripts/generate_knowledge_card.py","size":2930,"sha256":"207ca7143742ab6a3384a3ac4f14ebad7c43c35439fea5d47db0e9b822cd9486","contentType":"text/x-python; charset=utf-8"},{"id":"2658c807-cf52-512a-851f-c8f1b7f3a897","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/2658c807-cf52-512a-851f-c8f1b7f3a897/attachment.py","path":"scripts/image-generation-editing.py","size":8705,"sha256":"b353b335044316e277f6a2b88406078df0b2ebe89863efd819c0b4a87810ac8a","contentType":"text/x-python; charset=utf-8"},{"id":"9530e1e3-a97f-5e7d-ab78-7e03a0358fb2","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/9530e1e3-a97f-5e7d-ab78-7e03a0358fb2/attachment.py","path":"scripts/knowledge_card_generation.py","size":10855,"sha256":"e720eb3ad63ad75f1a8c3ea0df4629434c57b2515fa9ace246e0a5b3b05fc4d6","contentType":"text/x-python; charset=utf-8"},{"id":"7e86e424-7625-5d8d-ac03-19ee1170309e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/7e86e424-7625-5d8d-ac03-19ee1170309e/attachment.py","path":"scripts/knowledge_card_rendering.py","size":22082,"sha256":"77da8bd3b2d3c5cf79a4064dd3ff1b85cb776f09f7aa84884536ea814eafbdfd","contentType":"text/x-python; charset=utf-8"},{"id":"0d688b61-acc3-5fba-82cd-73871f291f25","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0d688b61-acc3-5fba-82cd-73871f291f25/attachment.py","path":"scripts/mentor_relay.py","size":3850,"sha256":"35062e449f26417eb5c2aaf4514d11dbcbd0f4241aa244b0bd6a3d7baa09f65f","contentType":"text/x-python; charset=utf-8"},{"id":"0641540d-0cf2-5aa8-af66-55150b5f9c8a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0641540d-0cf2-5aa8-af66-55150b5f9c8a/attachment.py","path":"scripts/openai_compatible_client.py","size":9253,"sha256":"7a777a66a585fac55902d71f977e2c5c9b897ffdd2b570d571a955fa2174e0e2","contentType":"text/x-python; charset=utf-8"},{"id":"512e97a7-46e8-5445-b34f-29347b885c02","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/512e97a7-46e8-5445-b34f-29347b885c02/attachment.py","path":"scripts/package_interactive_html.py","size":21403,"sha256":"27e9630198c371aef5f5b897824fe52ee38471784e415ef9806aed14dc2a7ff1","contentType":"text/x-python; charset=utf-8"},{"id":"8a0154df-2423-522f-9d6f-84a8279f90c0","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/8a0154df-2423-522f-9d6f-84a8279f90c0/attachment.py","path":"scripts/parse_resolution.py","size":5199,"sha256":"1ce0784038588960015b76598cd4ae0a9391d7056f59d5338f290009dd4bbe7a","contentType":"text/x-python; charset=utf-8"},{"id":"199ad7db-e8af-5ba9-b0f9-57887d4e9679","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/199ad7db-e8af-5ba9-b0f9-57887d4e9679/attachment.py","path":"scripts/quick_update.py","size":718,"sha256":"c83737c7daec47e5e250e539e537c0a8f9fe67556d539a00dce990b80cdd850b","contentType":"text/x-python; charset=utf-8"},{"id":"e9c57c1c-4395-5430-b6df-f9ee2227d010","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/e9c57c1c-4395-5430-b6df-f9ee2227d010/attachment.py","path":"scripts/regenerate_html.py","size":2425,"sha256":"40c3defd3192594c87203ef28dd3029c73d8837f4afc69d5049c08651c8f7345","contentType":"text/x-python; charset=utf-8"},{"id":"7e34f565-353e-5ecd-bb69-14e7dba12a27","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/7e34f565-353e-5ecd-bb69-14e7dba12a27/attachment.py","path":"scripts/rule_card_generator.py","size":12769,"sha256":"125cd10e4076a62484d14b83c9c5f4cebe0768f94e435fb1d46afd65f533c04e","contentType":"text/x-python; charset=utf-8"},{"id":"a878b026-d1e7-5ac6-a010-7e972e81125f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/a878b026-d1e7-5ac6-a010-7e972e81125f/attachment.py","path":"scripts/run_full_pipeline.py","size":17389,"sha256":"4c859c97d67b8945df809ce1fc2db456dea15e8f623e283070503082517cc41f","contentType":"text/x-python; charset=utf-8"},{"id":"d78f60e8-fb67-56cd-ab79-0d31cfbfea25","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/d78f60e8-fb67-56cd-ab79-0d31cfbfea25/attachment.py","path":"scripts/run_wan_generation.py","size":7924,"sha256":"7ae6cc29bbf60162d2cd4827b4c9dc9217dc1f6874b1107c1ab94400aeb5a4f6","contentType":"text/x-python; charset=utf-8"},{"id":"4f916571-eed9-584d-b391-a8dbf1bdbaa7","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4f916571-eed9-584d-b391-a8dbf1bdbaa7/attachment.py","path":"scripts/system_prompt_contract.py","size":4593,"sha256":"1666908f36545c2d0397b0ce31287c9d0e6eb6908a9f0d60c5093852dd5cd4e5","contentType":"text/x-python; charset=utf-8"},{"id":"4776fd13-62c7-545d-b600-304131652a5a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4776fd13-62c7-545d-b600-304131652a5a/attachment.py","path":"scripts/truth_anchor.py","size":16124,"sha256":"efbf282dc4f1083c665ba1e1bd9252b3e26a9a05c92f5e473db0cd7a5698ff10","contentType":"text/x-python; charset=utf-8"},{"id":"5d6171a7-3827-5b81-8a46-b22b06003ebc","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/5d6171a7-3827-5b81-8a46-b22b06003ebc/attachment.py","path":"scripts/update_css.py","size":1064,"sha256":"da1db4d69441b75e576c36f327c3c6821aa83745614e71246fcd7d7d3ab02283","contentType":"text/x-python; charset=utf-8"},{"id":"0b1e8666-66c0-5b92-834f-2ba2fb370ff3","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0b1e8666-66c0-5b92-834f-2ba2fb370ff3/attachment.py","path":"scripts/validate_knowledge_card.py","size":20437,"sha256":"a57406ff3fd7c7c5b71fe48631e342be18336e2ac39c4b041819dac8d80a71f1","contentType":"text/x-python; charset=utf-8"},{"id":"646df539-42cc-5cae-9e34-c64d9b015b3b","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/646df539-42cc-5cae-9e34-c64d9b015b3b/attachment.py","path":"scripts/wan_standalone.py","size":5472,"sha256":"ee0061df0c7937491448ef95ec506f091adb90e7626d5db9fe2c1fe317f2dd07","contentType":"text/x-python; charset=utf-8"}],"bundle_sha256":"b80ee5ee8f1010d518fa217798ff7f4e7969697e8f122ec212a49aa920fe375e","attachment_count":34,"text_attachments":34,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"knowledge-absorber/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"documents-office","category_label":"Documents"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"documents-office","import_tag":"clean-skills-v1","description":"深度解析链接/文档/代码,生成导师级教学笔记 + Wan 2.7 知识海报。\nUse when user asks to: 学习、分析、解读、整理、吸收、读懂 任何文档或代码\nTrigger keywords: 学习、分析、知识卡片、知识海报、解读文档、整理笔记、知识库、存入知识库\n支持 PDF/Word/Markdown/代码/图片,自动真理锚定验证,国学内容自动水墨风格。\nWhen user provides: URL链接、文件路径、代码文件、图片 → 生成知识卡片\nWhen user says: \"生成海报\"、\"知识海报\" → 额外生成 Wan 2.7 信息图\n"}},"renderedAt":1782986669282}

知识吸收器 Skill 你是一个"全能导师级知识编辑 + 信息图策划师"。 目标:深度解析链接、文档或代码,生成可学习、可搜索、可继续提问的学习成品,并支持 Wan 2.7 文生图 生成知识海报。 --- 专家思维框架 在每个步骤开始前,先问自己三个问题 : Q1: 用户真正要什么? | 用户说 | 可能实际要 | 判断方法 | |--------|-----------|----------| | "学习这个文档" | 可能只要知识卡片 | 是否提到"海报"或"图"? | | "做个知识海报" | 可能只要图片,不需要卡片 | 是否提供了源内容? | | "整理这份资料" | 可能要结构化摘要 | 是否问及"存入知识库"? | 原则 :不预设用户需要生图。海报是可选增值服务,不是默认输出。 Q2: 内容是否可信? 真理锚定协议 —— 任何内容在输出前必须过这一关: 不需要验证的 :观点、建议、方法论(主观内容) 必须验证的 :数据、API 签名、版本号、历史事件(客观事实) Q3: 信息密度对吗? 知识卡片 :追求完整,但不过度冗余 海报 Prompt :想象渲染到 3:4 画布上 —— 站在 1 米外能看清吗? | 错误 | 正确 | |------|------| | 500 字长段落 | 3-5 个要点,每点 < 30 字 | | 完整代码块 | 伪代码或核心片段 | |…