melhoramento do fall back da ia
This commit is contained in:
@@ -492,6 +492,33 @@ Usas formatação clara e organizada.''';
|
||||
}
|
||||
}
|
||||
|
||||
/// Cache do último contexto PDF enviado ao modelo — reutilizado em follow-ups
|
||||
static String _lastPdfContext = '';
|
||||
|
||||
/// Limpar contexto cacheado — chamar ao mudar de material
|
||||
static void clearLastContext() {
|
||||
_lastPdfContext = '';
|
||||
Logger.info('Last PDF context cleared');
|
||||
}
|
||||
|
||||
/// Detecta se a query é um follow-up (pergunta curta/vaga sem keywords de conteúdo)
|
||||
static bool _isFollowUp(String query) {
|
||||
final q = query.trim().toLowerCase();
|
||||
// Menos de 6 palavras E começa com pronome/advérbio de follow-up
|
||||
final words = q.split(RegExp(r'\s+'));
|
||||
if (words.length > 8) return false;
|
||||
const followUpStarters = [
|
||||
'e ', 'e o', 'e a', 'e os', 'e as', 'mas ', 'então ',
|
||||
'explica', 'explique', 'explica melhor', 'melhor', 'mais detalhes',
|
||||
'podes', 'pode ', 'consegues', 'e se ', 'e quando',
|
||||
'dá um exemplo', 'da um exemplo', 'um exemplo', 'exemplo',
|
||||
'como assim', 'o que significa', 'porquê', 'porque isso',
|
||||
'e o ponto', 'e a regra', 'continua', 'continua',
|
||||
'o que mais', 'mais algum', 'e depois', 'e agora',
|
||||
];
|
||||
return followUpStarters.any((s) => q.startsWith(s) || q == s.trim());
|
||||
}
|
||||
|
||||
/// Simple ask method for chat UI - uses conversation memory, teacher PDFs, and O GOAT identity
|
||||
/// [selectedMaterialIds] — se fornecido, limita o RAG apenas aos materiais escolhidos pelo aluno
|
||||
static Future<String> ask(
|
||||
@@ -537,15 +564,24 @@ REGRAS CRÍTICAS SOBRE O CONTEXTO:
|
||||
}
|
||||
|
||||
// PASSO 4 — BUSCAR PDFs DO PROFESSOR NO Firebase Storage (RAG CHUNK RETRIEVAL)
|
||||
final pdfContext = await MaterialsRAGService.getRelevantChunks(
|
||||
userQuery: userQuery,
|
||||
maxMaterials: 5,
|
||||
maxChunks: 5,
|
||||
selectedMaterialIds: selectedMaterialIds,
|
||||
);
|
||||
if (pdfContext.isNotEmpty) {
|
||||
Logger.info('PDF context sent to model (${pdfContext.length} chars): ${pdfContext.length > 300 ? pdfContext.substring(0, 300) : pdfContext}');
|
||||
} else if (selectedMaterialIds != null && selectedMaterialIds.isNotEmpty) {
|
||||
// Detectar follow-up e reutilizar contexto anterior se disponível
|
||||
String pdfContext;
|
||||
if (_isFollowUp(userQuery) && _lastPdfContext.isNotEmpty) {
|
||||
pdfContext = _lastPdfContext;
|
||||
Logger.info('Follow-up detected — reusing last PDF context (${pdfContext.length} chars)');
|
||||
} else {
|
||||
pdfContext = await MaterialsRAGService.getRelevantChunks(
|
||||
userQuery: userQuery,
|
||||
maxMaterials: 5,
|
||||
maxChunks: 5,
|
||||
selectedMaterialIds: selectedMaterialIds,
|
||||
);
|
||||
if (pdfContext.isNotEmpty) {
|
||||
_lastPdfContext = pdfContext;
|
||||
Logger.info('PDF context sent to model (${pdfContext.length} chars): ${pdfContext.length > 300 ? pdfContext.substring(0, 300) : pdfContext}');
|
||||
}
|
||||
}
|
||||
if (pdfContext.isEmpty && selectedMaterialIds != null && selectedMaterialIds.isNotEmpty) {
|
||||
// Contexto vazio com materiais seleccionados — retornar resposta local imediatamente
|
||||
const noContextReply =
|
||||
'Neste momento não tenho acesso ao conteúdo do ficheiro selecionado. '
|
||||
@@ -553,7 +589,8 @@ REGRAS CRÍTICAS SOBRE O CONTEXTO:
|
||||
await ChatMemoryService.saveMessage(role: 'user', content: userQuery);
|
||||
await ChatMemoryService.saveMessage(role: 'assistant', content: noContextReply);
|
||||
return noContextReply;
|
||||
} else {
|
||||
}
|
||||
if (pdfContext.isEmpty && (selectedMaterialIds == null || selectedMaterialIds.isEmpty)) {
|
||||
// Sem material seleccionado — pedir ao utilizador para seleccionar um
|
||||
const noMaterialReply =
|
||||
'Para responder a perguntas sobre conteúdo, preciso que selecciones um material primeiro. '
|
||||
|
||||
Reference in New Issue
Block a user