Spaces:
Sleeping
Sleeping
| """ | |
| 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() | |