"""Side-by-side page for reading the predicament pilot: the scene, its summary, and what each model made of it. python3 strip_names.py pilot-predicaments-3b.json pilot-3b-clean.json python3 strip_names.py pilot-predicaments-14b.json pilot-14b-clean.json python3 pilot_page.py pilot-3b-clean.json pilot-14b-clean.json > pilot-compare.html Takes strip_names.py's output, so the page shows what the full run would actually embed. (strip_names runs as a script on import, so it is not imported here.) Job, relationship and place words are highlighted. A pick per scene is kept in the browser only; the tally at the top is what to report back. No inference. """ import collections, html, json, pathlib, re, sys from topic_words import TOPIC_WORDS def clean(text): return text # inputs are already name-stripped a_path, b_path = sys.argv[1], sys.argv[2] cols = [json.loads(pathlib.Path(p).read_text(encoding='utf-8')) for p in (a_path, b_path)] labels = [c['model'] for c in cols] chunks = json.loads(pathlib.Path('chunks.json').read_text(encoding='utf-8')) summary = {x['chunk']: x['summary'] for x in json.loads(pathlib.Path('summaries_clean.json').read_text(encoding='utf-8'))['summaries']} def marked(text): out = [] for part in re.split(r"([A-Za-zé]+)", text): esc = html.escape(part) out.append(f'{esc}' if part.lower() in TOPIC_WORDS else esc) return ''.join(out) def leaks(text): return len(set(re.findall(r"[a-zé]+", text.lower())) & TOPIC_WORDS) def opening(text): return ' '.join(text.split()[:3]) rows, stats = [], [] for col in cols: texts = [clean(x['summary']) for x in col['summaries']] stats.append({ 'leaky': sum(leaks(t) > 0 for t in texts), 'city': sum('city' in t.lower() for t in texts), 'words': sum(len(t.split()) for t in texts) / len(texts), 'openings': collections.Counter(opening(t) for t in texts).most_common(3), }) n = min(len(c['summaries']) for c in cols) for i in range(n): x = cols[0]['summaries'][i] ch = chunks[x['chunk']] cells = ''.join( f'
{html.escape(labels[j])}' f'

{marked(clean(cols[j]["summaries"][i]["summary"]))}

' f'
' for j in range(2)) rows.append(f'''
{i + 1} {html.escape(ch["title"])}
Scene summary: {marked(summary.get(x["chunk"], ""))}

{html.escape(ch["text"][:1200])}{"…" if len(ch["text"]) > 1200 else ""}

{cells}
''') stat_rows = ''.join( f'{html.escape(labels[j])}{s["leaky"]} of {n}{s["city"]}' f'{s["words"]:.0f}{"; ".join(f"“{html.escape(o)}…” ×{c}" for o, c in s["openings"])}' for j, s in enumerate(stats)) print(f''' Predicament pilot

Predicament pilot

The first {n} scenes, each re-described by two models as the main person's predicament. Names are already removed as the full run would. Highlighted words are jobs, relationships and places, the words the old groups formed around. Pick the better sentence in each scene, or "neither". The column order is fixed: {html.escape(labels[0])} on the left.

What to look for: does the sentence say what the person is up against and what they want? Could it happen to anyone, anywhere? Would two scenes with the same predicament end up with similar sentences?

{stat_rows}
ModelHas a highlighted wordSays "city"Words, meanMost common openings
{"".join(rows)}
''')