The voice picker was a dropdown in the quiz player, beside the question — the one control on that screen with nothing to do with answering it, and one a learner sets once and never touches. It is a setting now, on the user rather than in a Redis blob, with a play button beside each voice because a voice is worth hearing before it is chosen. Choosing nothing stays a real choice: it means whatever an administrator marked default, so a site that changes its default reaches everybody without a row being edited. The tutor reads figures from `question_media` rather than the two legacy path columns. Those agree exactly today, so nothing was being lost — the first question given a second figure in the editor would have been the one that broke it, silently and only for the tutor. The legacy columns remain as a fallback for anything not projected into that table yet. And the retrieval thresholds are written down in docs/retrieval-thresholds.md: the three answers, the sixteen queries they were measured against, why they are deliberately not the retrieval floor, and how to re-measure when the corpus grows. Worth keeping the headline in mind — "discuss love" scores 0.491, alongside "tell me a joke". A number in the 0.4s is noise, not a weak signal. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
25 lines
690 B
Python
25 lines
690 B
Python
"""A learner's own reading voice.
|
|
|
|
It was a dropdown in the quiz player, beside the question — the one control on
|
|
that screen with nothing to do with answering, and one a learner would set once
|
|
and never touch again. That is a setting.
|
|
|
|
Revision ID: e7f8091a2b3c
|
|
Revises: d6e7f8091a2b
|
|
"""
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
|
|
revision = "e7f8091a2b3c"
|
|
down_revision = "d6e7f8091a2b"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade():
|
|
if "tts_voice" not in {c["name"] for c in sa.inspect(op.get_bind()).get_columns("users")}:
|
|
op.add_column("users", sa.Column("tts_voice", sa.String(), nullable=True))
|
|
|
|
|
|
def downgrade():
|
|
op.drop_column("users", "tts_voice")
|