danielraynaud commited on
Commit
cbb5c88
·
verified ·
1 Parent(s): e3e2a4c

Create utils/helpers.py

Browse files
Files changed (1) hide show
  1. utils/helpers.py +204 -0
utils/helpers.py ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # utils/helpers.py
2
+
3
+ import re
4
+ from datetime import datetime, timedelta
5
+ from typing import Dict, List, Optional, Union
6
+ import json
7
+ import logging
8
+
9
+ # Configuração de logging
10
+ logging.basicConfig(
11
+ level=logging.INFO,
12
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
13
+ )
14
+ logger = logging.getLogger(__name__)
15
+
16
+ class ValidationError(Exception):
17
+ """Exceção customizada para erros de validação"""
18
+ pass
19
+
20
+ def validate_email(email: str) -> bool:
21
+ """Valida formato de email"""
22
+ pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
23
+ return bool(re.match(pattern, email))
24
+
25
+ def validate_date_format(date_str: str) -> bool:
26
+ """Valida formato de data (YYYY-MM-DD)"""
27
+ try:
28
+ datetime.strptime(date_str, '%Y-%m-%d')
29
+ return True
30
+ except ValueError:
31
+ return False
32
+
33
+ def format_time_delta(minutes: int) -> str:
34
+ """Formata duração em minutos para formato legível"""
35
+ hours = minutes // 60
36
+ remaining_minutes = minutes % 60
37
+
38
+ if hours > 0:
39
+ return f"{hours}h{remaining_minutes:02d}min"
40
+ return f"{minutes}min"
41
+
42
+ def calculate_study_efficiency(hours_studied: float,
43
+ questions_answered: int,
44
+ correct_answers: int) -> float:
45
+ """Calcula eficiência de estudo"""
46
+ if hours_studied <= 0 or questions_answered == 0:
47
+ return 0.0
48
+
49
+ accuracy = correct_answers / questions_answered
50
+ questions_per_hour = questions_answered / hours_studied
51
+
52
+ # Fórmula personalizada para eficiência
53
+ efficiency = (accuracy * 0.7 + (questions_per_hour / 20) * 0.3) * 100
54
+ return round(min(efficiency, 100), 2)
55
+
56
+ def format_performance_message(score: float) -> str:
57
+ """Gera mensagem motivacional baseada no desempenho"""
58
+ if score >= 90:
59
+ return "🌟 Excelente! Você está dominando o conteúdo!"
60
+ elif score >= 80:
61
+ return "💪 Ótimo trabalho! Continue assim!"
62
+ elif score >= 70:
63
+ return "👍 Bom progresso! Mantenha o foco!"
64
+ elif score >= 60:
65
+ return "📚 Você está no caminho certo! Continue estudando!"
66
+ else:
67
+ return "💡 Não desanime! Cada questão é uma oportunidade de aprendizado!"
68
+
69
+ def generate_study_recommendations(weak_areas: List[str],
70
+ hours_available: float) -> Dict[str, any]:
71
+ """Gera recomendações de estudo baseadas em áreas fracas"""
72
+ total_weight = len(weak_areas)
73
+ hours_per_area = hours_available / total_weight if total_weight > 0 else 0
74
+
75
+ recommendations = {
76
+ "distribuicao_tempo": {},
77
+ "prioridades": [],
78
+ "recursos_sugeridos": []
79
+ }
80
+
81
+ for area in weak_areas:
82
+ recommendations["distribuicao_tempo"][area] = round(hours_per_area, 1)
83
+ recommendations["prioridades"].append({
84
+ "area": area,
85
+ "foco": ["Revisão teórica", "Questões práticas", "Casos clínicos"]
86
+ })
87
+
88
+ recommendations["recursos_sugeridos"] = [
89
+ "Material teórico focado",
90
+ "Questões comentadas",
91
+ "Vídeo-aulas específicas",
92
+ "Casos clínicos interativos"
93
+ ]
94
+
95
+ return recommendations
96
+
97
+ def parse_command_args(command: str) -> Dict[str, str]:
98
+ """Processa argumentos de comandos do bot"""
99
+ parts = command.split()
100
+ if len(parts) < 1:
101
+ return {}
102
+
103
+ command_dict = {
104
+ "command": parts[0]
105
+ }
106
+
107
+ # Processa argumentos nomeados (e.g., /comando area=pediatria tempo=2)
108
+ for part in parts[1:]:
109
+ if '=' in part:
110
+ key, value = part.split('=', 1)
111
+ command_dict[key.lower()] = value
112
+ else:
113
+ # Argumentos posicionais
114
+ if 'args' not in command_dict:
115
+ command_dict['args'] = []
116
+ command_dict['args'].append(part)
117
+
118
+ return command_dict
119
+
120
+ def format_question(question: Dict[str, any],
121
+ number: Optional[int] = None) -> str:
122
+ """Formata questão para exibição"""
123
+ formatted = ""
124
+
125
+ if number is not None:
126
+ formatted += f"Questão {number}:\n"
127
+
128
+ formatted += f"{question['texto']}\n\n"
129
+
130
+ for letra, texto in question['opcoes'].items():
131
+ formatted += f"{letra}) {texto}\n"
132
+
133
+ return formatted
134
+
135
+ def calculate_remaining_time(target_date: str) -> Dict[str, int]:
136
+ """Calcula tempo restante até a data alvo"""
137
+ target = datetime.strptime(target_date, '%Y-%m-%d').date()
138
+ today = datetime.now().date()
139
+
140
+ difference = target - today
141
+
142
+ return {
143
+ "dias": difference.days,
144
+ "semanas": difference.days // 7,
145
+ "meses": difference.days // 30
146
+ }
147
+
148
+ def format_study_summary(progress_data: Dict[str, any]) -> str:
149
+ """Formata resumo de estudos para exibição"""
150
+ summary = "📊 Resumo de Estudos:\n\n"
151
+
152
+ # Total de horas
153
+ total_hours = sum(progress_data.get('horas_por_area', {}).values())
154
+ summary += f"⏱ Total de horas estudadas: {total_hours:.1f}h\n"
155
+
156
+ # Desempenho por área
157
+ summary += "\n📈 Desempenho por área:\n"
158
+ for area, score in progress_data.get('desempenho_por_area', {}).items():
159
+ summary += f"• {area}: {score:.1f}%\n"
160
+
161
+ # Média geral
162
+ if 'media_geral' in progress_data:
163
+ summary += f"\n🎯 Média geral: {progress_data['media_geral']:.1f}%\n"
164
+
165
+ return summary
166
+
167
+ def safe_json_loads(json_str: str, default: Union[Dict, List] = None) -> Union[Dict, List]:
168
+ """Carrega JSON com segurança"""
169
+ try:
170
+ return json.loads(json_str)
171
+ except Exception as e:
172
+ logger.error(f"Erro ao carregar JSON: {e}")
173
+ return default if default is not None else {}
174
+
175
+ def sanitize_input(text: str) -> str:
176
+ """Sanitiza input do usuário"""
177
+ # Remove caracteres potencialmente perigosos
178
+ return re.sub(r'[<>&;]', '', text.strip())
179
+
180
+ def format_error_message(error: Exception) -> str:
181
+ """Formata mensagem de erro para usuário"""
182
+ return f"""❌ Ops! Ocorreu um erro:
183
+ {str(error)}
184
+
185
+ Por favor, tente novamente ou use /ajuda para ver os comandos disponíveis."""
186
+
187
+ if __name__ == "__main__":
188
+ # Testes básicos
189
+ print(validate_email("test@example.com")) # True
190
+ print(validate_email("invalid-email")) # False
191
+
192
+ print(format_time_delta(90)) # "1h30min"
193
+ print(format_time_delta(45)) # "45min"
194
+
195
+ test_question = {
196
+ "texto": "Qual é o principal sintoma da condição X?",
197
+ "opcoes": {
198
+ "A": "Sintoma 1",
199
+ "B": "Sintoma 2",
200
+ "C": "Sintoma 3",
201
+ "D": "Sintoma 4"
202
+ }
203
+ }
204
+ print(format_question(test_question, 1))