paper2ppt Skill
Generate a professional academic literature review PowerPoint (English PPT) from a paper DOI, PMID, PMCID, URL, local PDF, or search query.
Language Policy
- PPT output language: English only. All slide titles, body text, labels, and citations are in English.
- Input language: Accepts Chinese or English input from the user.
- Paper language: Works with papers in any language. If the paper is in Chinese, translate extracted content to English for the PPT.
- Journal name: Preserve the original journal name (e.g., "中国循证医学杂志" stays as-is), prefix with English if known.
Robustness Rules (Read First)
Apply these to every phase.
- Every external call must have a timeout. Use
curl --connect-timeout 10 --max-time 30for HTTP requests. - Every external call must have a fallback. If CrossRef fails, try NCBI. If NCBI fails, try WebSearch.
- Never leave a slide blank. If figures are missing, add text content instead. If text is missing, use available metadata.
- Never fabricate data. If IF is not found, show "IF: N/A". Never guess or infer IF.
- Validate before running. Check file paths, check figure files are non-empty, syntax-check the script with
node --check. - Kill long-running processes. Set
timeout: 60000on all curl/Node.js calls. - Handle special characters. Strip HTML tags, escape problematic characters in text.
- Check output file. Verify the .pptx file exists and has non-zero size.
Workflow Overview
User provides paper source (DOI/PMID/PMCID/URL/PDF path/title)
│
▼
Phase 0: Identify paper → cross-validate → confirm → resolve DOI
│
▼
Phase 1: Fetch metadata (CrossRef + NCBI cross-validation)
│
▼
Phase 2: WebSearch → Impact Factor + JCR quartile
│
▼
Phase 3: Extract figures + tables + section text
│ ├─ 3.1 Online: publisher HTML → figure URLs
│ ├─ 3.2 PDF available: PyMuPDF embedded images
│ ├─ 3.3 Tables: pdfplumber → addTable reconstruction
│ └─ 3.4 Section text: WebFetch / PyMuPDF text extraction
│
▼
Phase 4: Generate PPTX → plan → write script → run → QA → fix loop
Phase 0: Paper Identification (with Cross-Validation)
0.1 Input Type Detection
| Input | Example | Detection Method |
|---|---|---|
| DOI | 10.1186/s12913-026-14482-6 | Regex: 10\.\d{4,}/[^\s]+ |
| PMID | 13170306 or PMID: 13170306 | Regex: ^\d{8}$ or PMID:\s*\d+ |
| PMCID | PMC13170306 | Starts with PMC |
| URL | https://doi.org/... / https://pubmed.ncbi.nlm.nih.gov/... | Starts with http |
| Local PDF | D:/path/to/file.pdf or C:\path\to\file.pdf | Ends with .pdf or contains \ or / with .pdf |
| Title | "latent tuberculosis infection China" | Free text, no identifier pattern |
0.2 Local PDF Entry (NEW)
When the user provides a local PDF file path:
# Verify the file exists
ls -la "{PDF_PATH}"
Step 1 — Extract PDF metadata:
import fitz
doc = fitz.open("{PDF_PATH}")
meta = doc.metadata # title, author, subject
first_page = doc[0].get_text()[:2000] # first page text for DOI/title search
Step 2 — Search for DOI in first page text:
import re
doi_match = re.search(r'10\.\d{4,}/[^\s\)\]]+', first_page)
doi = doi_match.group(0) if doi_match else None
Step 3 — If DOI found: Proceed to Phase 0.3 (resolve and verify). Step 4 — If no DOI: Extract the paper title from the first page (usually the first large text block before "Abstract" or authors). Use it to search CrossRef:
curl -s "https://api.crossref.org/works?query.title={URL_ENCODED_TITLE}&rows=3"
Pick the best match by comparing titles. Then proceed to verification.
0.3 Resolution to DOI
| Input | Method |
|---|---|
| DOI | Use directly |
| PMID | curl -s "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id={PMID}&retmode=json" → extract elocationid (DOI) |
| PMCID | curl -s "https://www.ncbi.nlm.nih.gov/pmc/utils/idconv/v1.0/?ids={PMCID}&format=json" → extract DOI |
| DOI URL | Extract DOI from path after / |
| PubMed URL | Extract PMID, then resolve as above |
| PMC URL | Extract PMCID, then resolve as above |
| Publisher URL | Extract DOI from URL path (Springer/Wiley/etc.) |
0.4 Paper Verification (CRITICAL — Do Not Skip)
Never trust a single source without cross-validation. Wrong papers happen when identifiers are mismatched, search returns the wrong result, or metadata is stale.
Verification procedure:
-
Fetch title from CrossRef using the resolved DOI:
curl -s "https://api.crossref.org/works/{DOI}?mailto=user@example.com" | python -c "import sys,json; d=json.load(sys.stdin); print(d['message']['title'][0])" -
Fetch title from NCBI (if PMID or PMCID was available):
curl -s "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&term={DOI}&retmode=json" | python -c "import sys,json; d=json.load(sys.stdin); print(d['result'][list(d['result'].keys())[0]]['title'])" -
Compare titles — if both sources are available, check they refer to the same paper:
- Extract ~50 chars from each title
- Compare normalized strings (lowercase, remove punctuation)
- If match confidence < 80%, ask the user to confirm: "I found two candidates: ... Which one is correct?"
- If only one source is available, show the title to the user and ask: "Is this the correct paper?"
-
User confirmation: After verification (successful or single-source), show the user:
Paper: {Title} Authors: {Authors} Journal: {Journal} ({Year}) DOI: {DOI} Proceed? (Y/N)Wait for confirmation. If the user says no, stop and ask for a corrected identifier.
-
If the user provides a PDF: Extract the title from the first page and the DOI. Cross-validate them with CrossRef. If they mismatch, warn the user.
CRITICAL RULE: If you are uncertain about the paper identity (>80% confident), do not proceed. Ask the user.
Phase 1: Metadata Fetching
1.1 Primary: CrossRef API
curl -s --connect-timeout 10 --max-time 30 \
"https://api.crossref.org/works/{URL_ENCODED_DOI}?mailto=user@example.com"
Fields to extract:
| Field | JSON Path | Usage |
|---|---|---|
| Title | message.title[0] | PPT title |
| Authors | message.author[] → {given} {family} | Author list |
| Journal | message.container-title[0] | Journal name |
| Publication date | message.published.date-parts[0] → [year, month, day] | Date |
| Volume | message.volume | Citation |
| Issue | message.issue | Citation |
| Pages | message.page | Citation |
| DOI | message.DOI | Citation |
| ISSN | message.ISSN[0] | IF/JCR lookup |
| Abstract | message.abstract | Background (strip HTML tags) |
| URL | message.URL | Publisher link |
Strip HTML tags from abstract: Use sed 's/<[^>]*>//g' or JavaScript .replace(/<[^>]*>/g, '').
Author formatting:
- List first 3 authors, then "et al." if more than 3
- Format: "Given Family", e.g. "G. Kucsko, J. Smith, et al."
- If author names are in Chinese characters, use the romanized form from CrossRef.
1.2 Fallback: NCBI E-utilities
If CrossRef is unreachable:
curl -s "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&term={DOI}&retmode=json"
Extract: title, authors, journal, date, volume, issue, pages, PMID.
1.3 Last Resort: WebSearch
If both CrossRef and NCBI fail, use WebSearch with the DOI or paper title to find the paper info from publisher snippets. Build the best-effort title slide and mark it as "metadata from web search."
Phase 2: Impact Factor and JCR Quartile Lookup
Step 1: Prepare search query
"[journal name]" "impact factor" {year}
Step 2: Extract IF
Parse snippets for "IF: