Skip to main content
Glama
brazilian-educational-analyzer.ts10.6 kB
/** * Brazilian Educational Content Analyzer * Semantic-first approach with Brazilian Portuguese educational context */ export interface BrazilianEducationalContext { gradeLevel: string; // "fundamental-1", "fundamental-2", "medio", "superior", "tecnico" subject?: string; duration?: number; // minutes pedagogicalApproach?: string; bnccCompetencies?: string[]; } export class BrazilianEducationalAnalyzer { // High-confidence Brazilian educational triggers (additive, not restrictive) private brazilianEducationalBoosts = [ // Grade levels /\b(?:ensino\s+)?fundamental\s*[12]?\b/i, /\b(?:ensino\s+)?m[eé]dio\b/i, /\b(?:ensino\s+)?superior\b/i, /\b(?:ensino\s+)?t[eé]cnico\b/i, /\b(?:[1-9]º|primeiro|segundo|terceiro|quarto|quinto|sexto|s[eé]timo|oitavo|nono)\s+ano\b/i, // Time/duration /\bcarga\s+hor[aá]ria\b/i, /\bminutos?\s+de\s+aula\b/i, /\bper[ií]odo\s+(?:letivo|escolar)\b/i, /\bbimestre|trimestre|semestre\b/i, // Educational activities /\batividade\s+(?:pedag[oó]gica|educacional|escolar)\b/i, /\bsequência\s+did[aá]tica\b/i, /\bplano\s+de\s+aula\b/i, /\bobjetivos?\s+de\s+aprendizagem\b/i, /\bcompetências\s+e\s+habilidades\b/i, // Assessment (Brazilian context) /\bavalia[çc][aã]o\s+(?:diagn[oó]stica|formativa|somativa)\b/i, /\bquest[oõ]es?\s+de\s+(?:vestibular|enem|concurso)\b/i, /\bprova|teste|exerc[ií]cios?\b/i, // BNCC and curriculum /\bbncc|base\s+nacional\s+comum\s+curricular\b/i, /\bcurr[ií]culo\s+(?:escolar|nacional|estadual)\b/i, /\bpar[aâ]metros?\s+curriculares\b/i, ]; private gradeMapping = { // Ensino Fundamental I (1º ao 5º ano) 'fundamental-1': ['primeiro', 'segundo', 'terceiro', 'quarto', 'quinto', '1º', '2º', '3º', '4º', '5º'], // Ensino Fundamental II (6º ao 9º ano) 'fundamental-2': ['sexto', 'sétimo', 'oitavo', 'nono', '6º', '7º', '8º', '9º'], // Ensino Médio (1º ao 3º ano) 'medio': ['primeiro.*médio', 'segundo.*médio', 'terceiro.*médio', '1º.*médio', '2º.*médio', '3º.*médio'], }; private subjectKeywords = { 'matemática': ['matemática', 'álgebra', 'geometria', 'cálculo', 'estatística', 'números'], 'português': ['português', 'língua portuguesa', 'literatura', 'gramática', 'redação', 'texto'], 'ciências': ['ciências', 'biologia', 'física', 'química', 'natureza', 'experimento'], 'história': ['história', 'histórico', 'passado', 'civilização', 'época', 'período'], 'geografia': ['geografia', 'território', 'região', 'clima', 'relevo', 'população'], 'inglês': ['inglês', 'english', 'língua inglesa', 'vocabulary', 'grammar'], 'educação física': ['educação física', 'esporte', 'atividade física', 'corpo', 'movimento'], 'artes': ['artes', 'arte', 'pintura', 'música', 'teatro', 'dança', 'cultura'], }; public analyzeBrazilianContext(content: string, title?: string): BrazilianEducationalContext { const fullText = `${title || ''} ${content}`.toLowerCase(); return { gradeLevel: this.detectGradeLevel(fullText), subject: this.detectSubject(fullText), duration: this.extractDuration(fullText), pedagogicalApproach: this.detectPedagogicalApproach(fullText), bnccCompetencies: this.extractBNCC(fullText), }; } public calculateEducationalConfidence(content: string, title?: string): number { const fullText = `${title || ''} ${content}`.toLowerCase(); let confidence = 0.3; // Base semantic confidence // Add confidence boosts from Brazilian educational patterns this.brazilianEducationalBoosts.forEach(pattern => { const matches = fullText.match(pattern); if (matches) { confidence += 0.1 * matches.length; // Each match adds 10% confidence } }); // Subject matter boost const hasSubject = Object.values(this.subjectKeywords).some(keywords => keywords.some(keyword => fullText.includes(keyword)) ); if (hasSubject) confidence += 0.2; // Grade level boost const hasGradeLevel = Object.values(this.gradeMapping).some(grades => grades.some(grade => new RegExp(grade, 'i').test(fullText)) ); if (hasGradeLevel) confidence += 0.2; // Duration/time context boost if (this.extractDuration(fullText)) confidence += 0.1; return Math.min(1.0, confidence); } public isEducationalContent(content: string, title?: string): boolean { // Semantic-first approach: if it contains educational keywords, concepts, or structure const confidence = this.calculateEducationalConfidence(content, title); // Also check for semantic educational indicators const semanticIndicators = this.checkSemanticEducationalIndicators(content, title); return confidence > 0.4 || semanticIndicators; } private detectGradeLevel(text: string): string { // Check for explicit grade mentions for (const [level, patterns] of Object.entries(this.gradeMapping)) { for (const pattern of patterns) { if (new RegExp(pattern, 'i').test(text)) { return level; } } } // Semantic detection based on content complexity and vocabulary return this.inferGradeLevelFromContent(text); } private detectSubject(text: string): string | undefined { let bestMatch = ''; let maxScore = 0; for (const [subject, keywords] of Object.entries(this.subjectKeywords)) { let score = 0; keywords.forEach(keyword => { const regex = new RegExp(`\\b${keyword}\\b`, 'gi'); const matches = text.match(regex); if (matches) { score += matches.length; } }); if (score > maxScore) { maxScore = score; bestMatch = subject; } } return maxScore > 0 ? bestMatch : undefined; } private extractDuration(text: string): number | undefined { // Look for Brazilian duration patterns const durationPatterns = [ /(\d+)\s*minutos?\s*(?:de\s+aula)?/i, /(\d+)\s*horas?\s*(?:aula|atividade)?/i, /carga\s+horária\s*(?:de\s*)?(\d+)\s*(?:minutos?|horas?)/i, /período\s+de\s+(\d+)\s*(?:minutos?|horas?)/i, /duração\s*(?:de\s*)?(\d+)\s*(?:minutos?|horas?)/i, ]; for (const pattern of durationPatterns) { const match = text.match(pattern); if (match) { const value = parseInt(match[1]); // Convert hours to minutes if needed return text.includes('hora') ? value * 60 : value; } } return undefined; } private detectPedagogicalApproach(text: string): string | undefined { const approaches = { 'construtivista': /construtivism|construtivista|piaget|vygotsky/i, 'tradicional': /tradicional|expositiv|aula\s+magistral/i, 'ativa': /metodologia\s+ativa|aprendizagem\s+ativa|participativ/i, 'investigativa': /investigativ|pesquisa|descoberta|exploratóri/i, 'colaborativa': /colaborativ|grupo|equipe|cooperativ/i, 'lúdica': /lúdic|jogo|brincadeira|divertid/i, }; for (const [approach, pattern] of Object.entries(approaches)) { if (pattern.test(text)) { return approach; } } return undefined; } private extractBNCC(text: string): string[] { const competencies: string[] = []; // Look for explicit BNCC mentions const bnccPatterns = [ /competência\s+(\d+)/gi, /habilidade\s+(ef\d+[a-z]+\d+)/gi, /campo\s+de\s+experiência/i, /área\s+do\s+conhecimento/i, ]; bnccPatterns.forEach(pattern => { const matches = text.match(pattern); if (matches) { competencies.push(...matches); } }); return competencies; } private checkSemanticEducationalIndicators(content: string, title?: string): boolean { const fullText = `${title || ''} ${content}`.toLowerCase(); // Semantic indicators that suggest educational content const semanticIndicators = [ // Learning-focused language /\b(?:aprender|ensinar|estudar|compreender|entender)\b/, /\b(?:explicar|demonstrar|mostrar|apresentar)\b/, /\b(?:conhecimento|habilidade|competência|capacidade)\b/, // Student-focused language /\b(?:alunos?|estudantes?|discentes?)\b/, /\b(?:turma|classe|sala\s+de\s+aula)\b/, // Educational structure /\b(?:objetivo|meta|finalidade)\s+(?:de\s+)?(?:aprendizagem|educacional)\b/, /\b(?:conteúdo|matéria|disciplina|assunto)\b/, /\b(?:exercício|atividade|tarefa|trabalho)\s+(?:escolar|acadêmic|educacional)\b/, // Assessment language /\b(?:avaliar|verificar|testar|medir)\s+(?:conhecimento|aprendizagem|compreensão)\b/, /\b(?:questão|pergunta|resposta|solução)\b/, ]; const matchCount = semanticIndicators.filter(pattern => pattern.test(fullText)).length; // If we have multiple semantic indicators, it's likely educational return matchCount >= 2; } private inferGradeLevelFromContent(text: string): string { // Simple complexity-based inference const avgWordLength = text.split(/\s+/).reduce((sum, word) => sum + word.length, 0) / text.split(/\s+/).length; const sentenceCount = text.split(/[.!?]+/).length; const avgSentenceLength = text.split(/\s+/).length / sentenceCount; // Basic heuristics (can be refined) if (avgWordLength < 5 && avgSentenceLength < 10) { return 'fundamental-1'; } else if (avgWordLength < 6 && avgSentenceLength < 15) { return 'fundamental-2'; } else if (avgWordLength < 7 && avgSentenceLength < 20) { return 'medio'; } else { return 'superior'; } } // Map Brazilian grade levels to international equivalents for the main system public mapToInternationalAudience(gradeLevel: string): 'elementary' | 'middle' | 'high' | 'college' | 'adult' | 'professional' { const mapping = { 'fundamental-1': 'elementary', 'fundamental-2': 'middle', 'medio': 'high', 'superior': 'college', 'tecnico': 'professional', }; return (mapping[gradeLevel as keyof typeof mapping] || 'adult') as 'elementary' | 'middle' | 'high' | 'college' | 'adult' | 'professional'; } // Convert Brazilian duration to international complexity public mapComplexityFromDuration(duration?: number): 'basic' | 'intermediate' | 'advanced' { if (!duration) return 'intermediate'; if (duration <= 20) return 'basic'; if (duration <= 40) return 'intermediate'; return 'advanced'; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rkm097git/euconquisto-composer-mcp-poc'

If you have feedback or need assistance with the MCP directory API, please join our Discord server