rmayormartins commited on
Commit
3e31db0
·
1 Parent(s): 2db7ec0
Files changed (5) hide show
  1. app.py +443 -393
  2. assets/rubric.pdf +0 -0
  3. assets/rubric_table.PNG +0 -0
  4. rubric.pdf +0 -0
  5. rubric_table.png +0 -0
app.py CHANGED
@@ -1,28 +1,80 @@
1
-
2
- import gradio as gr
3
  import javalang
4
  from typing import Dict, List, Tuple
 
5
  import re
6
 
7
- class JavaStructuralEvaluator:
 
 
 
 
 
 
 
 
8
  """Avaliador baseado em estruturas usadas"""
9
  def __init__(self):
10
  self.rubric = {
11
- "declaracoes": 25, # Declarações e tipos
12
- "estruturas_controle": 25, # if, switch, loops
13
- "operadores": 25, # Operadores e expressões
14
- "io_strings": 25 # System.out, concatenação, etc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  }
16
-
17
- def analyze_declarations(self, code: str) -> Tuple[float, List[str]]:
18
- """Analisa declarações e tipos"""
19
  score = 0
 
20
  feedback = []
21
-
22
  try:
23
  tree = javalang.parse.parse(code)
24
 
25
- # Verificar tipos primitivos
26
  primitives = {
27
  'int': 'números inteiros',
28
  'double': 'números decimais',
@@ -33,474 +85,471 @@ class JavaStructuralEvaluator:
33
  'byte': 'valores byte',
34
  'short': 'números curtos'
35
  }
36
-
37
  used_types = set()
38
- for _, node in tree.filter(javalang.tree.LocalVariableDeclaration):
39
- type_name = node.type.name
 
40
  used_types.add(type_name)
41
-
42
- for type_name, description in primitives.items():
43
- if type_name in used_types:
44
- score += 3
45
- feedback.append(f"✓ Uso correto de {type_name} para {description}")
46
-
47
- # Verificar declarações de variáveis
48
- total_vars = len(list(tree.filter(javalang.tree.LocalVariableDeclaration)))
49
- if total_vars > 0:
50
- score += 5
51
- feedback.append(f"✓ {total_vars} variáveis declaradas corretamente")
52
-
53
- # Verificar constantes
54
- constants = list(tree.filter(javalang.tree.FieldDeclaration))
55
- if any('final' in node.modifiers for _, node in tree.filter(javalang.tree.FieldDeclaration)):
56
- score += 4
 
 
 
57
  feedback.append("✓ Uso adequado de constantes (final)")
58
-
59
  except Exception as e:
60
  feedback.append("⚠ Erro na análise de declarações")
61
-
62
- return score, feedback
63
 
64
- def analyze_control_structures(self, code: str) -> Tuple[float, List[str]]:
65
- """Analisa estruturas de controle"""
 
 
66
  score = 0
 
67
  feedback = []
68
-
69
  try:
70
  tree = javalang.parse.parse(code)
71
 
72
- # If/Else
73
- if_count = len(list(tree.filter(javalang.tree.IfStatement)))
74
- if if_count > 0:
75
- score += 5
76
- feedback.append(f"✓ Uso correto de {if_count} estrutura(s) if/else")
77
-
78
- # Switch
79
- switch_count = len(list(tree.filter(javalang.tree.SwitchStatement)))
80
- if switch_count > 0:
81
- score += 5
82
- feedback.append(f"✓ Uso correto de {switch_count} switch/case")
83
-
84
- # For loops
85
- for_count = len(list(tree.filter(javalang.tree.ForStatement)))
86
- if for_count > 0:
87
- score += 5
88
- feedback.append(f"✓ Uso correto de {for_count} loop(s) for")
89
-
90
- # While loops
91
- while_count = len(list(tree.filter(javalang.tree.WhileStatement)))
92
- if while_count > 0:
93
- score += 5
94
- feedback.append(f"✓ Uso correto de {while_count} loop(s) while")
95
-
96
- # Do-While loops
97
- do_while_count = len(list(tree.filter(javalang.tree.DoStatement)))
98
- if do_while_count > 0:
99
- score += 5
100
- feedback.append(f"✓ Uso correto de {do_while_count} loop(s) do-while")
101
-
102
  except Exception as e:
103
  feedback.append("⚠ Erro na análise de estruturas de controle")
104
-
105
- return score, feedback
106
 
107
- def analyze_operators(self, code: str) -> Tuple[float, List[str]]:
108
- """Analisa operadores e expressões"""
 
 
109
  score = 0
 
110
  feedback = []
111
-
112
  try:
113
- # Operadores aritméticos
114
- arithmetic = ['+', '-', '*', '/', '%']
115
- for op in arithmetic:
116
- if op in code:
117
- score += 2
118
- feedback.append(f"✓ Uso do operador aritmético {op}")
119
-
120
- # Operadores de comparação
121
- comparison = ['==', '!=', '>', '<', '>=', '<=']
122
- for op in comparison:
123
- if op in code:
124
- score += 2
125
- feedback.append(f"✓ Uso do operador de comparação {op}")
126
-
127
- # Operadores lógicos
128
- logical = ['&&', '||', '!']
129
- for op in logical:
130
- if op in code:
131
- score += 2
132
- feedback.append(f"✓ Uso do operador lógico {op}")
133
-
134
- # Operadores de atribuição
135
- assignment = ['+=', '-=', '*=', '/=']
136
- for op in assignment:
137
- if op in code:
138
- score += 2
139
- feedback.append(f"✓ Uso do operador de atribuição {op}")
140
-
141
  except Exception as e:
142
  feedback.append("⚠ Erro na análise de operadores")
143
-
144
- return score, feedback
145
 
146
- def analyze_io_strings(self, code: str) -> Tuple[float, List[str]]:
147
- """Analisa entrada/saída e manipulação de strings"""
 
 
148
  score = 0
 
149
  feedback = []
150
-
151
  try:
152
- # System.out
153
- if 'System.out.print' in code:
154
- score += 5
155
- feedback.append("✓ Uso correto de System.out.print")
156
-
157
- # Scanner
158
- if 'Scanner' in code:
159
- score += 5
160
- feedback.append("✓ Uso correto da classe Scanner para entrada")
161
-
162
- # Concatenação de strings
163
- if '+' in code and '"' in code:
164
- score += 5
165
- feedback.append("✓ Concatenação de strings com operador +")
166
-
167
- # Métodos de String
168
  string_methods = ['concat', 'substring', 'length', 'equals', 'compareTo']
169
- for method in string_methods:
170
- if f'.{method}(' in code:
171
- score += 2
172
- feedback.append(f"✓ Uso do método String.{method}")
173
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  except Exception as e:
175
  feedback.append("⚠ Erro na análise de I/O e strings")
176
-
177
- return score, feedback
178
 
179
  def evaluate_code(self, code: str) -> Dict:
180
- """Avalia o código Java"""
181
- # Análises individuais
182
- decl_score, decl_feedback = self.analyze_declarations(code)
183
- ctrl_score, ctrl_feedback = self.analyze_control_structures(code)
184
- op_score, op_feedback = self.analyze_operators(code)
185
- io_score, io_feedback = self.analyze_io_strings(code)
186
-
187
- # Calcular pontuação total
188
- total_score = sum([
189
- decl_score,
190
- ctrl_score,
191
- op_score,
192
- io_score
193
- ])
194
-
195
- # Normalizar para 100
196
- total_score = min(100, total_score)
197
-
198
- # Determinar nível
199
- proficiency = "Necessita Melhorias"
 
 
 
 
 
 
 
 
200
  if total_score >= 90:
201
- proficiency = "Excelente"
202
  elif total_score >= 75:
203
- proficiency = "Bom"
204
  elif total_score >= 60:
205
- proficiency = "Satisfatório"
206
-
207
- return {
208
- "total_score": total_score,
209
- "proficiency": proficiency,
210
- "feedback": {
211
- "declaracoes": decl_feedback,
212
- "estruturas_controle": ctrl_feedback,
213
- "operadores": op_feedback,
214
- "io_strings": io_feedback
215
- }
216
- }
217
 
218
- class CompetencyEvaluator:
 
219
  def __init__(self):
220
  self.rubric = {
221
- "syntax_correctness": 50,
222
- "competencies": 50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  }
224
-
225
- def analyze_syntax_correctness(self, code: str) -> Tuple[float, List[str]]:
 
226
  score = 0
 
227
  feedback = []
228
-
229
  try:
230
  tree = javalang.parse.parse(code)
231
 
232
- # 1. Estrutura básica do programa (10 pontos)
233
- if 'class' in code:
234
- score += 5
235
- feedback.append("✓ Estrutura de classe correta")
236
- if 'public static void main' in code:
237
- score += 5
238
- feedback.append("✓ Método main corretamente declarado")
239
-
240
- # 2. Declarações e Tipos (10 pontos)
241
  declarations = list(tree.filter(javalang.tree.LocalVariableDeclaration))
242
  if declarations:
243
- score += 5
244
- feedback.append("✓ Declarações de variáveis sintáticamente corretas")
245
- if any(hasattr(d, 'type') and d.type.name in ['int', 'double', 'String', 'boolean'] for d in declarations):
246
- score += 5
247
- feedback.append("✓ Tipos de dados usados corretamente")
248
-
249
- # 3. Expressões e Operadores (10 pontos)
250
- binary_operations = []
251
- for path, node in tree.filter(javalang.tree.BinaryOperation):
252
- if hasattr(node, 'operator'):
253
- binary_operations.append(node)
254
-
255
- if binary_operations:
256
  score += 10
257
- feedback.append("✓ Expressões e operadores usados corretamente")
258
 
259
- # 4. Blocos e Estruturas (10 pontos)
260
- open_braces = code.count('{')
261
- close_braces = code.count('}')
262
- if open_braces == close_braces and open_braces > 0:
263
- score += 5
264
  feedback.append("✓ Blocos corretamente delimitados")
265
-
266
- semicolons = len(re.findall(';[^;]*$', code, re.MULTILINE))
267
- if semicolons > 0:
268
- score += 5
269
- feedback.append("✓ Instruções corretamente terminadas")
270
-
271
- # 5. Entrada/Saída (10 pontos)
272
- if 'System.out' in code:
273
- score += 5
274
- feedback.append("✓ Sintaxe de saída correta")
275
- if 'Scanner' in code:
276
- score += 5
277
- feedback.append("✓ Sintaxe de entrada correta")
 
 
 
 
 
 
 
 
 
 
 
 
 
278
 
279
  except Exception as e:
280
  feedback.append(f"⚠ Erro de sintaxe: {str(e)}")
281
-
282
- return score, feedback
283
 
284
- def analyze_competencies(self, code: str) -> Tuple[float, List[str]]:
 
 
 
285
  score = 0
 
286
  feedback = []
287
-
288
  try:
289
  tree = javalang.parse.parse(code)
290
-
291
- # 1. Seleção de Estruturas (15 pontos)
292
  structures = {
293
  'if': list(tree.filter(javalang.tree.IfStatement)),
294
  'for': list(tree.filter(javalang.tree.ForStatement)),
295
  'while': list(tree.filter(javalang.tree.WhileStatement))
296
  }
297
 
 
298
  for struct_type, instances in structures.items():
299
  if instances:
300
- if struct_type == 'for':
301
- for path, node in tree.filter(javalang.tree.ForStatement):
302
- if any('length' in str(getattr(node, attr, '')) for attr in dir(node)):
303
- score += 5
304
- feedback.append("✓ Uso adequado de for para iteração em arrays")
305
- break
306
- elif struct_type == 'while':
307
- for path, node in tree.filter(javalang.tree.WhileStatement):
308
- if any('hasNext' in str(getattr(node, attr, '')) for attr in dir(node)):
309
- score += 5
310
- feedback.append("✓ Uso adequado de while para leitura de dados")
311
- break
312
- else:
313
- score += 5
314
- feedback.append(f"✓ Uso apropriado de {struct_type}")
315
-
316
- # 2. Manipulação de Dados (15 pontos)
317
- binary_operations = []
318
- for path, node in tree.filter(javalang.tree.BinaryOperation):
319
- if hasattr(node, 'operator'):
320
- binary_operations.append(node)
321
-
322
- if binary_operations:
323
- arithmetic_ops = [op for op in binary_operations if hasattr(op, 'operator') and op.operator in ['*', '/', '+', '-']]
324
- comparison_ops = [op for op in binary_operations if hasattr(op, 'operator') and op.operator in ['>', '<', '>=', '<=', '==']]
325
- assignment_ops = [op for op in binary_operations if hasattr(op, 'operator') and '=' in op.operator]
326
-
327
- if arithmetic_ops:
328
- score += 5
329
- feedback.append("✓ Cálculos implementados corretamente")
330
- if comparison_ops:
331
- score += 5
332
- feedback.append("✓ Comparações implementadas corretamente")
333
- if assignment_ops:
334
- score += 5
335
- feedback.append("✓ Atribuições implementadas corretamente")
336
-
337
- # 3. Clareza e Organização (10 pontos)
338
- # Verificar nomes significativos
339
- has_meaningful_names = True
340
- for path, node in tree.filter(javalang.tree.LocalVariableDeclaration):
341
- if hasattr(node, 'declarators') and node.declarators:
342
- for declarator in node.declarators:
343
- if hasattr(declarator, 'name') and len(declarator.name) <= 1:
344
- has_meaningful_names = False
345
- break
346
-
347
- if has_meaningful_names:
348
- score += 5
349
- feedback.append("✓ Nomes de variáveis significativos")
350
 
351
- # Verificar indentação e comentários
352
  lines = code.split('\n')
353
  if any('//' in line or '/*' in line for line in lines):
354
- score += 5
355
- feedback.append("✓ Código bem documentado")
356
 
357
- # 4. Resolução do Problema (10 pontos)
358
- has_input = 'Scanner' in code
359
- has_processing = bool(binary_operations)
360
- has_output = 'System.out' in code
361
-
362
- if has_input and has_output:
363
- score += 5
364
- feedback.append("✓ Programa com entrada e saída")
365
- if has_processing:
366
- score += 5
367
- feedback.append("✓ Lógica de processamento implementada")
 
 
 
 
 
368
 
369
  except Exception as e:
370
  feedback.append(f"⚠ Erro na análise de competências: {str(e)}")
371
-
372
- return score, feedback
373
 
374
  def evaluate_code(self, code: str) -> Dict:
375
- # Análises individuais
376
- syntax_score, syntax_feedback = self.analyze_syntax_correctness(code)
377
- comp_score, comp_feedback = self.analyze_competencies(code)
378
-
379
- # Calcular pontuação total
380
- total_score = syntax_score + comp_score
381
-
382
- # Determinar nível
383
- proficiency = "Necessita Melhorias"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
  if total_score >= 90:
385
- proficiency = "Excelente"
386
  elif total_score >= 75:
387
- proficiency = "Bom"
388
  elif total_score >= 60:
389
- proficiency = "Satisfatório"
390
-
391
- return {
392
- "total_score": total_score,
393
- "proficiency": proficiency,
394
- "feedback": {
395
- "corretude_sintatica": syntax_feedback,
396
- "competencias": comp_feedback
397
- }
398
- }
399
 
400
- def process_java_files(files) -> str:
401
- """Avalia código usando a rubrica estrutural"""
402
- evaluator = JavaStructuralEvaluator()
403
- return evaluate_files(files, evaluator, "Estrutural")
404
 
405
- def evaluate_competency(files) -> str:
406
- """Avalia código usando a rubrica de competências"""
407
- evaluator = CompetencyEvaluator()
408
- return evaluate_files(files, evaluator, "Competências")
409
 
410
- def evaluate_files(files, evaluator, evaluation_type: str) -> str:
411
- """Função auxiliar para avaliar arquivos com qualquer avaliador"""
412
  results = []
413
- project_files = {}
414
-
415
  try:
416
- if not isinstance(files, list):
417
- files = [files]
418
-
419
- # Primeiro, vamos ler todos os arquivos
 
 
 
420
  for file in files:
421
  with open(file.name, 'r', encoding='utf-8') as f:
422
- content = f.read()
423
- project_files[file.name] = content
424
-
425
- # Identificar arquivo principal
426
- main_file = None
427
- other_files = {}
428
- for filename, content in project_files.items():
429
- if "public static void main" in content:
430
- main_file = (filename, content)
431
- else:
432
- other_files[filename] = content
433
-
434
- # Resumo do projeto
435
- results.append(f"""
436
- {'='*50}
437
- AVALIAÇÃO {evaluation_type.upper()}
438
- {'='*50}
439
- Total de arquivos: {len(project_files)}
440
- Arquivo principal: {main_file[0] if main_file else 'Não encontrado'}
441
- Arquivos complementares: {len(other_files)}
442
- {'='*50}
443
- """)
444
-
445
- # Avaliar arquivo principal
446
- if main_file:
447
- result = f"\nARQUIVO PRINCIPAL: {main_file[0]}\n{'-'*30}\n"
448
- evaluation = evaluator.evaluate_code(main_file[1])
449
-
450
- result += f"Pontuação Total: {evaluation['total_score']:.1f}/100\n"
451
- result += f"Nível: {evaluation['proficiency']}\n\n"
452
-
453
- result += "Feedback Detalhado:\n"
454
- for category, comments in evaluation['feedback'].items():
455
- if comments:
456
- result += f"\n{category.title()}:\n"
457
- for comment in comments:
458
- result += f" {comment}\n"
459
-
460
  results.append(result)
461
-
462
- # Avaliar outros arquivos
463
- if other_files:
464
- results.append(f"\nARQUIVOS COMPLEMENTARES\n{'-'*30}")
465
-
466
- for filename, content in other_files.items():
467
- result = f"\nAvaliando: {filename}\n"
468
- evaluation = evaluator.evaluate_code(content)
469
-
470
- result += f"Pontuação: {evaluation['total_score']:.1f}/100\n"
471
- result += f"Nível: {evaluation['proficiency']}\n\n"
472
-
473
- result += "Feedback:\n"
474
- for category, comments in evaluation['feedback'].items():
475
- if comments:
476
- result += f"\n{category.title()}:\n"
477
- for comment in comments:
478
- result += f" {comment}\n"
479
-
480
- results.append(result)
481
-
482
  return "\n".join(results)
483
-
484
  except Exception as e:
485
- return f"Erro ao processar arquivos: {str(e)}\nTipo do erro: {type(e)}"
486
 
487
  # Interface Gradio com abas
488
- with gr.Blocks(title="Java-Judge-Syntax-Competencies") as demo:
489
  gr.Markdown("""
490
- # Java-Judge-Syntax-Competencies
491
 
492
- ### [Visualizar Rubrica em PDF](rubric.pdf)
493
- ### [Visualizar Rubrica em PNG](rubric_table.png)
494
- Este avaliador analisa código Java usando duas rubricas diferentes:
495
- 1. **Avaliação Estrutural**: Foca no uso correto de elementos da linguagem
496
- 2. **Avaliação por Competências**: Analisa qualidade e eficiência do código
497
  """)
498
-
499
  with gr.Tabs():
500
  with gr.Tab("Avaliação Estrutural"):
501
  upload_structural = gr.File(
502
  file_count="multiple",
503
- label="Upload dos arquivos Java"
 
504
  )
505
  evaluate_btn_structural = gr.Button("Avaliar Estruturas")
506
  output_structural = gr.Textbox(
@@ -508,15 +557,16 @@ with gr.Blocks(title="Java-Judge-Syntax-Competencies") as demo:
508
  lines=25
509
  )
510
  evaluate_btn_structural.click(
511
- fn=process_java_files,
512
  inputs=upload_structural,
513
  outputs=output_structural
514
  )
515
-
516
  with gr.Tab("Avaliação por Competências"):
517
  upload_competency = gr.File(
518
  file_count="multiple",
519
- label="Upload dos arquivos Java"
 
520
  )
521
  evaluate_btn_competency = gr.Button("Avaliar Competências")
522
  output_competency = gr.Textbox(
@@ -524,10 +574,10 @@ with gr.Blocks(title="Java-Judge-Syntax-Competencies") as demo:
524
  lines=25
525
  )
526
  evaluate_btn_competency.click(
527
- fn=evaluate_competency,
528
  inputs=upload_competency,
529
  outputs=output_competency
530
  )
531
 
532
  if __name__ == "__main__":
533
- demo.launch(share=True)
 
 
 
1
  import javalang
2
  from typing import Dict, List, Tuple
3
+ from dataclasses import dataclass
4
  import re
5
 
6
+ @dataclass
7
+ class RubricCriterion:
8
+ name: str
9
+ description: str
10
+ weight: int
11
+ is_essential: bool
12
+ levels: Dict[str, Dict[str, float]]
13
+
14
+ class EnhancedJavaStructuralEvaluator:
15
  """Avaliador baseado em estruturas usadas"""
16
  def __init__(self):
17
  self.rubric = {
18
+ "declarations": RubricCriterion(
19
+ name="Declarações",
20
+ description="Uso de tipos e declarações",
21
+ weight=25,
22
+ is_essential=True,
23
+ levels={
24
+ "Fraco": {"threshold": 0, "description": "Uso mínimo/incorreto"},
25
+ "Regular": {"threshold": 10, "description": "1-2 tipos primitivos, 1-2 variáveis"},
26
+ "Bom": {"threshold": 15, "description": "3 tipos primitivos, 3-4 variáveis"},
27
+ "Excelente": {"threshold": 20, "description": "≥4 tipos primitivos, ≥5 variáveis"}
28
+ }
29
+ ),
30
+ "control_structures": RubricCriterion(
31
+ name="Estruturas de Controle",
32
+ description="Controle de fluxo do programa",
33
+ weight=25,
34
+ is_essential=True,
35
+ levels={
36
+ "Fraco": {"threshold": 0, "description": "Uso mínimo/incorreto"},
37
+ "Regular": {"threshold": 10, "description": "1 tipo, uso básico"},
38
+ "Bom": {"threshold": 15, "description": "2 tipos diferentes, uso correto"},
39
+ "Excelente": {"threshold": 20, "description": "≥3 tipos diferentes, uso apropriado"}
40
+ }
41
+ ),
42
+ "operators": RubricCriterion(
43
+ name="Operadores",
44
+ description="Operações e expressões",
45
+ weight=25,
46
+ is_essential=True,
47
+ levels={
48
+ "Fraco": {"threshold": 0, "description": "Uso mínimo/incorreto"},
49
+ "Regular": {"threshold": 10, "description": "1-2 operadores"},
50
+ "Bom": {"threshold": 15, "description": "3-4 operadores"},
51
+ "Excelente": {"threshold": 20, "description": "≥5 operadores diferentes"}
52
+ }
53
+ ),
54
+ "io_strings": RubricCriterion(
55
+ name="I/O e Strings",
56
+ description="Entrada/saída e manipulação de texto",
57
+ weight=25,
58
+ is_essential=True,
59
+ levels={
60
+ "Fraco": {"threshold": 0, "description": "Uso mínimo/incorreto"},
61
+ "Regular": {"threshold": 10, "description": "E/S simples"},
62
+ "Bom": {"threshold": 15, "description": "E/S moderada, manipulação básica"},
63
+ "Excelente": {"threshold": 20, "description": "E/S complexa, manipulação avançada"}
64
+ }
65
+ )
66
  }
67
+
68
+ def evaluate_declarations(self, code: str) -> Tuple[float, str, List[str]]:
69
+ """Avalia declarações e tipos"""
70
  score = 0
71
+ level = "Fraco"
72
  feedback = []
73
+
74
  try:
75
  tree = javalang.parse.parse(code)
76
 
77
+ # Análise de tipos primitivos
78
  primitives = {
79
  'int': 'números inteiros',
80
  'double': 'números decimais',
 
85
  'byte': 'valores byte',
86
  'short': 'números curtos'
87
  }
88
+
89
  used_types = set()
90
+ declarations = [node for _, node in tree.filter(javalang.tree.LocalVariableDeclaration)]
91
+ for decl in declarations:
92
+ type_name = decl.type.name
93
  used_types.add(type_name)
94
+
95
+ num_types = len(used_types)
96
+ num_vars = len(declarations)
97
+ has_constants = any('final' in node.modifiers for _, node in tree.filter(javalang.tree.FieldDeclaration))
98
+
99
+ # Determinar nível
100
+ if num_types >= 4 and num_vars >= 5 and has_constants:
101
+ score = 25
102
+ level = "Excelente"
103
+ elif num_types >= 3 and num_vars >= 3:
104
+ score = 15
105
+ level = "Bom"
106
+ elif num_types >= 1 or num_vars >= 1:
107
+ score = 10
108
+ level = "Regular"
109
+
110
+ feedback.append(f"✓ {num_types} tipos primitivos diferentes utilizados")
111
+ feedback.append(f"✓ {num_vars} variáveis declaradas")
112
+ if has_constants:
113
  feedback.append("✓ Uso adequado de constantes (final)")
114
+
115
  except Exception as e:
116
  feedback.append("⚠ Erro na análise de declarações")
 
 
117
 
118
+ return score, level, feedback
119
+
120
+ def evaluate_control_structures(self, code: str) -> Tuple[float, str, List[str]]:
121
+ """Avalia estruturas de controle"""
122
  score = 0
123
+ level = "Fraco"
124
  feedback = []
125
+
126
  try:
127
  tree = javalang.parse.parse(code)
128
 
129
+ structures = {
130
+ 'if': len(list(tree.filter(javalang.tree.IfStatement))),
131
+ 'switch': len(list(tree.filter(javalang.tree.SwitchStatement))),
132
+ 'for': len(list(tree.filter(javalang.tree.ForStatement))),
133
+ 'while': len(list(tree.filter(javalang.tree.WhileStatement))),
134
+ 'do_while': len(list(tree.filter(javalang.tree.DoStatement)))
135
+ }
136
+
137
+ num_different_structures = sum(1 for count in structures.values() if count > 0)
138
+ total_structures = sum(structures.values())
139
+
140
+ # Determinar nível
141
+ if num_different_structures >= 3 and total_structures >= 4:
142
+ score = 25
143
+ level = "Excelente"
144
+ elif num_different_structures >= 2 and total_structures >= 2:
145
+ score = 15
146
+ level = "Bom"
147
+ elif num_different_structures >= 1:
148
+ score = 10
149
+ level = "Regular"
150
+
151
+ for struct, count in structures.items():
152
+ if count > 0:
153
+ feedback.append(f"✓ {count} estrutura(s) {struct}")
154
+
 
 
 
 
155
  except Exception as e:
156
  feedback.append("⚠ Erro na análise de estruturas de controle")
 
 
157
 
158
+ return score, level, feedback
159
+
160
+ def evaluate_operators(self, code: str) -> Tuple[float, str, List[str]]:
161
+ """Avalia operadores"""
162
  score = 0
163
+ level = "Fraco"
164
  feedback = []
165
+
166
  try:
167
+ operators = {
168
+ 'arithmetic': ['+', '-', '*', '/', '%'],
169
+ 'comparison': ['==', '!=', '>', '<', '>=', '<='],
170
+ 'logical': ['&&', '||', '!'],
171
+ 'assignment': ['+=', '-=', '*=', '/=']
172
+ }
173
+
174
+ used_operators = set()
175
+ for category, ops in operators.items():
176
+ for op in ops:
177
+ if op in code:
178
+ used_operators.add(op)
179
+ feedback.append(f"✓ Uso do operador {op}")
180
+
181
+ num_operators = len(used_operators)
182
+
183
+ # Determinar nível
184
+ if num_operators >= 5:
185
+ score = 25
186
+ level = "Excelente"
187
+ elif num_operators >= 3:
188
+ score = 15
189
+ level = "Bom"
190
+ elif num_operators >= 1:
191
+ score = 10
192
+ level = "Regular"
193
+
 
194
  except Exception as e:
195
  feedback.append("⚠ Erro na análise de operadores")
 
 
196
 
197
+ return score, level, feedback
198
+
199
+ def evaluate_io_strings(self, code: str) -> Tuple[float, str, List[str]]:
200
+ """Avalia entrada/saída e strings"""
201
  score = 0
202
+ level = "Fraco"
203
  feedback = []
204
+
205
  try:
206
+ features = {
207
+ 'output': 'System.out.print' in code,
208
+ 'input': 'Scanner' in code,
209
+ 'concatenation': '+' in code and '"' in code,
210
+ 'string_methods': False
211
+ }
212
+
213
+ # Verificar métodos de String
 
 
 
 
 
 
 
 
214
  string_methods = ['concat', 'substring', 'length', 'equals', 'compareTo']
215
+ methods_used = [method for method in string_methods if f'.{method}(' in code]
216
+ features['string_methods'] = len(methods_used) > 0
217
+
218
+ # Contar recursos utilizados
219
+ num_features = sum(1 for used in features.values() if used)
220
+
221
+ # Determinar nível
222
+ if num_features >= 3 and features['string_methods']:
223
+ score = 25
224
+ level = "Excelente"
225
+ elif num_features >= 2:
226
+ score = 15
227
+ level = "Bom"
228
+ elif num_features >= 1:
229
+ score = 10
230
+ level = "Regular"
231
+
232
+ if features['output']:
233
+ feedback.append("✓ Uso de saída (System.out)")
234
+ if features['input']:
235
+ feedback.append("✓ Uso de entrada (Scanner)")
236
+ if features['concatenation']:
237
+ feedback.append("✓ Concatenação de strings")
238
+ if methods_used:
239
+ feedback.append(f"✓ Uso de {len(methods_used)} métodos de String")
240
+
241
  except Exception as e:
242
  feedback.append("⚠ Erro na análise de I/O e strings")
243
+
244
+ return score, level, feedback
245
 
246
  def evaluate_code(self, code: str) -> Dict:
247
+ """Avalia o código Java usando todos os critérios"""
248
+ evaluation = {
249
+ "scores": {},
250
+ "levels": {},
251
+ "feedback": {},
252
+ "summary": {
253
+ "total_score": 0,
254
+ "proficiency": ""
255
+ }
256
+ }
257
+
258
+ # Avaliar cada critério
259
+ criteria_evaluations = {
260
+ "declarations": self.evaluate_declarations(code),
261
+ "control_structures": self.evaluate_control_structures(code),
262
+ "operators": self.evaluate_operators(code),
263
+ "io_strings": self.evaluate_io_strings(code)
264
+ }
265
+
266
+ # Compilar resultados
267
+ for criterion, (score, level, feedback) in criteria_evaluations.items():
268
+ evaluation["scores"][criterion] = score
269
+ evaluation["levels"][criterion] = level
270
+ evaluation["feedback"][criterion] = feedback
271
+ evaluation["summary"]["total_score"] += score
272
+
273
+ # Determinar proficiência geral
274
+ total_score = evaluation["summary"]["total_score"]
275
  if total_score >= 90:
276
+ evaluation["summary"]["proficiency"] = "Excelente"
277
  elif total_score >= 75:
278
+ evaluation["summary"]["proficiency"] = "Bom"
279
  elif total_score >= 60:
280
+ evaluation["summary"]["proficiency"] = "Satisfatório"
281
+ else:
282
+ evaluation["summary"]["proficiency"] = "Necessita Melhorias"
283
+
284
+ return evaluation
 
 
 
 
 
 
 
285
 
286
+ class EnhancedCompetencyEvaluator:
287
+ """Avaliador baseado em competências"""
288
  def __init__(self):
289
  self.rubric = {
290
+ "syntax": RubricCriterion(
291
+ name="Corretude Sintática",
292
+ description="Correção técnica do código",
293
+ weight=50,
294
+ is_essential=True,
295
+ levels={
296
+ "Fraco": {"threshold": 0, "description": "Muitos erros"},
297
+ "Regular": {"threshold": 20, "description": "Código funcional, alguns erros"},
298
+ "Bom": {"threshold": 30, "description": "Código correto, erros menores"},
299
+ "Excelente": {"threshold": 40, "description": "Código exemplar, sem erros"}
300
+ }
301
+ ),
302
+ "competencies": RubricCriterion(
303
+ name="Competências Práticas",
304
+ description="Qualidade da implementação",
305
+ weight=50,
306
+ is_essential=True,
307
+ levels={
308
+ "Fraco": {"threshold": 0, "description": "Implementação pobre"},
309
+ "Regular": {"threshold": 20, "description": "Implementação básica"},
310
+ "Bom": {"threshold": 30, "description": "Boa implementação"},
311
+ "Excelente": {"threshold": 40, "description": "Implementação sofisticada"}
312
+ }
313
+ )
314
  }
315
+
316
+ def evaluate_syntax(self, code: str) -> Tuple[float, str, List[str]]:
317
+ """Avalia corretude sintática"""
318
  score = 0
319
+ level = "Fraco"
320
  feedback = []
321
+
322
  try:
323
  tree = javalang.parse.parse(code)
324
 
325
+ # 1. Estrutura básica (10 pts)
326
+ has_class = 'class' in code
327
+ has_main = 'public static void main' in code
328
+ if has_class and has_main:
329
+ score += 10
330
+ feedback.append("✓ Estrutura básica correta (classe e main)")
331
+
332
+ # 2. Declarações (10 pts)
 
333
  declarations = list(tree.filter(javalang.tree.LocalVariableDeclaration))
334
  if declarations:
 
 
 
 
 
 
 
 
 
 
 
 
 
335
  score += 10
336
+ feedback.append(f"✓ {len(declarations)} declarações sintáticamente corretas")
337
 
338
+ # 3. Blocos e estruturas (10 pts)
339
+ if code.count('{') == code.count('}') and code.count('{') > 0:
340
+ score += 10
 
 
341
  feedback.append("✓ Blocos corretamente delimitados")
342
+
343
+ # 4. Expressões (10 pts)
344
+ expressions = list(tree.filter(javalang.tree.BinaryOperation))
345
+ if expressions:
346
+ score += 10
347
+ feedback.append("✓ Expressões bem formadas")
348
+
349
+ # 5. Pontuação e formatação (10 pts)
350
+ lines = code.split('\n')
351
+ well_formatted = all(line.strip().endswith(';') or
352
+ line.strip().endswith('{') or
353
+ line.strip().endswith('}') or
354
+ line.strip() == "" or
355
+ line.strip().startswith('//')
356
+ for line in lines if line.strip())
357
+ if well_formatted:
358
+ score += 10
359
+ feedback.append("✓ Código bem formatado e pontuado")
360
+
361
+ # Determinar nível
362
+ if score >= 40:
363
+ level = "Excelente"
364
+ elif score >= 30:
365
+ level = "Bom"
366
+ elif score >= 20:
367
+ level = "Regular"
368
 
369
  except Exception as e:
370
  feedback.append(f"⚠ Erro de sintaxe: {str(e)}")
 
 
371
 
372
+ return score, level, feedback
373
+
374
+ def evaluate_competencies(self, code: str) -> Tuple[float, str, List[str]]:
375
+ """Avalia competências práticas"""
376
  score = 0
377
+ level = "Fraco"
378
  feedback = []
379
+
380
  try:
381
  tree = javalang.parse.parse(code)
382
+
383
+ # 1. Seleção de estruturas (15 pts)
384
  structures = {
385
  'if': list(tree.filter(javalang.tree.IfStatement)),
386
  'for': list(tree.filter(javalang.tree.ForStatement)),
387
  'while': list(tree.filter(javalang.tree.WhileStatement))
388
  }
389
 
390
+ struct_score = 0
391
  for struct_type, instances in structures.items():
392
  if instances:
393
+ struct_score += 5
394
+ if struct_type == 'for' and any('length' in str(inst) for inst in instances):
395
+ struct_score += 2
396
+ elif struct_type == 'while' and any('hasNext' in str(inst) for inst in instances):
397
+ struct_score += 2
398
+
399
+ score += min(15, struct_score)
400
+ if struct_score > 0:
401
+ feedback.append(f"✓ Uso apropriado de estruturas de controle")
402
+
403
+ # 2. Manipulação de dados (15 pts)
404
+ data_score = 0
405
+ operations = list(tree.filter(javalang.tree.BinaryOperation))
406
+ if operations:
407
+ if any(op.operator in ['*', '/', '+', '-'] for op in operations):
408
+ data_score += 5
409
+ if any(op.operator in ['>', '<', '>=', '<=', '=='] for op in operations):
410
+ data_score += 5
411
+ if any('=' in str(op) for op in operations):
412
+ data_score += 5
413
+
414
+ score += min(15, data_score)
415
+ if data_score > 0:
416
+ feedback.append("✓ Manipulação de dados adequada")
417
+
418
+ # 3. Clareza e organização (10 pts)
419
+ org_score = 0
420
+ if all(len(decl.declarators[0].name) > 1 for _, decl in tree.filter(javalang.tree.LocalVariableDeclaration)):
421
+ org_score += 5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
422
 
 
423
  lines = code.split('\n')
424
  if any('//' in line or '/*' in line for line in lines):
425
+ org_score += 5
 
426
 
427
+ score += min(10, org_score)
428
+ if org_score > 0:
429
+ feedback.append("✓ Código bem organizado e documentado")
430
+
431
+ # 4. Resolução do problema (10 pts)
432
+ if 'Scanner' in code and 'System.out' in code and operations:
433
+ score += 10
434
+ feedback.append("✓ Solução completa com entrada, processamento e saída")
435
+
436
+ # Determinar nível
437
+ if score >= 40:
438
+ level = "Excelente"
439
+ elif score >= 30:
440
+ level = "Bom"
441
+ elif score >= 20:
442
+ level = "Regular"
443
 
444
  except Exception as e:
445
  feedback.append(f"⚠ Erro na análise de competências: {str(e)}")
446
+
447
+ return score, level, feedback
448
 
449
  def evaluate_code(self, code: str) -> Dict:
450
+ """Avalia o código Java usando todos os critérios"""
451
+ evaluation = {
452
+ "scores": {},
453
+ "levels": {},
454
+ "feedback": {},
455
+ "summary": {
456
+ "total_score": 0,
457
+ "proficiency": ""
458
+ }
459
+ }
460
+
461
+ # Avaliar cada critério
462
+ criteria_evaluations = {
463
+ "syntax": self.evaluate_syntax(code),
464
+ "competencies": self.evaluate_competencies(code)
465
+ }
466
+
467
+ # Compilar resultados
468
+ for criterion, (score, level, feedback) in criteria_evaluations.items():
469
+ evaluation["scores"][criterion] = score
470
+ evaluation["levels"][criterion] = level
471
+ evaluation["feedback"][criterion] = feedback
472
+ evaluation["summary"]["total_score"] += score
473
+
474
+ # Determinar proficiência geral
475
+ total_score = evaluation["summary"]["total_score"]
476
  if total_score >= 90:
477
+ evaluation["summary"]["proficiency"] = "Excelente"
478
  elif total_score >= 75:
479
+ evaluation["summary"]["proficiency"] = "Bom"
480
  elif total_score >= 60:
481
+ evaluation["summary"]["proficiency"] = "Satisfatório"
482
+ else:
483
+ evaluation["summary"]["proficiency"] = "Necessita Melhorias"
 
 
 
 
 
 
 
484
 
485
+ return evaluation
 
 
 
486
 
487
+ # Interface Gradio
488
+ import gradio as gr
 
 
489
 
490
+ def process_java_files(files, evaluation_type: str) -> str:
491
+ """Avalia arquivos Java usando o avaliador especificado"""
492
  results = []
493
+
 
494
  try:
495
+ # Criar avaliador apropriado
496
+ if evaluation_type == "structural":
497
+ evaluator = EnhancedJavaStructuralEvaluator()
498
+ else:
499
+ evaluator = EnhancedCompetencyEvaluator()
500
+
501
+ # Processar cada arquivo
502
  for file in files:
503
  with open(file.name, 'r', encoding='utf-8') as f:
504
+ code = f.read()
505
+
506
+ # Avaliar código
507
+ evaluation = evaluator.evaluate_code(code)
508
+
509
+ # Formatar resultado
510
+ result = f"\n{'='*50}\n"
511
+ result += f"Avaliação do arquivo: {file.name}\n"
512
+ result += f"{'='*50}\n\n"
513
+
514
+ # Pontuação e nível
515
+ result += f"Pontuação Total: {evaluation['summary']['total_score']:.1f}/100\n"
516
+ result += f"Nível de Proficiência: {evaluation['summary']['proficiency']}\n\n"
517
+
518
+ # Detalhamento por critério
519
+ result += "Avaliação Detalhada por Critério:\n"
520
+ result += "-" * 30 + "\n\n"
521
+
522
+ for criterion in evaluation["scores"].keys():
523
+ result += f"• {criterion.title()}:\n"
524
+ result += f" Nível: {evaluation['levels'][criterion]}\n"
525
+ result += f" Pontuação: {evaluation['scores'][criterion]:.1f}\n"
526
+ result += " Feedback:\n"
527
+ for fb in evaluation['feedback'][criterion]:
528
+ result += f" - {fb}\n"
529
+ result += "\n"
530
+
 
 
 
 
 
 
 
 
 
 
 
531
  results.append(result)
532
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
533
  return "\n".join(results)
 
534
  except Exception as e:
535
+ return f"Erro ao processar arquivos: {str(e)}"
536
 
537
  # Interface Gradio com abas
538
+ with gr.Blocks(title="Avaliador de Código Java") as demo:
539
  gr.Markdown("""
540
+ # Avaliador de Código Java
541
 
542
+ Este avaliador analisa código Java usando duas perspectivas diferentes:
543
+ 1. **Avaliação Estrutural**: Foca nos elementos fundamentais da linguagem
544
+ 2. **Avaliação por Competências**: Analisa a qualidade técnica e boas práticas
 
 
545
  """)
546
+
547
  with gr.Tabs():
548
  with gr.Tab("Avaliação Estrutural"):
549
  upload_structural = gr.File(
550
  file_count="multiple",
551
+ label="Upload dos arquivos Java",
552
+ file_types=[".java"]
553
  )
554
  evaluate_btn_structural = gr.Button("Avaliar Estruturas")
555
  output_structural = gr.Textbox(
 
557
  lines=25
558
  )
559
  evaluate_btn_structural.click(
560
+ fn=lambda x: process_java_files(x, "structural"),
561
  inputs=upload_structural,
562
  outputs=output_structural
563
  )
564
+
565
  with gr.Tab("Avaliação por Competências"):
566
  upload_competency = gr.File(
567
  file_count="multiple",
568
+ label="Upload dos arquivos Java",
569
+ file_types=[".java"]
570
  )
571
  evaluate_btn_competency = gr.Button("Avaliar Competências")
572
  output_competency = gr.Textbox(
 
574
  lines=25
575
  )
576
  evaluate_btn_competency.click(
577
+ fn=lambda x: process_java_files(x, "competency"),
578
  inputs=upload_competency,
579
  outputs=output_competency
580
  )
581
 
582
  if __name__ == "__main__":
583
+ demo.launch(debug=True)
assets/rubric.pdf ADDED
Binary file (120 kB). View file
 
assets/rubric_table.PNG ADDED
rubric.pdf DELETED
Binary file (170 kB)
 
rubric_table.png DELETED
Binary file (125 kB)