The skill metadata had drifted: every SKILL.md name field lacked the mpi- prefix, contradicting the directory names and the Agent Skills specification. Descriptions were also missing negative triggers, making it easy for the agent to load the wrong skill. Rewrote the pdf-to-docx skill to follow progressive disclosure: the main SKILL.md dropped from 318 lines to 80, with detailed code examples moved to on-demand references. Added uv run instructions and /// script PEP 723 metadata so dependencies are declared inline and installed automatically. Fixed the pptx skill's script paths and added CLI usage messages to both pptx scripts and the normalize script. Removed the empty self-review directory that was superseded by the unified translation-review skill.
80 lines
2.5 KiB
Python
80 lines
2.5 KiB
Python
# /// script
|
|
# requires-python = ">=3.9"
|
|
# dependencies = [
|
|
# "python-pptx",
|
|
# "pyyaml",
|
|
# ]
|
|
# ///
|
|
|
|
import sys, yaml
|
|
from pptx import Presentation
|
|
|
|
PLACEHOLDER_KINDS = {
|
|
1: "title", 2: "body", 3: "center_title",
|
|
4: "subtitle", 5: "body", 6: "body", 7: "body",
|
|
}
|
|
|
|
|
|
def shape_kind(shape):
|
|
if shape.has_table:
|
|
return "table"
|
|
try:
|
|
ph = shape.placeholder_format
|
|
if ph is not None and ph.type is not None:
|
|
return PLACEHOLDER_KINDS.get(ph.type, "body")
|
|
except ValueError:
|
|
pass
|
|
return "body"
|
|
|
|
|
|
def extract(pptx_path):
|
|
prs = Presentation(pptx_path)
|
|
entries = []
|
|
|
|
for slide_num, slide in enumerate(prs.slides, 1):
|
|
for shape_idx, shape in enumerate(slide.shapes):
|
|
kind = shape_kind(shape)
|
|
|
|
if shape.has_text_frame:
|
|
for para_idx, para in enumerate(shape.text_frame.paragraphs):
|
|
full = para.text.strip()
|
|
if not full:
|
|
continue
|
|
entries.append({
|
|
"slide": slide_num, "shape": shape_idx,
|
|
"run": para_idx, "kind": kind,
|
|
"zh": full, "en": "",
|
|
})
|
|
|
|
elif shape.has_table:
|
|
for row_idx, row in enumerate(shape.table.rows):
|
|
for col_idx, cell in enumerate(row.cells):
|
|
text = cell.text.strip()
|
|
if not text:
|
|
continue
|
|
entries.append({
|
|
"slide": slide_num, "shape": shape_idx,
|
|
"run": len(shape.table.rows) * col_idx + row_idx,
|
|
"kind": "table", "zh": text, "en": "",
|
|
})
|
|
|
|
if slide.has_notes_slide:
|
|
notes = slide.notes_slide.notes_text_frame.text.strip()
|
|
if notes:
|
|
entries.append({
|
|
"slide": slide_num, "shape": -1, "run": 0,
|
|
"kind": "notes", "zh": notes, "en": "",
|
|
})
|
|
|
|
return entries
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) != 3:
|
|
print("Usage: uv run extract.py <input.pptx> <output.yaml>", file=sys.stderr)
|
|
sys.exit(1)
|
|
entries = extract(sys.argv[1])
|
|
with open(sys.argv[2], "w") as f:
|
|
yaml.dump(entries, f, allow_unicode=True, default_flow_style=False, sort_keys=False)
|
|
print(f"Extracted {len(entries)} entries to {sys.argv[2]}")
|