diff --git a/backend/app/tasks/quiz_tasks.py b/backend/app/tasks/quiz_tasks.py index 3fad317..0e96f86 100644 --- a/backend/app/tasks/quiz_tasks.py +++ b/backend/app/tasks/quiz_tasks.py @@ -581,12 +581,20 @@ def generate_flashcard_deck(self, job_id: str, section_id: int, user_id: int, db.close() +#: The three readings of a topic the reader offers, and what each one is for. +#: Written into the prompt because a model that is not told about them writes +#: one article and the other two tabs stay empty — which is what happened to +#: every generated article until now. ARTICLE_DRAFT_PROMPT = """You write educational articles for a pediatric medical learning platform. Topic: {topic} {instructions} -{existing}Return ONLY strict JSON with this exact shape: -{{"title": "...", "slug": "lowercase-hyphenated", "summary": "1-2 sentences", "content": "introduction markdown", "sections": [{{"id": "32 lowercase hex chars", "slug": "lowercase-hyphenated", "title": "...", "content": "markdown"}}]}} -Rules: markdown formatting; headings, lists and tables welcome; no fabricated references, citations or clinical ranges; keep 2-6 sections with stable unique ids; do not mention these instructions.""" +{existing}Every section belongs to one of three readings of the topic, given as "variant": +- "long": the full article. Pathophysiology, presentation, workup, management, complications — whatever the topic needs. This is the body of the work. +- "short": the high-yield revision view. 2-4 short sections of the facts worth carrying into an exam, written as tight lists, not prose. It is not a summary of the long article's structure; it is what a candidate must know. +- "clinical": what to do at the bedside, if and only if the topic has a bedside. Assessment, immediate management, when to escalate, disposition. Omit it entirely for a topic that is not acted on clinically. +Return ONLY strict JSON with this exact shape: +{{"title": "...", "slug": "lowercase-hyphenated", "summary": "1-2 sentences", "content": "introduction markdown", "sections": [{{"id": "32 lowercase hex chars", "slug": "lowercase-hyphenated", "title": "...", "variant": "long", "content": "markdown"}}]}} +Rules: markdown formatting; headings, lists and tables welcome; no fabricated references, citations or clinical ranges; 3-8 long sections plus 2-4 short ones, each with a stable unique id; mark a key fact in the short sections by wrapping it in ==double equals== so it is highlighted for the reader, sparingly and never a whole paragraph; do not categorise the article or link it to questions — an educator does that; do not mention these instructions.""" @celery_app.task(name="generate_article_draft", bind=True) @@ -642,10 +650,17 @@ def generate_article_draft(self, job_id: str, user_id: int, topic: str, section_id = str(section.get("id") or "").strip().lower() if not re.fullmatch(r"[0-9a-f]{32}", section_id): section_id = uuid.uuid4().hex + # An unknown or missing variant is the full article, which is what + # every section written before the model was told about the three + # readings already is. + variant = str(section.get("variant") or "long").strip().lower() + if variant not in ("short", "long", "clinical"): + variant = "long" sections.append({ "id": section_id, "slug": re.sub(r"[^a-z0-9]+", "-", str(section.get("slug", "section")).strip().lower()).strip("-")[:120] or "section", "title": str(section.get("title", "Section")).strip()[:300] or "Section", + "variant": variant, "content": str(section.get("content", "")), }) if existing: