import json import uuid import logging from datetime import datetime, timedelta from typing import Dict, List, Optional, Tuple from difflib import SequenceMatcher import numpy as np # Configuração de logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) class SimuladoConstants: """Constantes para configuração de simulados""" TEMPO_PADRAO = 240 # minutos QUESTOES_TOTAIS = 120 NOTA_APROVACAO = 60 NIVEIS = ["facil", "medio", "dificil", "mixed"] PESO_SIMILARIDADE = 0.7 class SimuladoSystem: """Sistema avançado de simulados e casos clínicos""" def __init__(self, db_connection): self.conn = db_connection self.areas_simulado = { "ClínicaMédica": 40, "Cirurgia": 20, "Pediatria": 15, "GinecologiaObstetrícia": 15, "MedicinaFamília": 5, "SaúdeMental": 5 } self.simulados_ativos = {} # Cache de simulados em andamento class CasoClinicoSystem: """Sistema de gerenciamento de casos clínicos""" def __init__(self, db_connection): self.conn = db_connection def get_random_caso(self) -> Optional[Dict]: """Retorna um caso clínico aleatório""" try: cursor = self.conn.cursor() cursor.execute(''' SELECT id, titulo, descricao, imagem, pergunta, alternativas, gabarito FROM casos_clinicos ORDER BY RANDOM() LIMIT 1 ''') caso = cursor.fetchone() if caso: return { "id": caso[0], "titulo": caso[1], "descricao": caso[2], "imagem": caso[3], "pergunta": caso[4], "alternativas": json.loads(caso[5]), "gabarito": caso[6] } else: return None except Exception as e: logger.error(f"Erro ao obter caso clínico: {e}") return None def avaliar_resposta(self, caso_id: int, resposta: str) -> bool: """Avalia se a resposta está correta para o caso clínico""" try: cursor = self.conn.cursor() cursor.execute(''' SELECT gabarito FROM casos_clinicos WHERE id = ? ''', (caso_id,)) gabarito = cursor.fetchone()[0] return resposta.upper() == gabarito.upper() except Exception as e: logger.error(f"Erro ao avaliar resposta: {e}") return False def get_caso_details(self, caso_id: int) -> Optional[Dict]: """Retorna detalhes de um caso clínico específico""" try: cursor = self.conn.cursor() cursor.execute(''' SELECT id, titulo, descricao, imagem, pergunta, alternativas, gabarito, explicacao FROM casos_clinicos WHERE id = ? ''', (caso_id,)) caso = cursor.fetchone() if caso: return { "id": caso[0], "titulo": caso[1], "descricao": caso[2], "imagem": caso[3], "pergunta": caso[4], "alternativas": json.loads(caso[5]), "gabarito": caso[6], "explicacao": caso[7] } else: return None except Exception as e: logger.error(f"Erro ao obter detalhes do caso: {e}") return None def get_casos_by_topic(self, topico: str) -> List[Dict]: """Retorna casos clínicos de um tópico específico""" try: cursor = self.conn.cursor() cursor.execute(''' SELECT id, titulo, descricao, imagem, pergunta, alternativas, gabarito FROM casos_clinicos WHERE topico = ? ''', (topico,)) return [ { "id": caso[0], "titulo": caso[1], "descricao": caso[2], "imagem": caso[3], "pergunta": caso[4], "alternativas": json.loads(caso[5]), "gabarito": caso[6] } for caso in cursor.fetchall() ] except Exception as e: logger.error(f"Erro ao obter casos por tópico: {e}") return [] def create_simulado(self, difficulty: str = "mixed", num_questions: int = SimuladoConstants.QUESTOES_TOTAIS) -> Dict: """Cria simulado personalizado com mais opções""" try: simulado_id = str(uuid.uuid4()) simulado = { "id": simulado_id, "questoes": [], "tempo_sugerido": self._calculate_time(num_questions), "nivel": difficulty, "data_criacao": datetime.now().isoformat(), "status": "criado", "estatisticas": { "questoes_por_area": {}, "distribuicao_dificuldade": {} } } cursor = self.conn.cursor() # Distribuição de questões por área for area, percentual in self.areas_simulado.items(): num_area_questions = int((percentual/100) * num_questions) # Query considerando dificuldade difficulty_clause = "" if difficulty != "mixed": difficulty_clause = "AND difficulty = ?" params = (area, difficulty, num_area_questions) else: params = (area, num_area_questions) cursor.execute(f''' SELECT id, question_text, options, correct_answer, explanation, difficulty, references FROM previous_questions WHERE area = ? {difficulty_clause} ORDER BY RANDOM() LIMIT ? ''', params) questions = cursor.fetchall() for q in questions: question_data = { "id": q[0], "area": area, "texto": q[1], "opcoes": json.loads(q[2]), "resposta": q[3], "explicacao": q[4], "dificuldade": q[5], "referencias": json.loads(q[6]) if q[6] else [] } simulado["questoes"].append(question_data) # Atualizar estatísticas simulado["estatisticas"]["questoes_por_area"][area] = \ simulado["estatisticas"]["questoes_por_area"].get(area, 0) + 1 simulado["estatisticas"]["distribuicao_dificuldade"][q[5]] = \ simulado["estatisticas"]["distribuicao_dificuldade"].get(q[5], 0) + 1 self.simulados_ativos[simulado_id] = simulado return simulado except Exception as e: logger.error(f"Erro ao criar simulado: {e}") return None def _calculate_time(self, num_questions: int) -> int: """Calcula tempo sugerido baseado no número de questões""" return int(num_questions * 2) # 2 minutos por questão def evaluate_simulado(self, simulado_id: str, respostas: Dict[str, str], tempo_usado: int = None) -> Dict: """Avalia respostas do simulado com análise detalhada""" try: if simulado_id not in self.simulados_ativos: raise ValueError("Simulado não encontrado") simulado = self.simulados_ativos[simulado_id] resultado = { "id": simulado_id, "total_questoes": len(simulado["questoes"]), "corretas": 0, "tempo_usado": tempo_usado, "desempenho_por_area": {}, "analise_erros": [], "recomendacoes": [], "timestamp": datetime.now().isoformat() } # Análise detalhada por área area_stats = {} for area in self.areas_simulado: area_stats[area] = { "total": 0, "corretas": 0, "erros_comuns": [], "tempo_medio": 0 } # Avaliação de cada resposta for q_id, resp in respostas.items(): questao = next((q for q in simulado["questoes"] if q["id"] == q_id), None) if not questao: continue area = questao["area"] area_stats[area]["total"] += 1 if resp.upper() == questao["resposta"].upper(): area_stats[area]["corretas"] += 1 resultado["corretas"] += 1 else: # Análise do erro area_stats[area]["erros_comuns"].append({ "questao_id": q_id, "resposta_dada": resp, "resposta_correta": questao["resposta"], "tema": questao.get("tema", ""), "dificuldade": questao["dificuldade"] }) # Calcular porcentagens e gerar recomendações for area, stats in area_stats.items(): if stats["total"] > 0: percentual = (stats["corretas"] / stats["total"]) * 100 resultado["desempenho_por_area"][area] = { "total": stats["total"], "corretas": stats["corretas"], "percentual": percentual, "erros_comuns": stats["erros_comuns"] } if percentual < SimuladoConstants.NOTA_APROVACAO: resultado["recomendacoes"].append( self._generate_recommendations(area, stats) ) # Salvar resultado no banco de dados self._save_resultado(simulado_id, resultado) return resultado except Exception as e: logger.error(f"Erro ao avaliar simulado: {e}") return None def _generate_recommendations(self, area: str, stats: Dict) -> Dict: """Gera recomendações detalhadas baseadas no desempenho""" erros_comuns = self._analyze_common_errors(stats["erros_comuns"]) return { "area": area, "sugestoes": [ f"Revisar conceitos básicos de {area}", f"Focar em {', '.join(erros_comuns[:3])}", "Praticar questões similares", "Revisar casos clínicos relacionados" ], "recursos": [ "banco de questões", "casos clínicos", "revisão teórica", "videoaulas específicas" ], "plano_acao": self._create_action_plan(area, stats) } def _analyze_common_errors(self, erros: List[Dict]) -> List[str]: """Analisa padrões comuns de erros""" temas_errados = {} for erro in erros: tema = erro["tema"] if tema in temas_errados: temas_errados[tema] += 1 else: temas_errados[tema] = 1 return sorted(temas_errados.keys(), key=lambda x: temas_errados[x], reverse=True) def _create_action_plan(self, area: str, stats: Dict) -> Dict: """Cria plano de ação personalizado""" return { "prioridade": "alta" if len(stats["erros_comuns"]) > stats["corretas"] else "média", "etapas": [ "Revisão teórica dos temas com mais erros", "Resolução de questões comentadas", "Prática com casos clínicos", "Simulado focado na área" ], "tempo_sugerido": "2 semanas", "material_sugerido": [ "Bibliografia básica", "Questões anteriores comentadas", "Vídeo-aulas específicas" ] } def _save_resultado(self, simulado_id: str, resultado: Dict) -> None: """Salva resultado do simulado no banco de dados""" try: cursor = self.conn.cursor() cursor.execute(''' INSERT INTO resultados_simulados (simulado_id, data, resultado_json) VALUES (?, ?, ?) ''', ( simulado_id, datetime.now().isoformat(), json.dumps(resultado) )) self.conn.commit() except Exception as e: logger.error(f"Erro ao salvar resultado: {e}") def get_simulado_history(self, user_id: str) -> List[Dict]: """Obtém histórico de simulados do usuário""" try: cursor = self.conn.cursor() cursor.execute(''' SELECT simulado_id, data, resultado_json FROM resultados_simulados WHERE user_id = ? ORDER BY data DESC ''', (user_id,)) return [ { "id": row[0], "data": row[1], "resultado": json.loads(row[2]) } for row in cursor.fetchall() ] except Exception as e: logger.error(f"Erro ao obter histórico: {e}") return [] class CasoClinicoSystem: """ Sistema para gerenciar casos clínicos discursivos. """ def __init__(self): # Inicializa uma lista para armazenar os casos clínicos self.casos_clinicos = [] def adicionar_caso(self, titulo: str, descricao: str, resposta_correta: str): """ Adiciona um novo caso clínico ao sistema. :param titulo: Título do caso clínico :param descricao: Descrição do caso clínico :param resposta_correta: Resposta esperada para o caso clínico """ caso = { "titulo": titulo, "descricao": descricao, "resposta_correta": resposta_correta } self.casos_clinicos.append(caso) def listar_casos(self): """ Retorna a lista de todos os casos clínicos. """ return self.casos_clinicos def avaliar_resposta(self, indice: int, resposta_aluno: str) -> bool: """ Avalia a resposta de um aluno para um caso clínico específico. :param indice: Índice do caso clínico na lista :param resposta_aluno: Resposta fornecida pelo aluno :return: True se a resposta for correta, False caso contrário """ if 0 <= indice < len(self.casos_clinicos): caso = self.casos_clinicos[indice] return resposta_aluno.strip().lower() == caso["resposta_correta"].strip().lower() else: raise IndexError("Índice do caso clínico inválido.") # Exemplo de uso sistema_casos = CasoClinicoSystem() sistema_casos.adicionar_caso( titulo="Caso 1: Dor abdominal", descricao="Paciente de 45 anos com dor abdominal há 3 dias.", resposta_correta="Apendicite aguda" ) print(sistema_casos.listar_casos()) print(sistema_casos.avaliar_resposta(0, "Apendicite aguda")) def initialize_simulado_system(db_connection) -> Tuple[SimuladoSystem, CasoClinicoSystem]: """Inicializa o sistema de simulados""" try: simulado_sys = SimuladoSystem(db_connection) caso_sys = CasoClinicoSystem(db_connection) return simulado_sys, caso_sys except Exception as e: logger.error(f"Erro ao inicializar sistema de simulados: {e}") return None, None if __name__ == "__main__": # Código para testes import sqlite3 try: conn = sqlite3.connect('revalida.db') simulado_sys, caso_sys = initialize_simulado_system(conn) # Teste básico simulado = simulado_sys.create_simulado() if simulado: print("Sistema funcionando corretamente") print(f"Simulado criado: {json.dumps(simulado['estatisticas'], indent=2)}") except Exception as e: print(f"Erro nos testes: {e}") finally: conn.close()