
Academic Paper Writer Pro 2
- 28 installs
- 42 repo stars
- Updated April 19, 2026
- bohefan/academic-paper-writer-pro-2
Academic Paper Writer Pro 2 is a Claude Code skill that writes and typesets academic papers from PDF, Word, or Markdown inputs and can lower AI-detection rates.
About
Academic Paper Writer Pro 2 is a Claude Code skill for writing and typesetting academic papers, with documentation and prompts primarily in Chinese. It routes PDF, Word, and Markdown inputs through five pipelines: OCR extraction, re-typesetting, Markdown-to-Word conversion, content generation from project code, and an AI-detection reduction pass. A developer or researcher uses it to format a paper to a style like IEEE, generate a thesis from code, or lower AI-detection rates. It manages intermediate files, checkpoint recovery, figure cropping, incremental DOCX generation, quality checks, and BibTeX references.
- Routes PDF, Word, and Markdown inputs through OCR, re-typesetting, or direct-convert pipelines
- Formats papers to standards like IEEE and APA with checkpoint recovery and BibTeX references
- Adds an AI-detection reduction pipeline for Chinese rewriting and English LaTeX de-AI-ing
Academic Paper Writer Pro 2 by the numbers
- 28 all-time installs (skills.sh)
- Ranked #415 of 688 Office & Documents skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
academic-paper-writer-pro-2 capabilities & compatibility
- Capabilities
- typeset paper · generate paper content · ocr pdf · reduce ai detection · manage references
- Use cases
- documentation · pdf parsing
- Runs
- Runs locally
- Pricing
- Free
What academic-paper-writer-pro-2 says it does
学术论文写作与排版助手(增强版)。支持PDF/Word/Markdown多种格式,自动选择OCR管道、重排版管道或MD直转管道。
新增Pipeline E降AI率功能,支持中文改写和英文LaTeX去AI化。
所有中间文件放resources/,最终产物放outputs/。
npx skills add https://github.com/bohefan/academic-paper-writer-pro-2 --skill academic-paper-writer-pro-2Add your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 28 |
|---|---|
| repo stars | ★ 42 |
| Last updated | April 19, 2026 |
| Repository | bohefan/academic-paper-writer-pro-2 ↗ |
What it does
Write, typeset, and lower AI-detection of academic papers from PDF, Word, or Markdown inputs.
Who is it for?
Researchers and students formatting or generating academic papers and theses with citation management
Skip if: Placing generated files in the project root, which is explicitly forbidden by its directory convention
When should I use this skill?
a user needs to typeset a paper to a style like IEEE, generate a paper from code, or reduce AI-detection rate
What you get
A formatted DOCX paper is produced with managed figures, BibTeX references, quality checks, and optional AI-detection reduction.
- formatted .docx paper
- BibTeX .bib references
- compiled Markdown paper
By the numbers
- 5 pipelines (A OCR, B re-typeset, C MD-to-Word, D content-gen, E AI-reduction)
- quality check every 2 pages, suspend every 4 pages
Files
论文降AI率工作流 (AI Detection Rate Reduction Pipeline)
<!-- 本文件是 Pipeline E 的子模块规范,通过主 SKILL.md 调用。 不要在此添加 YAML frontmatter,否则会被识别为独立 skill。 -->
[!IMPORTANT]
本文件是 Pipeline E — AI降重管道 的完整规范。用于将AI生成的论文文本改写为更自然、更符合人类写作习惯的学术表达,降低AI检测率。
0. 概述与触发条件
0.1 适用场景
| 场景 | 说明 |
|---|---|
| AI生成内容降重 | 用户使用大模型生成的论文初稿,需要降低AI检测率 |
| 学术润色 | 已有论文需要提升语言自然度和学术规范性 |
| 格式转换后处理 | Pipeline A/B/C/D 完成后的可选后处理步骤 |
0.2 触发方式
1. 显式触发:用户直接指令
"使用 ai-reduction 功能对这篇论文进行降AI率处理""帮我降低这篇论文的AI检测率"
"对这段文字进行去AI化改写"
2. 自动触发:Pipeline D 完成后可选自动调用
- 在
content_generation/SKILL.md完成内容生成后 - 用户可选择是否自动进入 Pipeline E
0.3 支持的输入格式
| 格式 | 处理方式 |
|---|---|
.md | 直接读取,按段落/章节处理 |
.tex | LaTeX源文件,保持格式改写 |
.docx | 通过 docx/SKILL.md 读取内容 |
| 纯文本 | 直接处理 |
---
1. 语言检测与模式选择
1.1 自动语言检测
系统自动检测输入文本的主要语言:
检测规则:
- 中文字符占比 > 30% → 中文模式
- 英文字符占比 > 70% → 英文模式
- 混合内容 → 分段检测,按段落语言分别处理1.2 处理模式
| 模式 | Prompt文件 | 核心规则 |
|---|---|---|
| 中文改写 | prompts/chinese_rewrite.md | 动词扩展、词汇替换、句式调整 |
| 英文LaTeX去AI化 | prompts/english_latex.md | 词汇规范化、结构自然化、排版规范 |
---
2. 中文改写规则 (Chinese Rewrite Rules)
[!IMPORTANT]
详细规则见 prompts/chinese_rewrite.md,以下为核心要点摘要。2.1 核心改写手法
2.1.1 增加冗余与解释性 (Verbose Elaboration)
动词短语扩展:
| 原文 | 改写 |
|---|---|
| 管理 | 开展...的管理工作 / 进行管理 |
| 交互 | 进行交互 / 开展交互 |
| 配置 | 进行配置 |
| 处理 | 去处理...工作 |
| 恢复 | 进行恢复 |
| 实现 | 得以实现 / 来实现 |
增加辅助词:
- 适当增加 "了"、"的"、"地"、"所"、"会"、"可以"、"这个"、"方面"、"当中" 等
- 示例:"提供功能" → "拥有...功能"
2.1.2 系统性词汇替换 (Systematic Synonym Substitution)
| 原词 | 替换词 |
|---|---|
| 采用 / 使用 | 运用 / 选用 / 把...当作...来使用 |
| 基于 | 鉴于 / 基于...来开展 |
| 利用 | 借助 / 运用 / 凭借 |
| 通过 | 借助 / 依靠 / 凭借 |
| 和 / 及 / 与 | 以及(尤其是列举多项时) |
| 并 | 并且 / 还 / 同时 |
| 其 | 它 / 其(根据语境选择) |
| 原因 | 缘由 / 主要原因囊括... |
| 符合 | 契合 |
| 适合 | 适宜 |
| 特点 | 特性 |
| 提升 / 提高 | 提高 / 提升(可互换,保持多样性) |
| 极大(地) | 极大程度(上) |
| 立即 | 马上 |
2.1.3 括号内容处理 (Bracket Content Integration)
解释性括号:
- 优先整合:将括号内信息自然融入句子
- 使用引导词:"也就是"、"即"、"比如"、"像"
- 示例:
ORM(对象关系映射)→对象关系映射即ORM功能(如ORM、Admin)→功能,比如ORM、Admin等
代码/标识符旁括号:
- 通常直接移除括号
- 示例:
视图 (views.py) 中→视图也就是views.py中
2.1.4 句式微调与口语化倾向
使用"把"字句:
- 示例:"会将对象移动" → "会把对象移动"
条件句式转换:
- 示例:"若...,则..." → "要是...,那就..." 或 "如果...,就..."
增加语气词/连接词:
- 在句首或句中添加 "那么"、"这样"、"同时" 等
2.2 禁止事项
| 禁止 | 说明 |
|---|---|
| 过于口语化 | 不要出现 "至于xxx呢" 这类表达 |
| 字数膨胀 | 输出内容不应多于原文 |
| 第一人称 | 不使用 "我"、"我们" |
| 技术术语修改 | 所有技术术语、代码、API路径等绝对不变 |
2.3 技术术语保护清单
以下内容绝对禁止修改:
- 技术术语:Django, RESTful API, Ceph, RGW, S3, JWT, ORM, MySQL 等
- 代码片段:views.py, settings.py, accounts.CustomUser, .folder_marker 等
- 库名:Boto3, djangorestframework-simplejwt 等
- 配置项:CEPH_STORAGE, DATABASES 等
- API路径:/accounts/api/token/refresh/ 等
- 数学公式:保持原样
- 变量名、函数名、类名
---
3. 英文LaTeX去AI化规则 (English LaTeX De-AI Rules)
[!IMPORTANT]
详细规则见 prompts/english_latex.md,以下为核心要点摘要。3.1 词汇规范化 (Vocabulary Normalization)
3.1.1 AI高频词替换表
| 避免(AI高频) | 使用(自然表达) |
|---|---|
| leverage | use, utilize, employ |
| delve into | investigate, examine, explore |
| tapestry | context, framework, landscape |
| underscore | highlight, emphasize, show |
| paramount | important, critical, essential |
| pivotal | key, central, important |
| burgeoning | growing, expanding |
| multifaceted | complex, various |
| nuanced | subtle, detailed |
| robust | reliable, stable, strong |
| seamless | smooth, integrated |
| cutting-edge | advanced, modern, state-of-the-art |
| groundbreaking | innovative, novel |
| revolutionize | transform, change, improve |
3.1.2 词汇选择原则
- 朴实精准:优先使用简单、准确的学术词汇
- 避免堆砌:不要为"高级感"而使用复杂词汇
- 术语适度:仅在表达特定技术含义时使用术语
3.2 结构自然化 (Structure Naturalization)
3.2.1 禁止格式
| 禁止 | 替代方案 |
|---|---|
| 列表格式(itemize/enumerate) | 转化为逻辑连贯的普通段落 |
| 生硬过渡词 | 通过句子逻辑递进自然连接 |
机械连接词移除清单:
- First and foremost
- It is worth noting that
- It is important to note that
- In order to(简化为 to)
- On the one hand... On the other hand(简化或重组)
3.2.2 标点规范
| 减少使用 | 替代方案 |
|---|---|
| 破折号(—) | 逗号、括号或从句结构 |
| 连续多个逗号 | 重组句子结构 |
3.3 排版规范 (Formatting Rules)
| 规则 | 说明 |
|---|---|
| 禁用加粗 | 正文中不使用 \textbf{} 进行强调 |
| 禁用斜体 | 正文中不使用 \textit{} 或 \emph{} 进行强调 |
| 保持LaTeX纯净 | 不引入无关的格式指令 |
| 数学公式原样 | 保留所有 $...$ 和 \[...\] |
3.4 修改阈值 (Modification Threshold)
[!CAUTION]
宁缺毋滥:如果输入文本已经自然、地道且无明显AI特征,保留原文,不要为修改而修改。
判断标准:
- 文本语气自然,无机械感
- 词汇使用恰当,无AI高频词堆砌
- 句式多样,无模板化痕迹
- 逻辑流畅,无生硬过渡
正向反馈:对高质量输入,应在输出中明确肯定。
3.5 输出格式
## Part 1 [LaTeX]
(重写后的LaTeX代码,如果原文足够好则输出原文)
## Part 2 [Translation]
(对应的中文直译)
## Part 3 [Modification Log]
如果进行了修改:
- 简要说明调整了哪些机械化表达
如果未修改:
- 输出:[检测通过] 原文表达地道自然,无明显AI味,建议保留。---
4. 处理流程 (Processing Workflow)
4.1 预处理阶段
Step 1: 输入验证
├── 检查文件格式
├── 检测文本语言
└── 统计基本信息(段落数、字数)
Step 2: 内容拆分
├── Markdown: 按段落/章节拆分
├── LaTeX: 按段落/环境拆分
├── DOCX: 提取文本内容后按段落拆分
└── 创建 checkpoint.json 记录进度4.2 核心处理阶段
Step 3: 逐单元处理
├── 读取当前单元内容
├── 识别并标记技术术语(保护区域)
├── 应用对应语言的改写规则
├── 验证技术术语未被修改
├── 输出改写结果
└── 更新 checkpoint.json
Step 4: 质量检查(每2单元)
├── 检查字数是否超标(中文模式)
├── 检查技术术语完整性
├── 检查格式是否正确(LaTeX模式)
└── 标记需要人工复核的区域4.3 后处理阶段
Step 5: 汇总输出
├── 合并所有改写单元
├── 生成改写报告
├── 保存到 outputs/ 目录
└── 列出所有修改点供用户确认---
5. 技术术语保护机制
5.1 自动识别规则
# 技术术语识别正则
TECH_PATTERNS = [
r'[A-Z][a-z]+[A-Z][a-zA-Z]*', # CamelCase
r'[a-z_]+\.[a-z_]+', # dotted.names
r'/[a-zA-Z0-9/_\-]+', # API paths
r'\$[^\$]+\$', # LaTeX math
r'\\[a-zA-Z]+\{[^\}]*\}', # LaTeX commands
r'[A-Z]{2,}', # Acronyms (API, ORM, JWT)
]5.2 保护流程
1. 预处理标记:识别所有技术术语,用特殊标记包裹
- 示例:
Django→[[TECH:Django]]
2. 改写执行:对非标记区域应用改写规则
3. 后处理还原:移除保护标记,还原技术术语
- 示例:
[[TECH:Django]]→Django
4. 验证检查:对比原文和输出,确保技术术语完全一致
---
6. 目录规范
项目根目录/
├── resources/
│ ├── ai_reduction/
│ │ ├── original/ # 原始文本备份
│ │ ├── processed/ # 处理后的文本
│ │ └── report.json # 改写报告
│ └── checkpoint.json # 进度记录
├── outputs/
│ └── <name>_reduced_<date>.md # 最终输出
└── ai_reduction/
├── SKILL.md # 本文件
└── prompts/
├── chinese_rewrite.md
└── english_latex.md---
7. 使用示例
7.1 中文改写示例
原文:
本系统采用Django框架进行开发,通过RESTful API实现前后端交互。
系统具有用户管理、权限控制等功能。改写后:
本系统选用Django框架来开展开发工作,借助RESTful API来实现前后端的交互。
系统拥有用户管理、权限控制等方面的功能。7.2 英文LaTeX示例
原文:
First and foremost, we leverage the transformer architecture to delve into the
nuanced patterns in the data. It is worth noting that this approach is paramount
for achieving robust performance.改写后:
We use the transformer architecture to examine the subtle patterns in the data.
This approach is critical for achieving reliable performance.Modification Log:
- Removed "First and foremost" (mechanical transition)
- "leverage" → "use" (avoid AI high-frequency word)
- "delve into" → "examine" (avoid AI high-frequency word)
- "nuanced" → "subtle" (avoid AI high-frequency word)
- Removed "It is worth noting that" (mechanical transition)
- "paramount" → "critical" (avoid AI high-frequency word)
- "robust" → "reliable" (avoid AI high-frequency word)
---
8. 质量保证
8.1 自动检查项
| 检查项 | 说明 | 阈值 |
|---|---|---|
| 技术术语完整性 | 所有技术术语未被修改 | 100% |
| 字数控制(中文) | 输出字数不超过原文 | ≤ 105% |
| 格式完整性(LaTeX) | 所有LaTeX命令有效 | 100% |
| AI高频词检测 | 检测是否还有AI痕迹 | 报告残留 |
8.2 人工复核触发条件
以下情况需要人工复核:
- 技术术语被修改(自动拒绝)
- 改写后语义可能变化
- 原文已足够自然,无需修改
- 用户指定区域
---
9. 与其他Pipeline的集成
9.1 作为后处理步骤
Pipeline D (内容生成)
↓
[用户选择]
↓
Pipeline E (降AI率) ← 可选
↓
Pipeline C (排版)9.2 独立使用
用户可直接调用 Pipeline E 处理已有文档:
"使用 ai-reduction 对这篇论文进行降AI率处理"
---
10. 完成报告格式
【降AI率处理报告】
源文件:<source_file>
语言模式:<Chinese/English/Mixed>
处理单元数:<N> 段落
原文总字数:<original_count>
改写后字数:<rewritten_count>
字数变化率:<change_rate>%
技术术语保护:<preserved_count>/<total_count>
AI高频词替换:<replaced_count> 处
保留原文段落:<unchanged_count> 段(原文已足够自然)
最终文件:outputs/<name>_reduced_<date>.md# Auto detect text files and perform LF normalization
* text=auto
/media
/outputs
/drafts
node_modules中文论文改写助手 Prompt
Role
你是一位专业的"论文(或技术文档)修改助手"。你的核心任务是接收一段中文原文(通常是技术性或学术性的描述),并将其改写成一种特定的风格。这种风格的特点是:比原文稍微啰嗦、更具解释性、措辞上更偏向通俗或口语化(但保持专业底线),并且系统性地使用特定的替代词汇和句式结构。
你的目标是精确地模仿分析得出的修改模式,生成"修改后"风格的文本,同时务必保持原文的核心技术信息、逻辑关系和事实准确性,也不要添加过多的字数。
重要约束
- 不要过于口语化:通常情况下不会过于口语化,有一些比如"至于xxx呢",这种的不要有
- 字数控制:你输出的内容不应多于原文!应时刻记得字数和原文相符!
- 禁止"xxx呢"形式:不要有"xxx呢"这种形式,如"至于vue呢"
- 禁止第一人称:不使用"我"、"我们"
---
核心修改手法与规则(请严格遵守)
1. 增加冗余与解释性 (Verbose Elaboration)
1.1 动词短语扩展
将简洁的动词或动词短语替换为更长的、带有动作过程描述的短语。
| 原文 | 改写示例 |
|---|---|
| 管理 | 开展...的管理工作 / 进行管理 |
| 交互 | 进行交互 / 开展交互 |
| 配置 | 进行配置 |
| 处理 | 去处理...工作 |
| 恢复 | 进行恢复 |
| 实现 | 得以实现 / 来实现 |
1.2 增加辅助词/结构
在句子中添加语法上允许但非必需的词语,使句子更饱满。
可增加的词语:
- "了"、"的"、"地"、"所"、"会"、"可以"、"这个"、"方面"、"当中" 等
示例:
- "提供功能" → "有...功能" 或 "拥有...功能"
---
2. 系统性词汇替换 (Systematic Synonym/Phrasing Substitution)
这是模仿目标风格的关键。将原文中常用的某些词汇固定地替换为特定的替代词。
2.1 动词/介词/连词替换表
| 原词 | 替换词 |
|---|---|
| 采用 / 使用 | 运用 / 选用 / 把...当作...来使用 |
| 基于 | 鉴于 / 基于...来开展 |
| 利用 | 借助 / 运用 / 凭借 |
| 通过 | 借助 / 依靠 / 凭借 |
| 和 / 及 / 与 | 以及(尤其是在列举多项时) |
| 并 | 并且 / 还 / 同时 |
| 其 | 它 / 其(可根据语境选择,有时用"它"更口语化) |
2.2 名词/形容词替换表
| 原词 | 替换词 |
|---|---|
| 原因 | 缘由 / 主要原因囊括... |
| 符合 | 契合 |
| 适合 | 适宜 |
| 特点 | 特性 |
| 提升 / 提高 | 提高 / 提升(可互换使用,保持多样性) |
| 极大(地) | 极大程度(上) |
| 立即 | 马上 |
---
3. 括号内容处理 (Bracket Content Integration/Removal)
3.1 解释性括号
对于原文中用于解释、举例或说明缩写的括号 (...) 或 (...):
优先整合:尝试将括号内的信息自然地融入句子,使用引导词。
| 原文 | 改写 |
|---|---|
| ORM(对象关系映射) | 对象关系映射即ORM / ORM也就是对象关系映射 |
| 功能(如ORM、Admin) | 功能,比如ORM、Admin / 功能,像ORM、Admin等 |
谨慎省略:如果整合后语句极其冗长或别扭,并且括号内容并非核心关键信息(例如,非常基础的缩写全称),可以考虑省略。但要极其小心,避免丢失重要上下文或示例。
3.2 代码/标识符旁括号
对于紧跟在代码、文件名、类名旁的括号,通常直接移除括号。
| 原文 | 改写 |
|---|---|
| 视图 (views.py) 中 | 视图也就是views.py中 |
| 权限类 (admin_panel.permissions) | 权限类 admin_panel.permissions |
---
4. 句式微调与口语化倾向 (Sentence Structure & Colloquial Touch)
4.1 使用"把"字句
在合适的场景下,倾向于使用"把"字句。
| 原文 | 改写 |
|---|---|
| 会将对象移动 | 会把对象移动 |
4.2 条件句式转换
将较书面的条件句式改为稍口语化的形式。
| 原文 | 改写 |
|---|---|
| 若...,则... | 要是...,那就... / 如果...,就... |
4.3 名词化与动词化转换
根据需要进行调整,有时将名词性结构展开为动词性结构,反之亦然,以符合更自然的口语表达。
| 原文 | 改写 |
|---|---|
| 为了将...解耦 | 为了实现...的解耦 |
4.4 增加语气词/连接词
在句首或句中添加"那么"、"这样"、"同时"等。
---
5. 保持技术准确性 (Maintain Technical Accuracy)
5.1 绝对禁止修改的内容
以下内容必须保持原样,不得修改或错误转写:
- 技术术语:Django, RESTful API, Ceph, RGW, S3, JWT, ORM, MySQL 等
- 代码片段:views.py, settings.py, accounts.CustomUser, .folder_marker 等
- 库名:Boto3, djangorestframework-simplejwt 等
- 配置项:CEPH_STORAGE, DATABASES 等
- API路径:/accounts/api/token/refresh/ 等
- 数学公式:保持原样
- 变量名、函数名、类名
5.2 核心逻辑不变
修改后的句子必须表达与原文完全相同的技术逻辑、因果关系和功能描述。
---
执行指令
请根据以上所有规则,对接下来提供的"原文"进行修改,生成符合上述特定风格的"修改后"文本。
务必仔细揣摩每个规则的细节和示例,力求在风格上高度一致。
---
输入输出格式
输入:
原文:<用户提供的内容>输出:
修改后:<改写后的内容>---
示例
示例 1
原文:
本系统采用Django框架进行开发,通过RESTful API实现前后端交互。
系统具有用户管理、权限控制等功能。修改后:
本系统选用Django框架来开展开发工作,借助RESTful API来实现前后端的交互。
系统拥有用户管理、权限控制等方面的功能。示例 2
原文:
基于MySQL数据库存储数据,利用Redis进行缓存处理。
该设计符合高并发场景的需求。修改后:
鉴于MySQL数据库来存储数据,借助Redis开展缓存处理工作。
该设计契合高并发场景的需求。示例 3
原文:
若用户未登录,则系统会跳转至登录页面。
该功能极大地提升了用户体验。修改后:
如果用户未登录,系统就会跳转至登录页面。
该功能极大程度上提高了用户体验。英文 LaTeX 去AI化重写 Prompt
Role
你是一位专业的学术论文语言编辑,专门帮助提升论文的自然度与可读性。你的任务是将大模型生成的机械化文本重写为符合顶级会议(如 ACL, NeurIPS)标准的自然学术表达。
Task
请对我提供的【英文 LaTeX 代码片段】进行"去 AI 化"重写,使其语言风格接近人类母语研究者。
---
Constraints
1. 词汇规范化 (Vocabulary Normalization)
1.1 避免使用的AI高频词
以下词汇被过度滥用,应替换为更自然的表达:
| 避免(AI高频) | 使用(自然表达) |
|---|---|
| leverage | use, utilize, employ |
| delve into | investigate, examine, explore |
| tapestry | context, framework, landscape |
| underscore | highlight, emphasize, show |
| paramount | important, critical, essential |
| pivotal | key, central, important |
| burgeoning | growing, expanding |
| multifaceted | complex, various |
| nuanced | subtle, detailed |
| robust | reliable, stable, strong |
| seamless | smooth, integrated |
| cutting-edge | advanced, modern, state-of-the-art |
| groundbreaking | innovative, novel |
| revolutionize | transform, change, improve |
| paradigm | approach, framework, model |
| ecosystem | environment, system |
| synergy | cooperation, collaboration |
| holistic | comprehensive, complete |
| unprecedented | new, notable, significant |
| realm | area, field, domain |
1.2 词汇选择原则
- 朴实精准:优先使用简单、准确的学术词汇
- 避免堆砌:不要为"高级感"而使用复杂词汇
- 术语适度:仅在表达特定技术含义时使用术语
---
2. 结构自然化 (Structure Naturalization)
2.1 严禁使用列表格式
必须将所有的 \begin{itemize}...\end{itemize} 和 \begin{enumerate}...\end{enumerate} 内容转化为逻辑连贯的普通段落。
错误示例:
The system has several advantages:
\begin{itemize}
\item High efficiency
\item Low latency
\item Easy deployment
\end{itemize}正确示例:
The system offers several advantages, including high efficiency, low latency,
and straightforward deployment.2.2 移除机械连接词
删除生硬的过渡词,应通过句子间的逻辑递进自然连接。
需要移除的机械连接词:
- First and foremost
- It is worth noting that
- It is important to note that
- It should be noted that
- In order to(简化为 to)
- On the one hand... On the other hand
- Last but not least
- At the end of the day
- In conclusion(改用具体陈述)
2.3 减少插入符号
尽量减少破折号(—)的使用,建议使用逗号、括号或从句结构替代。
---
3. 排版规范 (Formatting Rules)
| 规则 | 说明 |
|---|---|
| 禁用加粗强调 | 正文中不使用 \textbf{} 进行强调 |
| 禁用斜体强调 | 正文中不使用 \textit{} 或 \emph{} 进行强调 |
| 保持LaTeX纯净 | 不引入无关的格式指令 |
| 数学公式原样 | 保留所有 $...$ 和 \[...\] 公式 |
注意:学术写作应通过句式结构来体现重点,而非格式强调。
---
4. 修改阈值 (Modification Threshold)
宁缺毋滥:如果输入的文本已经非常自然、地道且没有明显的 AI 特征,请保留原文,不要为了修改而修改。
4.1 判断标准
保留原文的情况:
- 文本语气自然,无机械感
- 词汇使用恰当,无AI高频词堆砌
- 句式多样,无模板化痕迹
- 逻辑流畅,无生硬过渡
4.2 正向反馈
对于高质量的输入,应在 Part 3 中给予明确的肯定和正向评价。
---
5. 输出格式
你的输出必须严格包含以下三个部分:
## Part 1 [LaTeX]
(重写后的LaTeX代码。如果原文已足够好,则输出原文。)
## Part 2 [Translation]
(对应的中文直译)
## Part 3 [Modification Log]
(如果进行了修改:简要说明调整了哪些机械化表达)
(如果未修改:请直接输出中文评价:"[检测通过] 原文表达地道自然,无明显AI味,建议保留。")5.1 Part 1 要求
- 语言要求:必须是全英文
- 转义要求:必须对特殊字符进行转义(例如:
%、_、&) - 公式要求:保持数学公式原样(保留
$符号)
5.2 Part 2 要求
- 提供准确的中文直译
- 保持技术术语的专业性
5.3 Part 3 要求
如果进行了修改:
- 列出具体的修改项
- 说明修改原因
如果未修改:
- 输出:
[检测通过] 原文表达地道自然,无明显AI味,建议保留。
---
Execution Protocol
在输出前,请自查:
1. 拟人度检查:确认文本语气自然 2. 必要性检查:当前的修改是否真的提升了可读性?如果是为了换词而换词,请撤销修改并判定为"检测通过"
---
示例
示例 1:需要修改的情况
Input:
First and foremost, we leverage the transformer architecture to delve into the
nuanced patterns in the data. It is worth noting that this approach is paramount
for achieving robust performance.Output:
Part 1 [LaTeX]
We use the transformer architecture to examine the subtle patterns in the data.
This approach is critical for achieving reliable performance.Part 2 [Translation]
我们使用transformer架构来检验数据中的细微模式。这种方法对于实现可靠的性能至关重要。
Part 3 [Modification Log]
- 移除 "First and foremost"(机械过渡词)
- "leverage" → "use"(避免AI高频词)
- "delve into" → "examine"(避免AI高频词)
- "nuanced" → "subtle"(避免AI高频词)
- 移除 "It is worth noting that"(机械过渡词)
- "paramount" → "critical"(避免AI高频词)
- "robust" → "reliable"(避免AI高频词)
---
示例 2:无需修改的情况
Input:
The proposed method achieves 95\% accuracy on the benchmark dataset,
outperforming existing approaches by a significant margin.Output:
Part 1 [LaTeX]
The proposed method achieves 95\% accuracy on the benchmark dataset,
outperforming existing approaches by a significant margin.Part 2 [Translation]
所提出的方法在基准数据集上达到了95%的准确率,显著优于现有方法。
Part 3 [Modification Log]
[检测通过] 原文表达地道自然,无明显AI味,建议保留。
---
示例 3:列表格式转换
Input:
Our contributions are as follows:
\begin{itemize}
\item We propose a novel framework for text classification.
\item We achieve state-of-the-art results on three benchmarks.
\item We release our code and pretrained models.
\end{itemize}Output:
Part 1 [LaTeX]
Our contributions include proposing a novel framework for text classification,
achieving state-of-the-art results on three benchmarks, and releasing our code
along with pretrained models.Part 2 [Translation]
我们的贡献包括:提出了一个新颖的文本分类框架,在三个基准测试上取得了最先进的结果,并发布了代码和预训练模型。
Part 3 [Modification Log]
- 将列表格式转换为连贯段落
- 移除机械的 "as follows" 引导
---
Input
[在此处粘贴你的英文 LaTeX 代码]
<div align="center">
Academic Paper Writer Pro
<img src="../resources/banner.svg" alt="Academic Paper Writer Pro Banner" width="100%"/>
<br/>
     
<br/>
    
<br/>
Ein professioneller AI-Agent-Skill zur Unterstützung bei Forschung, Verfassen und Satz akademischer Arbeiten.<br/> Dieser Skill erzwingt einen strukturierten Workflow mit präzisen .docx- und .pdf-Verarbeitungsfähigkeiten,<br/> und stellt sicher, dass Ihre Manuskripte strikt den jeweiligen akademischen Formatanforderungen entsprechen (IEEE, ACM, Springer, NeurIPS, MLA, APA und Hochschulvorlagen).
</div>
1. Voraussetzungen
Bevor Sie diesen Skill verwenden, benötigen Sie eine agentische Umgebung, die Dateioperationen und Kommandozeilentools unterstützt. Wir unterstützen die folgenden zwei Hauptumgebungen:
Option A: OpenCode (Empfohlen)
Ein Open-Source-Agentic-Framework, optimiert für Entwickler-Workflows.
- Installationsanleitung: Offizielle OpenCode-Dokumentation
- Schnellinstallation:
- Desktop-Version:
https://opencode.ai/download
- CLI-Version:
npm install -g opencodeOption B: Claude Code
Ein offiziell von Anthropic veröffentlichtes Agentic-CLI-Tool.
- Installationsanleitung: Offizielle Claude Code-Dokumentation
- Hinweis: Stellen Sie sicher, dass
gitundnpmin Ihrer Umgebung installiert sind.
---
2. Installation
Unter Berücksichtigung verschiedener Benutzerumgebungen bieten wir sowohl eine automatische Ein-Klick-Installation als auch eine manuelle Konfiguration an.
🔗 Offizielle Skill-Seite: https://skills.sh/tfboy1/academic-paper-writer/academic-paper-writer-pro
Option 1: Automatische Ein-Klick-Installation (Empfohlen)
Wenn Sie ein kompatibles Agentic-Framework (wie Claude Code oder OpenCode) verwenden, führen Sie einfach den folgenden Befehl in Ihrem Arbeitsverzeichnis aus. Das System ruft automatisch das Repository ab und konfiguriert die Abhängigkeiten:
npx skills add https://github.com/tfboy1/academic-paper-writer --skill academic-paper-writer-proOption 2: Manuelles Klonen und Konfigurieren
Wenn Netzwerk- oder Framework-Einschränkungen die Ein-Klick-Installation verhindern, folgen Sie diesen Schritten zum manuellen Import des Skills:
1. Repository klonen
Navigieren Sie zu Ihrem Agent-Workspace oder Skills-Verzeichnis und klonen Sie dieses Repository:
# In Ihr Skills-Verzeichnis klonen
git clone <your-repo-url> academic-paper-writer2. Skill laden
- Für OpenCode: Der Agent erkennt Skills im Konfigurationspfad automatisch. Möglicherweise müssen Sie die Sitzung neu starten oder den Agent explizit bitten, „den academic-paper-writer-Skill zu laden".
- Für Claude Code: Sie können dieses Verzeichnis im Kontextfenster bereitstellen oder einbinden und Claude anweisen, es als Toolset zu verwenden.
---
3. Bedienungsanleitung
Nach der Installation können Sie den gesamten Schreib- und Satzprozess in natürlicher Sprache steuern.
Schritt 1: Dateien vorbereiten
Erstellen Sie ein Arbeitsverzeichnis für Ihre Arbeit und bereiten Sie die folgenden Kerndateien vor: 1. Entwurf: Ihr Originalinhalt (Markdown, Text oder grobes Word-Dokument). 2. Stilvorlage/Vorlage: Zielformatanforderungen (z.B. IEEE_Template.docx oder Submission_Guidelines.pdf). 3. Literaturverzeichnis (Optional): Eine Referenzbibliothek im .bib-Format (empfohlen für Zitiergenauigkeit).
Schritt 2: Agent starten
Starten Sie Ihren Agent und zeigen Sie auf Ihr Arbeitsverzeichnis.
# OpenCode-Beispiel
opencodeSchritt 3: Skill auslösen
Verwenden Sie natürlichsprachliche Anweisungen, um den Workflow zu starten. Unser System enthält eingebaute Satzstandards für wichtige akademische Zeitschriften und Konferenzen (einschließlich IEEE, ACM, Springer LNCS, NeurIPS, APA, MLA und chinesische Dissertationsformate). Geben Sie einfach das benötigte Format an.
Direkte Satzbefehle (keine Vorlage erforderlich):
„Bitte formatieren Sie diesen Word-Entwurf im IEEE-Format um."
„Konvertieren Sie dieses Markdown in ein Springer LNCS Word-Dokument."
„Setzen Sie diesen Inhalt im ACM-Standard-Zweispaltenformat."
„Formatieren Sie gemäß den NeurIPS-Anforderungen im Einspalten-Layout."
„Verwenden Sie das MLA-Format für diese geisteswissenschaftliche Arbeit."
Satzbefehle mit benutzerdefinierter Vorlage:
„Helfen Sie mir, diese Arbeit zu setzen. Ich habe den Entwurf und die benutzerdefinierte Vorlagendatei in diesem Ordner abgelegt."
„Basierend auf diesem PDF-Formatierungsleitfaden, helfen Sie mir, das Zitierformat und das Layout zu korrigieren."
Was passiert als Nächstes?
1. Vorprüfung: Der Agent prüft, ob Sie einen Entwurf und einen Formatierungsleitfaden bereitgestellt haben. 2. Tiefenanalyse: Der Agent liest den .docx- oder .pdf-Formatierungsleitfaden, um Schriftart-, Rand- und Zitierstilanforderungen zu verstehen. 3. Satzausführung: Der Agent erstellt eine standardkonforme Version der Arbeit, die im Verzeichnis outputs/ gespeichert wird. 4. Verfeinerung: Sie können weitere Verbesserungen anfordern, z.B. „überprüfen Sie die Logik von Abschnitt 3" oder „erstellen Sie Bildunterschriften für diese Abbildungen".
---
4. Ressourcen
Dieses Repository bietet einige eingebaute Ressourcen, um Ihnen den schnellen Einstieg zu erleichtern:
- 📂 `templates/`: Enthält Download-Links für offizielle Vorlagen wichtiger akademischer Konferenzen und Zeitschriften, darunter IEEE, ACM, APA usw.
- 📂 `examples/`: Enthält einen Standard-Entwurf (
draft.md) und einen Stilleitfaden (style_guide.md) zum Testen der Skill-Funktionalität. - ❓ `TROUBLESHOOTING.md`: Leitfaden zur Fehlerbehebung häufiger Probleme (Formatierungsfehler, fehlende Zitate usw.).
---
Danksagungen
Dieses Projekt nutzt die leistungsstarken Dokumentenverarbeitungsfähigkeiten von Anthropic.
- Docx & PDF Skills: Besonderer Dank an das Anthropic Skills Repository für die Bereitstellung der grundlegenden Logik zur Interaktion mit Microsoft Word- und PDF-Dokumenten. Diese Module verleihen diesem Skill präzise Lese-, Bearbeitungs- und Satzfähigkeiten.
<div align="center">
Academic Paper Writer Pro
<img src="../resources/banner.svg" alt="Academic Paper Writer Pro Banner" width="100%"/>
<br/>
     
<br/>
    
<br/>
A professional AI Agent Skill for assisting with academic paper research, writing, and typesetting.<br/> This Skill enforces a structured workflow with precise .docx and .pdf processing capabilities,<br/> ensuring your manuscripts strictly comply with various academic format requirements (IEEE, ACM, Springer, NeurIPS, MLA, APA, and university templates).
</div>
1. Prerequisites
Before using this Skill, you need an Agentic environment that supports file operations and command-line tools. We support the following two mainstream environments:
Option A: OpenCode (Recommended)
An open-source Agentic framework optimized for developer workflows.
- Installation Guide: OpenCode Official Docs
- Quick Install:
- Desktop Version:
https://opencode.ai/download
- CLI Version:
npm install -g opencodeOption B: Claude Code
An Agentic CLI tool officially released by Anthropic.
- Installation Guide: Claude Code Official Docs
- Note: Ensure
gitandnpmare installed in your environment.
---
2. Installation
Considering different user environments, we provide both one-click automated installation and manual configuration methods.
🔗 Official Skill Page: https://skills.sh/tfboy1/academic-paper-writer/academic-paper-writer-pro
Option 1: One-Click Automated Installation (Recommended)
If you are using a compatible Agentic framework (such as Claude Code or OpenCode), simply run the following command in your working directory. The system will automatically fetch the repository and configure dependencies:
npx skills add https://github.com/tfboy1/academic-paper-writer --skill academic-paper-writer-proOption 2: Manual Clone and Configuration
If network or framework limitations prevent using the one-click installation, follow these steps to manually import the Skill:
1. Clone the Repository
Navigate to your Agent workspace or Skills directory and clone this repository:
# Clone to your skills directory
git clone <your-repo-url> academic-paper-writer2. Load the Skill
- For OpenCode: The Agent automatically detects Skills in the configuration path. You may need to restart the session or explicitly ask the Agent to "load the academic-paper-writer skill".
- For Claude Code: You can provide this directory in the context window or mount it, instructing Claude to use it as a toolset.
---
3. Usage Guide
After installation, you can control the entire writing and typesetting process using natural language.
Step 1: Prepare Files
Create a working directory for your paper and prepare the following core files: 1. Draft: Your original content (Markdown, Text, or a rough Word document). 2. Style Guide/Template: Target format requirements (e.g., IEEE_Template.docx or Submission_Guidelines.pdf). 3. References (Optional): A .bib reference library (recommended for citation accuracy).
Step 2: Launch the Agent
Start your Agent and point to your working directory.
# OpenCode example
opencodeStep 3: Trigger the Skill
Use natural language instructions to start the workflow. Our system includes built-in typesetting standards for major academic journals and conferences (including IEEE, ACM, Springer LNCS, NeurIPS, APA, MLA, and Chinese thesis formats). Simply specify the format you need.
Direct typesetting commands (no template required):
"Please reformat this Word draft according to IEEE format."
"Convert this Markdown to a Springer LNCS Word document."
"Typeset this content in ACM standard double-column format."
"Format according to NeurIPS requirements in single-column layout."
"Use MLA format for this humanities assignment."
"Convert this thesis to Chinese degree thesis format."
Custom template typesetting commands:
"Help me typeset this paper. I've placed the draft and custom template file in this folder."
"Based on this PDF formatting guide, help me fix the citation format and layout."
What happens next?
1. Pre-check: The Agent verifies that you've provided a draft and format guide. 2. Deep Analysis: The Agent reads the .docx or .pdf format guide to understand font, margin, citation style requirements. 3. Execute Typesetting: The Agent generates a standards-compliant paper version, saved in the outputs/ directory. 4. Refinement: You can further request improvements such as "check the logic of section 3" or "generate captions for these figures".
---
4. Resources
This repository provides some built-in resources to help you get started quickly:
- 📂 `templates/`: Contains download links for official templates of major academic conferences/journals including IEEE, ACM, APA, etc.
- 📂 `examples/`: Contains a standard draft (
draft.md) and style guide (style_guide.md) for testing Skill functionality. - ❓ `TROUBLESHOOTING.md`: Common issues troubleshooting guide (e.g., formatting errors, missing citations, etc.).
---
Credits & Acknowledgments
This project leverages the powerful document processing capabilities provided by Anthropic.
- Docx & PDF Skills: Special thanks to the Anthropic Skills Repository for providing the foundational logic for interacting with Microsoft Word and PDF documents. These modules give this Skill precise reading, editing, and typesetting capabilities.
<div align="center">
Academic Paper Writer Pro
<img src="../resources/banner.svg" alt="Academic Paper Writer Pro Banner" width="100%"/>
<br/>
     
<br/>
    
<br/>
Un Skill d'Agent IA professionnel pour assister la recherche, la rédaction et la mise en page de publications académiques.<br/> Ce Skill applique un workflow structuré avec des capacités de traitement .docx et .pdf précises,<br/> garantissant que vos manuscrits respectent strictement les exigences de format académique (IEEE, ACM, Springer, NeurIPS, MLA, APA et modèles universitaires).
</div>
1. Prérequis
Avant d'utiliser ce Skill, vous avez besoin d'un environnement Agentique prenant en charge les opérations sur les fichiers et les outils en ligne de commande. Nous supportons les deux environnements principaux suivants :
Option A : OpenCode (Recommandé)
Un framework Agentique open-source optimisé pour les workflows des développeurs.
- Guide d'installation : Documentation officielle OpenCode
- Installation rapide :
- Version bureau :
https://opencode.ai/download
- Version CLI :
npm install -g opencodeOption B : Claude Code
Un outil CLI Agentique officiellement publié par Anthropic.
- Guide d'installation : Documentation officielle Claude Code
- Note : Assurez-vous que
gitetnpmsont installés dans votre environnement.
---
2. Installation
Compte tenu des différents environnements utilisateurs, nous proposons à la fois une installation automatisée en un clic et une configuration manuelle.
🔗 Page officielle du Skill : https://skills.sh/tfboy1/academic-paper-writer/academic-paper-writer-pro
Option 1 : Installation automatisée en un clic (Recommandé)
Si vous utilisez un framework Agentique compatible (comme Claude Code ou OpenCode), exécutez simplement la commande suivante dans votre répertoire de travail. Le système récupérera automatiquement le dépôt et configurera les dépendances :
npx skills add https://github.com/tfboy1/academic-paper-writer --skill academic-paper-writer-proOption 2 : Clonage et configuration manuels
Si des limitations réseau ou de framework empêchent l'utilisation de l'installation en un clic, suivez ces étapes pour importer manuellement le Skill :
1. Cloner le dépôt
Naviguez vers votre espace de travail Agent ou répertoire de Skills et clonez ce dépôt :
# Cloner dans votre répertoire de skills
git clone <your-repo-url> academic-paper-writer2. Charger le Skill
- Pour OpenCode : L'Agent détecte automatiquement les Skills dans le chemin de configuration. Vous devrez peut-être redémarrer la session ou demander explicitement à l'Agent de « charger le skill academic-paper-writer ».
- Pour Claude Code : Vous pouvez fournir ce répertoire dans la fenêtre de contexte ou le monter, en indiquant à Claude de l'utiliser comme ensemble d'outils.
---
3. Guide d'utilisation
Après l'installation, vous pouvez contrôler l'ensemble du processus de rédaction et de mise en page en langage naturel.
Étape 1 : Préparer les fichiers
Créez un répertoire de travail pour votre article et préparez les fichiers essentiels suivants : 1. Brouillon : Votre contenu original (Markdown, Texte ou document Word brut). 2. Guide de style / Modèle : Exigences de format cibles (par exemple, IEEE_Template.docx ou Submission_Guidelines.pdf). 3. Références (Optionnel) : Une bibliothèque de références au format .bib (recommandé pour la précision des citations).
Étape 2 : Lancer l'Agent
Démarrez votre Agent et pointez vers votre répertoire de travail.
# Exemple OpenCode
opencodeÉtape 3 : Déclencher le Skill
Utilisez des instructions en langage naturel pour démarrer le workflow. Notre système intègre des normes de mise en page pour les principales revues et conférences académiques (IEEE, ACM, Springer LNCS, NeurIPS, APA, MLA et formats de thèses chinoises). Spécifiez simplement le format dont vous avez besoin.
Commandes de mise en page directe (sans modèle requis) :
« Veuillez reformater ce brouillon Word selon le format IEEE. »
« Convertir ce Markdown en document Word au format Springer LNCS. »
« Mettre en page ce contenu au format double colonne standard ACM. »
« Formater selon les exigences NeurIPS en mise en page simple colonne. »
« Utiliser le format MLA pour ce devoir en sciences humaines. »
Commandes avec modèle personnalisé :
« Aidez-moi à mettre en page cet article. J'ai placé le brouillon et le fichier de modèle personnalisé dans ce dossier. »
« Sur la base de ce guide de formatage PDF, aidez-moi à corriger le format des citations et la mise en page. »
Que se passe-t-il ensuite ?
1. Vérification préalable : L'Agent vérifie que vous avez fourni un brouillon et un guide de format. 2. Analyse approfondie : L'Agent lit le guide de format .docx ou .pdf pour comprendre les exigences en matière de police, marges et style de citation. 3. Exécution de la mise en page : L'Agent génère une version conforme aux normes, enregistrée dans le répertoire outputs/. 4. Raffinement : Vous pouvez demander des améliorations supplémentaires telles que « vérifier la logique de la section 3 » ou « générer des légendes pour ces figures ».
---
4. Ressources
Ce dépôt fournit des ressources intégrées pour vous aider à démarrer rapidement :
- 📂 `templates/` : Contient des liens de téléchargement pour les modèles officiels des principales conférences et revues académiques, notamment IEEE, ACM, APA, etc.
- 📂 `examples/` : Contient un brouillon standard (
draft.md) et un guide de style (style_guide.md) pour tester les fonctionnalités du Skill. - ❓ `TROUBLESHOOTING.md` : Guide de dépannage des problèmes courants (erreurs de formatage, citations manquantes, etc.).
---
Crédits et remerciements
Ce projet s'appuie sur les puissantes capacités de traitement de documents fournies par Anthropic.
- Docx & PDF Skills : Remerciements spéciaux au Anthropic Skills Repository pour avoir fourni la logique fondamentale d'interaction avec les documents Microsoft Word et PDF. Ces modules confèrent à ce Skill des capacités précises de lecture, d'édition et de mise en page.
<div align="center">
Academic Paper Writer Pro
<img src="../resources/banner.svg" alt="Academic Paper Writer Pro Banner" width="100%"/>
<br/>
     
<br/>
    
<br/>
学術論文の研究、執筆、組版を支援するプロフェッショナルなAIエージェントスキル。<br/> 構造化されたワークフローを実行し、.docx と .pdf の精密な処理能力を活用して、<br/> 原稿が各種学術フォーマット要件(IEEE、ACM、Springer、NeurIPS、MLA、APA、各大学テンプレート)に厳密に準拠することを保証します。
</div>
1. 前提条件
本スキルを使用する前に、ファイル操作とコマンドラインツールをサポートするAgenticな環境が必要です。以下の2つの主要環境をサポートしています:
オプション A: OpenCode(推奨)
開発者のワークフローに最適化されたオープンソースAgenticフレームワーク。
- インストールガイド: OpenCode 公式ドキュメント
- クイックインストール:
- デスクトップ版:
https://opencode.ai/download
- CLI版:
npm install -g opencodeオプション B: Claude Code
Anthropicが公式にリリースした Agentic CLI ツール。
- インストールガイド: Claude Code 公式ドキュメント
- 注意: 環境に
gitとnpmがインストールされていることを確認してください。
---
2. インストール
ユーザー環境の違いを考慮し、ワンクリック自動インストール と 手動設定 の2つの方法を提供しています。
🔗 公式スキルページ: https://skills.sh/tfboy1/academic-paper-writer/academic-paper-writer-pro
オプション1: ワンクリック自動インストール(推奨)
互換性のあるAgenticフレームワーク(Claude CodeやOpenCodeなど)を使用している場合、作業ディレクトリで以下のコマンドを実行するだけで、システムが自動的にリポジトリを取得し依存関係を設定します:
npx skills add https://github.com/tfboy1/academic-paper-writer --skill academic-paper-writer-proオプション2: 手動クローンと設定
ネットワークやフレームワークの制限でワンクリックインストールが使用できない場合、以下の手順でスキルを手動インポートしてください:
1. リポジトリのクローン
Agentのワークスペースまたはスキルディレクトリに移動し、リポジトリをクローンします:
# スキルディレクトリにクローン
git clone <your-repo-url> academic-paper-writer2. スキルの読み込み
- OpenCodeの場合: エージェントは設定パスのスキルを自動検出します。セッションの再起動が必要な場合や、エージェントに「academic-paper-writerスキルを読み込んでください」と明示的に指示する必要がある場合があります。
- Claude Codeの場合: コンテキストウィンドウでこのディレクトリを指定するか、マウントして、Claudeにツールセットとして使用するよう指示できます。
---
3. 使用ガイド
インストール完了後、自然言語で執筆と組版のプロセス全体を制御できます。
ステップ1: ファイルの準備
論文用の作業ディレクトリを作成し、以下のコアファイルを準備します: 1. ドラフト: 原稿内容(Markdown、テキスト、または粗いWordドキュメント)。 2. スタイルガイド/テンプレート: 目標フォーマット要件(例:IEEE_Template.docx や Submission_Guidelines.pdf)。 3. 参考文献(オプション): .bib 形式の参考文献ライブラリ(引用精度のため推奨)。
ステップ2: エージェントの起動
エージェントを起動し、作業ディレクトリを指定します。
# OpenCode の例
opencodeステップ3: スキルの起動
自然言語の指示でワークフローを開始します。システムには主要な学術ジャーナルや会議の組版規格(IEEE、ACM、Springer LNCS、NeurIPS、APA、MLA、中国学位論文フォーマット)が組み込まれています。必要なフォーマットを指定するだけです。
テンプレート不要の直接組版コマンド:
「このWordドラフトをIEEEフォーマットで再組版してください。」
「このMarkdownをSpringer LNCS形式のWordドキュメントに変換してください。」
「このコンテンツをACM標準ダブルカラム形式で組版してください。」
「NeurIPSの要件に従ってシングルカラムレイアウトにしてください。」
「この人文学の課題にMLAフォーマットを使用してください。」
カスタムテンプレートの組版コマンド:
「この論文の組版を手伝ってください。ドラフトとカスタムテンプレートファイルをこのフォルダに入れました。」
「このPDF組版ガイドに基づいて、引用フォーマットとレイアウトを修正してください。」
次に何が起こるか?
1. 事前チェック: エージェントがドラフトとフォーマットガイドが提供されているか確認します。 2. 深層分析: エージェントが .docx や .pdf のフォーマットガイドを読み取り、フォント、マージン、引用スタイルの要件を理解します。 3. 組版実行: エージェントが規格準拠の論文版を生成し、outputs/ ディレクトリに保存します。 4. 改良: 「第3節のロジックをチェック」や「これらの図にキャプションを生成」など、さらなる改善を要求できます。
---
4. リソース
このリポジトリは、迅速なスタートに役立つ組み込みリソースを提供しています:
- 📂 `templates/`: IEEE、ACM、APAなど、主要な学術会議・ジャーナルの公式テンプレートダウンロードリンクが含まれています。
- 📂 `examples/`: スキル機能をテストするための標準ドラフト(
draft.md)とスタイルガイド(style_guide.md)が含まれています。 - ❓ `TROUBLESHOOTING.md`: よくある問題のトラブルシューティングガイド(フォーマットエラー、引用の欠落など)。
---
クレジットと謝辞
本プロジェクトは、Anthropic が提供する強力なドキュメント処理能力を活用しています。
- Docx & PDF Skills: Microsoft WordやPDFドキュメントと対話するための基礎ロジックを提供してくれた Anthropic Skills Repository に特別な感謝を捧げます。これらのモジュールは、本スキルに精密な読み取り、編集、組版能力を付与しています。
© 2025 Anthropic, PBC. All rights reserved.
LICENSE: Use of these materials (including all code, prompts, assets, files,
and other components of this Skill) is governed by your agreement with
Anthropic regarding use of Anthropic's services. If no separate agreement
exists, use is governed by Anthropic's Consumer Terms of Service or
Commercial Terms of Service, as applicable:
https://www.anthropic.com/legal/consumer-terms
https://www.anthropic.com/legal/commercial-terms
Your applicable agreement is referred to as the "Agreement." "Services" are
as defined in the Agreement.
ADDITIONAL RESTRICTIONS: Notwithstanding anything in the Agreement to the
contrary, users may not:
- Extract these materials from the Services or retain copies of these
materials outside the Services
- Reproduce or copy these materials, except for temporary copies created
automatically during authorized use of the Services
- Create derivative works based on these materials
- Distribute, sublicense, or transfer these materials to any third party
- Make, offer to sell, sell, or import any inventions embodied in these
materials
- Reverse engineer, decompile, or disassemble these materials
The receipt, viewing, or possession of these materials does not convey or
imply any license or right beyond those expressly granted above.
Anthropic retains all right, title, and interest in these materials,
including all copyrights, patents, and other intellectual property rights.
"""Accept all tracked changes in a DOCX file using LibreOffice.
Requires LibreOffice (soffice) to be installed.
"""
import argparse
import logging
import shutil
import subprocess
from pathlib import Path
from office.soffice import get_soffice_env
logger = logging.getLogger(__name__)
LIBREOFFICE_PROFILE = "/tmp/libreoffice_docx_profile"
MACRO_DIR = f"{LIBREOFFICE_PROFILE}/user/basic/Standard"
ACCEPT_CHANGES_MACRO = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Module1" script:language="StarBasic">
Sub AcceptAllTrackedChanges()
Dim document As Object
Dim dispatcher As Object
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
dispatcher.executeDispatch(document, ".uno:AcceptAllTrackedChanges", "", 0, Array())
ThisComponent.store()
ThisComponent.close(True)
End Sub
</script:module>"""
def accept_changes(
input_file: str,
output_file: str,
) -> tuple[None, str]:
input_path = Path(input_file)
output_path = Path(output_file)
if not input_path.exists():
return None, f"Error: Input file not found: {input_file}"
if not input_path.suffix.lower() == ".docx":
return None, f"Error: Input file is not a DOCX file: {input_file}"
try:
output_path.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(input_path, output_path)
except Exception as e:
return None, f"Error: Failed to copy input file to output location: {e}"
if not _setup_libreoffice_macro():
return None, "Error: Failed to setup LibreOffice macro"
cmd = [
"soffice",
"--headless",
f"-env:UserInstallation=file://{LIBREOFFICE_PROFILE}",
"--norestore",
"vnd.sun.star.script:Standard.Module1.AcceptAllTrackedChanges?language=Basic&location=application",
str(output_path.absolute()),
]
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=30,
check=False,
env=get_soffice_env(),
)
except subprocess.TimeoutExpired:
return (
None,
f"Successfully accepted all tracked changes: {input_file} -> {output_file}",
)
if result.returncode != 0:
return None, f"Error: LibreOffice failed: {result.stderr}"
return (
None,
f"Successfully accepted all tracked changes: {input_file} -> {output_file}",
)
def _setup_libreoffice_macro() -> bool:
macro_dir = Path(MACRO_DIR)
macro_file = macro_dir / "Module1.xba"
if macro_file.exists() and "AcceptAllTrackedChanges" in macro_file.read_text():
return True
if not macro_dir.exists():
subprocess.run(
[
"soffice",
"--headless",
f"-env:UserInstallation=file://{LIBREOFFICE_PROFILE}",
"--terminate_after_init",
],
capture_output=True,
timeout=10,
check=False,
env=get_soffice_env(),
)
macro_dir.mkdir(parents=True, exist_ok=True)
try:
macro_file.write_text(ACCEPT_CHANGES_MACRO)
return True
except Exception as e:
logger.warning(f"Failed to setup LibreOffice macro: {e}")
return False
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Accept all tracked changes in a DOCX file"
)
parser.add_argument("input_file", help="Input DOCX file with tracked changes")
parser.add_argument(
"output_file", help="Output DOCX file (clean, no tracked changes)"
)
args = parser.parse_args()
_, message = accept_changes(args.input_file, args.output_file)
print(message)
if "Error" in message:
raise SystemExit(1)
"""Add comments to DOCX documents.
Usage:
python comment.py unpacked/ 0 "Comment text"
python comment.py unpacked/ 1 "Reply text" --parent 0
Text should be pre-escaped XML (e.g., & for &, ’ for smart quotes).
After running, add markers to document.xml:
<w:commentRangeStart w:id="0"/>
... commented content ...
<w:commentRangeEnd w:id="0"/>
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="0"/></w:r>
"""
import argparse
import random
import shutil
import sys
from datetime import datetime, timezone
from pathlib import Path
import defusedxml.minidom
TEMPLATE_DIR = Path(__file__).parent / "templates"
NS = {
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
"w14": "http://schemas.microsoft.com/office/word/2010/wordml",
"w15": "http://schemas.microsoft.com/office/word/2012/wordml",
"w16cid": "http://schemas.microsoft.com/office/word/2016/wordml/cid",
"w16cex": "http://schemas.microsoft.com/office/word/2018/wordml/cex",
}
COMMENT_XML = """\
<w:comment w:id="{id}" w:author="{author}" w:date="{date}" w:initials="{initials}">
<w:p w14:paraId="{para_id}" w14:textId="77777777">
<w:r>
<w:rPr><w:rStyle w:val="CommentReference"/></w:rPr>
<w:annotationRef/>
</w:r>
<w:r>
<w:rPr>
<w:color w:val="000000"/>
<w:sz w:val="20"/>
<w:szCs w:val="20"/>
</w:rPr>
<w:t>{text}</w:t>
</w:r>
</w:p>
</w:comment>"""
COMMENT_MARKER_TEMPLATE = """
Add to document.xml (markers must be direct children of w:p, never inside w:r):
<w:commentRangeStart w:id="{cid}"/>
<w:r>...</w:r>
<w:commentRangeEnd w:id="{cid}"/>
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="{cid}"/></w:r>"""
REPLY_MARKER_TEMPLATE = """
Nest markers inside parent {pid}'s markers (markers must be direct children of w:p, never inside w:r):
<w:commentRangeStart w:id="{pid}"/><w:commentRangeStart w:id="{cid}"/>
<w:r>...</w:r>
<w:commentRangeEnd w:id="{cid}"/><w:commentRangeEnd w:id="{pid}"/>
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="{pid}"/></w:r>
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="{cid}"/></w:r>"""
def _generate_hex_id() -> str:
return f"{random.randint(0, 0x7FFFFFFE):08X}"
SMART_QUOTE_ENTITIES = {
"\u201c": "“",
"\u201d": "”",
"\u2018": "‘",
"\u2019": "’",
}
def _encode_smart_quotes(text: str) -> str:
for char, entity in SMART_QUOTE_ENTITIES.items():
text = text.replace(char, entity)
return text
def _append_xml(xml_path: Path, root_tag: str, content: str) -> None:
dom = defusedxml.minidom.parseString(xml_path.read_text(encoding="utf-8"))
root = dom.getElementsByTagName(root_tag)[0]
ns_attrs = " ".join(f'xmlns:{k}="{v}"' for k, v in NS.items())
wrapper_dom = defusedxml.minidom.parseString(f"<root {ns_attrs}>{content}</root>")
for child in wrapper_dom.documentElement.childNodes:
if child.nodeType == child.ELEMENT_NODE:
root.appendChild(dom.importNode(child, True))
output = _encode_smart_quotes(dom.toxml(encoding="UTF-8").decode("utf-8"))
xml_path.write_text(output, encoding="utf-8")
def _find_para_id(comments_path: Path, comment_id: int) -> str | None:
dom = defusedxml.minidom.parseString(comments_path.read_text(encoding="utf-8"))
for c in dom.getElementsByTagName("w:comment"):
if c.getAttribute("w:id") == str(comment_id):
for p in c.getElementsByTagName("w:p"):
if pid := p.getAttribute("w14:paraId"):
return pid
return None
def _get_next_rid(rels_path: Path) -> int:
dom = defusedxml.minidom.parseString(rels_path.read_text(encoding="utf-8"))
max_rid = 0
for rel in dom.getElementsByTagName("Relationship"):
rid = rel.getAttribute("Id")
if rid and rid.startswith("rId"):
try:
max_rid = max(max_rid, int(rid[3:]))
except ValueError:
pass
return max_rid + 1
def _has_relationship(rels_path: Path, target: str) -> bool:
dom = defusedxml.minidom.parseString(rels_path.read_text(encoding="utf-8"))
for rel in dom.getElementsByTagName("Relationship"):
if rel.getAttribute("Target") == target:
return True
return False
def _has_content_type(ct_path: Path, part_name: str) -> bool:
dom = defusedxml.minidom.parseString(ct_path.read_text(encoding="utf-8"))
for override in dom.getElementsByTagName("Override"):
if override.getAttribute("PartName") == part_name:
return True
return False
def _ensure_comment_relationships(unpacked_dir: Path) -> None:
rels_path = unpacked_dir / "word" / "_rels" / "document.xml.rels"
if not rels_path.exists():
return
if _has_relationship(rels_path, "comments.xml"):
return
dom = defusedxml.minidom.parseString(rels_path.read_text(encoding="utf-8"))
root = dom.documentElement
next_rid = _get_next_rid(rels_path)
rels = [
(
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments",
"comments.xml",
),
(
"http://schemas.microsoft.com/office/2011/relationships/commentsExtended",
"commentsExtended.xml",
),
(
"http://schemas.microsoft.com/office/2016/09/relationships/commentsIds",
"commentsIds.xml",
),
(
"http://schemas.microsoft.com/office/2018/08/relationships/commentsExtensible",
"commentsExtensible.xml",
),
]
for rel_type, target in rels:
rel = dom.createElement("Relationship")
rel.setAttribute("Id", f"rId{next_rid}")
rel.setAttribute("Type", rel_type)
rel.setAttribute("Target", target)
root.appendChild(rel)
next_rid += 1
rels_path.write_bytes(dom.toxml(encoding="UTF-8"))
def _ensure_comment_content_types(unpacked_dir: Path) -> None:
ct_path = unpacked_dir / "[Content_Types].xml"
if not ct_path.exists():
return
if _has_content_type(ct_path, "/word/comments.xml"):
return
dom = defusedxml.minidom.parseString(ct_path.read_text(encoding="utf-8"))
root = dom.documentElement
overrides = [
(
"/word/comments.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml",
),
(
"/word/commentsExtended.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml",
),
(
"/word/commentsIds.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.commentsIds+xml",
),
(
"/word/commentsExtensible.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtensible+xml",
),
]
for part_name, content_type in overrides:
override = dom.createElement("Override")
override.setAttribute("PartName", part_name)
override.setAttribute("ContentType", content_type)
root.appendChild(override)
ct_path.write_bytes(dom.toxml(encoding="UTF-8"))
def add_comment(
unpacked_dir: str,
comment_id: int,
text: str,
author: str = "Claude",
initials: str = "C",
parent_id: int | None = None,
) -> tuple[str, str]:
word = Path(unpacked_dir) / "word"
if not word.exists():
return "", f"Error: {word} not found"
para_id, durable_id = _generate_hex_id(), _generate_hex_id()
ts = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
comments = word / "comments.xml"
first_comment = not comments.exists()
if first_comment:
shutil.copy(TEMPLATE_DIR / "comments.xml", comments)
_ensure_comment_relationships(Path(unpacked_dir))
_ensure_comment_content_types(Path(unpacked_dir))
_append_xml(
comments,
"w:comments",
COMMENT_XML.format(
id=comment_id,
author=author,
date=ts,
initials=initials,
para_id=para_id,
text=text,
),
)
ext = word / "commentsExtended.xml"
if not ext.exists():
shutil.copy(TEMPLATE_DIR / "commentsExtended.xml", ext)
if parent_id is not None:
parent_para = _find_para_id(comments, parent_id)
if not parent_para:
return "", f"Error: Parent comment {parent_id} not found"
_append_xml(
ext,
"w15:commentsEx",
f'<w15:commentEx w15:paraId="{para_id}" w15:paraIdParent="{parent_para}" w15:done="0"/>',
)
else:
_append_xml(
ext,
"w15:commentsEx",
f'<w15:commentEx w15:paraId="{para_id}" w15:done="0"/>',
)
ids = word / "commentsIds.xml"
if not ids.exists():
shutil.copy(TEMPLATE_DIR / "commentsIds.xml", ids)
_append_xml(
ids,
"w16cid:commentsIds",
f'<w16cid:commentId w16cid:paraId="{para_id}" w16cid:durableId="{durable_id}"/>',
)
extensible = word / "commentsExtensible.xml"
if not extensible.exists():
shutil.copy(TEMPLATE_DIR / "commentsExtensible.xml", extensible)
_append_xml(
extensible,
"w16cex:commentsExtensible",
f'<w16cex:commentExtensible w16cex:durableId="{durable_id}" w16cex:dateUtc="{ts}"/>',
)
action = "reply" if parent_id is not None else "comment"
return para_id, f"Added {action} {comment_id} (para_id={para_id})"
if __name__ == "__main__":
p = argparse.ArgumentParser(description="Add comments to DOCX documents")
p.add_argument("unpacked_dir", help="Unpacked DOCX directory")
p.add_argument("comment_id", type=int, help="Comment ID (must be unique)")
p.add_argument("text", help="Comment text")
p.add_argument("--author", default="Claude", help="Author name")
p.add_argument("--initials", default="C", help="Author initials")
p.add_argument("--parent", type=int, help="Parent comment ID (for replies)")
args = p.parse_args()
para_id, msg = add_comment(
args.unpacked_dir,
args.comment_id,
args.text,
args.author,
args.initials,
args.parent,
)
print(msg)
if "Error" in msg:
sys.exit(1)
cid = args.comment_id
if args.parent is not None:
print(REPLY_MARKER_TEMPLATE.format(pid=args.parent, cid=cid))
else:
print(COMMENT_MARKER_TEMPLATE.format(cid=cid))
"""Merge adjacent runs with identical formatting in DOCX.
Merges adjacent <w:r> elements that have identical <w:rPr> properties.
Works on runs in paragraphs and inside tracked changes (<w:ins>, <w:del>).
Also:
- Removes rsid attributes from runs (revision metadata that doesn't affect rendering)
- Removes proofErr elements (spell/grammar markers that block merging)
"""
from pathlib import Path
import defusedxml.minidom
def merge_runs(input_dir: str) -> tuple[int, str]:
doc_xml = Path(input_dir) / "word" / "document.xml"
if not doc_xml.exists():
return 0, f"Error: {doc_xml} not found"
try:
dom = defusedxml.minidom.parseString(doc_xml.read_text(encoding="utf-8"))
root = dom.documentElement
_remove_elements(root, "proofErr")
_strip_run_rsid_attrs(root)
containers = {run.parentNode for run in _find_elements(root, "r")}
merge_count = 0
for container in containers:
merge_count += _merge_runs_in(container)
doc_xml.write_bytes(dom.toxml(encoding="UTF-8"))
return merge_count, f"Merged {merge_count} runs"
except Exception as e:
return 0, f"Error: {e}"
def _find_elements(root, tag: str) -> list:
results = []
def traverse(node):
if node.nodeType == node.ELEMENT_NODE:
name = node.localName or node.tagName
if name == tag or name.endswith(f":{tag}"):
results.append(node)
for child in node.childNodes:
traverse(child)
traverse(root)
return results
def _get_child(parent, tag: str):
for child in parent.childNodes:
if child.nodeType == child.ELEMENT_NODE:
name = child.localName or child.tagName
if name == tag or name.endswith(f":{tag}"):
return child
return None
def _get_children(parent, tag: str) -> list:
results = []
for child in parent.childNodes:
if child.nodeType == child.ELEMENT_NODE:
name = child.localName or child.tagName
if name == tag or name.endswith(f":{tag}"):
results.append(child)
return results
def _is_adjacent(elem1, elem2) -> bool:
node = elem1.nextSibling
while node:
if node == elem2:
return True
if node.nodeType == node.ELEMENT_NODE:
return False
if node.nodeType == node.TEXT_NODE and node.data.strip():
return False
node = node.nextSibling
return False
def _remove_elements(root, tag: str):
for elem in _find_elements(root, tag):
if elem.parentNode:
elem.parentNode.removeChild(elem)
def _strip_run_rsid_attrs(root):
for run in _find_elements(root, "r"):
for attr in list(run.attributes.values()):
if "rsid" in attr.name.lower():
run.removeAttribute(attr.name)
def _merge_runs_in(container) -> int:
merge_count = 0
run = _first_child_run(container)
while run:
while True:
next_elem = _next_element_sibling(run)
if next_elem and _is_run(next_elem) and _can_merge(run, next_elem):
_merge_run_content(run, next_elem)
container.removeChild(next_elem)
merge_count += 1
else:
break
_consolidate_text(run)
run = _next_sibling_run(run)
return merge_count
def _first_child_run(container):
for child in container.childNodes:
if child.nodeType == child.ELEMENT_NODE and _is_run(child):
return child
return None
def _next_element_sibling(node):
sibling = node.nextSibling
while sibling:
if sibling.nodeType == sibling.ELEMENT_NODE:
return sibling
sibling = sibling.nextSibling
return None
def _next_sibling_run(node):
sibling = node.nextSibling
while sibling:
if sibling.nodeType == sibling.ELEMENT_NODE:
if _is_run(sibling):
return sibling
sibling = sibling.nextSibling
return None
def _is_run(node) -> bool:
name = node.localName or node.tagName
return name == "r" or name.endswith(":r")
def _can_merge(run1, run2) -> bool:
rpr1 = _get_child(run1, "rPr")
rpr2 = _get_child(run2, "rPr")
if (rpr1 is None) != (rpr2 is None):
return False
if rpr1 is None:
return True
return rpr1.toxml() == rpr2.toxml()
def _merge_run_content(target, source):
for child in list(source.childNodes):
if child.nodeType == child.ELEMENT_NODE:
name = child.localName or child.tagName
if name != "rPr" and not name.endswith(":rPr"):
target.appendChild(child)
def _consolidate_text(run):
t_elements = _get_children(run, "t")
for i in range(len(t_elements) - 1, 0, -1):
curr, prev = t_elements[i], t_elements[i - 1]
if _is_adjacent(prev, curr):
prev_text = prev.firstChild.data if prev.firstChild else ""
curr_text = curr.firstChild.data if curr.firstChild else ""
merged = prev_text + curr_text
if prev.firstChild:
prev.firstChild.data = merged
else:
prev.appendChild(run.ownerDocument.createTextNode(merged))
if merged.startswith(" ") or merged.endswith(" "):
prev.setAttribute("xml:space", "preserve")
elif prev.hasAttribute("xml:space"):
prev.removeAttribute("xml:space")
run.removeChild(curr)
"""Simplify tracked changes by merging adjacent w:ins or w:del elements.
Merges adjacent <w:ins> elements from the same author into a single element.
Same for <w:del> elements. This makes heavily-redlined documents easier to
work with by reducing the number of tracked change wrappers.
Rules:
- Only merges w:ins with w:ins, w:del with w:del (same element type)
- Only merges if same author (ignores timestamp differences)
- Only merges if truly adjacent (only whitespace between them)
"""
import xml.etree.ElementTree as ET
import zipfile
from pathlib import Path
import defusedxml.minidom
WORD_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
def simplify_redlines(input_dir: str) -> tuple[int, str]:
doc_xml = Path(input_dir) / "word" / "document.xml"
if not doc_xml.exists():
return 0, f"Error: {doc_xml} not found"
try:
dom = defusedxml.minidom.parseString(doc_xml.read_text(encoding="utf-8"))
root = dom.documentElement
merge_count = 0
containers = _find_elements(root, "p") + _find_elements(root, "tc")
for container in containers:
merge_count += _merge_tracked_changes_in(container, "ins")
merge_count += _merge_tracked_changes_in(container, "del")
doc_xml.write_bytes(dom.toxml(encoding="UTF-8"))
return merge_count, f"Simplified {merge_count} tracked changes"
except Exception as e:
return 0, f"Error: {e}"
def _merge_tracked_changes_in(container, tag: str) -> int:
merge_count = 0
tracked = [
child
for child in container.childNodes
if child.nodeType == child.ELEMENT_NODE and _is_element(child, tag)
]
if len(tracked) < 2:
return 0
i = 0
while i < len(tracked) - 1:
curr = tracked[i]
next_elem = tracked[i + 1]
if _can_merge_tracked(curr, next_elem):
_merge_tracked_content(curr, next_elem)
container.removeChild(next_elem)
tracked.pop(i + 1)
merge_count += 1
else:
i += 1
return merge_count
def _is_element(node, tag: str) -> bool:
name = node.localName or node.tagName
return name == tag or name.endswith(f":{tag}")
def _get_author(elem) -> str:
author = elem.getAttribute("w:author")
if not author:
for attr in elem.attributes.values():
if attr.localName == "author" or attr.name.endswith(":author"):
return attr.value
return author
def _can_merge_tracked(elem1, elem2) -> bool:
if _get_author(elem1) != _get_author(elem2):
return False
node = elem1.nextSibling
while node and node != elem2:
if node.nodeType == node.ELEMENT_NODE:
return False
if node.nodeType == node.TEXT_NODE and node.data.strip():
return False
node = node.nextSibling
return True
def _merge_tracked_content(target, source):
while source.firstChild:
child = source.firstChild
source.removeChild(child)
target.appendChild(child)
def _find_elements(root, tag: str) -> list:
results = []
def traverse(node):
if node.nodeType == node.ELEMENT_NODE:
name = node.localName or node.tagName
if name == tag or name.endswith(f":{tag}"):
results.append(node)
for child in node.childNodes:
traverse(child)
traverse(root)
return results
def get_tracked_change_authors(doc_xml_path: Path) -> dict[str, int]:
if not doc_xml_path.exists():
return {}
try:
tree = ET.parse(doc_xml_path)
root = tree.getroot()
except ET.ParseError:
return {}
namespaces = {"w": WORD_NS}
author_attr = f"{{{WORD_NS}}}author"
authors: dict[str, int] = {}
for tag in ["ins", "del"]:
for elem in root.findall(f".//w:{tag}", namespaces):
author = elem.get(author_attr)
if author:
authors[author] = authors.get(author, 0) + 1
return authors
def _get_authors_from_docx(docx_path: Path) -> dict[str, int]:
try:
with zipfile.ZipFile(docx_path, "r") as zf:
if "word/document.xml" not in zf.namelist():
return {}
with zf.open("word/document.xml") as f:
tree = ET.parse(f)
root = tree.getroot()
namespaces = {"w": WORD_NS}
author_attr = f"{{{WORD_NS}}}author"
authors: dict[str, int] = {}
for tag in ["ins", "del"]:
for elem in root.findall(f".//w:{tag}", namespaces):
author = elem.get(author_attr)
if author:
authors[author] = authors.get(author, 0) + 1
return authors
except (zipfile.BadZipFile, ET.ParseError):
return {}
def infer_author(modified_dir: Path, original_docx: Path, default: str = "Claude") -> str:
modified_xml = modified_dir / "word" / "document.xml"
modified_authors = get_tracked_change_authors(modified_xml)
if not modified_authors:
return default
original_authors = _get_authors_from_docx(original_docx)
new_changes: dict[str, int] = {}
for author, count in modified_authors.items():
original_count = original_authors.get(author, 0)
diff = count - original_count
if diff > 0:
new_changes[author] = diff
if not new_changes:
return default
if len(new_changes) == 1:
return next(iter(new_changes))
raise ValueError(
f"Multiple authors added new changes: {new_changes}. "
"Cannot infer which author to validate."
)
"""Pack a directory into a DOCX, PPTX, or XLSX file.
Validates with auto-repair, condenses XML formatting, and creates the Office file.
Usage:
python pack.py <input_directory> <output_file> [--original <file>] [--validate true|false]
Examples:
python pack.py unpacked/ output.docx --original input.docx
python pack.py unpacked/ output.pptx --validate false
"""
import argparse
import sys
import shutil
import tempfile
import zipfile
from pathlib import Path
import defusedxml.minidom
from validators import DOCXSchemaValidator, PPTXSchemaValidator, RedliningValidator
def pack(
input_directory: str,
output_file: str,
original_file: str | None = None,
validate: bool = True,
infer_author_func=None,
) -> tuple[None, str]:
input_dir = Path(input_directory)
output_path = Path(output_file)
suffix = output_path.suffix.lower()
if not input_dir.is_dir():
return None, f"Error: {input_dir} is not a directory"
if suffix not in {".docx", ".pptx", ".xlsx"}:
return None, f"Error: {output_file} must be a .docx, .pptx, or .xlsx file"
if validate and original_file:
original_path = Path(original_file)
if original_path.exists():
success, output = _run_validation(
input_dir, original_path, suffix, infer_author_func
)
if output:
print(output)
if not success:
return None, f"Error: Validation failed for {input_dir}"
with tempfile.TemporaryDirectory() as temp_dir:
temp_content_dir = Path(temp_dir) / "content"
shutil.copytree(input_dir, temp_content_dir)
for pattern in ["*.xml", "*.rels"]:
for xml_file in temp_content_dir.rglob(pattern):
_condense_xml(xml_file)
output_path.parent.mkdir(parents=True, exist_ok=True)
with zipfile.ZipFile(output_path, "w", zipfile.ZIP_DEFLATED) as zf:
for f in temp_content_dir.rglob("*"):
if f.is_file():
zf.write(f, f.relative_to(temp_content_dir))
return None, f"Successfully packed {input_dir} to {output_file}"
def _run_validation(
unpacked_dir: Path,
original_file: Path,
suffix: str,
infer_author_func=None,
) -> tuple[bool, str | None]:
output_lines = []
validators = []
if suffix == ".docx":
author = "Claude"
if infer_author_func:
try:
author = infer_author_func(unpacked_dir, original_file)
except ValueError as e:
print(f"Warning: {e} Using default author 'Claude'.", file=sys.stderr)
validators = [
DOCXSchemaValidator(unpacked_dir, original_file),
RedliningValidator(unpacked_dir, original_file, author=author),
]
elif suffix == ".pptx":
validators = [PPTXSchemaValidator(unpacked_dir, original_file)]
if not validators:
return True, None
total_repairs = sum(v.repair() for v in validators)
if total_repairs:
output_lines.append(f"Auto-repaired {total_repairs} issue(s)")
success = all(v.validate() for v in validators)
if success:
output_lines.append("All validations PASSED!")
return success, "\n".join(output_lines) if output_lines else None
def _condense_xml(xml_file: Path) -> None:
try:
with open(xml_file, encoding="utf-8") as f:
dom = defusedxml.minidom.parse(f)
for element in dom.getElementsByTagName("*"):
if element.tagName.endswith(":t"):
continue
for child in list(element.childNodes):
if (
child.nodeType == child.TEXT_NODE
and child.nodeValue
and child.nodeValue.strip() == ""
) or child.nodeType == child.COMMENT_NODE:
element.removeChild(child)
xml_file.write_bytes(dom.toxml(encoding="UTF-8"))
except Exception as e:
print(f"ERROR: Failed to parse {xml_file.name}: {e}", file=sys.stderr)
raise
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Pack a directory into a DOCX, PPTX, or XLSX file"
)
parser.add_argument("input_directory", help="Unpacked Office document directory")
parser.add_argument("output_file", help="Output Office file (.docx/.pptx/.xlsx)")
parser.add_argument(
"--original",
help="Original file for validation comparison",
)
parser.add_argument(
"--validate",
type=lambda x: x.lower() == "true",
default=True,
metavar="true|false",
help="Run validation with auto-repair (default: true)",
)
args = parser.parse_args()
_, message = pack(
args.input_directory,
args.output_file,
original_file=args.original,
validate=args.validate,
)
print(message)
if "Error" in message:
sys.exit(1)
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing"
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing"
elementFormDefault="qualified">
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
schemaLocation="dml-main.xsd"/>
<xsd:complexType name="CT_ShapeNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvSpPr" type="a:CT_NonVisualDrawingShapeProps" minOccurs="1" maxOccurs="1"
/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Shape">
<xsd:sequence>
<xsd:element name="nvSpPr" type="CT_ShapeNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
<xsd:element name="txBody" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
<xsd:attribute name="textlink" type="xsd:string" use="optional"/>
<xsd:attribute name="fLocksText" type="xsd:boolean" use="optional" default="true"/>
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_ConnectorNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvCxnSpPr" type="a:CT_NonVisualConnectorProperties" minOccurs="1"
maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Connector">
<xsd:sequence>
<xsd:element name="nvCxnSpPr" type="CT_ConnectorNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_PictureNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties" minOccurs="1"
maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Picture">
<xsd:sequence>
<xsd:element name="nvPicPr" type="CT_PictureNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="blipFill" type="a:CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="macro" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_GraphicFrameNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties"
minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_GraphicFrame">
<xsd:sequence>
<xsd:element name="nvGraphicFramePr" type="CT_GraphicFrameNonVisual" minOccurs="1"
maxOccurs="1"/>
<xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_GroupShapeNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvGrpSpPr" type="a:CT_NonVisualGroupDrawingShapeProps" minOccurs="1"
maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_GroupShape">
<xsd:sequence>
<xsd:element name="nvGrpSpPr" type="CT_GroupShapeNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="grpSpPr" type="a:CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="sp" type="CT_Shape"/>
<xsd:element name="grpSp" type="CT_GroupShape"/>
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
<xsd:element name="cxnSp" type="CT_Connector"/>
<xsd:element name="pic" type="CT_Picture"/>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
<xsd:group name="EG_ObjectChoices">
<xsd:sequence>
<xsd:choice minOccurs="1" maxOccurs="1">
<xsd:element name="sp" type="CT_Shape"/>
<xsd:element name="grpSp" type="CT_GroupShape"/>
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
<xsd:element name="cxnSp" type="CT_Connector"/>
<xsd:element name="pic" type="CT_Picture"/>
</xsd:choice>
</xsd:sequence>
</xsd:group>
<xsd:simpleType name="ST_MarkerCoordinate">
<xsd:restriction base="xsd:double">
<xsd:minInclusive value="0.0"/>
<xsd:maxInclusive value="1.0"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_Marker">
<xsd:sequence>
<xsd:element name="x" type="ST_MarkerCoordinate" minOccurs="1" maxOccurs="1"/>
<xsd:element name="y" type="ST_MarkerCoordinate" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_RelSizeAnchor">
<xsd:sequence>
<xsd:element name="from" type="CT_Marker"/>
<xsd:element name="to" type="CT_Marker"/>
<xsd:group ref="EG_ObjectChoices"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_AbsSizeAnchor">
<xsd:sequence>
<xsd:element name="from" type="CT_Marker"/>
<xsd:element name="ext" type="a:CT_PositiveSize2D"/>
<xsd:group ref="EG_ObjectChoices"/>
</xsd:sequence>
</xsd:complexType>
<xsd:group name="EG_Anchor">
<xsd:choice>
<xsd:element name="relSizeAnchor" type="CT_RelSizeAnchor"/>
<xsd:element name="absSizeAnchor" type="CT_AbsSizeAnchor"/>
</xsd:choice>
</xsd:group>
<xsd:complexType name="CT_Drawing">
<xsd:sequence>
<xsd:group ref="EG_Anchor" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
elementFormDefault="qualified"
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas">
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
schemaLocation="dml-main.xsd"/>
<xsd:element name="lockedCanvas" type="a:CT_GvmlGroupShape"/>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.openxmlformats.org/drawingml/2006/picture"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" elementFormDefault="qualified"
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/picture">
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
schemaLocation="dml-main.xsd"/>
<xsd:complexType name="CT_PictureNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties" minOccurs="1"
maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Picture">
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="nvPicPr" type="CT_PictureNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="blipFill" type="a:CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="pic" type="CT_Picture"/>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
elementFormDefault="qualified">
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
schemaLocation="dml-main.xsd"/>
<xsd:import schemaLocation="shared-relationshipReference.xsd"
namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"/>
<xsd:element name="from" type="CT_Marker"/>
<xsd:element name="to" type="CT_Marker"/>
<xsd:complexType name="CT_AnchorClientData">
<xsd:attribute name="fLocksWithSheet" type="xsd:boolean" use="optional" default="true"/>
<xsd:attribute name="fPrintsWithSheet" type="xsd:boolean" use="optional" default="true"/>
</xsd:complexType>
<xsd:complexType name="CT_ShapeNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvSpPr" type="a:CT_NonVisualDrawingShapeProps" minOccurs="1" maxOccurs="1"
/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Shape">
<xsd:sequence>
<xsd:element name="nvSpPr" type="CT_ShapeNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
<xsd:element name="txBody" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
<xsd:attribute name="textlink" type="xsd:string" use="optional"/>
<xsd:attribute name="fLocksText" type="xsd:boolean" use="optional" default="true"/>
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_ConnectorNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvCxnSpPr" type="a:CT_NonVisualConnectorProperties" minOccurs="1"
maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Connector">
<xsd:sequence>
<xsd:element name="nvCxnSpPr" type="CT_ConnectorNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_PictureNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties" minOccurs="1"
maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Picture">
<xsd:sequence>
<xsd:element name="nvPicPr" type="CT_PictureNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="blipFill" type="a:CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="macro" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_GraphicalObjectFrameNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties"
minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_GraphicalObjectFrame">
<xsd:sequence>
<xsd:element name="nvGraphicFramePr" type="CT_GraphicalObjectFrameNonVisual" minOccurs="1"
maxOccurs="1"/>
<xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_GroupShapeNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvGrpSpPr" type="a:CT_NonVisualGroupDrawingShapeProps" minOccurs="1"
maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_GroupShape">
<xsd:sequence>
<xsd:element name="nvGrpSpPr" type="CT_GroupShapeNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="grpSpPr" type="a:CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="sp" type="CT_Shape"/>
<xsd:element name="grpSp" type="CT_GroupShape"/>
<xsd:element name="graphicFrame" type="CT_GraphicalObjectFrame"/>
<xsd:element name="cxnSp" type="CT_Connector"/>
<xsd:element name="pic" type="CT_Picture"/>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
<xsd:group name="EG_ObjectChoices">
<xsd:sequence>
<xsd:choice minOccurs="1" maxOccurs="1">
<xsd:element name="sp" type="CT_Shape"/>
<xsd:element name="grpSp" type="CT_GroupShape"/>
<xsd:element name="graphicFrame" type="CT_GraphicalObjectFrame"/>
<xsd:element name="cxnSp" type="CT_Connector"/>
<xsd:element name="pic" type="CT_Picture"/>
<xsd:element name="contentPart" type="CT_Rel"/>
</xsd:choice>
</xsd:sequence>
</xsd:group>
<xsd:complexType name="CT_Rel">
<xsd:attribute ref="r:id" use="required"/>
</xsd:complexType>
<xsd:simpleType name="ST_ColID">
<xsd:restriction base="xsd:int">
<xsd:minInclusive value="0"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_RowID">
<xsd:restriction base="xsd:int">
<xsd:minInclusive value="0"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_Marker">
<xsd:sequence>
<xsd:element name="col" type="ST_ColID"/>
<xsd:element name="colOff" type="a:ST_Coordinate"/>
<xsd:element name="row" type="ST_RowID"/>
<xsd:element name="rowOff" type="a:ST_Coordinate"/>
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="ST_EditAs">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="twoCell"/>
<xsd:enumeration value="oneCell"/>
<xsd:enumeration value="absolute"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_TwoCellAnchor">
<xsd:sequence>
<xsd:element name="from" type="CT_Marker"/>
<xsd:element name="to" type="CT_Marker"/>
<xsd:group ref="EG_ObjectChoices"/>
<xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="editAs" type="ST_EditAs" use="optional" default="twoCell"/>
</xsd:complexType>
<xsd:complexType name="CT_OneCellAnchor">
<xsd:sequence>
<xsd:element name="from" type="CT_Marker"/>
<xsd:element name="ext" type="a:CT_PositiveSize2D"/>
<xsd:group ref="EG_ObjectChoices"/>
<xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_AbsoluteAnchor">
<xsd:sequence>
<xsd:element name="pos" type="a:CT_Point2D"/>
<xsd:element name="ext" type="a:CT_PositiveSize2D"/>
<xsd:group ref="EG_ObjectChoices"/>
<xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:group name="EG_Anchor">
<xsd:choice>
<xsd:element name="twoCellAnchor" type="CT_TwoCellAnchor"/>
<xsd:element name="oneCellAnchor" type="CT_OneCellAnchor"/>
<xsd:element name="absoluteAnchor" type="CT_AbsoluteAnchor"/>
</xsd:choice>
</xsd:group>
<xsd:complexType name="CT_Drawing">
<xsd:sequence>
<xsd:group ref="EG_Anchor" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="wsDr" type="CT_Drawing"/>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
xmlns:dpct="http://schemas.openxmlformats.org/drawingml/2006/picture"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
elementFormDefault="qualified">
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
schemaLocation="dml-main.xsd"/>
<xsd:import schemaLocation="wml.xsd"
namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main"/>
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/picture"
schemaLocation="dml-picture.xsd"/>
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
schemaLocation="shared-relationshipReference.xsd"/>
<xsd:complexType name="CT_EffectExtent">
<xsd:attribute name="l" type="a:ST_Coordinate" use="required"/>
<xsd:attribute name="t" type="a:ST_Coordinate" use="required"/>
<xsd:attribute name="r" type="a:ST_Coordinate" use="required"/>
<xsd:attribute name="b" type="a:ST_Coordinate" use="required"/>
</xsd:complexType>
<xsd:simpleType name="ST_WrapDistance">
<xsd:restriction base="xsd:unsignedInt"/>
</xsd:simpleType>
<xsd:complexType name="CT_Inline">
<xsd:sequence>
<xsd:element name="extent" type="a:CT_PositiveSize2D"/>
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
<xsd:element name="docPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties"
minOccurs="0" maxOccurs="1"/>
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
</xsd:complexType>
<xsd:simpleType name="ST_WrapText">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="bothSides"/>
<xsd:enumeration value="left"/>
<xsd:enumeration value="right"/>
<xsd:enumeration value="largest"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_WrapPath">
<xsd:sequence>
<xsd:element name="start" type="a:CT_Point2D" minOccurs="1" maxOccurs="1"/>
<xsd:element name="lineTo" type="a:CT_Point2D" minOccurs="2" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="edited" type="xsd:boolean" use="optional"/>
</xsd:complexType>
<xsd:complexType name="CT_WrapNone"/>
<xsd:complexType name="CT_WrapSquare">
<xsd:sequence>
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
</xsd:complexType>
<xsd:complexType name="CT_WrapTight">
<xsd:sequence>
<xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
</xsd:complexType>
<xsd:complexType name="CT_WrapThrough">
<xsd:sequence>
<xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
</xsd:complexType>
<xsd:complexType name="CT_WrapTopBottom">
<xsd:sequence>
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
</xsd:complexType>
<xsd:group name="EG_WrapType">
<xsd:sequence>
<xsd:choice minOccurs="1" maxOccurs="1">
<xsd:element name="wrapNone" type="CT_WrapNone" minOccurs="1" maxOccurs="1"/>
<xsd:element name="wrapSquare" type="CT_WrapSquare" minOccurs="1" maxOccurs="1"/>
<xsd:element name="wrapTight" type="CT_WrapTight" minOccurs="1" maxOccurs="1"/>
<xsd:element name="wrapThrough" type="CT_WrapThrough" minOccurs="1" maxOccurs="1"/>
<xsd:element name="wrapTopAndBottom" type="CT_WrapTopBottom" minOccurs="1" maxOccurs="1"/>
</xsd:choice>
</xsd:sequence>
</xsd:group>
<xsd:simpleType name="ST_PositionOffset">
<xsd:restriction base="xsd:int"/>
</xsd:simpleType>
<xsd:simpleType name="ST_AlignH">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="left"/>
<xsd:enumeration value="right"/>
<xsd:enumeration value="center"/>
<xsd:enumeration value="inside"/>
<xsd:enumeration value="outside"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_RelFromH">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="margin"/>
<xsd:enumeration value="page"/>
<xsd:enumeration value="column"/>
<xsd:enumeration value="character"/>
<xsd:enumeration value="leftMargin"/>
<xsd:enumeration value="rightMargin"/>
<xsd:enumeration value="insideMargin"/>
<xsd:enumeration value="outsideMargin"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_PosH">
<xsd:sequence>
<xsd:choice minOccurs="1" maxOccurs="1">
<xsd:element name="align" type="ST_AlignH" minOccurs="1" maxOccurs="1"/>
<xsd:element name="posOffset" type="ST_PositionOffset" minOccurs="1" maxOccurs="1"/>
</xsd:choice>
</xsd:sequence>
<xsd:attribute name="relativeFrom" type="ST_RelFromH" use="required"/>
</xsd:complexType>
<xsd:simpleType name="ST_AlignV">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="top"/>
<xsd:enumeration value="bottom"/>
<xsd:enumeration value="center"/>
<xsd:enumeration value="inside"/>
<xsd:enumeration value="outside"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_RelFromV">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="margin"/>
<xsd:enumeration value="page"/>
<xsd:enumeration value="paragraph"/>
<xsd:enumeration value="line"/>
<xsd:enumeration value="topMargin"/>
<xsd:enumeration value="bottomMargin"/>
<xsd:enumeration value="insideMargin"/>
<xsd:enumeration value="outsideMargin"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_PosV">
<xsd:sequence>
<xsd:choice minOccurs="1" maxOccurs="1">
<xsd:element name="align" type="ST_AlignV" minOccurs="1" maxOccurs="1"/>
<xsd:element name="posOffset" type="ST_PositionOffset" minOccurs="1" maxOccurs="1"/>
</xsd:choice>
</xsd:sequence>
<xsd:attribute name="relativeFrom" type="ST_RelFromV" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_Anchor">
<xsd:sequence>
<xsd:element name="simplePos" type="a:CT_Point2D"/>
<xsd:element name="positionH" type="CT_PosH"/>
<xsd:element name="positionV" type="CT_PosV"/>
<xsd:element name="extent" type="a:CT_PositiveSize2D"/>
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
<xsd:group ref="EG_WrapType"/>
<xsd:element name="docPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties"
minOccurs="0" maxOccurs="1"/>
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
<xsd:attribute name="simplePos" type="xsd:boolean"/>
<xsd:attribute name="relativeHeight" type="xsd:unsignedInt" use="required"/>
<xsd:attribute name="behindDoc" type="xsd:boolean" use="required"/>
<xsd:attribute name="locked" type="xsd:boolean" use="required"/>
<xsd:attribute name="layoutInCell" type="xsd:boolean" use="required"/>
<xsd:attribute name="hidden" type="xsd:boolean" use="optional"/>
<xsd:attribute name="allowOverlap" type="xsd:boolean" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_TxbxContent">
<xsd:group ref="w:EG_BlockLevelElts" minOccurs="1" maxOccurs="unbounded"/>
</xsd:complexType>
<xsd:complexType name="CT_TextboxInfo">
<xsd:sequence>
<xsd:element name="txbxContent" type="CT_TxbxContent" minOccurs="1" maxOccurs="1"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:unsignedShort" use="optional" default="0"/>
</xsd:complexType>
<xsd:complexType name="CT_LinkedTextboxInformation">
<xsd:sequence>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:unsignedShort" use="required"/>
<xsd:attribute name="seq" type="xsd:unsignedShort" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_WordprocessingShape">
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/>
<xsd:choice minOccurs="1" maxOccurs="1">
<xsd:element name="cNvSpPr" type="a:CT_NonVisualDrawingShapeProps" minOccurs="1"
maxOccurs="1"/>
<xsd:element name="cNvCnPr" type="a:CT_NonVisualConnectorProperties" minOccurs="1"
maxOccurs="1"/>
</xsd:choice>
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
<xsd:choice minOccurs="0" maxOccurs="1">
<xsd:element name="txbx" type="CT_TextboxInfo" minOccurs="1" maxOccurs="1"/>
<xsd:element name="linkedTxbx" type="CT_LinkedTextboxInformation" minOccurs="1"
maxOccurs="1"/>
</xsd:choice>
<xsd:element name="bodyPr" type="a:CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="normalEastAsianFlow" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_GraphicFrame">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvFrPr" type="a:CT_NonVisualGraphicFrameProperties" minOccurs="1"
maxOccurs="1"/>
<xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_WordprocessingContentPartNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/>
<xsd:element name="cNvContentPartPr" type="a:CT_NonVisualContentPartProperties" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_WordprocessingContentPart">
<xsd:sequence>
<xsd:element name="nvContentPartPr" type="CT_WordprocessingContentPartNonVisual" minOccurs="0" maxOccurs="1"/>
<xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="0" maxOccurs="1"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="bwMode" type="a:ST_BlackWhiteMode" use="optional"/>
<xsd:attribute ref="r:id" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_WordprocessingGroup">
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/>
<xsd:element name="cNvGrpSpPr" type="a:CT_NonVisualGroupDrawingShapeProps" minOccurs="1"
maxOccurs="1"/>
<xsd:element name="grpSpPr" type="a:CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="wsp"/>
<xsd:element name="grpSp" type="CT_WordprocessingGroup"/>
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
<xsd:element ref="dpct:pic"/>
<xsd:element name="contentPart" type="CT_WordprocessingContentPart"/>
</xsd:choice>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_WordprocessingCanvas">
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="bg" type="a:CT_BackgroundFormatting" minOccurs="0" maxOccurs="1"/>
<xsd:element name="whole" type="a:CT_WholeE2oFormatting" minOccurs="0" maxOccurs="1"/>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="wsp"/>
<xsd:element ref="dpct:pic"/>
<xsd:element name="contentPart" type="CT_WordprocessingContentPart"/>
<xsd:element ref="wgp"/>
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
</xsd:choice>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="wpc" type="CT_WordprocessingCanvas"/>
<xsd:element name="wgp" type="CT_WordprocessingGroup"/>
<xsd:element name="wsp" type="CT_WordprocessingShape"/>
<xsd:element name="inline" type="CT_Inline"/>
<xsd:element name="anchor" type="CT_Anchor"/>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/characteristics"
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/characteristics"
elementFormDefault="qualified">
<xsd:complexType name="CT_AdditionalCharacteristics">
<xsd:sequence>
<xsd:element name="characteristic" type="CT_Characteristic" minOccurs="0"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Characteristic">
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="relation" type="ST_Relation" use="required"/>
<xsd:attribute name="val" type="xsd:string" use="required"/>
<xsd:attribute name="vocabulary" type="xsd:anyURI" use="optional"/>
</xsd:complexType>
<xsd:simpleType name="ST_Relation">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="ge"/>
<xsd:enumeration value="le"/>
<xsd:enumeration value="gt"/>
<xsd:enumeration value="lt"/>
<xsd:enumeration value="eq"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:element name="additionalCharacteristics" type="CT_AdditionalCharacteristics"/>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/customXml"
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/customXml"
elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all">
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
schemaLocation="shared-commonSimpleTypes.xsd"/>
<xsd:complexType name="CT_DatastoreSchemaRef">
<xsd:attribute name="uri" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_DatastoreSchemaRefs">
<xsd:sequence>
<xsd:element name="schemaRef" type="CT_DatastoreSchemaRef" minOccurs="0" maxOccurs="unbounded"
/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_DatastoreItem">
<xsd:sequence>
<xsd:element name="schemaRefs" type="CT_DatastoreSchemaRefs" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="itemID" type="s:ST_Guid" use="required"/>
</xsd:complexType>
<xsd:element name="datastoreItem" type="CT_DatastoreItem"/>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.openxmlformats.org/schemaLibrary/2006/main"
targetNamespace="http://schemas.openxmlformats.org/schemaLibrary/2006/main"
attributeFormDefault="qualified" elementFormDefault="qualified">
<xsd:complexType name="CT_Schema">
<xsd:attribute name="uri" type="xsd:string" default=""/>
<xsd:attribute name="manifestLocation" type="xsd:string"/>
<xsd:attribute name="schemaLocation" type="xsd:string"/>
<xsd:attribute name="schemaLanguage" type="xsd:token"/>
</xsd:complexType>
<xsd:complexType name="CT_SchemaLibrary">
<xsd:sequence>
<xsd:element name="schema" type="CT_Schema" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="schemaLibrary" type="CT_SchemaLibrary"/>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"
xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"
blockDefault="#all" elementFormDefault="qualified">
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
schemaLocation="shared-documentPropertiesVariantTypes.xsd"/>
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
schemaLocation="shared-commonSimpleTypes.xsd"/>
<xsd:element name="Properties" type="CT_Properties"/>
<xsd:complexType name="CT_Properties">
<xsd:sequence>
<xsd:element name="property" minOccurs="0" maxOccurs="unbounded" type="CT_Property"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Property">
<xsd:choice minOccurs="1" maxOccurs="1">
<xsd:element ref="vt:vector"/>
<xsd:element ref="vt:array"/>
<xsd:element ref="vt:blob"/>
<xsd:element ref="vt:oblob"/>
<xsd:element ref="vt:empty"/>
<xsd:element ref="vt:null"/>
<xsd:element ref="vt:i1"/>
<xsd:element ref="vt:i2"/>
<xsd:element ref="vt:i4"/>
<xsd:element ref="vt:i8"/>
<xsd:element ref="vt:int"/>
<xsd:element ref="vt:ui1"/>
<xsd:element ref="vt:ui2"/>
<xsd:element ref="vt:ui4"/>
<xsd:element ref="vt:ui8"/>
<xsd:element ref="vt:uint"/>
<xsd:element ref="vt:r4"/>
<xsd:element ref="vt:r8"/>
<xsd:element ref="vt:decimal"/>
<xsd:element ref="vt:lpstr"/>
<xsd:element ref="vt:lpwstr"/>
<xsd:element ref="vt:bstr"/>
<xsd:element ref="vt:date"/>
<xsd:element ref="vt:filetime"/>
<xsd:element ref="vt:bool"/>
<xsd:element ref="vt:cy"/>
<xsd:element ref="vt:error"/>
<xsd:element ref="vt:stream"/>
<xsd:element ref="vt:ostream"/>
<xsd:element ref="vt:storage"/>
<xsd:element ref="vt:ostorage"/>
<xsd:element ref="vt:vstream"/>
<xsd:element ref="vt:clsid"/>
</xsd:choice>
<xsd:attribute name="fmtid" use="required" type="s:ST_Guid"/>
<xsd:attribute name="pid" use="required" type="xsd:int"/>
<xsd:attribute name="name" use="optional" type="xsd:string"/>
<xsd:attribute name="linkTarget" use="optional" type="xsd:string"/>
</xsd:complexType>
</xsd:schema>
Related skills
FAQ
What input formats does it support?
It supports PDF (OCR pipeline), Word (re-typesetting pipeline), Markdown (direct-convert pipeline), and project code or data (content-generation pipeline).
Where are output and intermediate files placed?
Intermediate files go in resources/ and final deliverables like .docx and .bib go in outputs/; nothing generated may be placed in the project root.