Files
upbeatBytes/goodnews/quote.py
T
thejayman77 84b1fb514f Small joys: Codex audit #2 fixes (route resolution, noindex, sense/tone, exclude-current re-pick)
- Admin joy item route moved to /api/admin/joys/{kind}/items/{item_id} so the
  /add and /repick verbs resolve to their own routes instead of 422-ing as a
  non-int item id (the launch blocker). Frontend mutate URL updated to match.
- Re-pick now excludes the currently-shown item: the endpoint reads today's
  daily pool_id and passes it as `avoid`, so "Re-pick today" yields a different
  item. Added `avoid` to pick_daily/_candidates across wotd/quote/onthisday.
- WOTD sense selection: the LLM now proposes word + intended part of speech, and
  _lookup prefers that sense (fixes "serene" returning the archaic noun).
- On This Day tone prompt tightened to favor genuinely uplifting events and
  exclude merely procedural/political-administrative ones.
- Caddy @hidden now also noindexes /word /quote /onthisday /admin (+ .html).
- Regression tests: add/repick resolve (401 not 422), add/feature/block/delete,
  re-pick excludes current; WOTD pos-preference + proposal parsing units.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 20:19:02 -04:00

124 lines
6.2 KiB
Python

"""Quote of the Day — a hopeful, public-domain quote a day.
Curated, never LLM-invented (misattribution is the one thing that would burn trust). A
vetted starter set seeds the pool; admin grows it. The "what it means" explainer IS
LLM-generated, but it only *interprets a real, known quote* — low risk — and is filled
lazily the first time a quote is shown, then cached.
Same lifecycle as the other small joys: pool → deterministic daily pick → cached row.
"""
from __future__ import annotations
import sqlite3
from . import daily
from .localtime import local_today
_NO_REPEAT_POOL = 60
# Public-domain (ancient / author died well over a century ago), uplifting. Admin curates.
SEED = [
("Very little is needed to make a happy life; it is all within yourself, in your way of thinking.", "Marcus Aurelius", "Meditations"),
("The happiness of your life depends upon the quality of your thoughts.", "Marcus Aurelius", "Meditations"),
("The journey of a thousand miles begins with a single step.", "Lao Tzu", "Tao Te Ching"),
("Nature does not hurry, yet everything is accomplished.", "Lao Tzu", "Tao Te Ching"),
("It does not matter how slowly you go as long as you do not stop.", "Confucius", None),
("Knowing yourself is the beginning of all wisdom.", "Aristotle", None),
("We suffer more often in imagination than in reality.", "Seneca", None),
("It's not what happens to you, but how you react to it that matters.", "Epictetus", None),
("The wound is the place where the Light enters you.", "Rumi", None),
("Write it on your heart that every day is the best day in the year.", "Ralph Waldo Emerson", None),
("Go confidently in the direction of your dreams. Live the life you have imagined.", "Henry David Thoreau", None),
("Hope is the thing with feathers that perches in the soul.", "Emily Dickinson", None),
("The best portion of a good man's life: his little, nameless, unremembered acts of kindness and of love.", "William Wordsworth", None),
("Great things are done by a series of small things brought together.", "Vincent van Gogh", None),
("I am not afraid of storms, for I am learning how to sail my ship.", "Louisa May Alcott", "Little Women"),
("I exist as I am, that is enough.", "Walt Whitman", "Leaves of Grass"),
]
def seed(conn: sqlite3.Connection) -> int:
"""Insert the curated starter quotes (idempotent via content key). Returns # added."""
before = conn.execute("SELECT COUNT(*) FROM quote_pool").fetchone()[0]
conn.executemany(
"INSERT OR IGNORE INTO quote_pool (source, ckey, text, author, work) VALUES ('curated', ?, ?, ?, ?)",
[(daily.content_key(text, author), text, author, work) for text, author, work in SEED],
)
conn.commit()
return conn.execute("SELECT COUNT(*) FROM quote_pool").fetchone()[0] - before
def _explain(client, text: str, author: str | None) -> str | None:
user = (
"In one or two plain, warm sentences, explain what this quote means and why it's worth "
"remembering, for a general audience who may not be familiar with it. No preamble, no "
f'quoting it back.\n\nQuote: "{text}"' + (f"\n{author}" if author else "")
)
out = " ".join(client.chat_text([{"role": "user", "content": user}]).split()).strip()
return out or None
def _candidates(conn: sqlite3.Connection, avoid: int | None = None) -> list[int]:
featured = conn.execute(
"SELECT id FROM quote_pool WHERE blocked=0 AND featured=1 ORDER BY id"
).fetchall()
if featured:
ids = [r[0] for r in featured]
else:
rows = conn.execute(
"SELECT id FROM quote_pool WHERE blocked=0 ORDER BY shown_at IS NOT NULL, shown_at, id LIMIT ?",
(_NO_REPEAT_POOL,),
).fetchall()
ids = [r[0] for r in rows]
if avoid is not None:
ids = [i for i in ids if i != avoid] or ids
return ids
def pick_daily(conn: sqlite3.Connection, feature_date: str | None = None, client=None,
force: bool = False, avoid: int | None = None) -> dict | None:
feature_date = feature_date or local_today()
existing = conn.execute("SELECT * FROM daily_quote WHERE feature_date=?", (feature_date,)).fetchone()
if existing and not force:
return dict(existing)
ids = _candidates(conn, avoid)
if not ids:
return None
pick_id = daily.seeded_order(ids, feature_date)[0]
row = conn.execute("SELECT * FROM quote_pool WHERE id=?", (pick_id,)).fetchone()
meaning = row["meaning"]
if not meaning and client: # lazy, cached; LLM done before the write
try:
meaning = _explain(client, row["text"], row["author"])
if meaning:
conn.execute("UPDATE quote_pool SET meaning=? WHERE id=?", (meaning, pick_id))
except Exception: # noqa: BLE001 — explainer is optional
meaning = None
conn.execute(
"INSERT INTO daily_quote (feature_date, pool_id, source, text, author, work, year, meaning) "
"VALUES (?,?,?,?,?,?,?,?) "
"ON CONFLICT(feature_date) DO UPDATE SET pool_id=excluded.pool_id, text=excluded.text, "
"author=excluded.author, work=excluded.work, year=excluded.year, meaning=excluded.meaning",
(feature_date, row["id"], row["source"], row["text"], row["author"], row["work"], row["year"], meaning),
)
conn.execute("UPDATE quote_pool SET shown_at=? WHERE id=?", (feature_date, pick_id))
conn.commit()
return dict(conn.execute("SELECT * FROM daily_quote WHERE feature_date=?", (feature_date,)).fetchone())
def get_today(conn: sqlite3.Connection, feature_date: str | None = None) -> dict | None:
if feature_date:
row = conn.execute("SELECT * FROM daily_quote WHERE feature_date=?", (feature_date,)).fetchone()
if row:
return dict(row)
row = conn.execute("SELECT * FROM daily_quote ORDER BY feature_date DESC LIMIT 1").fetchone()
return dict(row) if row else None
def run_daily(conn: sqlite3.Connection, client=None) -> dict:
if conn.execute("SELECT COUNT(*) FROM quote_pool").fetchone()[0] == 0:
seed(conn)
picked = pick_daily(conn, client=client)
return {"pool": conn.execute("SELECT COUNT(*) FROM quote_pool").fetchone()[0],
"picked": (picked or {}).get("author")}