[AI Generation] Make Teacher Personality Generation Non-Interactive - Part 1/2
Resolved 💬 3 comments Opened Nov 30, 2025 by UberBlackCat Closed Jan 30, 2026
[AI Generation] Make Teacher Personality Generation Non-Interactive - Part 1/2
Parent: #410 (Epic) | Dependencies: None
Description
Remove the two-stage clarification flow from teacher personality generation. Instead of asking follow-up questions, the AI should infer all personality details directly from the initial description.
Example:
- Input: "A friendly cafe waiter"
- Current: Returns 3-5 questions about formality, correction style, etc.
- New: Generates complete personality with inferred low formality, gentle corrections, casual tone
Scope
Included:
- ✅ Teacher personality generation service (
teacher_personality_generation_service.py) - ✅ Teacher personality schemas (
teacher_personality.py) - ✅ Teacher personality API endpoint (
/api/admin/teacher-personalities/generate) - ✅ Admin personality edit form (
AdminPersonalityEdit.tsx) - ✅ API client (
teacherPersonalityApi.ts) - ✅ Tests (
test_teacher_personality_generation.py)
NOT Included:
- ❌ Lesson generators (handled in Part 2/2)
- ❌ Other generation features
Rationale
Why single-stage is better:
- Users can see results immediately and edit if needed
- LLMs are sophisticated enough to infer appropriate characteristics
- Follows "generate first, refine later" UX pattern (industry best practice)
- Reduces cognitive load - no abstract questions upfront
Technical Context
Current Two-Stage Flow:
- Stage 1 (
answers=None): Check if clarification needed
- Service:
_build_initial_prompt()(lines 133-207) - Returns:
{"needs_clarification": true, "questions": [...]}
- Stage 2 (
answersprovided): Generate with answers
- Service:
_build_generation_prompt()(lines 210-289) - Returns:
{"needs_clarification": false, "personality": {...}}
Files implementing pattern:
backend/src/services/teacher_personality_generation_service.py(lines 18-131)backend/src/api/schemas/teacher_personality.py(lines 223-286)backend/src/api/admin/teacher_personalities.py(lines 144-299)frontend/src/pages/admin/AdminPersonalityEdit.tsx(lines 92-97, 310-365)frontend/src/utils/teacherPersonalityApi.tsbackend/tests/test_teacher_personality_generation.py(lines 69-93)
Implementation Approach
1. Backend Service (teacher_personality_generation_service.py)
Remove two-stage logic:
# OLD signature:
def generate_personality_from_description(
db: Session,
description: str,
language: str,
answers: Optional[Dict[str, str]] = None # ❌ Remove this
) -> Dict[str, Any]:
# NEW signature:
def generate_personality_from_description(
db: Session,
description: str,
language: str
) -> Dict[str, Any]: # Always returns {"personality": {...}}
Changes:
- Remove
answersparameter (line 22) - Remove conditional logic checking for
answers(lines 49-58) - Remove
_build_initial_prompt()function (lines 133-207) - Rename
_build_generation_prompt()→_build_prompt()and simplify (lines 210-289) - Remove
needs_clarificationresponse logic (lines 102-110) - Always return
{"personality": {...}}structure
New single-stage prompt:
def _build_prompt(description: str, language: str) -> str:
"""Build prompt that infers all details from description."""
return f"""Create a comprehensive teacher personality configuration from this description.
DESCRIPTION: {description}
TARGET LANGUAGE: {language}
CRITICAL INSTRUCTIONS:
1. INFER all missing details from the description rather than asking questions
2. Make reasonable assumptions about formality, correction style, and other attributes
3. Generate a complete, internally consistent personality
4. If description is brief, infer appropriate defaults based on context clues
INFERENCE EXAMPLES:
- "friendly cafe waiter" → infer low formality, gentle corrections, casual tone
- "strict business mentor" → infer high formality, direct corrections, formal tone
- "patient beginner tutor" → infer gentle corrections, frequent encouragement
PERSONALITY SCHEMA:
{{
"name": "unique_snake_case_name",
"language": "{language}",
"role_description": "...",
"tone": "...",
"conversational_style": "...",
"correction_style": "gentle|balanced|direct",
"formality": "low|medium|high",
"behavior_guidelines": ["guideline1", "guideline2", ...5-10 guidelines...],
"example_phrases": ["phrase1 in {language}", "phrase2 in {language}", ...10-15 phrases...],
"behavior_config": {{...}},
"language_style": {{...}},
"encouragement": {{...}},
"consistency": {{...}}
}}
Return valid JSON with the complete personality:
{{
"personality": {{ ...personality object... }}
}}
"""
2. Backend Schema (teacher_personality.py)
Remove two-stage response:
# REMOVE (lines 244-247):
answers: Optional[Dict[str, str]] = Field(
None,
description="Optional clarification answers from Stage 1 questions (Stage 2 only)"
)
# REMOVE (lines 256-286):
class TeacherPersonalityGenerateResponse(BaseModel):
stage: str = Field(...)
questions: Optional[List[str]] = None
personality: Optional[Dict[str, Any]] = None
# REPLACE WITH:
class TeacherPersonalityGenerateResponse(BaseModel):
"""Response for AI-assisted personality generation (single-stage)."""
personality: Dict[str, Any] = Field(
...,
description="Generated personality configuration matching TeacherPersonalityCreateRequest schema"
)
3. Backend API (teacher_personalities.py)
Simplify endpoint (lines 144-299):
- Remove two-stage response logic (lines 230-259)
- Always return generated personality directly
- Update docstring (remove "Stage 1" and "Stage 2" references)
- Update error handling
4. Frontend UI (AdminPersonalityEdit.tsx)
Remove two-stage state:
// REMOVE (lines 95-96):
const [aiQuestions, setAiQuestions] = useState<string[]>([]);
const [aiAnswers, setAiAnswers] = useState<Record<string, string>>({});
// REMOVE (lines 363-365):
const handleAIAnswerChange = () => { ... }
Simplify generation:
const handleAIGenerate = async () => {
if (!token || !aiDescription.trim()) return;
setAiGenerating(true);
setMessage(null);
try {
const response = await generatePersonalityWithAI(token, {
description: aiDescription,
language: aiLanguage,
});
// Directly populate form with generated personality
populateFormFromGenerated(response.personality);
setAiGenerationOpen(false);
setMessage({
type: 'success',
text: 'AI personality generated! Review and edit as needed.',
});
} catch (error) {
// Error handling...
} finally {
setAiGenerating(false);
}
};
Simplify modal UI (lines 1181-1280):
- Remove conditional rendering based on
aiQuestions.length - Show only description input (no question/answer forms)
- Single "Generate" button (not "Next" then "Generate")
5. Frontend API Client (teacherPersonalityApi.ts)
Update types:
export interface GeneratePersonalityRequest {
description: string;
language: string;
// REMOVE: answers?: Record<string, string>;
}
export interface GeneratePersonalityResponse {
personality: TeacherPersonalityCreateRequest;
// REMOVE: stage, questions
}
6. Tests (test_teacher_personality_generation.py)
Remove two-stage tests:
- Remove
TestGenerationServiceStage1class (lines 69-93) - Remove
test_brief_description_returns_questions() - Remove
test_detailed_description_skips_questions()
Add inference tests:
def test_brief_description_infers_defaults(db_session, mock_llm_response, complete_personality_data):
"""AI infers reasonable defaults from brief descriptions."""
mock_llm_response({"personality": complete_personality_data})
result = generation_service.generate_personality_from_description(
db=db_session,
description="A friendly tutor", # Brief
language="en"
)
assert "personality" in result
# Verify AI inferred appropriately:
assert result["personality"]["formality"] == "low" # from "friendly"
assert result["personality"]["correction_style"] == "gentle"
def test_ambiguous_description_still_generates(db_session, mock_llm_response, complete_personality_data):
"""Even ambiguous descriptions generate without asking questions."""
mock_llm_response({"personality": complete_personality_data})
result = generation_service.generate_personality_from_description(
db=db_session,
description="a teacher", # Very vague
language="en"
)
# Should still generate, not ask questions
assert "personality" in result
assert isinstance(result["personality"], dict)
Acceptance Criteria
Backend
- [ ]
generate_personality_from_description()no longer acceptsanswersparameter - [ ] Two-stage prompt logic removed (
_build_initial_prompt()deleted) - [ ] New prompt explicitly instructs AI to infer rather than ask questions
- [ ] Response schema simplified (no
stage,questionsfields) - [ ] Endpoint always returns direct results (
{"personality": {...}}) - [ ] Tests updated to verify inference behavior
- [ ] All tests pass:
docker compose -f docker/docker-compose.yml exec backend pytest tests/test_teacher_personality_generation.py -v
Frontend
- [ ] Generation modal shows only description input (no question forms)
- [ ] Single "Generate" button (no two-step flow)
- [ ] Form auto-populates immediately after generation
- [ ] Success message guides user to review/edit generated content
- [ ] TypeScript types updated (no
stage,questions,answers) - [ ] Frontend builds:
cd frontend && npm run build
Quality Assurance
- [ ] Inference quality test: Generate 10 personalities from brief descriptions ("friendly waiter", "strict teacher", etc.)
- [ ] Edge case handling: Test with vague descriptions ("a teacher") - should still generate reasonable defaults
- [ ] Non-English descriptions: Test with descriptions in non-English for non-English personalities
- [ ] Consistency check: Generated personalities should be internally consistent (tone matches example phrases)
- [ ] User testing: 2-3 admins test the new flow and confirm it's faster/easier
Integration
- [ ] End-to-end test: Generate personality from "friendly tutor" → form populates with low formality, gentle corrections
- [ ] Manual test: UI feels faster and more streamlined
- [ ] No references to "Stage 1" or "Stage 2" remain in active code (search codebase)
Files to Modify
Backend (3 files)
backend/src/services/teacher_personality_generation_service.py(lines 18-289)backend/src/api/schemas/teacher_personality.py(lines 223-286)backend/src/api/admin/teacher_personalities.py(lines 144-299)
Frontend (2 files)
frontend/src/pages/admin/AdminPersonalityEdit.tsx(lines 92-97, 310-365, 1181-1280)frontend/src/utils/teacherPersonalityApi.ts
Tests (1 file)
backend/tests/test_teacher_personality_generation.py(lines 69-93)
Total: 6 files
Testing
# Backend tests
docker compose -f docker/docker-compose.yml exec backend pytest tests/test_teacher_personality_generation.py -v
# Frontend build
cd frontend && npm run build
# Manual testing
1. Navigate to Admin → Teacher Personalities → Create
2. Click "Generate with AI"
3. Enter brief description: "friendly waiter"
4. Select language: "en"
5. Click "Generate" (should be single button, not "Next")
6. Verify form populates immediately with complete personality
7. Verify inferred values are appropriate:
- formality: "low" (from "friendly")
- correction_style: "gentle" or "balanced"
- tone: includes "friendly"
8. Edit generated personality and save
Migration & Deployment
Database
- ✅ No database schema changes required
- ✅ No migrations needed
API Changes
- ⚠️ Breaking change: Request schema removes
answersfield - ⚠️ Breaking change: Response schema changes from two-stage to single-stage
- ✅ Can deploy independently (no dependencies on Part 2/2)
Deployment Steps
- Deploy backend changes first (backward compatible - old frontend still works initially)
- Deploy frontend changes second
- Test end-to-end flow
- Monitor for 24-48 hours
Rollback Plan
- Keep commented-out two-stage code for 2 weeks
- If generation quality degrades significantly, can revert
- Monitor user feedback and generation success rate
Notes
- Self-contained: This part has no dependencies and can be deployed independently
- Testing focus: Inference quality is critical - test with various description types
- User guidance: Success message should mention "Review and edit as needed" to set expectations
- Prompt engineering: Single-stage prompt is longer and more detailed than two-stage prompts combined
Definition of Done
- [ ] All acceptance criteria met
- [ ] All tests pass (backend + frontend build)
- [ ] Manual testing completed with 3 different description types
- [ ] Code reviewed (if applicable)
- [ ] Can deploy independently without breaking existing functionality
- [ ] No references to Stage 1/Stage 2 remain in teacher personality code
---
Generated with Claude Code
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗