milwright commited on
Commit
2b8632d
·
1 Parent(s): 7a48149

refactor: proper separation of concerns - aiService as API wrapper, conversationManager builds prompts

Browse files
Files changed (2) hide show
  1. src/aiService.js +4 -13
  2. src/conversationManager.js +28 -49
src/aiService.js CHANGED
@@ -68,7 +68,7 @@ class OpenRouterService {
68
  this.apiKey = key;
69
  }
70
 
71
- async generateContextualHint(questionType, word, sentence, bookTitle, wordContext) {
72
  // Check for API key at runtime
73
  const currentKey = this.getApiKey();
74
  if (currentKey && !this.apiKey) {
@@ -76,19 +76,10 @@ class OpenRouterService {
76
  }
77
 
78
  if (!this.apiKey) {
79
- return this.getEnhancedFallback(questionType, word, sentence, bookTitle);
80
  }
81
 
82
  try {
83
- const baseContext = `From "${bookTitle}" by ${author}: "${sentence}"`;
84
-
85
- const prompts = {
86
- part_of_speech: `${baseContext}\n\nWhat part of speech is the missing word? Look at the sentence structure.`,
87
- sentence_role: `${baseContext}\n\nWhat grammatical role does the missing word play? How does it function in the sentence?`,
88
- word_category: `${baseContext}\n\nIs the missing word concrete or abstract? What type of concept does it represent?`,
89
- synonym: `${baseContext}\n\nWhat's a related word or concept that would fit in this blank?`
90
- };
91
-
92
  const response = await fetch(this.apiUrl, {
93
  method: 'POST',
94
  headers: {
@@ -104,7 +95,7 @@ class OpenRouterService {
104
  content: 'You provide clues for word puzzles. Give useful information about grammar, meaning, or context. Keep responses short and focused. Never reveal the actual word.'
105
  }, {
106
  role: 'user',
107
- content: prompts[questionType] || `${baseContext}\n\nProvide a helpful hint about the missing word. Use contextual clues and guide the reader toward the answer without revealing it.`
108
  }],
109
  max_tokens: 100,
110
  temperature: 0.6
@@ -119,7 +110,7 @@ class OpenRouterService {
119
  return data.choices[0].message.content.trim();
120
  } catch (error) {
121
  console.error('Error generating contextual hint:', error);
122
- return this.getEnhancedFallback(questionType, word, sentence, bookTitle);
123
  }
124
  }
125
 
 
68
  this.apiKey = key;
69
  }
70
 
71
+ async generateContextualHint(prompt) {
72
  // Check for API key at runtime
73
  const currentKey = this.getApiKey();
74
  if (currentKey && !this.apiKey) {
 
76
  }
77
 
78
  if (!this.apiKey) {
79
+ return 'API key required for hints';
80
  }
81
 
82
  try {
 
 
 
 
 
 
 
 
 
83
  const response = await fetch(this.apiUrl, {
84
  method: 'POST',
85
  headers: {
 
95
  content: 'You provide clues for word puzzles. Give useful information about grammar, meaning, or context. Keep responses short and focused. Never reveal the actual word.'
96
  }, {
97
  role: 'user',
98
+ content: prompt
99
  }],
100
  max_tokens: 100,
101
  temperature: 0.6
 
110
  return data.choices[0].message.content.trim();
111
  } catch (error) {
112
  console.error('Error generating contextual hint:', error);
113
+ return 'Unable to generate hint at this time';
114
  }
115
  }
116
 
src/conversationManager.js CHANGED
@@ -78,14 +78,14 @@ class ChatService {
78
  const sentenceWithBlank = sentence.replace(new RegExp(`\\b${word}\\b`, 'gi'), '____');
79
 
80
  try {
81
- // Use the enhanced contextual hint generation WITHOUT revealing the target word
82
- const aiResponse = await this.aiService.generateContextualHint(
83
- questionType,
84
- '____', // Don't pass the actual word
85
- sentenceWithBlank,
86
- bookTitle,
87
- author
88
- );
89
 
90
  if (aiResponse && typeof aiResponse === 'string' && aiResponse.length > 10) {
91
  return aiResponse;
@@ -95,59 +95,38 @@ class ChatService {
95
  }
96
 
97
  // Fallback - return enhanced fallback response without revealing word
98
- return this.aiService.getEnhancedFallback(questionType, '____', sentenceWithBlank, bookTitle);
99
  }
100
 
101
  // Build focused prompt for specific question types with level awareness
102
  buildFocusedPrompt(context, questionType, userInput) {
103
- const { sentence, bookTitle, author, targetWord } = context;
104
- const level = this.currentLevel;
105
-
106
- // Level 1 questions - Basic identification
107
- if (level === 1) {
108
- const prompts = {
109
- 'basic_grammar': `What type of word (person/place/thing or action word) fits in the blank in: "${sentence}"? Keep it simple.`,
110
- 'letter_hint': `The missing word is "${targetWord}". Tell me it starts with "${targetWord[0]}" without revealing the full word.`,
111
- 'length_hint': `The missing word has ${targetWord.length} letters. Mention this fact helpfully.`,
112
- 'category_hint': `Is the missing word in "${sentence}" a person, place, thing, or action? Give a simple answer.`,
113
- 'basic_clue': `Give a very simple hint about the missing word in: "${sentence}". Make it easy to understand.`
114
- };
115
- return prompts[questionType] || prompts['basic_clue'];
116
- }
117
-
118
- // Level 2 questions - Contextual understanding
119
- if (level === 2) {
120
- const prompts = {
121
- 'grammar_analysis': `In "${bookTitle}", what part of speech (noun, verb, adjective, etc.) is needed in: "${sentence}"? Explain simply.`,
122
- 'contextual_meaning': `What does the missing word mean in this context from "${bookTitle}": "${sentence}"? Explain without revealing it.`,
123
- 'synonym_clue': `Give a synonym or similar word to the one missing in: "${sentence}". Don't reveal the exact word.`,
124
- 'narrative_connection': `How does the missing word connect to the story in "${bookTitle}"? Context: "${sentence}"`,
125
- 'emotional_context': `What feeling or mood does the missing word express in: "${sentence}"?`
126
- };
127
- return prompts[questionType] || prompts['contextual_meaning'];
128
- }
129
 
130
- // Level 3+ questions - Literary analysis
131
  const prompts = {
132
- 'deep_grammar': `Analyze the grammatical function of the missing word in this passage from "${bookTitle}" by ${author}: "${sentence}"`,
133
- 'literary_analysis': `What literary significance does the missing word have in "${bookTitle}"? Context: "${sentence}"`,
134
- 'authorial_intent': `What would ${author} intend with the word choice here in "${bookTitle}": "${sentence}"?`,
135
- 'comparative_analysis': `How does this word usage compare to similar passages in "${bookTitle}"? Context: "${sentence}"`,
136
- 'style_analysis': `Explain the stylistic choice of the missing word in ${author}'s writing: "${sentence}"`
137
  };
138
 
139
- return prompts[questionType] || prompts['literary_analysis'];
140
  }
141
 
142
  // Simple fallback responses
143
  getSimpleFallback(context, questionType) {
144
- // Use the enhanced fallback from HuggingFace service
145
- return this.aiService.getEnhancedFallback(
146
- questionType,
147
- context.targetWord,
148
- context.sentence,
149
- context.bookTitle
150
- );
 
 
 
 
 
151
  }
152
 
153
  // Helper method to get words before the target word
 
78
  const sentenceWithBlank = sentence.replace(new RegExp(`\\b${word}\\b`, 'gi'), '____');
79
 
80
  try {
81
+ // Build focused prompt using the conversation manager's logic
82
+ const prompt = this.buildFocusedPrompt({
83
+ ...context,
84
+ sentence: sentenceWithBlank
85
+ }, questionType, userInput);
86
+
87
+ // Use the AI service as a simple API wrapper
88
+ const aiResponse = await this.aiService.generateContextualHint(prompt);
89
 
90
  if (aiResponse && typeof aiResponse === 'string' && aiResponse.length > 10) {
91
  return aiResponse;
 
95
  }
96
 
97
  // Fallback - return enhanced fallback response without revealing word
98
+ return this.getSimpleFallback(context, questionType);
99
  }
100
 
101
  // Build focused prompt for specific question types with level awareness
102
  buildFocusedPrompt(context, questionType, userInput) {
103
+ const { sentence, bookTitle, author } = context;
104
+ const baseContext = `From "${bookTitle}" by ${author}: "${sentence}"`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
 
106
  const prompts = {
107
+ part_of_speech: `${baseContext}\n\nWhat part of speech is the missing word? Look at the sentence structure.`,
108
+ sentence_role: `${baseContext}\n\nWhat grammatical role does the missing word play? How does it function in the sentence?`,
109
+ word_category: `${baseContext}\n\nIs the missing word concrete or abstract? What type of concept does it represent?`,
110
+ synonym: `${baseContext}\n\nWhat's a related word or concept that would fit in this blank?`
 
111
  };
112
 
113
+ return prompts[questionType] || `${baseContext}\n\nProvide a helpful hint about the missing word without revealing it.`;
114
  }
115
 
116
  // Simple fallback responses
117
  getSimpleFallback(context, questionType) {
118
+ const fallbacks = {
119
+ part_of_speech: "Look at the surrounding words. Is it describing something, showing action, or naming something?",
120
+ sentence_role: "Consider how this word connects to the other parts of the sentence.",
121
+ word_category: "Think about whether this represents something concrete or an abstract idea.",
122
+ synonym: "What other word could fit in this same spot with similar meaning?"
123
+ };
124
+
125
+ return {
126
+ success: true,
127
+ response: fallbacks[questionType] || "Consider the context and what word would make sense here.",
128
+ questionType: questionType
129
+ };
130
  }
131
 
132
  // Helper method to get words before the target word