Small joys: Quote of the Day + Word of the Day engines
- quote.py: curated public-domain quote pool (16 seeded, admin-grows), deterministic daily
pick, lazy AI "what it means" explainer of the real quote (cached). No LLM-invented quotes.
- wotd.py: LLM proposes positive words → validated/enriched against dictionaryapi.dev (real
definition, IPA, examples, audio) → audio clip cached to our origin (TTS fallback) →
deterministic daily pick. Tops the pool up toward 30/day.
- db.py: quote_pool/daily_quote + wotd_pool/daily_wotd tables.
- api.py: /api/quote/today, /api/word/today, /api/word/audio/{word} (GET+HEAD).
- cli.py: cycle steps for both (under --no-joys), shared LLM client.
- tests: test_quote.py (6) + test_wotd.py (5). 393 backend tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -304,6 +304,55 @@ CREATE TABLE IF NOT EXISTS daily_onthisday (
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Quote of the Day: curated public-domain quotes; one picked per day. `meaning` is an
|
||||
-- AI explainer of the (real) quote, filled lazily the first time it's shown.
|
||||
CREATE TABLE IF NOT EXISTS quote_pool (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
source TEXT NOT NULL DEFAULT 'curated',
|
||||
ckey TEXT NOT NULL UNIQUE,
|
||||
text TEXT NOT NULL,
|
||||
author TEXT,
|
||||
work TEXT,
|
||||
year TEXT,
|
||||
meaning TEXT,
|
||||
shown_at TEXT,
|
||||
blocked INTEGER NOT NULL DEFAULT 0,
|
||||
featured INTEGER NOT NULL DEFAULT 0,
|
||||
added_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS daily_quote (
|
||||
feature_date TEXT PRIMARY KEY,
|
||||
pool_id INTEGER NOT NULL,
|
||||
source TEXT NOT NULL DEFAULT 'curated',
|
||||
text TEXT, author TEXT, work TEXT, year TEXT, meaning TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Word of the Day: LLM-proposed positive words, validated/enriched against a real
|
||||
-- dictionary (definition, IPA, examples, cached audio clip); one picked per day.
|
||||
CREATE TABLE IF NOT EXISTS wotd_pool (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
source TEXT NOT NULL DEFAULT 'llm',
|
||||
word TEXT NOT NULL UNIQUE,
|
||||
part_of_speech TEXT,
|
||||
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
|
||||
shown_at TEXT,
|
||||
blocked INTEGER NOT NULL DEFAULT 0,
|
||||
featured INTEGER NOT NULL DEFAULT 0,
|
||||
added_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
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,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Privacy-respecting, first-party analytics. NO IP / user-agent / referrer / raw
|
||||
-- URL. visitor_hash is a hash of a random localStorage token (never email/IP).
|
||||
-- The UNIQUE key dedups to one row per (kind, article, visitor, day) — that both
|
||||
|
||||
Reference in New Issue
Block a user