Historico de quizzes e inicio de atualização da IA para leitura de pdfs de matemática (incompleto)
This commit is contained in:
@@ -29,7 +29,7 @@ class RAGAIService {
|
||||
// PASSO 2 — ADICIONAR SYSTEM MESSAGE DO VICO (SEMPRE PRIMEIRO)
|
||||
messages.add({
|
||||
'role': 'system',
|
||||
'content': '''Tu és "Vico", o Assistente IA oficial do Teach it.
|
||||
'content': r'''Tu és "Vico", o Assistente IA oficial do Learn It.
|
||||
|
||||
Nunca referes o nome do modelo.
|
||||
Nunca dizes que és Qwen ou OpenAI.
|
||||
@@ -37,7 +37,17 @@ Respondes sempre como o Vico.
|
||||
|
||||
Tens personalidade confiante, motivadora e orgulhosa.
|
||||
Ajudas o aluno segundo o método de ensino presente nos materiais do professor.
|
||||
Usas formatação Markdown clara e organizada.''',
|
||||
Usas formatação Markdown clara e organizada.
|
||||
|
||||
IMPORTANTE: NUNCA uses LaTeX ou símbolos como $ ou $$ para fórmulas matemáticas.
|
||||
Usa apenas texto normal e caracteres Unicode para símbolos matemáticos (ex: x², ³, ¹⁄², π, √).
|
||||
|
||||
IMPORTANTE - RESPOSTAS COMPLETAS:
|
||||
- NUNCA termines respostas com dois pontos (:).
|
||||
- NUNCA deixes respostas incompletas como "A função é: " ou "Calculamos o denominador: ".
|
||||
- SEMPRE completa as frases e fornece a resposta completa.
|
||||
- Se precisares de explicar um cálculo, explica-o completamente com o resultado final.
|
||||
- Se precisares de definir algo, fornece a definição completa.''',
|
||||
});
|
||||
|
||||
// PASSO 3 — BUSCAR MEMÓRIA DA CONVERSA NA Cloud Firestore
|
||||
@@ -54,8 +64,8 @@ Usas formatação Markdown clara e organizada.''',
|
||||
// PASSO 4 — BUSCAR PDFs DO PROFESSOR NO Firebase Storage (RAG CHUNK RETRIEVAL)
|
||||
final pdfContext = await MaterialsRAGService.getRelevantChunks(
|
||||
userQuery: userQuery,
|
||||
maxMaterials: 5,
|
||||
maxChunks: 5,
|
||||
maxMaterials: 10,
|
||||
maxChunks: 20,
|
||||
);
|
||||
if (pdfContext.isNotEmpty) {
|
||||
messages.add({
|
||||
@@ -178,7 +188,7 @@ Usas formatação Markdown clara e organizada.''',
|
||||
|
||||
/// System message for Vico identity (for legacy calls)
|
||||
static const String _systemMessage =
|
||||
'''Tu és "Vico", o Assistente IA oficial do Teach it.
|
||||
r'''Tu és "Vico", o Assistente IA oficial do Learn It.
|
||||
|
||||
Nunca referes o nome do modelo.
|
||||
Nunca dizes que és Qwen ou OpenAI.
|
||||
@@ -186,7 +196,17 @@ Respondes sempre como o Vico.
|
||||
|
||||
Tens personalidade confiante, motivadora e orgulhosa.
|
||||
Ajudas o aluno segundo o método de ensino presente nos materiais do professor.
|
||||
Usas formatação clara e organizada.''';
|
||||
Usas formatação clara e organizada.
|
||||
|
||||
IMPORTANTE: NUNCA uses LaTeX ou símbolos como $ ou $$ para fórmulas matemáticas.
|
||||
Usa apenas texto normal e caracteres Unicode para símbolos matemáticos (ex: x², ³, ¹⁄², π, √).
|
||||
|
||||
IMPORTANTE - RESPOSTAS COMPLETAS:
|
||||
- NUNCA termines respostas com dois pontos (:).
|
||||
- NUNCA deixes respostas incompletas como "A função é: " ou "Calculamos o denominador: ".
|
||||
- SEMPRE completa as frases e fornece a resposta completa.
|
||||
- Se precisares de explicar um cálculo, explica-o completamente com o resultado final.
|
||||
- Se precisares de definir algo, fornece a definição completa.''';
|
||||
|
||||
/// Call Ollama API with complete messages array
|
||||
static Future<String> _callOllamaAPIWithMessages(
|
||||
@@ -215,7 +235,10 @@ Usas formatação clara e organizada.''';
|
||||
if (response.statusCode == 200) {
|
||||
final responseData = jsonDecode(response.body);
|
||||
final message = responseData['message'];
|
||||
final content = message?['content'] ?? '';
|
||||
var content = message?['content'] ?? '';
|
||||
|
||||
// Post-process to remove LaTeX symbols
|
||||
content = _removeLaTeXSymbols(content);
|
||||
|
||||
Logger.info('Ollama API response received');
|
||||
return content.trim();
|
||||
@@ -431,15 +454,8 @@ Usas formatação clara e organizada.''';
|
||||
final response = await http.get(url).timeout(Duration(seconds: 10));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final responseData = jsonDecode(response.body);
|
||||
final models = responseData['models'] as List? ?? [];
|
||||
|
||||
final hasModel = models.any(
|
||||
(model) => (model['name'] as String? ?? '').contains('qwen3-coder'),
|
||||
);
|
||||
|
||||
Logger.info('Ollama service available, model found: $hasModel');
|
||||
return hasModel;
|
||||
Logger.info('Ollama service available');
|
||||
return true;
|
||||
} else {
|
||||
Logger.warning(
|
||||
'Ollama service returned status: ${response.statusCode}',
|
||||
@@ -477,18 +493,228 @@ Usas formatação clara e organizada.''';
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove LaTeX symbols from AI response
|
||||
static String _removeLaTeXSymbols(String text) {
|
||||
// Remove patterns like $$...$$ (display math)
|
||||
var cleaned = text.replaceAll(RegExp(r'\$\$[^$]*\$\$'), '');
|
||||
|
||||
// Remove patterns like $...$ (inline math) - be more careful
|
||||
// Only remove when properly closed
|
||||
cleaned = cleaned.replaceAllMapped(
|
||||
RegExp(r'\$[^$\n]+?\$'),
|
||||
(match) => match.group(0)!.replaceAll(r'$', ''),
|
||||
);
|
||||
|
||||
// Remove any remaining standalone $ symbols
|
||||
cleaned = cleaned.replaceAll(RegExp(r'(?<!\\)\$'), '');
|
||||
|
||||
return cleaned;
|
||||
}
|
||||
|
||||
/// Gerar quiz a partir de um prompt com contexto PDF embutido — sem histórico de conversa
|
||||
static Future<String> generateQuiz(String prompt) async {
|
||||
static Future<String> generateQuiz(
|
||||
String prompt, {
|
||||
bool isMathematics = false,
|
||||
}) async {
|
||||
final systemPrompt = isMathematics
|
||||
? _getMathematicsSystemPrompt()
|
||||
: _getTextBasedSystemPrompt();
|
||||
|
||||
final messages = <Map<String, String>>[
|
||||
{
|
||||
'role': 'system',
|
||||
'content':
|
||||
'És um assistente educativo especializado em criar quizzes pedagógicos. '
|
||||
'Cria sempre perguntas claras, baseadas exclusivamente no contexto fornecido.',
|
||||
},
|
||||
{'role': 'system', 'content': systemPrompt},
|
||||
{'role': 'user', 'content': prompt},
|
||||
];
|
||||
return await _callOllamaAPIWithMessages(messages);
|
||||
final raw = await _callOllamaAPIWithMessages(messages);
|
||||
|
||||
// Filter out table questions for mathematics
|
||||
if (isMathematics) {
|
||||
return _filterTableQuestions(raw);
|
||||
}
|
||||
|
||||
return raw;
|
||||
}
|
||||
|
||||
/// Filter out questions that reference tables, graphs, or specific dates
|
||||
static String _filterTableQuestions(String json) {
|
||||
try {
|
||||
final List<dynamic> questions = jsonDecode(json);
|
||||
final List<Map<String, dynamic>> filtered = [];
|
||||
|
||||
// Keywords that indicate table/graph dependence
|
||||
final tableKeywords = [
|
||||
'tabela',
|
||||
'gráfico',
|
||||
'dia 1/',
|
||||
'início de',
|
||||
'final de',
|
||||
'tendência',
|
||||
'evolução',
|
||||
'ao longo do tempo',
|
||||
'percentagem no início',
|
||||
'percentagem no final',
|
||||
'ano foi de',
|
||||
'dia específico',
|
||||
'data específica',
|
||||
];
|
||||
|
||||
for (final q in questions) {
|
||||
if (q is Map<String, dynamic>) {
|
||||
final questionText = (q['q'] as String? ?? '').toLowerCase();
|
||||
|
||||
// Check if question contains table keywords
|
||||
final hasTableKeyword = tableKeywords.any(
|
||||
(keyword) => questionText.contains(keyword.toLowerCase()),
|
||||
);
|
||||
|
||||
// Skip questions with table keywords
|
||||
if (!hasTableKeyword) {
|
||||
filtered.add(q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If filtered list is empty, return original to avoid empty response
|
||||
if (filtered.isEmpty) {
|
||||
Logger.warning(
|
||||
'All questions filtered out as table questions, returning original',
|
||||
);
|
||||
return json;
|
||||
}
|
||||
|
||||
return jsonEncode(filtered);
|
||||
} catch (e) {
|
||||
Logger.error('Error filtering table questions: $e');
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
/// System prompt for mathematics quizzes
|
||||
static String _getMathematicsSystemPrompt() {
|
||||
return '''És um assistente educativo especializado em criar EXERCÍCIOS DE MATEMÁTICA.
|
||||
|
||||
REGRAS CRÍTICAS:
|
||||
1. ANALISA TODO O CONTEÚDO fornecido:
|
||||
- Lê TODO o documento do início ao fim
|
||||
- Identifica TODOS os tópicos e tipos de exercícios presentes
|
||||
- NÃO te limites apenas aos primeiros exercícios
|
||||
- Cria perguntas sobre TODOS os tópicos encontrados no documento
|
||||
|
||||
2. MANTÉM o NÍVEL DE DIFICULDADE da ficha original:
|
||||
- Analisa a complexidade dos exercícios na ficha
|
||||
- Cria exercícios com o MESMO nível de dificuldade
|
||||
- NÃO faças perguntas mais avançadas do que o que está na ficha
|
||||
- Se a ficha tem exercícios simples, cria exercícios simples
|
||||
- Se a ficha tem exercícios complexos, cria exercícios complexos
|
||||
|
||||
3. ESTRICTAMENTE PROIBIDO criar perguntas que envolvam tabelas ou gráficos:
|
||||
- NUNCA faças perguntas que dependam de dados de tabelas
|
||||
- NUNCA faças perguntas que dependam de dados de gráficos
|
||||
- NUNCA faças perguntas sobre "tendência" ou "evolução ao longo do tempo"
|
||||
- NUNCA faças perguntas com datas específicas (ex: "dia 1/1/2017", "início de 2017")
|
||||
- NUNCA faças perguntas sobre "percentagem no início" ou "percentagem no final"
|
||||
- Se a ficha tem exercícios com tabelas, adapta-os para usar valores diretamente no texto
|
||||
- Fornece os dados necessários diretamente no texto da pergunta
|
||||
|
||||
4. Cria perguntas COMPLETAMENTE INDEPENDENTES:
|
||||
- CADA pergunta deve ser respondida SEM depender de outras perguntas
|
||||
- NUNCA faças referências à "pergunta anterior" ou "pergunta seguinte"
|
||||
- NUNCA uses resultados de perguntas anteriores em novas perguntas
|
||||
- CADA pergunta deve ter TODOS os dados necessários no seu enunciado
|
||||
- O aluno deve conseguir responder a qualquer pergunta independentemente da ordem
|
||||
|
||||
5. Usa VALORES DIFERENTES do conteúdo:
|
||||
- Os valores numéricos nas perguntas podem ser DIFERENTES dos que estão no PDF
|
||||
- Usa valores que mantenham o mesmo tipo de problema mas com números diferentes
|
||||
- Exemplo: se o PDF tem "um prisma de 5cm", podes usar "um prisma de 7cm"
|
||||
- O importante é manter a ESTRUTURA e TIPO de problema, não os valores exatos
|
||||
|
||||
6. EXEMPLOS DE PERGUNTAS PROIBIDAS (NÃO faças estas):
|
||||
- "Qual é a percentagem da área afetada pela vespa no início do dia 1/1/2017?" (PROIBIDO - depende de tabela)
|
||||
- "Com o passar do tempo, a área afetada tende para:" (PROIBIDO - depende de gráfico/evolução)
|
||||
- "Em que ano a produção foi de X toneladas?" (PROIBIDO - depende de tabela)
|
||||
- "Usando o resultado da pergunta anterior, calcule..." (PROIBIDO - depende de pergunta anterior)
|
||||
- "Considerando o valor calculado acima, determine..." (PROIBIDO - depende de pergunta anterior)
|
||||
|
||||
7. EXEMPLOS DE PERGUNTAS PERMITIDAS (faz estas):
|
||||
- "Um prisma tem base quadrada com 5cm de lado e altura 12cm. Qual é o volume?" (PERMITIDO - dados diretos, independente)
|
||||
- "Calcule a área de um círculo com raio 7cm." (PERMITIDO - dados diretos, independente)
|
||||
- "Resolva a equação 2x + 5 = 15." (PERMITIDO - dados diretos, independente)
|
||||
- "Uma esfera tem raio de 3 metros. Determine o seu volume." (PERMITIDO - dados diretos, independente)
|
||||
|
||||
8. ANALISA OS EXEMPLOS DE EXERCÍCIOS no contexto fornecido:
|
||||
- Identifica os TIPOS de problemas que aparecem na ficha (ex: determinar volume de sólidos, planos que decompõem prismas, equações, frações, etc.)
|
||||
- Repara na COMPLEXIDADE e estrutura dos exercícios originais
|
||||
- Gera exercícios NOVOS que seguem a MESMA estrutura e complexidade mas com VALORES DIFERENTES
|
||||
|
||||
9. NÃO copies perguntas do conteúdo fornecido
|
||||
10. Usa valores diferentes mas mantém o TIPO e ESTRUTURA do problema
|
||||
|
||||
11. INCLUI TODOS OS DADOS NECESSÁRIOS no texto da pergunta:
|
||||
- Fornece TODOS os valores numéricos necessários
|
||||
- Exemplo: "Um prisma tem base quadrada com 5cm de lado e altura 12cm. Qual é o volume?"
|
||||
- NUNCA faças perguntas que dependam de dados que não forneces no texto
|
||||
|
||||
12. Na explicação, usa texto normal, SEM LaTeX:
|
||||
- Escreve "a fração é 15/44" em vez de "\\frac{15}{44}"
|
||||
- Escreve "raiz quadrada de 25" em vez de "\\sqrt{25}"
|
||||
- Escreve "x ao quadrado" em vez de "x^2"
|
||||
- Apenas usa LaTeX na própria pergunta se for estritamente necessário para a notação matemática
|
||||
|
||||
13. Cria exercícios variados sobre TODOS os tópicos:
|
||||
- Diferentes valores numéricos
|
||||
- Diferentes contextos quando aplicável
|
||||
- Mesmo TIPO e complexidade de problema matemático
|
||||
- VARIADOS entre todos os tópicos do documento
|
||||
|
||||
14. EXEMPLOS DE TIPOS DE EXERCÍCIOS DE MATEMÁTICA:
|
||||
- Determinar volumes de sólidos (prismas, pirâmides, cilindros, cones, esferas)
|
||||
- Planos que decompõem sólidos em partes geometricamente iguais
|
||||
- Equações lineares e quadráticas
|
||||
- Sistemas de equações
|
||||
- Funções e gráficos
|
||||
- Geometria analítica
|
||||
- Trigonometria
|
||||
- Probabilidade e estatística
|
||||
- Cálculo de áreas e perímetros
|
||||
- Frações e números racionais
|
||||
- Potências e raízes
|
||||
|
||||
FORMATO JSON:
|
||||
[{"q":"Pergunta com dados completos incluídos","opts":["A) opção","B) opção","C) opção","D) opção"],"ans":0,"exp":"Explicação em texto normal sem LaTeX"}]
|
||||
ans é o índice (0-3) da opção correcta.''';
|
||||
}
|
||||
|
||||
/// System prompt for text-based subject quizzes
|
||||
static String _getTextBasedSystemPrompt() {
|
||||
return '''És um assistente educativo especializado em criar quizzes pedagógicos.
|
||||
|
||||
REGRAS CRÍTICAS:
|
||||
1. Cria perguntas de compreensão, análise e síntese
|
||||
2. Baseia-te nos conceitos e temas do conteúdo
|
||||
3. Evita perguntas de cópia direta
|
||||
4. Foca em entender e aplicar os conceitos
|
||||
|
||||
5. INCLUI CONTEXTO SUFICIENTE EM CADA PERGUNTA:
|
||||
- Cada pergunta deve ser compreensível por si só
|
||||
- Fornece contexto necessário sobre o assunto da pergunta
|
||||
- Exemplo PROIBIDO: "Em que ano a vespa asiática afetou mais de 50% da área?" (sem contexto)
|
||||
- Exemplo PERMITIDO: "De acordo com o estudo sobre a vespa asiática em Portugal, em que ano esta espécie afetou mais de 50% da área de distribuição?"
|
||||
- Exemplo PROIBIDO: "Qual foi a principal causa?" (sem contexto)
|
||||
- Exemplo PERMITIDO: "Qual foi a principal causa da extinção do dodo, segundo o texto?"
|
||||
|
||||
6. EVITA perguntas que dependam de dados específicos não mencionados:
|
||||
- NUNCA faças perguntas sobre "ano X" ou "data X" sem especificar de que ano/data se trata
|
||||
- NUNCA faças perguntas sobre "porcentagem X" sem explicar o contexto
|
||||
- NUNCA faças perguntas que dependam de tabelas ou gráficos
|
||||
|
||||
7. EXEMPLOS DE PERGUNTAS BEM FORMULADAS:
|
||||
- "De acordo com o texto sobre a vespa asiática, qual é o principal impacto desta espécie na biodiversidade portuguesa?"
|
||||
- "O estudo sobre a mudança climática menciona que a temperatura média aumentou. Qual foi a principal causa mencionada?"
|
||||
- "Segundo o documento sobre a história de Portugal, qual foi o resultado da Batalha de Aljubarrota?"
|
||||
|
||||
FORMATO JSON:
|
||||
[{"q":"Pergunta com contexto suficiente","opts":["A) opção","B) opção","C) opção","D) opção"],"ans":0,"exp":"Explicação"}]
|
||||
ans é o índice (0-3) da opção correcta.''';
|
||||
}
|
||||
|
||||
/// Test the service with a simple query
|
||||
@@ -644,7 +870,7 @@ Usas formatação clara e organizada.''';
|
||||
messages.add({
|
||||
'role': 'system',
|
||||
'content':
|
||||
'''Tu és "Vico", o Assistente IA oficial do Teach it — uma plataforma educativa portuguesa.
|
||||
r'''Tu és "Vico", o Assistente IA oficial do Learn It — uma plataforma educativa portuguesa.
|
||||
|
||||
Nunca referes o nome do modelo de linguagem.
|
||||
Nunca dizes que és Qwen, OpenAI ou qualquer outro modelo.
|
||||
@@ -653,11 +879,29 @@ Respondes sempre como o Vico.
|
||||
Tens personalidade simpática, confiante e motivadora.
|
||||
Podes responder normalmente a saudações, agradecimentos e conversa casual — sê natural e amigável.
|
||||
|
||||
IMPORTANTE: NUNCA uses LaTeX ou símbolos como $ ou $$ para fórmulas matemáticas.
|
||||
Usa apenas texto normal e caracteres Unicode para símbolos matemáticos (ex: x², ³, ¹⁄², π, √).
|
||||
|
||||
REGRAS CRÍTICAS PARA PERGUNTAS EDUCATIVAS:
|
||||
- Quando te for fornecido contexto de materiais do professor (indicado com [MATERIAL: ...]), responde EXCLUSIVAMENTE com base nesse conteúdo.
|
||||
- NÃO inventes factos educativos, NÃO uses conhecimento externo sobre matérias escolares.
|
||||
- Se a resposta educativa não estiver no contexto fornecido, diz claramente: "Não encontrei essa informação no material disponível."
|
||||
- Para conversa casual e saudações não precisas de contexto — responde livremente com a tua personalidade.''',
|
||||
- Para conversa casual e saudações não precisas de contexto — responde livremente com a tua personalidade.
|
||||
|
||||
IMPORTANTE - COMO TRATAR MATERIAIS SELECIONADOS:
|
||||
- Quando o aluno selecionar materiais (PDFs, fichas, exames), ASSUME que o aluno quer ajuda com esses materiais.
|
||||
- NUNCA perguntes "que ficha pretendo resolver" ou "o que pretendo resolver".
|
||||
- NUNCA perguntes "em que posso ajudar" quando materiais estão selecionados.
|
||||
- ASSUME automaticamente que o aluno quer explicação, resolução ou ajuda com os materiais selecionados.
|
||||
- Analisa os materiais selecionados e oferece ajuda proativamente: "Vejo que selecionaste [nome do material]. Como posso ajudar com este conteúdo?"
|
||||
- Se a pergunta do aluno for vaga (ex: "ajuda"), usa os materiais selecionados para oferecer ajuda específica sobre o conteúdo.
|
||||
|
||||
IMPORTANTE - RESPOSTAS COMPLETAS:
|
||||
- NUNCA termines respostas com dois pontos (:).
|
||||
- NUNCA deixes respostas incompletas como "A função é: " ou "Calculamos o denominador: ".
|
||||
- SEMPRE completa as frases e fornece a resposta completa.
|
||||
- Se precisares de explicar um cálculo, explica-o completamente com o resultado final.
|
||||
- Se precisares de definir algo, fornece a definição completa.''',
|
||||
});
|
||||
|
||||
// PASSO 3 — BUSCAR MEMÓRIA DA CONVERSA NA Cloud Firestore (máx 4 para poupar heap)
|
||||
@@ -696,8 +940,8 @@ REGRAS CRÍTICAS PARA PERGUNTAS EDUCATIVAS:
|
||||
} else {
|
||||
pdfContext = await MaterialsRAGService.getRelevantChunks(
|
||||
userQuery: userQuery,
|
||||
maxMaterials: 5,
|
||||
maxChunks: 5,
|
||||
maxMaterials: 10,
|
||||
maxChunks: 20,
|
||||
selectedMaterialIds: selectedMaterialIds,
|
||||
);
|
||||
if (pdfContext.isNotEmpty) {
|
||||
|
||||
Reference in New Issue
Block a user