danielraynaud commited on
Commit
be9b915
·
verified ·
1 Parent(s): 97d12e6

Create simulado_system.py

Browse files
Files changed (1) hide show
  1. simulado_system.py +310 -0
simulado_system.py ADDED
@@ -0,0 +1,310 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # simulado_system.py
2
+
3
+ import json
4
+ import uuid
5
+ import logging
6
+ from datetime import datetime, timedelta
7
+ from typing import Dict, List, Optional, Tuple
8
+ from difflib import SequenceMatcher
9
+ import numpy as np
10
+
11
+ # Configuração de logging
12
+ logging.basicConfig(
13
+ level=logging.INFO,
14
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
15
+ )
16
+ logger = logging.getLogger(__name__)
17
+
18
+ class SimuladoConstants:
19
+ """Constantes para configuração de simulados"""
20
+ TEMPO_PADRAO = 240 # minutos
21
+ QUESTOES_TOTAIS = 120
22
+ NOTA_APROVACAO = 60
23
+ NIVEIS = ["facil", "medio", "dificil", "mixed"]
24
+ PESO_SIMILARIDADE = 0.7
25
+
26
+ class SimuladoSystem:
27
+ """Sistema avançado de simulados e casos clínicos"""
28
+
29
+ def __init__(self, db_connection):
30
+ self.conn = db_connection
31
+ self.areas_simulado = {
32
+ "ClínicaMédica": 40,
33
+ "Cirurgia": 20,
34
+ "Pediatria": 15,
35
+ "GinecologiaObstetrícia": 15,
36
+ "MedicinaFamília": 5,
37
+ "SaúdeMental": 5
38
+ }
39
+ self.simulados_ativos = {} # Cache de simulados em andamento
40
+
41
+ def create_simulado(self, difficulty: str = "mixed",
42
+ num_questions: int = SimuladoConstants.QUESTOES_TOTAIS) -> Dict:
43
+ """Cria simulado personalizado com mais opções"""
44
+ try:
45
+ simulado_id = str(uuid.uuid4())
46
+ simulado = {
47
+ "id": simulado_id,
48
+ "questoes": [],
49
+ "tempo_sugerido": self._calculate_time(num_questions),
50
+ "nivel": difficulty,
51
+ "data_criacao": datetime.now().isoformat(),
52
+ "status": "criado",
53
+ "estatisticas": {
54
+ "questoes_por_area": {},
55
+ "distribuicao_dificuldade": {}
56
+ }
57
+ }
58
+
59
+ cursor = self.conn.cursor()
60
+
61
+ # Distribuição de questões por área
62
+ for area, percentual in self.areas_simulado.items():
63
+ num_area_questions = int((percentual/100) * num_questions)
64
+
65
+ # Query considerando dificuldade
66
+ difficulty_clause = ""
67
+ if difficulty != "mixed":
68
+ difficulty_clause = "AND difficulty = ?"
69
+ params = (area, difficulty, num_area_questions)
70
+ else:
71
+ params = (area, num_area_questions)
72
+
73
+ cursor.execute(f'''
74
+ SELECT id, question_text, options, correct_answer,
75
+ explanation, difficulty, references
76
+ FROM previous_questions
77
+ WHERE area = ? {difficulty_clause}
78
+ ORDER BY RANDOM()
79
+ LIMIT ?
80
+ ''', params)
81
+
82
+ questions = cursor.fetchall()
83
+ for q in questions:
84
+ question_data = {
85
+ "id": q[0],
86
+ "area": area,
87
+ "texto": q[1],
88
+ "opcoes": json.loads(q[2]),
89
+ "resposta": q[3],
90
+ "explicacao": q[4],
91
+ "dificuldade": q[5],
92
+ "referencias": json.loads(q[6]) if q[6] else []
93
+ }
94
+ simulado["questoes"].append(question_data)
95
+
96
+ # Atualizar estatísticas
97
+ simulado["estatisticas"]["questoes_por_area"][area] = \
98
+ simulado["estatisticas"]["questoes_por_area"].get(area, 0) + 1
99
+ simulado["estatisticas"]["distribuicao_dificuldade"][q[5]] = \
100
+ simulado["estatisticas"]["distribuicao_dificuldade"].get(q[5], 0) + 1
101
+
102
+ self.simulados_ativos[simulado_id] = simulado
103
+ return simulado
104
+
105
+ except Exception as e:
106
+ logger.error(f"Erro ao criar simulado: {e}")
107
+ return None
108
+
109
+ def _calculate_time(self, num_questions: int) -> int:
110
+ """Calcula tempo sugerido baseado no número de questões"""
111
+ return int(num_questions * 2) # 2 minutos por questão
112
+
113
+ def evaluate_simulado(self, simulado_id: str,
114
+ respostas: Dict[str, str],
115
+ tempo_usado: int = None) -> Dict:
116
+ """Avalia respostas do simulado com análise detalhada"""
117
+ try:
118
+ if simulado_id not in self.simulados_ativos:
119
+ raise ValueError("Simulado não encontrado")
120
+
121
+ simulado = self.simulados_ativos[simulado_id]
122
+ resultado = {
123
+ "id": simulado_id,
124
+ "total_questoes": len(simulado["questoes"]),
125
+ "corretas": 0,
126
+ "tempo_usado": tempo_usado,
127
+ "desempenho_por_area": {},
128
+ "analise_erros": [],
129
+ "recomendacoes": [],
130
+ "timestamp": datetime.now().isoformat()
131
+ }
132
+
133
+ # Análise detalhada por área
134
+ area_stats = {}
135
+ for area in self.areas_simulado:
136
+ area_stats[area] = {
137
+ "total": 0,
138
+ "corretas": 0,
139
+ "erros_comuns": [],
140
+ "tempo_medio": 0
141
+ }
142
+
143
+ # Avaliação de cada resposta
144
+ for q_id, resp in respostas.items():
145
+ questao = next((q for q in simulado["questoes"] if q["id"] == q_id), None)
146
+ if not questao:
147
+ continue
148
+
149
+ area = questao["area"]
150
+ area_stats[area]["total"] += 1
151
+
152
+ if resp.upper() == questao["resposta"].upper():
153
+ area_stats[area]["corretas"] += 1
154
+ resultado["corretas"] += 1
155
+ else:
156
+ # Análise do erro
157
+ area_stats[area]["erros_comuns"].append({
158
+ "questao_id": q_id,
159
+ "resposta_dada": resp,
160
+ "resposta_correta": questao["resposta"],
161
+ "tema": questao.get("tema", ""),
162
+ "dificuldade": questao["dificuldade"]
163
+ })
164
+
165
+ # Calcular porcentagens e gerar recomendações
166
+ for area, stats in area_stats.items():
167
+ if stats["total"] > 0:
168
+ percentual = (stats["corretas"] / stats["total"]) * 100
169
+ resultado["desempenho_por_area"][area] = {
170
+ "total": stats["total"],
171
+ "corretas": stats["corretas"],
172
+ "percentual": percentual,
173
+ "erros_comuns": stats["erros_comuns"]
174
+ }
175
+
176
+ if percentual < SimuladoConstants.NOTA_APROVACAO:
177
+ resultado["recomendacoes"].append(
178
+ self._generate_recommendations(area, stats)
179
+ )
180
+
181
+ # Salvar resultado no banco de dados
182
+ self._save_resultado(simulado_id, resultado)
183
+
184
+ return resultado
185
+
186
+ except Exception as e:
187
+ logger.error(f"Erro ao avaliar simulado: {e}")
188
+ return None
189
+
190
+ def _generate_recommendations(self, area: str, stats: Dict) -> Dict:
191
+ """Gera recomendações detalhadas baseadas no desempenho"""
192
+ erros_comuns = self._analyze_common_errors(stats["erros_comuns"])
193
+ return {
194
+ "area": area,
195
+ "sugestoes": [
196
+ f"Revisar conceitos básicos de {area}",
197
+ f"Focar em {', '.join(erros_comuns[:3])}",
198
+ "Praticar questões similares",
199
+ "Revisar casos clínicos relacionados"
200
+ ],
201
+ "recursos": [
202
+ "banco de questões",
203
+ "casos clínicos",
204
+ "revisão teórica",
205
+ "videoaulas específicas"
206
+ ],
207
+ "plano_acao": self._create_action_plan(area, stats)
208
+ }
209
+
210
+ def _analyze_common_errors(self, erros: List[Dict]) -> List[str]:
211
+ """Analisa padrões comuns de erros"""
212
+ temas_errados = {}
213
+ for erro in erros:
214
+ tema = erro["tema"]
215
+ if tema in temas_errados:
216
+ temas_errados[tema] += 1
217
+ else:
218
+ temas_errados[tema] = 1
219
+
220
+ return sorted(temas_errados.keys(),
221
+ key=lambda x: temas_errados[x],
222
+ reverse=True)
223
+
224
+ def _create_action_plan(self, area: str, stats: Dict) -> Dict:
225
+ """Cria plano de ação personalizado"""
226
+ return {
227
+ "prioridade": "alta" if len(stats["erros_comuns"]) > stats["corretas"] else "média",
228
+ "etapas": [
229
+ "Revisão teórica dos temas com mais erros",
230
+ "Resolução de questões comentadas",
231
+ "Prática com casos clínicos",
232
+ "Simulado focado na área"
233
+ ],
234
+ "tempo_sugerido": "2 semanas",
235
+ "material_sugerido": [
236
+ "Bibliografia básica",
237
+ "Questões anteriores comentadas",
238
+ "Vídeo-aulas específicas"
239
+ ]
240
+ }
241
+
242
+ def _save_resultado(self, simulado_id: str, resultado: Dict) -> None:
243
+ """Salva resultado do simulado no banco de dados"""
244
+ try:
245
+ cursor = self.conn.cursor()
246
+ cursor.execute('''
247
+ INSERT INTO resultados_simulados
248
+ (simulado_id, data, resultado_json)
249
+ VALUES (?, ?, ?)
250
+ ''', (
251
+ simulado_id,
252
+ datetime.now().isoformat(),
253
+ json.dumps(resultado)
254
+ ))
255
+ self.conn.commit()
256
+ except Exception as e:
257
+ logger.error(f"Erro ao salvar resultado: {e}")
258
+
259
+ def get_simulado_history(self, user_id: str) -> List[Dict]:
260
+ """Obtém histórico de simulados do usuário"""
261
+ try:
262
+ cursor = self.conn.cursor()
263
+ cursor.execute('''
264
+ SELECT simulado_id, data, resultado_json
265
+ FROM resultados_simulados
266
+ WHERE user_id = ?
267
+ ORDER BY data DESC
268
+ ''', (user_id,))
269
+
270
+ return [
271
+ {
272
+ "id": row[0],
273
+ "data": row[1],
274
+ "resultado": json.loads(row[2])
275
+ }
276
+ for row in cursor.fetchall()
277
+ ]
278
+ except Exception as e:
279
+ logger.error(f"Erro ao obter histórico: {e}")
280
+ return []
281
+
282
+ # [O resto do código do CasoClinicoSystem continua o mesmo...]
283
+
284
+ def initialize_simulado_system(db_connection) -> Tuple[SimuladoSystem, CasoClinicoSystem]:
285
+ """Inicializa o sistema de simulados"""
286
+ try:
287
+ simulado_sys = SimuladoSystem(db_connection)
288
+ caso_sys = CasoClinicoSystem(db_connection)
289
+ return simulado_sys, caso_sys
290
+ except Exception as e:
291
+ logger.error(f"Erro ao inicializar sistema de simulados: {e}")
292
+ return None, None
293
+
294
+ if __name__ == "__main__":
295
+ # Código para testes
296
+ import sqlite3
297
+
298
+ try:
299
+ conn = sqlite3.connect('revalida.db')
300
+ simulado_sys, caso_sys = initialize_simulado_system(conn)
301
+
302
+ # Teste básico
303
+ simulado = simulado_sys.create_simulado()
304
+ if simulado:
305
+ print("Sistema funcionando corretamente")
306
+ print(f"Simulado criado: {json.dumps(simulado['estatisticas'], indent=2)}")
307
+ except Exception as e:
308
+ print(f"Erro nos testes: {e}")
309
+ finally:
310
+ conn.close()