Initial QQwrite skill
This commit is contained in:
commit
28e04853f1
|
|
@ -0,0 +1,75 @@
|
||||||
|
---
|
||||||
|
name: qqwrite
|
||||||
|
description: Adjust manuscript Word documents to match journal or group writing templates. Use when the user asks QQwrite to format, restructure, clean, or align a .docx manuscript according to a Word template from the local template library, especially for scientific manuscripts, AFM-style templates, section order, title page metadata, abstract/keywords placement, headings, captions, references, SI pointers, and submission-ready Word formatting.
|
||||||
|
---
|
||||||
|
|
||||||
|
# QQwrite
|
||||||
|
|
||||||
|
QQwrite is the Word-template execution skill for manuscript writing workflows. Its current scope is intentionally narrow: use a template from the local template library to adjust a user's manuscript Word file while preserving scientific meaning.
|
||||||
|
|
||||||
|
## Core Rule
|
||||||
|
|
||||||
|
Do not overwrite the source manuscript. Always create a revised copy and a short Markdown report.
|
||||||
|
|
||||||
|
Default outputs:
|
||||||
|
|
||||||
|
- `*_qqwrite_adjusted.docx`
|
||||||
|
- `*_qqwrite_report.md`
|
||||||
|
|
||||||
|
## Template Library
|
||||||
|
|
||||||
|
Use bundled templates first:
|
||||||
|
|
||||||
|
- `assets/templates/afm/article-template.docx` for Advanced Functional Materials-style manuscript formatting.
|
||||||
|
|
||||||
|
If the user provides another template path, use the user-provided template instead.
|
||||||
|
|
||||||
|
For template handling details, read `references/template-adjustment.md`.
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Identify inputs:
|
||||||
|
- source manuscript `.docx`
|
||||||
|
- template `.docx`
|
||||||
|
- target journal or template name if provided
|
||||||
|
- output directory
|
||||||
|
|
||||||
|
2. Preflight both documents:
|
||||||
|
- inspect section order and heading hierarchy
|
||||||
|
- compare title page fields, abstract, keywords, main text, methods, references, captions, acknowledgements, and supporting information pointers
|
||||||
|
- inspect paragraph styles, table count, figure-caption patterns, references section, and obvious empty or duplicated sections
|
||||||
|
- run `scripts/docx_template_audit.py` when a quick structural report is useful
|
||||||
|
|
||||||
|
3. Adjust only formatting and template structure unless the user explicitly asks for rewriting:
|
||||||
|
- move or relabel sections to match the template
|
||||||
|
- normalize heading levels
|
||||||
|
- normalize title, author, affiliation, abstract, keywords, captions, references, and acknowledgements placement
|
||||||
|
- preserve scientific claims, numbers, units, equations, citations, and figure/table labels
|
||||||
|
- flag unclear template conflicts in the report instead of guessing silently
|
||||||
|
|
||||||
|
4. Produce the revised Word file:
|
||||||
|
- copy the original manuscript first
|
||||||
|
- apply template-compatible styles and section order
|
||||||
|
- keep original content recoverable
|
||||||
|
- avoid converting citations to plain text unless unavoidable and reported
|
||||||
|
|
||||||
|
5. Produce the report:
|
||||||
|
- list template used
|
||||||
|
- list changed sections and formatting changes
|
||||||
|
- list unresolved issues requiring author decision
|
||||||
|
- list any content that appears missing relative to the template
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
|
||||||
|
- QQwrite does not decide manuscript novelty, literature strength, or reviewer risk. Route those tasks to QQsci.
|
||||||
|
- QQwrite does not generate Zotero/DeepSeek literature notes. Route those tasks to QQnote.
|
||||||
|
- QQwrite may lightly fix obvious Word-format inconsistencies, but substantial scientific rewriting belongs in QQsci or a future writing module expansion.
|
||||||
|
- For citation suggestions inside Word, follow QQsci's DOI-only comment convention if the task explicitly involves citation comments.
|
||||||
|
|
||||||
|
## Current Capability
|
||||||
|
|
||||||
|
Only one capability is active now:
|
||||||
|
|
||||||
|
`template-adjust-docx`: adjust a manuscript `.docx` according to a `.docx` template from the local library.
|
||||||
|
|
||||||
|
Future capabilities can be added later, but keep this skill focused on Word-template execution.
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
interface:
|
||||||
|
display_name: "QQwrite"
|
||||||
|
short_description: "Adjust manuscript Word documents to match writing templates."
|
||||||
|
default_prompt: "Help me adjust this manuscript Word document using a template from the template library. Preserve scientific meaning, compare structure and formatting with the template, and produce a revised .docx plus a short Markdown report."
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,62 @@
|
||||||
|
# Word Template Adjustment
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Make the user's manuscript follow the selected Word template without changing the scientific meaning.
|
||||||
|
|
||||||
|
## What To Compare
|
||||||
|
|
||||||
|
Compare these elements before editing:
|
||||||
|
|
||||||
|
- title page fields: title, authors, affiliations, corresponding author, abstract, keywords
|
||||||
|
- section order: introduction, results/discussion, conclusion, experimental/methods, acknowledgements, conflict of interest, data availability, references
|
||||||
|
- heading hierarchy and visible heading text
|
||||||
|
- figure and table caption style and numbering
|
||||||
|
- references section placement and numbering style
|
||||||
|
- SI references, graphical abstract/TOC notes, highlights, and cover letter cross-references when present
|
||||||
|
- page setup, margins, columns, headers/footers, and line spacing when detectable
|
||||||
|
|
||||||
|
## Editing Rules
|
||||||
|
|
||||||
|
- Work on a copied `.docx`; never overwrite the source.
|
||||||
|
- Prefer Word-native styles when available.
|
||||||
|
- Preserve all numbers, units, chemical formulas, gene/protein names, sample names, equations, citation markers, figure labels, and table labels.
|
||||||
|
- Do not silently delete content that has no obvious template location. Move it to the closest suitable section or flag it in the report.
|
||||||
|
- If the template contains placeholder text, replace only with matching manuscript content; remove unused placeholders in the revised copy.
|
||||||
|
- Keep references and citations intact. If field codes are lost by tooling, report that explicitly.
|
||||||
|
|
||||||
|
## Report Format
|
||||||
|
|
||||||
|
Use this Markdown shape:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# QQwrite Template Adjustment Report
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
- Manuscript:
|
||||||
|
- Template:
|
||||||
|
- Output:
|
||||||
|
|
||||||
|
## Changes Made
|
||||||
|
- ...
|
||||||
|
|
||||||
|
## Missing Or Unclear Items
|
||||||
|
- ...
|
||||||
|
|
||||||
|
## Checks
|
||||||
|
- Section order:
|
||||||
|
- Heading hierarchy:
|
||||||
|
- Captions:
|
||||||
|
- References:
|
||||||
|
- Citation fields:
|
||||||
|
```
|
||||||
|
|
||||||
|
## When To Stop And Ask
|
||||||
|
|
||||||
|
Ask the user before continuing if:
|
||||||
|
|
||||||
|
- the manuscript and template are for clearly different article types
|
||||||
|
- the manuscript has no recognizable title/abstract/main sections
|
||||||
|
- a template-required section is missing and cannot be inferred
|
||||||
|
- editing would require scientific rewriting rather than formatting/structure adjustment
|
||||||
|
- citation fields, equations, or embedded objects are at risk of being flattened
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Create a lightweight structural audit for a manuscript/template DOCX pair.
|
||||||
|
|
||||||
|
This script intentionally uses only the Python standard library. It inspects the
|
||||||
|
OOXML package directly and reports headings, paragraph-style usage, section-like
|
||||||
|
paragraphs, table count, and image count. It does not modify documents.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import collections
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import zipfile
|
||||||
|
from pathlib import Path
|
||||||
|
from xml.etree import ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
|
NS = {
|
||||||
|
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||||
|
"a": "http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SECTION_PATTERNS = [
|
||||||
|
"abstract",
|
||||||
|
"keywords",
|
||||||
|
"introduction",
|
||||||
|
"results",
|
||||||
|
"discussion",
|
||||||
|
"conclusion",
|
||||||
|
"experimental",
|
||||||
|
"methods",
|
||||||
|
"acknowledgements",
|
||||||
|
"acknowledgments",
|
||||||
|
"conflict of interest",
|
||||||
|
"data availability",
|
||||||
|
"references",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def read_xml(zf: zipfile.ZipFile, name: str) -> ET.Element | None:
|
||||||
|
try:
|
||||||
|
return ET.fromstring(zf.read(name))
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def text_from_paragraph(p: ET.Element) -> str:
|
||||||
|
parts = []
|
||||||
|
for t in p.findall(".//w:t", NS):
|
||||||
|
if t.text:
|
||||||
|
parts.append(t.text)
|
||||||
|
return "".join(parts).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def style_from_paragraph(p: ET.Element) -> str:
|
||||||
|
style = p.find("./w:pPr/w:pStyle", NS)
|
||||||
|
if style is None:
|
||||||
|
return "(none)"
|
||||||
|
return style.attrib.get(f"{{{NS['w']}}}val", "(unknown)")
|
||||||
|
|
||||||
|
|
||||||
|
def inspect_docx(path: Path) -> dict:
|
||||||
|
with zipfile.ZipFile(path) as zf:
|
||||||
|
document = read_xml(zf, "word/document.xml")
|
||||||
|
if document is None:
|
||||||
|
raise ValueError(f"{path} does not contain word/document.xml")
|
||||||
|
|
||||||
|
paragraphs = document.findall(".//w:p", NS)
|
||||||
|
tables = document.findall(".//w:tbl", NS)
|
||||||
|
drawings = document.findall(".//w:drawing", NS)
|
||||||
|
|
||||||
|
style_counts: collections.Counter[str] = collections.Counter()
|
||||||
|
headings = []
|
||||||
|
section_hits = []
|
||||||
|
nonempty_count = 0
|
||||||
|
|
||||||
|
for index, p in enumerate(paragraphs, start=1):
|
||||||
|
text = text_from_paragraph(p)
|
||||||
|
style = style_from_paragraph(p)
|
||||||
|
style_counts[style] += 1
|
||||||
|
if not text:
|
||||||
|
continue
|
||||||
|
nonempty_count += 1
|
||||||
|
normalized = re.sub(r"\s+", " ", text).strip().lower()
|
||||||
|
if style.lower().startswith("heading") or style.lower().startswith("title"):
|
||||||
|
headings.append({"index": index, "style": style, "text": text[:160]})
|
||||||
|
if any(pattern == normalized or normalized.startswith(pattern + ":") for pattern in SECTION_PATTERNS):
|
||||||
|
section_hits.append({"index": index, "style": style, "text": text[:160]})
|
||||||
|
|
||||||
|
return {
|
||||||
|
"path": str(path),
|
||||||
|
"paragraphs": len(paragraphs),
|
||||||
|
"nonempty_paragraphs": nonempty_count,
|
||||||
|
"tables": len(tables),
|
||||||
|
"drawings": len(drawings),
|
||||||
|
"top_styles": style_counts.most_common(20),
|
||||||
|
"headings": headings[:80],
|
||||||
|
"section_hits": section_hits[:80],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description="Audit a manuscript DOCX against a template DOCX.")
|
||||||
|
parser.add_argument("--manuscript", required=True, type=Path)
|
||||||
|
parser.add_argument("--template", required=True, type=Path)
|
||||||
|
parser.add_argument("--out", type=Path, help="Optional JSON output path.")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
report = {
|
||||||
|
"manuscript": inspect_docx(args.manuscript),
|
||||||
|
"template": inspect_docx(args.template),
|
||||||
|
}
|
||||||
|
|
||||||
|
payload = json.dumps(report, ensure_ascii=False, indent=2)
|
||||||
|
if args.out:
|
||||||
|
args.out.write_text(payload, encoding="utf-8")
|
||||||
|
else:
|
||||||
|
print(payload)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
Loading…
Reference in New Issue