Study cards: from-your-notes, read aloud, timed runs
From your notes: the generator now stores a verbatim source quote with every activity (schema + prompt + a server-side clamp so a chatty model cannot drop a card), and the feedback panel shows the sentence that carries it with the quote highlighted green. Decks made before the change, and quotes the model trimmed, fall back to a local IDF-weighted match over the saved notes text (lib/notes-source.ts): nothing is shown unless at least two distinct terms land. The passage hides in exam mode with the other reveals. Read aloud: a Web Speech API speaker control on the text a learner reads (flashcard faces, questions, statements, sentences, instructions) via lib/speech.ts and components/SpeakButton.tsx — one utterance app-wide, a voice matched to the deck's language, and no button at all where the browser has no speech synthesis. It used to sit inside the flashcard's flip button (nested buttons, tapping it flipped the card); it now lives next to the hint row. Timed runs: the feed chrome carries a timer chip (off by default) that gives each card 30 seconds; a card that runs out is recorded as a miss through the same path as a wrong answer (history + SRS agree), shows a toast, and the feed moves straight on with a fresh budget. handleAnswered ignores a second result per card, so a timeout plus a manual answer cannot record twice. The generator's type spec now names what each type suits (language decks lean on flashcards/matching/fill blank, ordering needs a real sequence, short answer reasoning), so the deck-aware guidance covers all seven types. New activities-test suite (24 checks: quote path, local path, the green mark, the speech stub, the timed run on Playwright's fake clock), registered in run-all; phase2 pins that the notes passage stays hidden in exam mode; en+cs keys for every new string; no new dependencies. Version 0.6.1, SW v83.
This commit is contained in:
parent
786d6cf1ae
commit
796e2e9fe9
26 changed files with 1068 additions and 51 deletions
46
README.md
46
README.md
|
|
@ -172,6 +172,13 @@ no database, no data leaving your machine except the requests you send to Ollama
|
|||
| `ordering` | Drag with the mouse/finger, or use ▲▼ buttons, then check |
|
||||
| `short_answer` | Typed answer graded by the AI via `/api/grade`, with a self-check fallback |
|
||||
|
||||
Every card carries the extras that make it studyable: a **speaker** control (Web Speech API,
|
||||
the deck's language, on the text you are meant to read — flashcard faces, questions, statements,
|
||||
instructions), a **“From your notes”** passage after you answer (the generator stores a verbatim
|
||||
quote with each activity; decks made before that get a local, IDF-weighted sentence match over
|
||||
the saved notes) with the matching words highlighted green, and the feed chrome's **⏱ timed run**
|
||||
(off by default — 30 seconds a card, running out counts as a miss and the feed moves on).
|
||||
|
||||
**First run**
|
||||
|
||||
- A full-screen **API-key gate** replaces the app until a key is saved (in `user-key` mode): one
|
||||
|
|
@ -846,11 +853,13 @@ app/
|
|||
components/
|
||||
activities/ one component per activity type + shared shell
|
||||
Flashcard.tsx MultipleChoice.tsx TrueFalse.tsx FillBlank.tsx
|
||||
Matching.tsx Ordering.tsx ShortAnswer.tsx shared.tsx index.tsx
|
||||
Matching.tsx Ordering.tsx ShortAnswer.tsx shared.tsx context.tsx
|
||||
NotesSource.tsx index.tsx
|
||||
homework/ make-my-homework screens (input, result, guide feed, history)
|
||||
chat/ chat screen, composer, message rows, markdown + math, pickers
|
||||
UploadScreen.tsx StudyFeed.tsx ResultsScreen.tsx DeckCard.tsx ApiKeyGate.tsx
|
||||
InstallSheet.tsx TabBar.tsx ServiceWorkerRegistrar.tsx FolderBar.tsx
|
||||
SpeakButton.tsx (read-aloud control for study cards)
|
||||
LibraryScreen.tsx SettingsDialog.tsx AppHeader.tsx ThemeToggle.tsx icons.tsx ui.tsx
|
||||
lib/
|
||||
ollama.ts server-only HTTP client (timeouts, auth, error mapping)
|
||||
|
|
@ -871,6 +880,8 @@ lib/
|
|||
homework.ts localStorage homework results + solution assembly
|
||||
use-notes-intake.ts shared client-side photo/document intake hook
|
||||
clipboard.ts copy helper with a non-secure-context fallback
|
||||
notes-source.ts "from your notes": quote lookup + local sentence matching
|
||||
speech.ts Web Speech API wrapper (one utterance, deck language)
|
||||
image.ts client-side validation, resize and compression
|
||||
client-api.ts browser client for the API routes (NDJSON reader)
|
||||
chat.ts chat types + last-model memory
|
||||
|
|
@ -1423,6 +1434,39 @@ Things I chose while building, with the reasoning:
|
|||
(measured: 268..1280 at a 1280 window) — a flat pane floating 40px inside the scene read as
|
||||
"cut off next to the sidebar".
|
||||
|
||||
92. **Study cards: where the answer came from, read aloud, and timed runs.** Three additions to
|
||||
the study feed, all local and dependency-free.
|
||||
- **From your notes.** The generator now returns `source` with every activity: the verbatim
|
||||
words from the notes that prove the answer (max 25 words; `clampQuote` in `lib/ai.ts` trims
|
||||
anything longer to a clean cut, so a chatty model cannot drop a card). After an answer the
|
||||
feedback panel shows the sentence that carries it with the quote highlighted green
|
||||
(`mark`). Decks made before the change — and quotes the model trimmed — fall back to a
|
||||
local, IDF-weighted match over the stored notes text (`lib/notes-source.ts`): a query from
|
||||
the activity's own wording, sentence scoring where rare words weigh more, word-boundary
|
||||
highlighting, and nothing shown unless at least two distinct terms land (a random sentence
|
||||
would be worse than silence). It disappears in exam mode with the other reveals.
|
||||
- **Read aloud.** A speaker control on the text a learner is meant to read (both flashcard
|
||||
faces, the visible one only; questions, statements, sentences, instructions) on the Web
|
||||
Speech API (`lib/speech.ts`, `components/SpeakButton.tsx`): one utterance at a time
|
||||
app-wide, a voice matched to the deck's language (BCP-47 table, interface locale as the
|
||||
fallback, 0.95 rate), and no button at all where the browser has no speech synthesis.
|
||||
Tapping the speaker used to flip the flashcard — it sat inside the flip button (nested
|
||||
buttons) — so it now lives next to the hint row, outside the flip target.
|
||||
- **Timed runs.** The feed chrome carries a timer chip (off by default): on, each card gets
|
||||
30 seconds (`TIMED_CARD_SECONDS`), the chip counts down, and a card that runs out is
|
||||
recorded as a miss through the same path as a wrong answer (history + SRS agree), shows a
|
||||
toast, and the feed moves straight on to the next card with a fresh budget. The auto-advance
|
||||
is deliberately not deferred: recording the miss re-renders the feed and would cancel a
|
||||
queued scroll with its effect cleanup. `handleAnswered` now ignores a second result for the
|
||||
same card, so a timeout followed by a manual answer cannot write two history entries.
|
||||
- The generator's type spec now names what each type suits (flashcards, matching and fill in
|
||||
the blank for language decks; ordering for real sequences; short answer for reasoning), so
|
||||
the deck-aware guidance covers all seven types, not just ordering.
|
||||
New suite `activities-test` (24 checks: quote path, local path, the green mark, the speech
|
||||
stub — real `SpeechSynthesisUtterance`, recording `speak`/`cancel` — and the timed run with
|
||||
Playwright's fake clock), registered in run-all; the exam suite pins that the notes passage
|
||||
stays hidden with the other reveals; en + cs keys for every new string; no new dependencies.
|
||||
|
||||
91. **The chat chrome floats: one gutter, one radius scale, one glass recipe.** The header and
|
||||
the composer were full-bleed bands inside the main pane — flush to the viewport's top, right
|
||||
and bottom edges, with the composer's bottom corners cropped off-screen — while the rail
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue