WOTD #4/#5 content quality + Editorial Asymmetric /word page (CD)

Content quality ("LLM polishes, dictionary anchors"):
- New wotd._polish: rewrites the real dictionary gloss into ONE warm plain
  sentence + two clear everyday example sentences, grounded in the real
  definition (no invented meanings). Stored in new wotd_pool/daily_wotd columns
  gloss + usage, alongside the raw definition/examples which stay the anchor.
- harvest() polishes each new word; pick_daily() lazily polishes + caches back
  any older pooled word that lacks a gloss (client threaded through run_daily).
- Admin word-add polishes on insert; re-pick passes an LLM client so quote
  meaning / word gloss fill on a forced fresh pick.
- /api/word/today now prefers gloss + usage, falling back to the raw dictionary
  def/examples when polish is absent (so it's always safe).
- db._migrate adds gloss/usage to wotd_pool + daily_wotd (idempotent ALTER).

Frontend — /word redesigned to CD's "Editorial Asymmetric": faded oversized
initial bleeding off the right, vertical part-of-speech rail, big Newsreader
word, airy definition, left-ruled italic example sentences, outline Listen
button + date. (Uses our self-hosted Newsreader/Hanken stack rather than the
mockup's Google fonts; the made-up syllable respelling is omitted since we only
have real IPA.)

Tests: _polish parse/trim/cap, harvest stores gloss/usage, pick lazy-polishes
older words, admin gloss flows through to /api/word/today. 403 backend + 27 fe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jay
2026-06-23 06:08:14 -04:00
parent e5f3d942e2
commit cebbed58ab
6 changed files with 196 additions and 65 deletions
+13 -3
View File
@@ -338,8 +338,10 @@ CREATE TABLE IF NOT EXISTS wotd_pool (
phonetic TEXT, -- IPA
audio_file TEXT, -- our cached pronunciation clip (or null → browser TTS)
audio_url TEXT, -- source clip URL
definition TEXT NOT NULL,
examples TEXT, -- JSON array of example sentences
definition TEXT NOT NULL, -- raw dictionary gloss (anchor / ground truth)
examples TEXT, -- JSON array of raw dictionary example sentences (anchor)
gloss TEXT, -- LLM plain-language rewrite of the definition (for display)
usage TEXT, -- JSON array of LLM everyday example sentences (for display)
shown_at TEXT,
blocked INTEGER NOT NULL DEFAULT 0,
featured INTEGER NOT NULL DEFAULT 0,
@@ -349,7 +351,7 @@ CREATE TABLE IF NOT EXISTS daily_wotd (
feature_date TEXT PRIMARY KEY,
pool_id INTEGER NOT NULL,
word TEXT, part_of_speech TEXT, phonetic TEXT, audio_file TEXT,
definition TEXT, examples TEXT,
definition TEXT, examples TEXT, gloss TEXT, usage TEXT,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);
@@ -648,3 +650,11 @@ def _migrate(conn: sqlite3.Connection) -> None:
for column in ("what_happened", "why_matters", "why_belongs"):
if sum_cols and column not in sum_cols:
conn.execute(f"ALTER TABLE article_summaries ADD COLUMN {column} TEXT")
# WOTD display polish: LLM plain-language gloss + everyday example sentences, kept
# alongside the raw dictionary def/examples (which stay the anchor / ground truth).
for tbl in ("wotd_pool", "daily_wotd"):
cols = {row["name"] for row in conn.execute(f"PRAGMA table_info({tbl})")}
for column in ("gloss", "usage"):
if cols and column not in cols:
conn.execute(f"ALTER TABLE {tbl} ADD COLUMN {column} TEXT")