Spaces:
Running
Running
File size: 6,696 Bytes
5dd5427 2f6bbd8 5dd5427 13ed840 09d70c8 5dd5427 13ed840 2b8632d 13ed840 2b8632d 5dd5427 bd503ab 5dd5427 bd503ab 5dd5427 2f6bbd8 5dd5427 2f6bbd8 18f0d59 2f6bbd8 18f0d59 2f6bbd8 18f0d59 2f6bbd8 5dd5427 13ed840 5dd5427 2b8632d bd503ab 5dd5427 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
// Chat service for contextual, personalized hints
class ChatService {
constructor(aiService) {
this.aiService = aiService;
this.conversations = new Map(); // blankId -> conversation history
this.wordContexts = new Map(); // blankId -> detailed context
this.blankQuestions = new Map(); // blankId -> Set of used question types (per-blank tracking)
this.currentLevel = 1; // Track current difficulty level
// Distinct, non-overlapping question set
this.questions = [
{ text: "What is its part of speech?", type: "part_of_speech" },
{ text: "What role does it play in the sentence?", type: "sentence_role" },
{ text: "Is it abstract or a person, place, or thing?", type: "word_category" },
{ text: "What is a synonym for this word?", type: "synonym" }
];
}
// Initialize chat context for a specific blank
initializeWordContext(blankId, wordData) {
const context = {
blankId,
targetWord: wordData.originalWord,
sentence: wordData.sentence,
fullPassage: wordData.passage,
bookTitle: wordData.bookTitle,
author: wordData.author,
year: wordData.year || null,
wordPosition: wordData.wordPosition,
difficulty: wordData.difficulty,
previousAttempts: [],
userQuestions: [],
hintLevel: 0 // Progressive hint difficulty
};
this.wordContexts.set(blankId, context);
this.conversations.set(blankId, []);
return context;
}
// Per-blank question tracking with level awareness
async askQuestion(blankId, questionType, userInput = '') {
const context = this.wordContexts.get(blankId);
if (!context) {
return {
error: true,
message: "Context not found for this word."
};
}
// Mark question as used for this specific blank
if (!this.blankQuestions.has(blankId)) {
this.blankQuestions.set(blankId, new Set());
}
this.blankQuestions.get(blankId).add(questionType);
try {
const response = await this.generateSpecificResponse(context, questionType, userInput);
return {
success: true,
response: response,
questionType: questionType
};
} catch (error) {
console.error('Chat error:', error);
return this.getSimpleFallback(context, questionType);
}
}
// Generate specific response based on question type
async generateSpecificResponse(context, questionType, userInput) {
const word = context.targetWord;
const sentence = context.sentence;
const bookTitle = context.bookTitle;
const author = context.author;
// Create sentence with blank for context, but tell AI the actual word
const sentenceWithBlank = sentence.replace(new RegExp(`\\b${word}\\b`, 'gi'), '____');
try {
// Build focused prompt that includes the target word but forbids revealing it
const prompt = this.buildFocusedPrompt({
...context,
sentence: sentenceWithBlank,
targetWord: word
}, questionType, userInput);
// Use the AI service as a simple API wrapper
const aiResponse = await this.aiService.generateContextualHint(prompt);
if (aiResponse && typeof aiResponse === 'string' && aiResponse.length > 10) {
return aiResponse;
}
} catch (error) {
console.warn('AI response failed:', error);
}
// Fallback - return simple fallback response
return this.getSimpleFallback(context, questionType);
}
// Build focused prompt for specific question types
buildFocusedPrompt(context, questionType, userInput) {
const { sentence, bookTitle, author, targetWord, year } = context;
const yearPrefix = year ? `Published in ${year}, ` : '';
const baseContext = `${yearPrefix}from "${bookTitle}" by ${author}: "${sentence}"`;
const safetyRule = `Important: The hidden word is "${targetWord}". Never say this word directly - use "it," "this word," or "the word" instead.`;
const prompts = {
part_of_speech: `${baseContext}\n\n${safetyRule}\n\nIdentify the part of speech and share one interesting grammar tip about this type of word. Keep it conversational and under 25 words.\nExample: "It's a verb! These words show action or states of being, like 'run' or 'exist'."`,
sentence_role: `${baseContext}\n\n${safetyRule}\n\nExplain what role this word plays in the sentence - what's its job here? Be specific to THIS sentence. Keep it under 20 words and conversational.\nExample: "Here it connects two ideas, showing how one thing relates to another."`,
word_category: `${baseContext}\n\n${safetyRule}\n\nWhat general category does this word belong to? Think broadly - is it about people, things, actions, qualities, feelings, places, or ideas? Explain briefly in under 20 words.\nExample: "This word fits in the 'qualities' category - it describes how something looks or feels."`,
synonym: `${baseContext}\n\n${safetyRule}\n\nSuggest a word that could replace it in this sentence. Pick something simple and explain why it works. Under 15 words.\nExample: "You could use 'bright' here - it captures the same feeling of intensity."`
};
return prompts[questionType] || `${baseContext}\n\n${wordInstruction}\n\nProvide a helpful hint about "${targetWord}" without revealing it.`;
}
// Simple fallback responses
getSimpleFallback(context, questionType) {
const fallbacks = {
part_of_speech: "Look at the surrounding words. Is it describing something, showing action, or naming something?",
sentence_role: "Consider how this word connects to the other parts of the sentence.",
word_category: "Think about whether this represents something concrete or an abstract idea.",
synonym: "What other word could fit in this same spot with similar meaning?"
};
return fallbacks[questionType] || "Consider the context and what word would make sense here.";
}
// Clear conversations and reset tracking
clearConversations() {
this.conversations.clear();
this.wordContexts.clear();
this.blankQuestions.clear();
}
// Set current level for question selection
setLevel(level) {
this.currentLevel = level;
}
// Get suggested questions for a specific blank
getSuggestedQuestions(blankId) {
const usedQuestions = this.blankQuestions.get(blankId) || new Set();
return this.questions.map(q => ({
...q,
used: usedQuestions.has(q.type)
}));
}
// Reset for new game (clears everything including across-game state)
resetForNewGame() {
this.clearConversations();
this.currentLevel = 1;
}
}
export default ChatService; |