totes-emosh / scratch /build_emotionmap_template.py
drdeception
feat: six-emotion replication challenge — totes-emosh EmotionMap build
0d27c43
Raw
History Blame Contribute Delete
6.19 kB
"""
Generate the Lesson 4 EmotionMap Word fallback template.
The primary submission route is the single-page PDF the toy app
exports. This Word document is the paper fallback for students who
cannot run the app — six labelled slots in a 2x3 grid, a Format
checkbox, the privacy confirm, and a short reflection prompt.
Run with:
uv run python scratch/build_emotionmap_template.py
"""
from __future__ import annotations
from pathlib import Path
from docx import Document
from docx.enum.table import WD_ALIGN_VERTICAL
from docx.shared import Cm, Pt, RGBColor
REPO_ROOT = Path(__file__).resolve().parent.parent
# The Word doc is a teaching-bundle artefact, not a Space asset.
# Default output is the lesson folder; override with $TOTES_TEMPLATE_OUT
# if running from a different machine.
DEFAULT_OUT = (
Path.home() / "Code/teaching/online-teaching-for-bence"
/ "Lesson4-EmotionMap-template.docx"
)
OUT_PATH = Path(
__import__("os").environ.get("TOTES_TEMPLATE_OUT", DEFAULT_OUT)
)
GREY = RGBColor(0x55, 0x55, 0x55)
EMOTIONS = ["Happy", "Sad", "Fear", "Disgust", "Anger", "Surprise"]
def add_heading(doc, text, level):
return doc.add_heading(text, level=level)
def add_para(doc, text, italic=False, grey=False, bold=False, size=None):
p = doc.add_paragraph()
run = p.add_run(text)
run.italic = italic
run.bold = bold
if grey:
run.font.color.rgb = GREY
if size is not None:
run.font.size = Pt(size)
return p
def add_instruction(doc, text):
add_para(doc, text, italic=True, grey=True, size=10)
def add_kv_table(doc, fields):
tbl = doc.add_table(rows=1 + len(fields), cols=2)
tbl.style = "Table Grid"
hdr = tbl.rows[0].cells
hdr[0].text = "Field"
hdr[1].text = "Your entry"
for cell in hdr:
for p in cell.paragraphs:
for run in p.runs:
run.bold = True
for i, field in enumerate(fields, start=1):
tbl.rows[i].cells[0].text = field
tbl.rows[i].cells[1].text = ""
doc.add_paragraph()
def add_replication_grid(doc):
"""2x3 grid of slot cells. Each cell has the emotion name, a
paste-image placeholder, and a one-line classifier-result field."""
tbl = doc.add_table(rows=2, cols=3)
tbl.style = "Table Grid"
for row in range(2):
for col in range(3):
idx = row * 3 + col
emo = EMOTIONS[idx]
cell = tbl.rows[row].cells[col]
cell.vertical_alignment = WD_ALIGN_VERTICAL.TOP
cell.text = ""
# Slot number and intended emotion
p_title = cell.paragraphs[0]
r_title = p_title.add_run(f"{idx + 1}. {emo.upper()}")
r_title.bold = True
r_title.font.size = Pt(11)
# Image placeholder
p_img = cell.add_paragraph()
r_img = p_img.add_run("[paste face or wireframe here]")
r_img.italic = True
r_img.font.color.rgb = GREY
r_img.font.size = Pt(9)
# Classifier line
p_cls = cell.add_paragraph()
r_cls = p_cls.add_run("Classifier said: ____________ (___ .__ )")
r_cls.font.size = Pt(9)
# Verdict
p_v = cell.add_paragraph()
r_v = p_v.add_run("Agreed / Disagreed (circle one)")
r_v.font.size = Pt(9)
r_v.font.color.rgb = GREY
doc.add_paragraph()
def build():
doc = Document()
for section in doc.sections:
section.top_margin = Cm(1.5)
section.bottom_margin = Cm(1.5)
section.left_margin = Cm(1.8)
section.right_margin = Cm(1.8)
doc.add_heading("Lesson 4 EmotionMap — six-emotion replication challenge", level=0)
add_para(
doc,
"Pose each of the six basic emotions in turn. Note what the toy "
"app's classifier read on each attempt. This Word document is "
"the paper fallback — the primary submission is the single-page "
"PDF exported from the app.",
italic=True,
grey=True,
)
add_heading(doc, "Your details", 1)
add_kv_table(doc, ["Name", "Student number", "Format chosen (A or B)", "Date"])
add_instruction(
doc,
"Format A — Face: paste cropped face thumbnails in each slot. "
"Format B — Wireframe: paste the anonymised landmark wireframes "
"the app generates when Wireframe mode is on. Both formats "
"carry equal weight.",
)
add_heading(doc, "Replication grid", 1)
add_replication_grid(doc)
add_heading(doc, "Privacy ground rules — confirm", 1)
add_para(doc, "[ ] I chose my format before I started posing.")
add_para(doc, "[ ] I understand that the toy app uploads nothing "
"beyond the model inference call and stores nothing on "
"a server.")
add_para(doc, "[ ] (Format A only) I consent to my tutor reviewing "
"my face-bearing captures.")
add_heading(doc, "Reflection (2–3 sentences)", 1)
add_para(doc, "Pick ONE of the prompts and answer in 2–3 sentences.")
add_para(
doc,
"1. Which of the six basic emotions was easiest for the "
"classifier to recognise on your face? Which was hardest? What "
"do you think drives that gap — your face, the model, or both?",
)
add_para(
doc,
"2. Look across your six slots. Are some emotions consistently "
"recognised, and others much more variable? What does that "
"variability look like for you, and how might it differ for "
"someone else in the cohort?",
)
add_para(
doc,
"3. Did the classifier ever pick a different top emotion from "
"the one you intended? When it did, what did it pick instead — "
"and what does that suggest about how 'readable' a felt state "
"is on a face?",
)
# blank space for the reflection answer
rtbl = doc.add_table(rows=5, cols=1)
rtbl.style = "Table Grid"
for r in rtbl.rows:
r.cells[0].text = ""
doc.save(OUT_PATH)
print(f"Wrote {OUT_PATH}")
if __name__ == "__main__":
build()