feat: Add AI-Powered Story Explanation Feature with 3D Avatar Narration#506
feat: Add AI-Powered Story Explanation Feature with 3D Avatar Narration#506mukul-sharma-tech wants to merge 3 commits intoAOSSIE-Org:mainfrom
Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughA story generation and narration feature: backend adds POST /generate_story to assemble narratives (optional MediaWiki, ShortQGen questions); frontend adds ChooseTopic (text/PDF input) and StoryNarrator (Web Speech + 3D Avatar) pages, routing, a 3D Avatar component, new runtime dependencies, and a VS Code settings file. Changes
Sequence DiagramsequenceDiagram
participant User as User
participant FrontendUI as Frontend (ChooseTopic)
participant Backend as Backend API
participant MediaWiki as MediaWiki
participant ShortQGen as ShortQGen
participant FrontendStory as Frontend (StoryNarrator)
participant Avatar as Avatar Component
participant SpeechAPI as Web Speech API
User->>FrontendUI: Enter topic / Upload PDF
FrontendUI->>FrontendUI: Validate / extract text
FrontendUI->>Backend: POST /generate_story (input_text, language, use_mediawiki)
Backend->>MediaWiki: Optional processing (use_mediawiki)
MediaWiki-->>Backend: Processed text
Backend->>ShortQGen: Generate short questions
ShortQGen-->>Backend: Questions
Backend->>Backend: Assemble story (intro, context, key points)
Backend-->>FrontendUI: { story, language }
FrontendUI->>User: Display Generated Story
User->>FrontendUI: Click Proceed
FrontendUI->>FrontendStory: Navigate with {topic, story, language}
FrontendStory->>SpeechAPI: Synthesize speech (story, lang)
SpeechAPI->>FrontendStory: onstart event
FrontendStory->>Avatar: set isSpeaking = true
Avatar->>Avatar: animate lip-sync, blink, head sway
SpeechAPI->>FrontendStory: onend event
FrontendStory->>Avatar: set isSpeaking = false
Avatar->>Avatar: reset morphs / idle
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~75 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 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: 5
🧹 Nitpick comments (7)
eduaid_web/src/components/Avatar.jsx (1)
25-26: Remove debug console.log statements before merging.These logging statements are useful during development but should be removed for production to avoid cluttering the browser console.
♻️ Proposed fix
headMesh.current = child const dict = child.morphTargetDictionary - console.log('✅ Head Mesh Found:', child.name) - console.log('🧠 Morph Targets:', dict) morphIndexRef.current = {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@eduaid_web/src/components/Avatar.jsx` around lines 25 - 26, Remove the debug console.log calls in Avatar.jsx that print the head mesh and morph targets (the two console.log lines that output '✅ Head Mesh Found:' and '🧠 Morph Targets:'); either delete them or gate them behind an environment/debug flag (e.g., a DEBUG constant) so they don't run in production, ensuring the logic around detecting the head mesh and building dict (the surrounding code that references child.name and dict) remains unchanged.eduaid_web/src/pages/story/ChooseTopic.jsx (2)
3-3: Remove unused imports and state.
MoonandSunare imported but never used, anddarkModestate is declared but not utilized in the UI. Remove these to clean up the code.♻️ Proposed fix
-import { Moon, Sun, ChevronRight, Upload, BookText } from 'lucide-react'; +import { ChevronRight, Upload, BookText } from 'lucide-react';export default function ChooseTopic() { - const [darkMode, setDarkMode] = useState(false); const [activeTab, setActiveTab] = useState('text');Also applies to: 9-9
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@eduaid_web/src/pages/story/ChooseTopic.jsx` at line 3, Remove the unused imports Moon and Sun from the import list in ChooseTopic (remove them from the statement that currently imports Moon, Sun, ChevronRight, Upload, BookText) and delete the unused darkMode state declaration (and any setDarkMode if present) inside the ChooseTopic component so there are no unused variables; keep ChevronRight, Upload, BookText as-is and ensure no other references to Moon, Sun, or darkMode remain in the file.
50-52: Avoid hardcoding localhost URL in user-facing error messages.The error message exposes an internal implementation detail (
localhost:5000) which is incorrect for production deployments and confusing for end users.♻️ Proposed fix
} catch (err) { console.error(err); - alert('Story generation failed. Please ensure the backend server is running on http://localhost:5000'); + alert('Story generation failed. Please try again later.'); } finally {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@eduaid_web/src/pages/story/ChooseTopic.jsx` around lines 50 - 52, The catch block in the ChooseTopic component currently alerts a hardcoded backend URL (http://localhost:5000); replace this user-facing message with a non-environment-specific, friendly error (e.g., "Story generation failed — please try again later or contact support") and keep the detailed error for developer logs (console.error(err)). Update the error handling in the catch of the async story generation/fetch logic inside ChooseTopic.jsx to remove the hardcoded URL and provide a generic, production-safe alert while preserving the original err logging for diagnostics..vscode/settings.json (1)
1-2: Consider removing this empty settings file.An empty
.vscode/settings.jsonadds no value to the repository. Either add meaningful workspace settings (e.g., editor configuration, extension recommendations) or remove this file to reduce repository noise.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.vscode/settings.json around lines 1 - 2, This .vscode/settings.json is empty and should be removed to avoid repo noise or replaced with meaningful workspace settings; either delete the empty file from the PR or populate settings.json with explicit editor/workspace preferences (e.g., "editor.formatOnSave", "files.exclude", or extension recommendations) so it carries value.backend/server.py (2)
496-502: Consider adding input length validation.There's no upper limit on
input_textlength. Very large inputs could cause performance issues or resource exhaustion. Consider adding a reasonable maximum length.♻️ Proposed fix
input_text = data.get("input_text", "") language = data.get("language", "english") use_mediawiki = data.get("use_mediawiki", 0) if not input_text: return jsonify({"error": "No input text provided"}), 400 + + MAX_INPUT_LENGTH = 10000 # Adjust as needed + if len(input_text) > MAX_INPUT_LENGTH: + return jsonify({"error": f"Input text exceeds maximum length of {MAX_INPUT_LENGTH} characters"}), 400🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/server.py` around lines 496 - 502, Add an upper bound check for the request payload by defining a MAX_INPUT_LENGTH (e.g. 10_000) and validating the length of the extracted input_text (from request.get_json() and the input_text variable). After the existing empty check, return a 400 JSON error if len(input_text) exceeds MAX_INPUT_LENGTH with a clear message like "input_text too long, max X characters" so the endpoint (where input_text is used) is protected from overly large inputs.
553-555: Consider catching more specific exceptions.Catching a broad
Exceptioncan mask unexpected errors and make debugging harder. Consider catching specific exceptions (e.g.,ValueError,KeyError) that you expect from the story generation logic, and let unexpected errors propagate for proper logging/monitoring.♻️ Proposed fix
- except Exception as e: - print(f"Error generating story: {str(e)}") - return jsonify({"error": f"Story generation failed: {str(e)}"}), 500 + except (ValueError, KeyError) as e: + print(f"Error generating story: {e!r}") + return jsonify({"error": f"Story generation failed: {e!s}"}), 500 + except Exception as e: + # Log unexpected errors for debugging + print(f"Unexpected error generating story: {e!r}") + return jsonify({"error": "Story generation failed unexpectedly"}), 500🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/server.py` around lines 553 - 555, Replace the broad "except Exception as e" in the story-generation error handler with targeted exception handlers for expected failure modes (for example: "except (ValueError, KeyError) as e" and/or any domain-specific StoryGenerationError) and return the same jsonify error response for those cases; do not swallow unexpected exceptions—either let them propagate or catch them and re-raise/log appropriately (e.g., use a final "except Exception: raise" or remove the broad catch) so unexpected errors surface to your monitoring.eduaid_web/src/pages/story/StoryNarrator.jsx (1)
7-16: Handle direct navigation without state.If a user navigates directly to
/story(e.g., via URL or bookmark),location.statewill be null, resulting in an empty page. Consider redirecting to/choose-topicor displaying a helpful message.♻️ Proposed fix
export default function StoryNarrator() { const location = useLocation(); const navigate = useNavigate(); const { story = '', topic = '', language = 'english' } = location.state || {}; const [isSpeaking, setIsSpeaking] = useState(false); const [animation, setAnimation] = useState('Idle'); + useEffect(() => { + if (!location.state || !location.state.story) { + navigate('/choose-topic', { replace: true }); + } + }, [location.state, navigate]); + useEffect(() => { if (!story) return;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@eduaid_web/src/pages/story/StoryNarrator.jsx` around lines 7 - 16, The StoryNarrator component currently reads story/topic/language from location.state which can be null when a user navigates directly; update the component to detect a missing story (and/or topic) inside the existing useEffect (or at top of render) and perform a programmatic redirect to the topic selection route (use the existing navigate from useNavigate to navigate('/choose-topic')) or render a friendly fallback message/UI if you prefer; specifically modify the logic around location.state / the story/topic variables in StoryNarrator so when story is falsy you call navigate('/choose-topic') (or return the fallback UI) to avoid showing an empty page.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@backend/server.py`:
- Around line 516-518: The first_sentence extraction can be empty when
input_text begins with a period; update the logic that builds first_sentence
(variable first_sentence in the block that appends to story_parts) to trim
leading dots/whitespace and pick the first non-empty segment, falling back to a
safe substring (e.g., input_text[:100] after stripping) if no non-empty sentence
exists; ensure the subsequent append uses this sanitized first_sentence so you
don't produce "Let me explain ." for inputs like "." or ".Hello".
In `@eduaid_web/src/components/Avatar.jsx`:
- Around line 63-68: The setTimeout used to reset head.morphTargetInfluences for
morphs.blinkL and morphs.blinkR can fire after the Avatar component unmounts;
store the timeout ID in a ref (e.g., blinkTimeoutRef) when calling setTimeout
and clear it in the component's cleanup (useEffect return) using
clearTimeout(blinkTimeoutRef.current) and null the ref; ensure any code that
accesses head.morphTargetInfluences checks the component is still mounted (or
head exists) before touching morph indices.
In `@eduaid_web/src/pages/story/ChooseTopic.jsx`:
- Around line 19-25: The cleanText function's regex ([^\w\s.,?!]) is too
aggressive and strips useful punctuation (hyphens, apostrophes, quotes, colons,
parentheses); update the cleanText implementation to allow those characters by
expanding the allowed character class (e.g., include - ' " : () and any
preferred Unicode apostrophes) while still removing other unwanted characters,
then keep the subsequent whitespace normalization (.replace(/\s+/g, '
').trim()); modify the cleanText function accordingly so strings like "It's a
well-known fact (see: Wikipedia)" retain expected punctuation.
In `@eduaid_web/src/pages/story/StoryNarrator.jsx`:
- Around line 15-19: The useEffect currently assumes Web Speech API exists; add
a feature-detection guard before using window.speechSynthesis and
SpeechSynthesisUtterance in the useEffect that creates synth and utterance
(e.g., check window.speechSynthesis && typeof SpeechSynthesisUtterance !==
'undefined'), and handle the unsupported case by early-returning or triggering a
fallback/user notification (so modify the effect that defines synth and
utterance to bail out or call a fallback handler when the API is unavailable).
- Around line 23-25: The hinglish branch currently strips any word lacking ASCII
letters causing mixed-language content loss; update the hinglish handling so
utterance.lang is set to 'hi-IN' but do not filter words—use the original story
(optionally only remove punctuation like periods/commas) for utterance.text
instead of the map/filter that drops non-ASCII words; change the code that
assigns utterance.text in the hinglish branch (the line that currently calls
.replace(...).split(' ').map(...).join(' ')) to preserve all words.
---
Nitpick comments:
In @.vscode/settings.json:
- Around line 1-2: This .vscode/settings.json is empty and should be removed to
avoid repo noise or replaced with meaningful workspace settings; either delete
the empty file from the PR or populate settings.json with explicit
editor/workspace preferences (e.g., "editor.formatOnSave", "files.exclude", or
extension recommendations) so it carries value.
In `@backend/server.py`:
- Around line 496-502: Add an upper bound check for the request payload by
defining a MAX_INPUT_LENGTH (e.g. 10_000) and validating the length of the
extracted input_text (from request.get_json() and the input_text variable).
After the existing empty check, return a 400 JSON error if len(input_text)
exceeds MAX_INPUT_LENGTH with a clear message like "input_text too long, max X
characters" so the endpoint (where input_text is used) is protected from overly
large inputs.
- Around line 553-555: Replace the broad "except Exception as e" in the
story-generation error handler with targeted exception handlers for expected
failure modes (for example: "except (ValueError, KeyError) as e" and/or any
domain-specific StoryGenerationError) and return the same jsonify error response
for those cases; do not swallow unexpected exceptions—either let them propagate
or catch them and re-raise/log appropriately (e.g., use a final "except
Exception: raise" or remove the broad catch) so unexpected errors surface to
your monitoring.
In `@eduaid_web/src/components/Avatar.jsx`:
- Around line 25-26: Remove the debug console.log calls in Avatar.jsx that print
the head mesh and morph targets (the two console.log lines that output '✅ Head
Mesh Found:' and '🧠 Morph Targets:'); either delete them or gate them behind an
environment/debug flag (e.g., a DEBUG constant) so they don't run in production,
ensuring the logic around detecting the head mesh and building dict (the
surrounding code that references child.name and dict) remains unchanged.
In `@eduaid_web/src/pages/story/ChooseTopic.jsx`:
- Line 3: Remove the unused imports Moon and Sun from the import list in
ChooseTopic (remove them from the statement that currently imports Moon, Sun,
ChevronRight, Upload, BookText) and delete the unused darkMode state declaration
(and any setDarkMode if present) inside the ChooseTopic component so there are
no unused variables; keep ChevronRight, Upload, BookText as-is and ensure no
other references to Moon, Sun, or darkMode remain in the file.
- Around line 50-52: The catch block in the ChooseTopic component currently
alerts a hardcoded backend URL (http://localhost:5000); replace this user-facing
message with a non-environment-specific, friendly error (e.g., "Story generation
failed — please try again later or contact support") and keep the detailed error
for developer logs (console.error(err)). Update the error handling in the catch
of the async story generation/fetch logic inside ChooseTopic.jsx to remove the
hardcoded URL and provide a generic, production-safe alert while preserving the
original err logging for diagnostics.
In `@eduaid_web/src/pages/story/StoryNarrator.jsx`:
- Around line 7-16: The StoryNarrator component currently reads
story/topic/language from location.state which can be null when a user navigates
directly; update the component to detect a missing story (and/or topic) inside
the existing useEffect (or at top of render) and perform a programmatic redirect
to the topic selection route (use the existing navigate from useNavigate to
navigate('/choose-topic')) or render a friendly fallback message/UI if you
prefer; specifically modify the logic around location.state / the story/topic
variables in StoryNarrator so when story is falsy you call
navigate('/choose-topic') (or return the fallback UI) to avoid showing an empty
page.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
eduaid_web/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (9)
.vscode/settings.jsonbackend/server.pyeduaid_web/package.jsoneduaid_web/public/models/human.glbeduaid_web/src/App.jseduaid_web/src/components/Avatar.jsxeduaid_web/src/pages/Home.jsxeduaid_web/src/pages/story/ChooseTopic.jsxeduaid_web/src/pages/story/StoryNarrator.jsx
|
Thanks for review! I will do the changes suggested |
There was a problem hiding this comment.
Actionable comments posted: 5
♻️ Duplicate comments (3)
backend/server.py (1)
517-520:⚠️ Potential issue | 🟡 Minor
first_sentencefallback still mishandles leading-dot input.For inputs like
.or.Hello, the current fallback can still produce awkward intros (e.g.,Let me explain ..). This is the same edge case class previously flagged.Suggested fix
- first_sentence = input_text.split('.')[0].strip() if '.' in input_text else input_text[:100] - if not first_sentence: - first_sentence = input_text[:100].strip() or "this topic" + segments = [seg.strip() for seg in input_text.split('.') if seg.strip()] + first_sentence = segments[0] if segments else input_text.lstrip('. ').strip()[:100] + if not first_sentence: + first_sentence = "this topic"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/server.py` around lines 517 - 520, The computation of first_sentence mishandles inputs starting with dots (e.g., "." or ".Hello"), so sanitize input_text before extracting the first sentence: create a sanitized variable (e.g., sanitized = input_text.lstrip('. ').strip()) and use sanitized.split('.')[0] if '.' in sanitized else sanitized[:100]; then fall back to sanitized[:100].strip() or "this topic" for empty results, and use that sanitized first_sentence when calling story_parts.append; update the logic around the existing first_sentence assignment and the story_parts.append call to avoid generating leading/trailing dots in the output.eduaid_web/src/pages/story/ChooseTopic.jsx (1)
20-24:⚠️ Potential issue | 🟠 Major
cleanTextremoves non-Latin text and breaks Hindi/Hinglish stories.Line 22 relies on
\w, which strips Devanagari and other scripts. That conflicts with the language selector (Lines 155-157).Suggested fix
const cleanText = (text) => { return text - .replace(/[^\w\s.,?!:;'"\-()]/g, '') // preserve common punctuation + .replace(/[^\p{L}\p{N}\s.,?!:;'"\-()]/gu, '') // keep letters/numbers across languages .replace(/\s+/g, ' ') .trim(); };What is browser support for JavaScript RegExp Unicode property escapes (`\p{L}`, `\p{N}` with the `u` flag), especially for React apps targeting modern Chrome, Firefox, and Safari?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@eduaid_web/src/pages/story/ChooseTopic.jsx` around lines 20 - 24, The cleanText function is currently using \w which strips non-Latin scripts (breaking Hindi/Hinglish); update the character-class to use Unicode property escapes (e.g., allow \p{L} and \p{N} with the u flag) so letters and numbers from Devanagari and other scripts are preserved, keep the allowed punctuation (.,?!:;'"-()) and whitespace handling, and ensure the regex uses the global + unicode flags (or add a graceful fallback if the runtime lacks Unicode property escape support); locate and modify the cleanText arrow function to replace the offending regex and retain the subsequent .replace(/\s+/g, ' ').trim() logic.eduaid_web/src/pages/story/StoryNarrator.jsx (1)
18-24:⚠️ Potential issue | 🟡 MinorAdd constructor feature detection for
SpeechSynthesisUtterance.Line 18 guards
speechSynthesis, but Line 24 still assumesSpeechSynthesisUtteranceexists. Some browsers expose one without fully supporting the other.Suggested fix
- if (!window.speechSynthesis) { + if (!window.speechSynthesis || typeof SpeechSynthesisUtterance === 'undefined') { console.warn('Web Speech API not supported'); return; }In current browser compatibility docs, can `window.speechSynthesis` exist while `SpeechSynthesisUtterance` is unavailable or partially unsupported? Please include support notes for Chrome, Safari (iOS/macOS), and Firefox.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@backend/server.py`:
- Around line 555-557: The except block that prints and returns the raw
exception (the print statement and the jsonify response in the except Exception
as e handler) is leaking internal error details to clients; update the handler
to log the full exception internally using an application logger (e.g.,
logger.exception or app.logger.error with the exception) and change the API
response (the jsonify call) to return a generic error message such as "Story
generation failed" without including str(e) or other internals, keeping the HTTP
500 status; ensure you remove or replace the print(f"Error generating story:
{str(e)}") with the internal logging call.
- Around line 496-503: The handler calls request.get_json() and immediately uses
data.get which will raise if get_json() returned None; update the input
validation to guard for non-JSON or None payloads by checking that data is
truthy before accessing keys (i.e., verify data is not None), and if it is None
return a 400 JSON response like {"error":"Invalid or missing JSON payload"}
instead of proceeding; update the block around request.get_json(), data,
input_text, language, and use_mediawiki to perform this None check first and
then extract data.get("input_text", "") etc.
In `@eduaid_web/src/components/Avatar.jsx`:
- Around line 52-53: The frame loop currently bails out whenever
morphs.mouthOpen is null (if (!head || morphs.mouthOpen == null) return), which
prevents blink/head-sway from running; change the guard to only return when head
is missing (if (!head) return) or when neither mouth nor blink morphs exist
(e.g., if (!head || (!hasMouthMorph && !hasBlinkMorph)) return), then move the
mouthOpen usage into the mouth-specific branch so mouth code checks
morphs.mouthOpen before using it while blink/head-sway logic only depends on
blink morph presence (reference the head variable and morphs.mouthOpen and your
blink morph keys in Avatar.jsx).
- Line 97: The forEach callback currently uses an expression arrow `(a) =>
a.stop()` which creates an implicit return flagged by Biome; change the callback
on the Object.values(actions).forEach call to use a statement block so the
callback explicitly calls `a.stop()` without returning a value (e.g., convert to
a block arrow or a regular function) to satisfy the useIterableCallbackReturn
rule and keep the call site (`Object.values(actions).forEach`, `actions`,
`stop`) intact.
In `@eduaid_web/src/pages/story/ChooseTopic.jsx`:
- Around line 85-87: The component sets topicText to the entire extracted PDF
content via setTopicText(extractedText) and then places that full text into the
route navigation state as `topic`, which bloats history; change the
navigation/state payload to include a trimmed title or preview instead of the
full text (e.g., derive a topicTitle/topicPreview from topicText by taking the
first N characters or generating a concise title) and pass that smaller string
in the navigation call (where you currently pass topicText), while keeping the
full topicText only in component state if needed for display or processing in
ChooseTopic.jsx.
---
Duplicate comments:
In `@backend/server.py`:
- Around line 517-520: The computation of first_sentence mishandles inputs
starting with dots (e.g., "." or ".Hello"), so sanitize input_text before
extracting the first sentence: create a sanitized variable (e.g., sanitized =
input_text.lstrip('. ').strip()) and use sanitized.split('.')[0] if '.' in
sanitized else sanitized[:100]; then fall back to sanitized[:100].strip() or
"this topic" for empty results, and use that sanitized first_sentence when
calling story_parts.append; update the logic around the existing first_sentence
assignment and the story_parts.append call to avoid generating leading/trailing
dots in the output.
In `@eduaid_web/src/pages/story/ChooseTopic.jsx`:
- Around line 20-24: The cleanText function is currently using \w which strips
non-Latin scripts (breaking Hindi/Hinglish); update the character-class to use
Unicode property escapes (e.g., allow \p{L} and \p{N} with the u flag) so
letters and numbers from Devanagari and other scripts are preserved, keep the
allowed punctuation (.,?!:;'"-()) and whitespace handling, and ensure the regex
uses the global + unicode flags (or add a graceful fallback if the runtime lacks
Unicode property escape support); locate and modify the cleanText arrow function
to replace the offending regex and retain the subsequent .replace(/\s+/g, '
').trim() logic.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
backend/server.pyeduaid_web/src/components/Avatar.jsxeduaid_web/src/pages/story/ChooseTopic.jsxeduaid_web/src/pages/story/StoryNarrator.jsx
backend/server.py
Outdated
| data = request.get_json() | ||
| input_text = data.get("input_text", "") | ||
| language = data.get("language", "english") | ||
| use_mediawiki = data.get("use_mediawiki", 0) | ||
|
|
||
| if not input_text: | ||
| return jsonify({"error": "No input text provided"}), 400 | ||
|
|
There was a problem hiding this comment.
Guard non-JSON payloads before using data.get.
On Line 496, request.get_json() can return None; Line 497 then raises and falls into a 500 path instead of returning a 400 validation error.
Suggested fix
- data = request.get_json()
- input_text = data.get("input_text", "")
+ data = request.get_json(silent=True) or {}
+ input_text = (data.get("input_text") or "").strip()
language = data.get("language", "english")
use_mediawiki = data.get("use_mediawiki", 0)
if not input_text:
return jsonify({"error": "No input text provided"}), 400📝 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.
| data = request.get_json() | |
| input_text = data.get("input_text", "") | |
| language = data.get("language", "english") | |
| use_mediawiki = data.get("use_mediawiki", 0) | |
| if not input_text: | |
| return jsonify({"error": "No input text provided"}), 400 | |
| data = request.get_json(silent=True) or {} | |
| input_text = (data.get("input_text") or "").strip() | |
| language = data.get("language", "english") | |
| use_mediawiki = data.get("use_mediawiki", 0) | |
| if not input_text: | |
| return jsonify({"error": "No input text provided"}), 400 | |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@backend/server.py` around lines 496 - 503, The handler calls
request.get_json() and immediately uses data.get which will raise if get_json()
returned None; update the input validation to guard for non-JSON or None
payloads by checking that data is truthy before accessing keys (i.e., verify
data is not None), and if it is None return a 400 JSON response like
{"error":"Invalid or missing JSON payload"} instead of proceeding; update the
block around request.get_json(), data, input_text, language, and use_mediawiki
to perform this None check first and then extract data.get("input_text", "")
etc.
|
@coderabbitai Thanks for the thorough review! I've addressed all the issues |
|
Tip For best results, initiate chat on the files or code changes.
If you'd like me to review the changes, feel free to ask and I'll take another look at the updated code. If you found this review helpful, would you consider giving us a shout-out on X? Thank you for using CodeRabbit! |
|
@coderabbitai when will u merge it |
|
Tip For best results, initiate chat on the files or code changes.
Only repository maintainers with write access can merge pull requests. Since this is the AOSSIE-Org/EduAid repository, you'll need to wait for one of the maintainers to:
Since you've already addressed the review feedback, your PR is ready for human review. The maintainers will merge it when they have a chance to review and approve your work. If you'd like to speed up the process, you could:
Good luck with your PR! 🚀 |
feat: Add AI-Powered Story Explanation Feature with 3D Avatar Narration
🎯 Overview
This PR introduces an interactive story explanation feature that transforms educational topics into engaging narratives, presented by an animated 3D avatar with synchronized speech synthesis.
✨ What's New
🔧 Technical Changes
Frontend (
eduaid_web/)New Components:
src/components/Avatar.jsx- 3D avatar with morph target animationssrc/pages/story/ChooseTopic.jsx- Story generation interfacesrc/pages/story/StoryNarrator.jsx- Avatar narration displayUpdated Files:
src/App.js- Added/choose-topicand/storyroutessrc/pages/Home.jsx- Added "Try Story Feature" navigation buttonpackage.json- Added dependencies:framer-motion,lucide-react,@react-three/fiber,@react-three/drei,threeBackend (
backend/)New Endpoint:
POST /generate_storyinput_text,language,use_mediawikiShortQGenmodel for content generation🎨 Features
📦 Dependencies Added
{ "framer-motion": "^10.16.0", "lucide-react": "^0.294.0", "@react-three/fiber": "^8.15.0", "@react-three/drei": "^9.88.0", "three": "^0.158.0" }🚀 How to Test
1. Start Backend:
cd backend python server.py2. Start Frontend:
cd eduaid_web npm install npm start3. Test Story Feature:
📝 Notes
http://localhost:5000/public/models/human.glb(falls back to placeholder if missing)📸 Screenshots
Home Page - New Story Feature Button
Story Generation Interface
3D Avatar Narration
Type of Change
Checklist
AI Usage Disclosure
AI Models and Tools Used:
AI-Generated Components:
Avatar.jsxcomponent (heavily modified with custom morph target animations)/generate_storyendpoint implementationChooseTopic.jsxfor API communicationManual Modifications:
Testing Performed:
I acknowledge that I have used AI tools responsibly when creating this Pull Request. I have thoroughly tested all code locally, verified that it meets the task requirements, builds successfully, and generates no errors or warnings. I understand the changes I am proposing and take full responsibility for the code quality and functionality.
Summary by CodeRabbit
New Features
Chores
Style