Spaces:
Runtime error
Runtime error
| import { WikimediaAPI } from './wikimedia-api'; | |
| import { AIProviderManager } from './ai-providers'; | |
| import { StudyPlan, StudyTopic } from '../types'; | |
| export class AIEnhancedWikimedia extends WikimediaAPI { | |
| static async generateEnhancedStudyPlan(topic: string, difficulty: 'beginner' | 'intermediate' | 'advanced' = 'beginner'): Promise<StudyPlan> { | |
| try { | |
| // First, get base content from Wikimedia | |
| const searchResults = await this.searchMultipleProjects(topic, ['wikipedia', 'wikibooks', 'wikiversity'], 15); | |
| if (searchResults.length === 0) { | |
| throw new Error('No content found for this topic'); | |
| } | |
| // Check if AI is available and configured | |
| let useAI = false; | |
| try { | |
| const config = AIProviderManager.getConfig(); | |
| const provider = AIProviderManager.getProviderById(config.selectedProvider); | |
| if (provider) { | |
| // Check if API key is required and available | |
| if (provider.requiresApiKey) { | |
| useAI = !!(config.apiKeys && config.apiKeys[config.selectedProvider]); | |
| } else { | |
| useAI = true; // Local providers don't need API keys | |
| } | |
| // Test connection if we think AI should be available | |
| if (useAI) { | |
| useAI = await AIProviderManager.testConnection(config.selectedProvider); | |
| } | |
| } | |
| } catch (error) { | |
| console.log('AI availability check failed, using fallback'); | |
| useAI = false; | |
| } | |
| if (useAI) { | |
| // Use AI to enhance the study plan | |
| const aiPrompt = `Create a comprehensive study plan for "${topic}" at ${difficulty} level. | |
| Available resources from Wikimedia: | |
| ${searchResults.slice(0, 8).map((result, i) => `${i + 1}. ${result.title} - ${result.snippet.substring(0, 100)}...`).join('\n')} | |
| Please create a structured study plan with: | |
| 1. A compelling title and description | |
| 2. 5-8 learning topics in logical order | |
| 3. For each topic, provide: | |
| - Clear learning objectives | |
| - Estimated study time | |
| - Key concepts to focus on | |
| Format as JSON with this structure: | |
| { | |
| "title": "Study Plan Title", | |
| "description": "Brief description", | |
| "topics": [ | |
| { | |
| "title": "Topic Title", | |
| "description": "What students will learn", | |
| "objectives": ["objective1", "objective2"], | |
| "estimatedTime": "2 hours", | |
| "keyPoints": ["point1", "point2"] | |
| } | |
| ] | |
| }`; | |
| try { | |
| const aiResponse = await AIProviderManager.generateText(aiPrompt, { | |
| maxTokens: 2000, | |
| temperature: 0.7, | |
| systemPrompt: 'You are an expert educational content creator. Create well-structured, engaging study plans that help students learn effectively.' | |
| }); | |
| // Parse AI response | |
| let aiPlan; | |
| try { | |
| // Extract JSON from AI response | |
| const jsonMatch = aiResponse.match(/\{[\s\S]*\}/); | |
| if (jsonMatch) { | |
| aiPlan = JSON.parse(jsonMatch[0]); | |
| } else { | |
| throw new Error('No valid JSON found in AI response'); | |
| } | |
| } catch (parseError) { | |
| console.log('Failed to parse AI response, using fallback'); | |
| return await this.generateStudyPlan(topic, difficulty); | |
| } | |
| // Create enhanced study plan with real Wikimedia resources | |
| const enhancedTopics: StudyTopic[] = []; | |
| for (let i = 0; i < Math.min(aiPlan.topics.length, searchResults.length); i++) { | |
| const aiTopic = aiPlan.topics[i]; | |
| const resource = searchResults[i]; | |
| // Get detailed content for each topic | |
| let detailedContent = resource.snippet; | |
| try { | |
| const fullContent = await this.getPageSnippet(resource.title, resource.project); | |
| if (fullContent && fullContent !== 'No description available') { | |
| detailedContent = fullContent; | |
| } | |
| } catch (error) { | |
| console.log(`Could not get detailed content for ${resource.title}`); | |
| } | |
| enhancedTopics.push({ | |
| id: `topic-${Date.now()}-${i}`, | |
| title: aiTopic.title || resource.title, | |
| description: aiTopic.description || detailedContent.substring(0, 200) + '...', | |
| content: detailedContent, | |
| completed: false, | |
| estimatedTime: aiTopic.estimatedTime || `${Math.ceil(Math.random() * 2 + 1)} hours`, | |
| resources: [ | |
| { | |
| title: resource.title, | |
| url: resource.url, | |
| type: 'article' as const, | |
| project: resource.project | |
| } | |
| ] | |
| }); | |
| } | |
| const studyPlan: StudyPlan = { | |
| id: `ai-plan-${Date.now()}`, | |
| title: aiPlan.title || `${topic} Study Plan`, | |
| description: aiPlan.description || `AI-enhanced ${difficulty} level study plan for ${topic}`, | |
| difficulty, | |
| estimatedTime: this.estimateStudyTime(enhancedTopics.length, difficulty), | |
| created: new Date().toISOString(), | |
| topics: enhancedTopics | |
| }; | |
| return studyPlan; | |
| } catch (aiError) { | |
| console.log('AI enhancement failed, using fallback method:', aiError); | |
| return await this.generateStudyPlan(topic, difficulty); | |
| } | |
| } else { | |
| // AI not available, use standard method | |
| return await this.generateStudyPlan(topic, difficulty); | |
| } | |
| } catch (error) { | |
| console.error('Enhanced study plan generation failed:', error); | |
| // Fallback to original method | |
| return await this.generateStudyPlan(topic, difficulty); | |
| } | |
| } | |
| static async generateQuizFromContent(content: string, title: string): Promise<any> { | |
| // Check AI availability first | |
| let useAI = false; | |
| try { | |
| const config = AIProviderManager.getConfig(); | |
| const provider = AIProviderManager.getProviderById(config.selectedProvider); | |
| if (provider) { | |
| if (provider.requiresApiKey) { | |
| useAI = !!(config.apiKeys && config.apiKeys[config.selectedProvider]); | |
| } else { | |
| useAI = true; | |
| } | |
| if (useAI) { | |
| useAI = await AIProviderManager.testConnection(config.selectedProvider); | |
| } | |
| } | |
| } catch (error) { | |
| useAI = false; | |
| } | |
| if (!useAI) { | |
| return this.generateFallbackQuiz(title); | |
| } | |
| const aiPrompt = `Create a quiz based on this content about "${title}": | |
| ${content.substring(0, 2000)} | |
| Generate 5 multiple-choice questions that test understanding of key concepts. Format as JSON: | |
| { | |
| "questions": [ | |
| { | |
| "question": "Question text", | |
| "options": ["Option A", "Option B", "Option C", "Option D"], | |
| "correct": 0, | |
| "explanation": "Why this answer is correct" | |
| } | |
| ] | |
| }`; | |
| try { | |
| const aiResponse = await AIProviderManager.generateText(aiPrompt, { | |
| maxTokens: 1500, | |
| temperature: 0.5, | |
| systemPrompt: 'You are an expert quiz creator. Create challenging but fair questions that test real understanding.' | |
| }); | |
| const jsonMatch = aiResponse.match(/\{[\s\S]*\}/); | |
| if (jsonMatch) { | |
| const quiz = JSON.parse(jsonMatch[0]); | |
| return { | |
| type: 'quiz', | |
| title: `Quiz: ${title}`, | |
| questions: quiz.questions | |
| }; | |
| } | |
| } catch (error) { | |
| console.error('AI quiz generation failed:', error); | |
| } | |
| // Fallback to rule-based quiz generation | |
| return this.generateFallbackQuiz(title); | |
| } | |
| static async generateSummaryFromContent(content: string, title: string): Promise<any> { | |
| // Check AI availability | |
| let useAI = false; | |
| try { | |
| const config = AIProviderManager.getConfig(); | |
| const provider = AIProviderManager.getProviderById(config.selectedProvider); | |
| if (provider) { | |
| if (provider.requiresApiKey) { | |
| useAI = !!(config.apiKeys && config.apiKeys[config.selectedProvider]); | |
| } else { | |
| useAI = true; | |
| } | |
| if (useAI) { | |
| useAI = await AIProviderManager.testConnection(config.selectedProvider); | |
| } | |
| } | |
| } catch (error) { | |
| useAI = false; | |
| } | |
| if (!useAI) { | |
| return this.generateFallbackSummary(content, title); | |
| } | |
| const aiPrompt = `Summarize this content about "${title}" in a clear, educational way: | |
| ${content.substring(0, 3000)} | |
| Create: | |
| 1. A concise summary (2-3 paragraphs) | |
| 2. 5-7 key points that capture the most important information | |
| Format as JSON: | |
| { | |
| "summary": "Main summary text", | |
| "keyPoints": ["Point 1", "Point 2", ...] | |
| }`; | |
| try { | |
| const aiResponse = await AIProviderManager.generateText(aiPrompt, { | |
| maxTokens: 1000, | |
| temperature: 0.3, | |
| systemPrompt: 'You are an expert at creating clear, educational summaries that help students understand complex topics.' | |
| }); | |
| const jsonMatch = aiResponse.match(/\{[\s\S]*\}/); | |
| if (jsonMatch) { | |
| const summary = JSON.parse(jsonMatch[0]); | |
| return { | |
| type: 'summary', | |
| title: `Summary: ${title}`, | |
| content: summary.summary, | |
| keyPoints: summary.keyPoints | |
| }; | |
| } | |
| } catch (error) { | |
| console.error('AI summary generation failed:', error); | |
| } | |
| // Fallback to rule-based summary | |
| return this.generateFallbackSummary(content, title); | |
| } | |
| static async generateStudyOutline(content: string, title: string): Promise<any> { | |
| // Check AI availability | |
| let useAI = false; | |
| try { | |
| const config = AIProviderManager.getConfig(); | |
| const provider = AIProviderManager.getProviderById(config.selectedProvider); | |
| if (provider) { | |
| if (provider.requiresApiKey) { | |
| useAI = !!(config.apiKeys && config.apiKeys[config.selectedProvider]); | |
| } else { | |
| useAI = true; | |
| } | |
| if (useAI) { | |
| useAI = await AIProviderManager.testConnection(config.selectedProvider); | |
| } | |
| } | |
| } catch (error) { | |
| useAI = false; | |
| } | |
| if (!useAI) { | |
| return this.generateFallbackOutline(title); | |
| } | |
| const aiPrompt = `Create a detailed study outline for "${title}" based on this content: | |
| ${content.substring(0, 2500)} | |
| Organize into 4-6 main sections with subsections. Format as JSON: | |
| { | |
| "sections": [ | |
| { | |
| "title": "Section Title", | |
| "points": ["Point 1", "Point 2", "Point 3"] | |
| } | |
| ] | |
| }`; | |
| try { | |
| const aiResponse = await AIProviderManager.generateText(aiPrompt, { | |
| maxTokens: 1200, | |
| temperature: 0.4, | |
| systemPrompt: 'You are an expert at creating structured study outlines that help students organize their learning.' | |
| }); | |
| const jsonMatch = aiResponse.match(/\{[\s\S]*\}/); | |
| if (jsonMatch) { | |
| const outline = JSON.parse(jsonMatch[0]); | |
| return { | |
| type: 'outline', | |
| title: `Study Outline: ${title}`, | |
| sections: outline.sections | |
| }; | |
| } | |
| } catch (error) { | |
| console.error('AI outline generation failed:', error); | |
| } | |
| // Fallback to rule-based outline | |
| return this.generateFallbackOutline(title); | |
| } | |
| static async generateFlashcards(content: string, title: string): Promise<any> { | |
| // Check AI availability | |
| let useAI = false; | |
| try { | |
| const config = AIProviderManager.getConfig(); | |
| const provider = AIProviderManager.getProviderById(config.selectedProvider); | |
| if (provider) { | |
| if (provider.requiresApiKey) { | |
| useAI = !!(config.apiKeys && config.apiKeys[config.selectedProvider]); | |
| } else { | |
| useAI = true; | |
| } | |
| if (useAI) { | |
| useAI = await AIProviderManager.testConnection(config.selectedProvider); | |
| } | |
| } | |
| } catch (error) { | |
| useAI = false; | |
| } | |
| if (!useAI) { | |
| return this.generateFallbackFlashcards(title); | |
| } | |
| const aiPrompt = `Create flashcards for studying "${title}" based on this content: | |
| ${content.substring(0, 2000)} | |
| Generate 6-8 flashcards with questions and answers. Format as JSON: | |
| { | |
| "cards": [ | |
| { | |
| "front": "Question or term", | |
| "back": "Answer or definition" | |
| } | |
| ] | |
| }`; | |
| try { | |
| const aiResponse = await AIProviderManager.generateText(aiPrompt, { | |
| maxTokens: 1000, | |
| temperature: 0.5, | |
| systemPrompt: 'You are an expert at creating effective flashcards that help with memorization and understanding.' | |
| }); | |
| const jsonMatch = aiResponse.match(/\{[\s\S]*\}/); | |
| if (jsonMatch) { | |
| const flashcards = JSON.parse(jsonMatch[0]); | |
| return { | |
| type: 'flashcards', | |
| title: `Flashcards: ${title}`, | |
| cards: flashcards.cards | |
| }; | |
| } | |
| } catch (error) { | |
| console.error('AI flashcard generation failed:', error); | |
| } | |
| // Fallback to rule-based flashcards | |
| return this.generateFallbackFlashcards(title); | |
| } | |
| // Fallback methods (existing rule-based generation) | |
| private static generateFallbackQuiz(title: string) { | |
| const questions = [ | |
| { | |
| question: `What is the main topic discussed in the article about ${title}?`, | |
| options: [ | |
| `The fundamental concepts and principles of ${title}`, | |
| `The historical development of ${title}`, | |
| `The practical applications of ${title}`, | |
| `The criticism and controversies surrounding ${title}` | |
| ], | |
| correct: 0, | |
| explanation: 'This question tests basic comprehension of the main topic.' | |
| } | |
| ]; | |
| return { | |
| type: 'quiz', | |
| title: `Quiz: ${title}`, | |
| questions | |
| }; | |
| } | |
| private static generateFallbackSummary(content: string, title: string) { | |
| const sentences = content.split('.').filter(s => s.trim().length > 20); | |
| const keySentences = sentences.slice(0, 5); | |
| return { | |
| type: 'summary', | |
| title: `Summary: ${title}`, | |
| content: keySentences.join('. ') + '.', | |
| keyPoints: sentences.slice(5, 10).map(s => s.trim()).filter(s => s.length > 0) | |
| }; | |
| } | |
| private static generateFallbackOutline(title: string) { | |
| return { | |
| type: 'outline', | |
| title: `Study Outline: ${title}`, | |
| sections: [ | |
| { | |
| title: 'Introduction', | |
| points: [ | |
| `Overview and definition of ${title}`, | |
| 'Historical context and background', | |
| 'Key terminology and concepts' | |
| ] | |
| }, | |
| { | |
| title: 'Main Concepts', | |
| points: [ | |
| 'Core principles and theories', | |
| 'Important characteristics and features', | |
| 'Fundamental mechanisms and processes' | |
| ] | |
| } | |
| ] | |
| }; | |
| } | |
| private static generateFallbackFlashcards(title: string) { | |
| const cards = [ | |
| { | |
| front: `What is ${title}?`, | |
| back: `${title} is a comprehensive topic that encompasses various concepts, principles, and applications within its field of study.` | |
| }, | |
| { | |
| front: 'Key characteristics', | |
| back: `The main features include fundamental principles, practical applications, and significant impact on related areas.` | |
| } | |
| ]; | |
| return { | |
| type: 'flashcards', | |
| title: `Flashcards: ${title}`, | |
| cards | |
| }; | |
| } | |
| } |