Write the short academic abstract for a finished paper or thesis: pull the background, method, results, and conclusion moves from the paper itself, hold a word budget, copy result numbers exactly, keep citations out, pick keywords from terms the paper uses, and check every number in the abstract against the paper. Use when a paper or thesis is finished and needs an abstract, or when an existing abstract needs a check against its paper.
./install.sh abstract-writing-basicsname: abstract_writing_basics description: "Write the short academic abstract for a finished paper or thesis: pull the background, method, results, and conclusion moves from the paper itself, hold a word budget, copy result numbers exactly, keep citations out, pick keywords from terms the paper uses, and check every number in the abstract against the paper. Use when a paper or thesis is finished and needs an abstract, or when an existing abstract needs a check against its paper." metadata: { "includeInPrompt": true }
Write an abstract that reports the paper in front of you, in a short space, without adding anything the paper does not say. The routine extracts four moves from the finished paper itself, drafts them in order, holds a stated word budget, copies result numbers exactly, keeps citations out, picks keywords from terms the paper actually uses, and runs a final check that every number and claim in the abstract appears in the paper.
Scope:
python3 --version returned on the drafting machine, against a fixture built by the script itself in a temporary directory. The fixture run returned abstract_word_count: 42, budget_status: below, citations_found: 1, numbers_total: 2, numbers_missing_from_paper: 1, move_method_signal: missing, move_result_signal: present, verdict: REVIEW. The script uses only the Python standard library (os, re, and sys), so no package version is quoted and no install step is needed. What was NOT verified: no specific journal or university abstract limit was checked, and no specific venue limit is claimed. Word ranges in this skill are guidance to confirm with the target venue.python3 abstract_check.py ABSTRACT_FILE PAPER_FILE, adding --budget-min N --budget-max N when the venue limit differs from the default 150 to 250 range. The checker changes no file. It reports word count against the budget, citation markers found, numbers in the abstract that do not appear in the paper, and method and result move signals.Deliver these items, in this order:
Run: python3 abstract_check.py --make-fixture fixture builds the worked fixture in a folder named fixture, holding a paper.txt file and an abstract.txt file. Then run: python3 abstract_check.py fixture/abstract.txt fixture/paper.txt to reproduce the output below. Run it on real work with python3 abstract_check.py ABSTRACT_FILE PAPER_FILE and add --budget-min N --budget-max N when the venue limit differs from the default range.
Expected output for the fixture run:
text
abstract_file: fixture/abstract.txt
paper_file: fixture/paper.txt
abstract_word_count: 42
budget_min: 150
budget_max: 250
budget_status: below
citations_found: 1
CITATION marker=(Smith, 2020)
numbers_total: 2
numbers_missing_from_paper: 1
NUMBER_MISSING value=87
move_method_signal: missing
move_result_signal: present
verdict: REVIEW
The fixture is built to show each checker result once: the fixture abstract is short, at 42 words against the 150 to 250 default budget, so its budget status is below. It holds one citation marker, (Smith, 2020), and two numbers, of which one, 87, does not appear in the fixture paper, while 2020 does appear in the paper. It holds result language, so the result signal is present, and no method term from the check list, so the method signal is missing, which gives a verdict of REVIEW.
abstract_check.py (uses only the Python standard library). Save this code as abstract_check.py:
python
#!/usr/bin/env python3
"""Check an academic abstract against its paper.
Usage:
python3 abstract_check.py --make-fixture DIR
python3 abstract_check.py ABSTRACT_FILE PAPER_FILE [--budget-min N --budget-max N]
The default budget is 150 to 250 words. Pass --budget-min and
--budget-max to use the limit for a specific target venue.
Checks:
word count against the budget
citation markers in the abstract
numbers in the abstract that do not appear in the paper
move signals for method language and result language
Citation markers checked:
bracket markers with a digit, such as [1]
parenthetical markers with a four digit year, such as (Smith, 2020)
doi markers, such as doi:10.1000/example
Numbers are tokens matching digits with an optional decimal part,
such as 42 or 87.5. Comparison is by exact token text after commas
are removed.
Move signals are simple keyword checks, labeled as signals and
not proof. Method signal terms: method, recruited, assigned,
measured, survey, interview, randomi, participant, sample, trial.
Result signal terms: result, found, showed, scored, improved,
increased, decreased, reduced, fell, difference, percent,
compared, higher, lower. A signal is present when at least one
term appears in the abstract as a substring of the lowercased text.
Output prints the word count and budget status, each citation
marker found, each missing number, both move signals, and a
verdict. Exit code is 0 when both files can be read, 1 when a
file cannot be read, and 2 for bad arguments. Standard library
only.
"""
import os
import re
import sys
NUMBER_RE = re.compile(r"\d+(?:,\d{3})*(?:\.\d+)?")
CITATION_PATTERNS = [
re.compile(r"\[[^\]]*\d[^\]]*\]"),
re.compile(r"\([^)]*\b(?:18|19|20)\d{2}[a-z]?\b[^)]*\)"),
re.compile(r"doi:\S+", re.IGNORECASE),
]
METHOD_TERMS = [
"method",
"recruited",
"assigned",
"measured",
"survey",
"interview",
"randomi",
"participant",
"sample",
"trial",
]
RESULT_TERMS = [
"result",
"found",
"showed",
"scored",
"improved",
"increased",
"decreased",
"reduced",
"fell",
"difference",
"percent",
"compared",
"higher",
"lower",
]
def find_citations(text):
found = []
for pattern in CITATION_PATTERNS:
for match in pattern.finditer(text):
found.append((match.start(), match.group(0)))
found.sort(key=lambda item: (item[0], item[1]))
seen = set()
ordered = []
for pos, marker in found:
key = (pos, marker)
if key not in seen:
seen.add(key)
ordered.append(marker)
return ordered
def find_numbers(text):
numbers = []
seen = set()
for match in NUMBER_RE.finditer(text):
token = match.group(0).replace(",", "")
if token not in seen:
seen.add(token)
numbers.append(token)
return numbers
def check(abstract_path, paper_path, budget_min, budget_max):
if not os.path.isfile(abstract_path):
print(f"error: abstract file not found: {abstract_path}")
return 1
if not os.path.isfile(paper_path):
print(f"error: paper file not found: {paper_path}")
return 1
with open(abstract_path, "r", encoding="utf-8", errors="replace") as fh:
abstract = fh.read()
with open(paper_path, "r", encoding="utf-8", errors="replace") as fh:
paper = fh.read()
word_count = len(abstract.split())
if word_count < budget_min:
budget_status = "below"
elif word_count > budget_max:
budget_status = "above"
else:
budget_status = "within"
citations = find_citations(abstract)
abstract_numbers = find_numbers(abstract)
paper_numbers = set(find_numbers(paper))
missing_numbers = [n for n in abstract_numbers if n not in paper_numbers]
lower = abstract.lower()
method_signal = "present" if any(term in lower for term in METHOD_TERMS) else "missing"
result_signal = "present" if any(term in lower for term in RESULT_TERMS) else "missing"
print(f"abstract_file: {abstract_path}")
print(f"paper_file: {paper_path}")
print(f"abstract_word_count: {word_count}")
print(f"budget_min: {budget_min}")
print(f"budget_max: {budget_max}")
print(f"budget_status: {budget_status}")
print(f"citations_found: {len(citations)}")
for marker in citations:
print(f"CITATION marker={marker}")
print(f"numbers_total: {len(abstract_numbers)}")
print(f"numbers_missing_from_paper: {len(missing_numbers)}")
for number in missing_numbers:
print(f"NUMBER_MISSING value={number}")
print(f"move_method_signal: {method_signal}")
print(f"move_result_signal: {result_signal}")
ok = (
budget_status == "within"
and len(citations) == 0
and len(missing_numbers) == 0
and method_signal == "present"
and result_signal == "present"
)
print(f"verdict: {'PASS' if ok else 'REVIEW'}")
return 0
def make_fixture(base):
os.makedirs(base, exist_ok=True)
paper = (
"Morning light and alertness in office workers\n"
"Data were collected in 2020 from two sites.\n"
"Background. Low alertness in the morning is a common problem in office settings.\n"
"Method. We recruited 120 office workers and assigned them to bright light or dim light for 8 days. Alertness was measured with a validated scale each morning.\n"
"Results. The bright light group scored 42 points on average compared with 31 points in the dim light group, a difference of 11 points. Response time fell by 15 percent in the bright light group.\n"
"Conclusion. Morning bright light improved alertness in this sample of office workers.\n"
"Keywords: alertness, bright light, office workers\n"
)
abstract = (
"Low morning alertness affects office work. This study tested bright light. The bright light group improved alertness by 87 percent and scored higher than controls (Smith, 2020). Morning bright light may help office workers stay alert.\n"
"Keywords: alertness, bright light, office workers\n"
)
paper_path = os.path.join(base, "paper.txt")
abstract_path = os.path.join(base, "abstract.txt")
with open(paper_path, "w", encoding="utf-8") as fh:
fh.write(paper)
with open(abstract_path, "w", encoding="utf-8") as fh:
fh.write(abstract)
print(f"fixture_paper: {paper_path}")
print(f"fixture_abstract: {abstract_path}")
return 0
def main():
args = sys.argv[1:]
if len(args) == 2 and args[0] == "--make-fixture":
return make_fixture(args[1])
budget_min = 150
budget_max = 250
positional = []
i = 0
while i < len(args):
if args[i] == "--budget-min" and i + 1 < len(args):
try:
budget_min = int(args[i + 1])
except ValueError:
print("error: --budget-min needs an integer")
return 2
i += 2
elif args[i] == "--budget-max" and i + 1 < len(args):
try:
budget_max = int(args[i + 1])
except ValueError:
print("error: --budget-max needs an integer")
return 2
i += 2
else:
positional.append(args[i])
i += 1
if len(positional) != 2:
print("usage: abstract_check.py ABSTRACT_FILE PAPER_FILE [--budget-min N --budget-max N]")
print(" abstract_check.py --make-fixture DIR")
return 2
return check(positional[0], positional[1], budget_min, budget_max)
if __name__ == "__main__":
raise SystemExit(main())
publisher key 2e43c913833850e6d80f939677e3de76e806d47785c0f1caaca90f9d18c98e1e
No ratings yet — be the first to rate it.