feat: adaptive and explainable quiz generation (Phase 1)#397
feat: adaptive and explainable quiz generation (Phase 1)#397maheshxsharmask wants to merge 1 commit intoAOSSIE-Org:mainfrom
Conversation
📝 WalkthroughWalkthroughThese changes implement difficulty-controlled question generation with automatic deduplication and source-grounded explanations. The backend now supports difficulty levels (Easy/Medium/Hard) across all question types, with dedicated hard-variant endpoints, while the frontend routes requests to appropriate endpoints based on selected difficulty. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant Frontend as Frontend<br/>(Text_Input.jsx)
participant Backend as Backend<br/>(server.py)
participant Generator as Question<br/>Generators
participant DocsService as Google Docs<br/>Service
User->>Frontend: Select content, difficulty level
Frontend->>Backend: POST with input_text + difficulty
alt Difficulty != "Easy"
Backend->>Backend: Route to *_hard endpoint
else Difficulty = "Easy"
Backend->>Backend: Route to standard endpoint
end
Backend->>DocsService: Fetch content context
DocsService-->>Backend: Return content
Backend->>Generator: Generate questions<br/>(with hardening if needed)
Generator-->>Backend: Raw questions
Backend->>Backend: Deduplicate by<br/>question_statement
Backend->>Backend: Populate explanations<br/>from context/input_text
Backend-->>Frontend: Formatted questions with<br/>explanations
Frontend-->>User: Display quiz
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@backend/server.py`:
- Around line 432-436: Check for a missing responderUri before returning and
calling webbrowser.open_new_tab: read result.get("responderUri") into edit_url,
and if it's falsy, build a safe fallback using result["formId"] (e.g.,
"https://docs.google.com/forms/d/<formId>/edit") or return a clear error
response (jsonify with an error and 400) instead of returning None. Update the
webbrowser.open_new_tab call to use the same resolved link and ensure the
jsonify({"form_link": edit_url}) returns the resolved (fallback or error) value;
reference symbols: result, responderUri, formId, edit_url,
webbrowser.open_new_tab, jsonify.
🧹 Nitpick comments (4)
backend/server.py (4)
41-47: Consider logging the exception for debugging purposes.The bare
except Exceptionsilently swallows all errors during service initialization. While falling back toNoneis appropriate for optional functionality, logging the exception would aid debugging when the service unexpectedly fails to initialize.♻️ Suggested improvement
+import logging + try: if os.path.exists(SERVICE_ACCOUNT_FILE): docs_service = main.GoogleDocsService(SERVICE_ACCOUNT_FILE, SCOPES) else: docs_service = None -except Exception: +except Exception as e: + logging.warning("Google Docs service initialization failed: %s", e) docs_service = None
444-456: Missing deduplication for consistency with/get_shortq.The regular
/get_shortqendpoint applies_dedup_questionsbefore processing, but this hard endpoint does not. This inconsistency could result in duplicate questions in hard mode output.♻️ Suggested fix
qa_list = qg.generate(article=input_text, use_evaluator=True, num_questions=max_questions, answer_style="sentences") + qa_list = _dedup_questions(qa_list, lambda x: x.get("question")) out = [] for qa in qa_list:
464-489: Missing deduplication and potentialNonecorrect answer.Two concerns:
No deduplication: Unlike
/get_mcq, this hard endpoint doesn't deduplicate questions.
correctcan beNone: If no option has"correct": True,correctwill beNone, which may cause issues for consumers expecting a valid answer.♻️ Suggested fix
qa_list = qg.generate(article=input_text, use_evaluator=True, num_questions=max_questions, answer_style="multiple_choice") + qa_list = _dedup_questions(qa_list, lambda x: x.get("question")) out = [] for qa in qa_list: q_text = make_question_harder(qa.get("question")) ans = qa.get("answer") if isinstance(ans, list): opts = [o.get("answer") for o in ans if o.get("answer")] correct = next((o.get("answer") for o in ans if o.get("correct")), None) + if not correct and opts: + correct = opts[0] # Fallback to first option if no correct flag out.append({
496-502: Missing deduplication and inconsistent output format.
No deduplication:
/get_problemsapplies_dedup_stringsto boolean questions, but this endpoint does not.Output format: Returns a flat list of strings, while other hard endpoints return dicts with
question_typeandexplanation. Consider aligning the format for consistency.♻️ Suggested fix for deduplication
questions = final.get("Boolean_Questions", []) + questions = _dedup_strings(questions) harder = [make_question_harder(q) for q in questions] return jsonify({"output": harder})
| edit_url = result.get("responderUri") | ||
| webbrowser.open_new_tab( | ||
| "https://docs.google.com/forms/d/" + result["formId"] + "/edit" | ||
| ) | ||
| return edit_url | ||
| return jsonify({"form_link": edit_url}) |
There was a problem hiding this comment.
Handle missing responderUri gracefully.
If the Forms API response doesn't include responderUri, form_link will be None, which may cause frontend issues. Consider providing a fallback or returning an error.
🛡️ Suggested fix
edit_url = result.get("responderUri")
+ if not edit_url:
+ # Fallback to constructing the URL from formId
+ edit_url = f"https://docs.google.com/forms/d/{result['formId']}/viewform"
webbrowser.open_new_tab(
"https://docs.google.com/forms/d/" + result["formId"] + "/edit"
)
return jsonify({"form_link": edit_url})📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| edit_url = result.get("responderUri") | |
| webbrowser.open_new_tab( | |
| "https://docs.google.com/forms/d/" + result["formId"] + "/edit" | |
| ) | |
| return edit_url | |
| return jsonify({"form_link": edit_url}) | |
| edit_url = result.get("responderUri") | |
| if not edit_url: | |
| # Fallback to constructing the URL from formId | |
| edit_url = f"https://docs.google.com/forms/d/{result['formId']}/viewform" | |
| webbrowser.open_new_tab( | |
| "https://docs.google.com/forms/d/" + result["formId"] + "/edit" | |
| ) | |
| return jsonify({"form_link": edit_url}) |
🤖 Prompt for AI Agents
In `@backend/server.py` around lines 432 - 436, Check for a missing responderUri
before returning and calling webbrowser.open_new_tab: read
result.get("responderUri") into edit_url, and if it's falsy, build a safe
fallback using result["formId"] (e.g.,
"https://docs.google.com/forms/d/<formId>/edit") or return a clear error
response (jsonify with an error and 400) instead of returning None. Update the
webbrowser.open_new_tab call to use the same resolved link and ensure the
jsonify({"form_link": edit_url}) returns the resolved (fallback or error) value;
reference symbols: result, responderUri, formId, edit_url,
webbrowser.open_new_tab, jsonify.
|
Hi @Aditya062003 @yatikakain |
Summary
This PR implements Phase 1 of Issue #392 by adding difficulty control, source-grounded explanations, and basic question quality improvements across the quiz generation pipeline.
The focus is on backend robustness and generation quality while keeping frontend changes minimal.
Changes
Backend
Difficulty-Controlled Generation
Source-Grounded Explanations
Question Quality Control
Stability Improvements
Google Forms Integration
Frontend
Validation
Backend
Short Hard
Boolean Hard
MCQ Hard
Frontend
Limitations
Follow-Up (Phase 2)
Closes #392
Summary by CodeRabbit
New Features
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.