Skip to content

Conversation

@aritro-datta
Copy link

Implement personalized lesson orientation with LLM-generated messages

Adds personalized lesson orientation messages using OpenAI, based on student intake responses. Students see tailored messages explaining how each lesson supports their career goals.

Features:

Backend:

  • New API route /api/generate-personalized-message that uses OpenAI to generate personalized lesson messages
  • Industry extraction: normalizes student responses (e.g., "tech startup" → "Tech Entrepreneurship") for display in lesson headings
  • Handles lesson title parsing to extract meaningful topics from formats like "Lesson Professional: Skills"
  • Error handling and logging for the personalization pipeline

Frontend:

  • Student intake form with 3 questions (motivation, enrollment reason, desired field)
  • Personalized message display on the lesson confirmation page (moved from modal)
  • Dynamic heading: "How This Lesson Supports Your Career in [Industry]"
  • Timer waits for both LLM messages to load before starting the countdown
  • Button countdown only appears after the timer actually starts

Technical details:

  • Uses gpt-4o-mini for cost-effective personalization
  • Stores intake responses in localStorage keyed by user ID and course
  • Parallel API calls for message generation and industry extraction
  • Graceful fallbacks when personalization fails or intake data is missing

Files changed:

  • New: routes/personalizedMessage.js (backend API)
  • New: components/problem-layout/IntakeForm.js
  • Modified: components/problem-layout/LessonConfirmation.js (integrated personalization)
  • Environment variable support via dotenv for OpenAI API key

shreyabhandari0220 and others added 26 commits July 6, 2025 23:30
This commit adds comprehensive personalization features to the OATutor platform,
enabling dynamic, context-aware lesson orientation messages based on student intake data.

Backend Changes (aws/lti-middleware/):
- Added new personalizedMessage route handler that generates custom lesson messages
  using OpenAI GPT-4o-mini based on student intake responses
- Implemented intelligent industry/field extraction from student responses with
  robust normalization to proper, grammatical industry names
- Enhanced prompt engineering to understand context and nuance, transforming
  informal language (e.g., 'tech startup') into professional terminology
  (e.g., 'Tech Entrepreneurship')
- Added lesson title parsing to extract meaningful topics from formatted titles
  (e.g., 'Lesson Professional: Skills' → 'Skills')
- Implemented parallel API calls for industry extraction and message generation
  for improved performance
- Added graceful error handling with fallback mechanisms for industry extraction
- Updated Firebase initialization with try-catch for local development support

Frontend Changes:
- Enhanced LessonConfirmation component to fetch and display personalized messages
  and extracted industry names
- Updated IntakeForm to show confirmation modal after submission
- Improved UI to display industry-specific career support messaging
- Added loading states and error handling for personalization API calls

Key Features:
- Context-aware industry extraction that understands student intent beyond
  literal responses
- Grammatical normalization ensuring industry names work correctly in display
  sentences like 'How This Lesson Supports Your Career in [Industry]'
- Lesson topic extraction from structured titles to avoid redundant prefixes
- Comprehensive documentation with JSDoc comments throughout
- All code properly attributed and documented

Technical Details:
- Uses OpenAI GPT-4o-mini for both message generation and industry extraction
- Implements robust text cleaning and normalization for industry names
- Handles edge cases with fallback extraction methods
- Maintains backward compatibility with existing lesson confirmation flow

Author: Aritro Datta
This commit addresses a UX issue where the lesson confirmation timer was
starting immediately on page load, before users had a chance to read the
personalized messages generated by the LLM.

Changes made:
- Modified the timer useEffect hook to wait until personalization loading
  is complete before starting the countdown
- Added logic to check if both personalizedMessage and extractedIndustry
  are available (when intake data exists) before starting the timer
- If no intake data exists, the timer starts immediately after loading
  completes since there are no messages to wait for
- Updated the button text logic so the countdown in parentheses (e.g.,
  'Start Lesson (15)') only appears once the timer has actually started
  (elapsed > 0), rather than showing the full duration before the timer
  begins

The timer now properly waits for both LLM-generated messages to be
displayed, ensuring users have time to read the personalized lesson
orientation before the countdown begins. This creates a better user
experience by not rushing users through the confirmation screen before
they've had a chance to see the personalized content.

Technical details:
- Timer state is reset (startRef and elapsed) when the timer actually
  starts, ensuring accurate timing
- The useEffect dependencies include personalizationLoading,
  personalizedMessage, extractedIndustry, and personalizationError to
  properly react to all relevant state changes
- The button text condition now checks both elapsed > 0 and !timerDone
  to show the countdown only during the active countdown period
@aritro-datta aritro-datta force-pushed the aritro-connect-frontend-backend branch from 40da2ea to 6a3359d Compare January 3, 2026 02:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants