tudo sobre a memoria da ia, formatação, memória e conhecimento de pdfs, junto da inserção de pdfs
This commit is contained in:
@@ -2,6 +2,8 @@ import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import '../utils/logger.dart';
|
||||
import 'rag_service.dart';
|
||||
import 'chat_memory_service.dart';
|
||||
import 'materials_rag_service.dart';
|
||||
import '../models/content_chunk.dart';
|
||||
|
||||
/// Service for RAG-enhanced AI communication using Ollama API
|
||||
@@ -11,7 +13,7 @@ class RAGAIService {
|
||||
static const int _timeoutSeconds = 60;
|
||||
static const int _maxTokens = 4000;
|
||||
|
||||
/// Generate AI response with RAG context
|
||||
/// Generate AI response with RAG context, conversation memory, and teacher materials
|
||||
static Future<RAGResponse> generateRAGResponse({
|
||||
required String userQuery,
|
||||
required String context,
|
||||
@@ -21,13 +23,70 @@ class RAGAIService {
|
||||
try {
|
||||
Logger.info('Generating RAG response with ${sources.length} sources');
|
||||
|
||||
// 1. Build the prompt with context
|
||||
final prompt = _buildRAGPrompt(userQuery, context, mode);
|
||||
// PASSO 1 — Criar a lista messages vazia
|
||||
List<Map<String, String>> messages = [];
|
||||
|
||||
// 2. Call Ollama API
|
||||
final response = await _callOllamaAPI(prompt);
|
||||
// PASSO 2 — ADICIONAR SYSTEM MESSAGE DO GOAT (SEMPRE PRIMEIRO)
|
||||
messages.add({
|
||||
'role': 'system',
|
||||
'content': '''Tu és "O GOAT", o Assistente IA oficial do Teach it.
|
||||
|
||||
// 3. Process response and create RAGResponse
|
||||
Nunca referes o nome do modelo.
|
||||
Nunca dizes que és Qwen ou OpenAI.
|
||||
Respondes sempre como o GOAT.
|
||||
|
||||
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.''',
|
||||
});
|
||||
|
||||
// PASSO 3 — BUSCAR MEMÓRIA DA CONVERSA NA Cloud Firestore
|
||||
final conversationHistory = await ChatMemoryService.getRecentMessages(limit: 20);
|
||||
for (final msg in conversationHistory) {
|
||||
messages.add({
|
||||
'role': msg['role'] as String,
|
||||
'content': msg['content'] as String,
|
||||
});
|
||||
}
|
||||
|
||||
// PASSO 4 — BUSCAR PDFs DO PROFESSOR NO Firebase Storage (RAG CHUNK RETRIEVAL)
|
||||
final pdfContext = await MaterialsRAGService.getRelevantChunks(
|
||||
userQuery: userQuery,
|
||||
maxMaterials: 5,
|
||||
maxChunks: 5,
|
||||
);
|
||||
if (pdfContext.isNotEmpty) {
|
||||
messages.add({
|
||||
'role': 'system',
|
||||
'content': pdfContext, // Já vem formatado com [CHUNK 1], [CHUNK 2], etc.
|
||||
});
|
||||
}
|
||||
|
||||
// PASSO 5 — SÓ AGORA adicionar a pergunta do user
|
||||
messages.add({
|
||||
'role': 'user',
|
||||
'content': userQuery,
|
||||
});
|
||||
|
||||
// Log do tamanho do array para verificação
|
||||
Logger.info('Built messages array with ${messages.length} messages for API');
|
||||
|
||||
// Save user message to Firestore (after building the messages array)
|
||||
await ChatMemoryService.saveMessage(
|
||||
role: 'user',
|
||||
content: userQuery,
|
||||
);
|
||||
|
||||
// Call Ollama API with complete messages array
|
||||
final response = await _callOllamaAPIWithMessages(messages);
|
||||
|
||||
// Save AI response to memory
|
||||
await ChatMemoryService.saveMessage(
|
||||
role: 'assistant',
|
||||
content: response,
|
||||
);
|
||||
|
||||
// Process response and create RAGResponse
|
||||
final ragResponse = _createRAGResponse(
|
||||
query: userQuery,
|
||||
aiResponse: response,
|
||||
@@ -43,10 +102,11 @@ class RAGAIService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Build RAG-enhanced prompt for Ollama
|
||||
/// Build RAG-enhanced prompt for Ollama with teacher materials
|
||||
static String _buildRAGPrompt(
|
||||
String userQuery,
|
||||
String context,
|
||||
String materialsContext,
|
||||
TutorMode mode,
|
||||
) {
|
||||
final promptBuilder = StringBuffer();
|
||||
@@ -63,6 +123,13 @@ class RAGAIService {
|
||||
);
|
||||
promptBuilder.writeln('Seja claro, paciente e educativo.\n');
|
||||
|
||||
// Add teacher materials (PDFs) if available
|
||||
if (materialsContext.isNotEmpty) {
|
||||
promptBuilder.writeln('=== MATERIAL DO PROFESSOR ===');
|
||||
promptBuilder.writeln(materialsContext);
|
||||
promptBuilder.writeln('\n=== FIM DO MATERIAL DO PROFESSOR ===\n');
|
||||
}
|
||||
|
||||
// Add context
|
||||
promptBuilder.writeln('=== CONTEÚDO EDUCACIONAL DISPONÍVEL ===');
|
||||
promptBuilder.writeln(context);
|
||||
@@ -113,18 +180,29 @@ class RAGAIService {
|
||||
return promptBuilder.toString();
|
||||
}
|
||||
|
||||
/// Call Ollama API
|
||||
static Future<String> _callOllamaAPI(String prompt) async {
|
||||
/// System message for O GOAT identity (for legacy calls)
|
||||
static const String _systemMessage = '''Tu és "O GOAT", o Assistente IA oficial do Teach it.
|
||||
|
||||
Nunca referes o nome do modelo.
|
||||
Nunca dizes que és Qwen ou OpenAI.
|
||||
Respondes sempre como o GOAT.
|
||||
|
||||
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.''';
|
||||
|
||||
/// Call Ollama API with complete messages array
|
||||
static Future<String> _callOllamaAPIWithMessages(
|
||||
List<Map<String, String>> messages,
|
||||
) async {
|
||||
try {
|
||||
Logger.info('Calling Ollama API with model: $_model');
|
||||
Logger.info('Calling Ollama API with ${messages.length} messages');
|
||||
|
||||
final url = Uri.parse(_baseUrl);
|
||||
|
||||
final requestBody = {
|
||||
'model': _model,
|
||||
'messages': [
|
||||
{'role': 'user', 'content': prompt},
|
||||
],
|
||||
'messages': messages,
|
||||
'stream': false,
|
||||
'options': {'temperature': 0.7, 'top_p': 0.9, 'max_tokens': _maxTokens},
|
||||
};
|
||||
@@ -153,6 +231,14 @@ class RAGAIService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Legacy: Call Ollama API with single prompt (for backward compatibility)
|
||||
static Future<String> _callOllamaAPI(String prompt) async {
|
||||
return _callOllamaAPIWithMessages([
|
||||
{'role': 'system', 'content': _systemMessage},
|
||||
{'role': 'user', 'content': prompt},
|
||||
]);
|
||||
}
|
||||
|
||||
/// Create RAGResponse from AI response
|
||||
static RAGResponse _createRAGResponse({
|
||||
required String query,
|
||||
@@ -405,4 +491,72 @@ class RAGAIService {
|
||||
return 'Service test failed: $e';
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple ask method for chat UI - uses conversation memory, teacher PDFs, and O GOAT identity
|
||||
static Future<String> ask(String userQuery) async {
|
||||
Logger.info('USING RAG AI SERVICE');
|
||||
|
||||
// PASSO 1 — Criar a lista messages vazia
|
||||
List<Map<String, String>> messages = [];
|
||||
|
||||
// PASSO 2 — ADICIONAR SYSTEM MESSAGE DO GOAT (SEMPRE PRIMEIRO)
|
||||
messages.add({
|
||||
'role': 'system',
|
||||
'content': '''Tu és "O GOAT", o Assistente IA oficial do Teach it.
|
||||
|
||||
Nunca referes o nome do modelo.
|
||||
Nunca dizes que és Qwen ou OpenAI.
|
||||
Respondes sempre como o GOAT.
|
||||
|
||||
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.''',
|
||||
});
|
||||
|
||||
// PASSO 3 — BUSCAR MEMÓRIA DA CONVERSA NA Cloud Firestore
|
||||
final conversationHistory = await ChatMemoryService.getRecentMessages(limit: 20);
|
||||
for (final msg in conversationHistory) {
|
||||
messages.add({
|
||||
'role': msg['role'] as String,
|
||||
'content': msg['content'] as String,
|
||||
});
|
||||
}
|
||||
|
||||
// Log de confirmação de ordem do histórico
|
||||
if (messages.length > 1) {
|
||||
Logger.info('History order fixed. First message: ${messages[1]}');
|
||||
}
|
||||
|
||||
// PASSO 4 — BUSCAR PDFs DO PROFESSOR NO Firebase Storage (RAG CHUNK RETRIEVAL)
|
||||
final pdfContext = await MaterialsRAGService.getRelevantChunks(
|
||||
userQuery: userQuery,
|
||||
maxMaterials: 5,
|
||||
maxChunks: 5,
|
||||
);
|
||||
if (pdfContext.isNotEmpty) {
|
||||
messages.add({
|
||||
'role': 'system',
|
||||
'content': pdfContext, // Já vem formatado com [CHUNK 1], [CHUNK 2], etc.
|
||||
});
|
||||
}
|
||||
|
||||
// PASSO 5 — SÓ AGORA adicionar a pergunta do user
|
||||
messages.add({
|
||||
'role': 'user',
|
||||
'content': userQuery,
|
||||
});
|
||||
|
||||
Logger.info('USING RAG AI SERVICE - Built messages array with ${messages.length} messages');
|
||||
|
||||
// Save user message to Firestore
|
||||
await ChatMemoryService.saveMessage(role: 'user', content: userQuery);
|
||||
|
||||
// Call API
|
||||
final response = await _callOllamaAPIWithMessages(messages);
|
||||
|
||||
// Save AI response to memory
|
||||
await ChatMemoryService.saveMessage(role: 'assistant', content: response);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user