Add persian-tutor: Gradio-based GCSE Persian language learning app

Vocabulary study with FSRS spaced repetition, AI tutoring (Ollama/Claude),
essay marking, idioms browser, Anki export, and dashboard. 918 vocabulary
entries across 39 categories. 41 tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
local
2026-02-08 01:57:44 +00:00
parent 104da381fb
commit 2e8c2c11d0
22 changed files with 10664 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
"""Essay writing and AI marking."""
import db
from ai import ask
MARKING_SYSTEM_PROMPT = """You are an expert Persian (Farsi) language teacher marking a GCSE-level essay.
You write in English but can read and correct Persian text.
Always provide constructive, encouraging feedback suitable for a language learner."""
MARKING_PROMPT_TEMPLATE = """Please mark this Persian essay written by a GCSE student.
Theme: {theme}
Student's essay:
{essay_text}
Please provide your response in this exact format:
**Grade:** [Give a grade from 1-9 matching GCSE grading, or a descriptive level like A2/B1]
**Summary:** [1-2 sentence overview of the essay quality]
**Corrections:**
[List specific errors with corrections. For each error, show the original text and the corrected version in Persian, with an English explanation]
**Improved version:**
[Rewrite the essay in corrected Persian]
**Tips for improvement:**
[3-5 specific, actionable tips for the student]"""
GCSE_THEMES = [
"Identity and culture",
"Local area and environment",
"School and work",
"Travel and tourism",
"International and global dimension",
]
def mark_essay(essay_text, theme="General"):
"""Send essay to AI for marking. Returns structured feedback."""
if not essay_text or not essay_text.strip():
return "Please write an essay first."
prompt = MARKING_PROMPT_TEMPLATE.format(
theme=theme,
essay_text=essay_text.strip(),
)
feedback = ask(prompt, system=MARKING_SYSTEM_PROMPT, quality="smart")
# Extract grade from feedback (best-effort)
grade = ""
for line in feedback.split("\n"):
if line.strip().startswith("**Grade:**"):
grade = line.replace("**Grade:**", "").strip()
break
# Save to database
db.save_essay(essay_text.strip(), grade, feedback, theme)
return feedback
def get_essay_history(limit=10):
"""Return recent essays for the history view."""
essays = db.get_recent_essays(limit)
result = []
for e in essays:
result.append({
"Date": e["timestamp"],
"Theme": e["theme"] or "General",
"Grade": e["grade"] or "-",
"Preview": (e["essay_text"] or "")[:50] + "...",
})
return result