Spaces:
Running on Zero
Running on Zero
File size: 2,996 Bytes
7563305 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | """
Recall — shared data contract (§4 of the main plan).
This is the single source of truth all three modules build against.
We use plain dicts (Gradio gr.State friendly) + light dataclasses/factories
so nobody is blocked on each other. DO NOT change these shapes without a
team sync — content_pipeline, learning_engine, and app.py all depend on them.
"""
from __future__ import annotations
import uuid
from typing import Optional, TypedDict
# ---- Core types ------------------------------------------------------------
class Card(TypedDict):
id: str
question: str
answer: str # reference answer
topic: str # short tag, e.g. "Photosynthesis"
source_chunk: str # text it came from (grounding / explanations)
difficulty: int # 1 (easy) .. 3 (hard)
parent_id: Optional[str] # set when this card is a generated follow-up
class CardState(TypedDict):
card_id: str
ease: float # SM-2-style, starts 2.5
interval: int # positions until it reappears in the queue
reps: int
lapses: int
last_grade: int # 0..5 from the grader
class GradeResult(TypedDict):
score: int # 0..5
correct: bool # score >= 3
explanation: str # shown to the user
missed_concept: str # seed for follow-up generation
class Session(TypedDict):
deck: list[Card]
states: dict[str, CardState] # card_id -> CardState
queue: list[str] # ordered card_ids to serve
history: list[dict] # {card_id, user_answer, grade}
streak: int
# ---- Factories (use these instead of building dicts by hand) ---------------
def new_card(
question: str,
answer: str,
topic: str = "General",
source_chunk: str = "",
difficulty: int = 1,
parent_id: Optional[str] = None,
card_id: Optional[str] = None,
) -> Card:
return Card(
id=card_id or str(uuid.uuid4()),
question=question,
answer=answer,
topic=topic,
source_chunk=source_chunk,
difficulty=difficulty,
parent_id=parent_id,
)
def new_card_state(card_id: str) -> CardState:
return CardState(
card_id=card_id, ease=2.5, interval=1, reps=0, lapses=0, last_grade=0
)
def new_grade(score: int, explanation: str, missed_concept: str = "") -> GradeResult:
score = max(0, min(5, int(score)))
return GradeResult(
score=score,
correct=score >= 3,
explanation=explanation,
missed_concept=missed_concept,
)
def validate_card(card: dict) -> bool:
"""Cheap guard so a malformed model card never crashes the deck."""
required = ("id", "question", "answer", "topic", "source_chunk",
"difficulty", "parent_id")
return (
isinstance(card, dict)
and all(k in card for k in required)
and bool(str(card.get("question", "")).strip())
and bool(str(card.get("answer", "")).strip())
)
|