Update app.py
Browse files
app.py
CHANGED
|
@@ -116,16 +116,32 @@ AGENT_PROMPTS: dict[str, str] = {
|
|
| 116 |
),
|
| 117 |
}
|
| 118 |
NARRATOR_PROMPT = (
|
| 119 |
-
"You are the pompous editor-in-chief of The Tinywick Hollow Gazette
|
| 120 |
-
"
|
| 121 |
-
"
|
| 122 |
-
"
|
| 123 |
-
"
|
| 124 |
-
"
|
| 125 |
-
"
|
| 126 |
-
"
|
| 127 |
-
"
|
| 128 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
)
|
| 130 |
|
| 131 |
# ═══════════════════════════════════════════════════════════════════
|
|
@@ -187,28 +203,76 @@ def _nudge_ctx(nudge_type, nudge_value, nudge_target, day_number):
|
|
| 187 |
return f"A new law proposed: '{nudge_value}'."
|
| 188 |
return ""
|
| 189 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
def _parse_newspaper_full(raw: str, day_number: int) -> dict:
|
| 191 |
lines = [l.strip() for l in raw.strip().splitlines() if l.strip()]
|
| 192 |
result = {
|
| 193 |
-
"headline": f"
|
| 194 |
"article": "", "weather": "Overcast, with philosophical observations.",
|
| 195 |
-
"briefs": {c:
|
| 196 |
}
|
| 197 |
body_start = 0
|
|
|
|
|
|
|
| 198 |
for i, line in enumerate(lines):
|
| 199 |
-
cleaned = re.sub(r'[*_#"\'`]', "", line).strip()
|
| 200 |
-
if
|
| 201 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
article_lines = []
|
|
|
|
| 203 |
for line in lines[body_start:]:
|
| 204 |
-
u = line.upper()
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 211 |
result["article"] = " ".join(article_lines).strip() or raw.strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
return result
|
| 213 |
|
| 214 |
def _run_simulation_step(nudge_type, nudge_value, nudge_target):
|
|
|
|
| 116 |
),
|
| 117 |
}
|
| 118 |
NARRATOR_PROMPT = (
|
| 119 |
+
"You are the pompous editor-in-chief of The Tinywick Hollow Gazette, "
|
| 120 |
+
"a broadsheet for an absurd woodland civilisation. "
|
| 121 |
+
"Given today's events, write the front page. "
|
| 122 |
+
"Copy this format EXACTLY — including the blank lines, the colon labels, "
|
| 123 |
+
"and writing the headline in ALL CAPITALS:\n\n"
|
| 124 |
+
"WRITE YOUR ACTUAL HEADLINE HERE IN ALL CAPS\n\n"
|
| 125 |
+
"Write the actual article here. Three to four sentences. "
|
| 126 |
+
"Pompous, formal, treating trivial events as major news.\n\n"
|
| 127 |
+
"WEATHER: One sentence of absurd woodland weather.\n"
|
| 128 |
+
"FOX: One sentence about what Reginald Fox did today.\n"
|
| 129 |
+
"BADGER: One sentence about what Beatrice Badger did today.\n"
|
| 130 |
+
"SQUIRREL: One sentence about what Cornelius Squirrel did today.\n"
|
| 131 |
+
"MOLE: One cryptic sentence about Millicent Mole.\n\n"
|
| 132 |
+
"EXAMPLE OF CORRECT OUTPUT:\n"
|
| 133 |
+
"FOX PROPOSES REPLACING ACORNS WITH FORGED CERTIFICATES\n\n"
|
| 134 |
+
"Reginald Fox has formally proposed that the hollow's economy be restructured "
|
| 135 |
+
"entirely around certificates of authenticity, a development which Beatrice Badger "
|
| 136 |
+
"has declared unconstitutional on eleven separate counts. "
|
| 137 |
+
"The proposal has garnered significant attention from those who already "
|
| 138 |
+
"own several suspicious certificates.\n\n"
|
| 139 |
+
"WEATHER: Partly suspicious, with a seventy percent chance of decrees.\n"
|
| 140 |
+
"FOX: Forged three certificates before the morning dew had lifted.\n"
|
| 141 |
+
"BADGER: Filed eleven formal objections before elevenses.\n"
|
| 142 |
+
"SQUIRREL: Invented a certificate-counting machine that counts to seven then resets.\n"
|
| 143 |
+
"MOLE: Something certificated is already circulating underground.\n\n"
|
| 144 |
+
"NOW WRITE THE REAL GAZETTE ENTRY FOR TODAY."
|
| 145 |
)
|
| 146 |
|
| 147 |
# ═══════════════════════════════════════════════════════════════════
|
|
|
|
| 203 |
return f"A new law proposed: '{nudge_value}'."
|
| 204 |
return ""
|
| 205 |
|
| 206 |
+
# Words that indicate the model echoed a template instead of writing a real headline
|
| 207 |
+
_TEMPLATE_WORDS = {"HEADLINE", "INSERT", "PLACEHOLDER", "CAPS HERE",
|
| 208 |
+
"YOUR HEADLINE", "ACTUAL HEADLINE", "WRITE YOUR", "EXAMPLE"}
|
| 209 |
+
|
| 210 |
+
def _is_template_headline(text: str) -> bool:
|
| 211 |
+
up = text.upper()
|
| 212 |
+
return any(w in up for w in _TEMPLATE_WORDS)
|
| 213 |
+
|
| 214 |
+
# Labels that should never land in the article body
|
| 215 |
+
_KNOWN_LABELS = {"WEATHER","FOX","BADGER","SQUIRREL","MOLE",
|
| 216 |
+
"CLASSIFIEDS","EXAMPLE","NOW WRITE","CORRECT OUTPUT"}
|
| 217 |
+
|
| 218 |
def _parse_newspaper_full(raw: str, day_number: int) -> dict:
|
| 219 |
lines = [l.strip() for l in raw.strip().splitlines() if l.strip()]
|
| 220 |
result = {
|
| 221 |
+
"headline": f"BREAKING: DAY {day_number} IN TINYWICK HOLLOW",
|
| 222 |
"article": "", "weather": "Overcast, with philosophical observations.",
|
| 223 |
+
"briefs": {c: "" for c in CREATURES},
|
| 224 |
}
|
| 225 |
body_start = 0
|
| 226 |
+
|
| 227 |
+
# Find headline: first ALL-CAPS line that isn't a template echo
|
| 228 |
for i, line in enumerate(lines):
|
| 229 |
+
cleaned = re.sub(r'[*_#"\'`]', "", line).strip().rstrip(":")
|
| 230 |
+
if not cleaned:
|
| 231 |
+
continue
|
| 232 |
+
if cleaned == cleaned.upper() and len(cleaned) > 8 and not _is_template_headline(cleaned):
|
| 233 |
+
result["headline"] = cleaned
|
| 234 |
+
body_start = i + 1
|
| 235 |
+
break
|
| 236 |
+
# Fallback: first line regardless (but still reject templates)
|
| 237 |
+
if i == 0 and not _is_template_headline(cleaned):
|
| 238 |
+
result["headline"] = cleaned.upper()
|
| 239 |
+
body_start = 1
|
| 240 |
+
break
|
| 241 |
+
|
| 242 |
article_lines = []
|
| 243 |
+
skip_rest = False
|
| 244 |
for line in lines[body_start:]:
|
| 245 |
+
u = line.upper().strip()
|
| 246 |
+
# Stop collecting article when we hit the example block
|
| 247 |
+
if "EXAMPLE OF CORRECT" in u or "NOW WRITE THE REAL" in u:
|
| 248 |
+
skip_rest = True
|
| 249 |
+
if skip_rest:
|
| 250 |
+
continue
|
| 251 |
+
# Route labelled lines to the right bucket
|
| 252 |
+
if u.startswith("WEATHER:"): result["weather"] = line.split(":",1)[1].strip()
|
| 253 |
+
elif u.startswith("FOX:"): result["briefs"]["fox"] = line.split(":",1)[1].strip()
|
| 254 |
+
elif u.startswith("BADGER:"): result["briefs"]["badger"] = line.split(":",1)[1].strip()
|
| 255 |
+
elif u.startswith("SQUIRREL:"): result["briefs"]["squirrel"] = line.split(":",1)[1].strip()
|
| 256 |
+
elif u.startswith("MOLE:"): result["briefs"]["mole"] = line.split(":",1)[1].strip()
|
| 257 |
+
elif u.startswith("CLASSIFIEDS:"): pass # skip — we supply our own
|
| 258 |
+
elif any(u.startswith(lbl+":") for lbl in _KNOWN_LABELS): pass # skip other labels
|
| 259 |
+
elif _is_template_headline(line): pass # skip echoed format instructions
|
| 260 |
+
else:
|
| 261 |
+
article_lines.append(line)
|
| 262 |
+
|
| 263 |
result["article"] = " ".join(article_lines).strip() or raw.strip()
|
| 264 |
+
|
| 265 |
+
# Fill in any empty briefs with a sensible default
|
| 266 |
+
defaults = {
|
| 267 |
+
"fox": "Reginald Fox was seen conducting suspicious business.",
|
| 268 |
+
"badger": "Beatrice Badger issued a firm statement.",
|
| 269 |
+
"squirrel": "Cornelius Squirrel invented something that nearly worked.",
|
| 270 |
+
"mole": "Something is happening underground.",
|
| 271 |
+
}
|
| 272 |
+
for c in CREATURES:
|
| 273 |
+
if not result["briefs"].get(c):
|
| 274 |
+
result["briefs"][c] = defaults[c]
|
| 275 |
+
|
| 276 |
return result
|
| 277 |
|
| 278 |
def _run_simulation_step(nudge_type, nudge_value, nudge_target):
|