rmayormartins's picture
go11
5b7d571
raw
history blame
23.4 kB
import javalang
from typing import Dict, List, Tuple
from dataclasses import dataclass
import re
@dataclass
class RubricCriterion:
name: str
description: str
weight: int
is_essential: bool
levels: Dict[str, Dict[str, float]]
class EnhancedJavaStructuralEvaluator:
"""Avaliador baseado em estruturas usadas"""
def __init__(self):
self.rubric = {
"declarations": RubricCriterion(
name="Declarações",
description="Uso de tipos e declarações",
weight=25,
is_essential=True,
levels={
"Fraco": {"threshold": 0, "description": "Uso mínimo/incorreto"},
"Regular": {"threshold": 10, "description": "1-2 tipos primitivos, 1-2 variáveis"},
"Bom": {"threshold": 15, "description": "3 tipos primitivos, 3-4 variáveis"},
"Excelente": {"threshold": 20, "description": "≥4 tipos primitivos, ≥5 variáveis"}
}
),
"control_structures": RubricCriterion(
name="Estruturas de Controle",
description="Controle de fluxo do programa",
weight=25,
is_essential=True,
levels={
"Fraco": {"threshold": 0, "description": "Uso mínimo/incorreto"},
"Regular": {"threshold": 10, "description": "1 tipo, uso básico"},
"Bom": {"threshold": 15, "description": "2 tipos diferentes, uso correto"},
"Excelente": {"threshold": 20, "description": "≥3 tipos diferentes, uso apropriado"}
}
),
"operators": RubricCriterion(
name="Operadores",
description="Operações e expressões",
weight=25,
is_essential=True,
levels={
"Fraco": {"threshold": 0, "description": "Uso mínimo/incorreto"},
"Regular": {"threshold": 10, "description": "1-2 operadores"},
"Bom": {"threshold": 15, "description": "3-4 operadores"},
"Excelente": {"threshold": 20, "description": "≥5 operadores diferentes"}
}
),
"io_strings": RubricCriterion(
name="I/O e Strings",
description="Entrada/saída e manipulação de texto",
weight=25,
is_essential=True,
levels={
"Fraco": {"threshold": 0, "description": "Uso mínimo/incorreto"},
"Regular": {"threshold": 10, "description": "E/S simples"},
"Bom": {"threshold": 15, "description": "E/S moderada, manipulação básica"},
"Excelente": {"threshold": 20, "description": "E/S complexa, manipulação avançada"}
}
)
}
def evaluate_declarations(self, code: str) -> Tuple[float, str, List[str]]:
"""Avalia declarações e tipos"""
score = 0
level = "Fraco"
feedback = []
try:
tree = javalang.parse.parse(code)
# Análise de tipos primitivos
primitives = {
'int': 'números inteiros',
'double': 'números decimais',
'boolean': 'valores lógicos',
'char': 'caracteres',
'float': 'números decimais (float)',
'long': 'números longos',
'byte': 'valores byte',
'short': 'números curtos'
}
used_types = set()
declarations = [node for _, node in tree.filter(javalang.tree.LocalVariableDeclaration)]
for decl in declarations:
type_name = decl.type.name
used_types.add(type_name)
num_types = len(used_types)
num_vars = len(declarations)
has_constants = any('final' in node.modifiers for _, node in tree.filter(javalang.tree.FieldDeclaration))
# Determinar nível
if num_types >= 4 and num_vars >= 5 and has_constants:
score = 25
level = "Excelente"
elif num_types >= 3 and num_vars >= 3:
score = 15
level = "Bom"
elif num_types >= 1 or num_vars >= 1:
score = 10
level = "Regular"
feedback.append(f"✓ {num_types} tipos primitivos diferentes utilizados")
feedback.append(f"✓ {num_vars} variáveis declaradas")
if has_constants:
feedback.append("✓ Uso adequado de constantes (final)")
except Exception as e:
feedback.append("⚠ Erro na análise de declarações")
return score, level, feedback
def evaluate_control_structures(self, code: str) -> Tuple[float, str, List[str]]:
"""Avalia estruturas de controle"""
score = 0
level = "Fraco"
feedback = []
try:
tree = javalang.parse.parse(code)
structures = {
'if': len(list(tree.filter(javalang.tree.IfStatement))),
'switch': len(list(tree.filter(javalang.tree.SwitchStatement))),
'for': len(list(tree.filter(javalang.tree.ForStatement))),
'while': len(list(tree.filter(javalang.tree.WhileStatement))),
'do_while': len(list(tree.filter(javalang.tree.DoStatement)))
}
num_different_structures = sum(1 for count in structures.values() if count > 0)
total_structures = sum(structures.values())
# Determinar nível
if num_different_structures >= 3 and total_structures >= 4:
score = 25
level = "Excelente"
elif num_different_structures >= 2 and total_structures >= 2:
score = 15
level = "Bom"
elif num_different_structures >= 1:
score = 10
level = "Regular"
for struct, count in structures.items():
if count > 0:
feedback.append(f"✓ {count} estrutura(s) {struct}")
except Exception as e:
feedback.append("⚠ Erro na análise de estruturas de controle")
return score, level, feedback
def evaluate_operators(self, code: str) -> Tuple[float, str, List[str]]:
"""Avalia operadores"""
score = 0
level = "Fraco"
feedback = []
try:
operators = {
'arithmetic': ['+', '-', '*', '/', '%'],
'comparison': ['==', '!=', '>', '<', '>=', '<='],
'logical': ['&&', '||', '!'],
'assignment': ['+=', '-=', '*=', '/=']
}
used_operators = set()
for category, ops in operators.items():
for op in ops:
if op in code:
used_operators.add(op)
feedback.append(f"✓ Uso do operador {op}")
num_operators = len(used_operators)
# Determinar nível
if num_operators >= 5:
score = 25
level = "Excelente"
elif num_operators >= 3:
score = 15
level = "Bom"
elif num_operators >= 1:
score = 10
level = "Regular"
except Exception as e:
feedback.append("⚠ Erro na análise de operadores")
return score, level, feedback
def evaluate_io_strings(self, code: str) -> Tuple[float, str, List[str]]:
"""Avalia entrada/saída e strings"""
score = 0
level = "Fraco"
feedback = []
try:
features = {
'output': 'System.out.print' in code,
'input': 'Scanner' in code,
'concatenation': '+' in code and '"' in code,
'string_methods': False
}
# Verificar métodos de String
string_methods = ['concat', 'substring', 'length', 'equals', 'compareTo']
methods_used = [method for method in string_methods if f'.{method}(' in code]
features['string_methods'] = len(methods_used) > 0
# Contar recursos utilizados
num_features = sum(1 for used in features.values() if used)
# Determinar nível
if num_features >= 3 and features['string_methods']:
score = 25
level = "Excelente"
elif num_features >= 2:
score = 15
level = "Bom"
elif num_features >= 1:
score = 10
level = "Regular"
if features['output']:
feedback.append("✓ Uso de saída (System.out)")
if features['input']:
feedback.append("✓ Uso de entrada (Scanner)")
if features['concatenation']:
feedback.append("✓ Concatenação de strings")
if methods_used:
feedback.append(f"✓ Uso de {len(methods_used)} métodos de String")
except Exception as e:
feedback.append("⚠ Erro na análise de I/O e strings")
return score, level, feedback
def evaluate_code(self, code: str) -> Dict:
"""Avalia o código Java usando todos os critérios"""
evaluation = {
"scores": {},
"levels": {},
"feedback": {},
"summary": {
"total_score": 0,
"proficiency": ""
}
}
# Avaliar cada critério
criteria_evaluations = {
"declarations": self.evaluate_declarations(code),
"control_structures": self.evaluate_control_structures(code),
"operators": self.evaluate_operators(code),
"io_strings": self.evaluate_io_strings(code)
}
# Compilar resultados
for criterion, (score, level, feedback) in criteria_evaluations.items():
evaluation["scores"][criterion] = score
evaluation["levels"][criterion] = level
evaluation["feedback"][criterion] = feedback
evaluation["summary"]["total_score"] += score
# Determinar proficiência geral
total_score = evaluation["summary"]["total_score"]
if total_score >= 90:
evaluation["summary"]["proficiency"] = "Excelente"
elif total_score >= 75:
evaluation["summary"]["proficiency"] = "Bom"
elif total_score >= 60:
evaluation["summary"]["proficiency"] = "Satisfatório"
else:
evaluation["summary"]["proficiency"] = "Necessita Melhorias"
return evaluation
class EnhancedCompetencyEvaluator:
"""Avaliador baseado em competências"""
def __init__(self):
self.rubric = {
"syntax": RubricCriterion(
name="Corretude Sintática",
description="Correção técnica do código",
weight=50,
is_essential=True,
levels={
"Fraco": {"threshold": 0, "description": "Muitos erros"},
"Regular": {"threshold": 20, "description": "Código funcional, alguns erros"},
"Bom": {"threshold": 30, "description": "Código correto, erros menores"},
"Excelente": {"threshold": 40, "description": "Código exemplar, sem erros"}
}
),
"competencies": RubricCriterion(
name="Competências Práticas",
description="Qualidade da implementação",
weight=50,
is_essential=True,
levels={
"Fraco": {"threshold": 0, "description": "Implementação pobre"},
"Regular": {"threshold": 20, "description": "Implementação básica"},
"Bom": {"threshold": 30, "description": "Boa implementação"},
"Excelente": {"threshold": 40, "description": "Implementação sofisticada"}
}
)
}
def evaluate_syntax(self, code: str) -> Tuple[float, str, List[str]]:
"""Avalia corretude sintática"""
score = 0
level = "Fraco"
feedback = []
try:
tree = javalang.parse.parse(code)
# 1. Estrutura básica (10 pts)
has_class = 'class' in code
has_main = 'public static void main' in code
if has_class and has_main:
score += 10
feedback.append("✓ Estrutura básica correta (classe e main)")
# 2. Declarações (10 pts)
declarations = list(tree.filter(javalang.tree.LocalVariableDeclaration))
if declarations:
score += 10
feedback.append(f"✓ {len(declarations)} declarações sintáticamente corretas")
# 3. Blocos e estruturas (10 pts)
if code.count('{') == code.count('}') and code.count('{') > 0:
score += 10
feedback.append("✓ Blocos corretamente delimitados")
# 4. Expressões (10 pts)
expressions = list(tree.filter(javalang.tree.BinaryOperation))
if expressions:
score += 10
feedback.append("✓ Expressões bem formadas")
# 5. Pontuação e formatação (10 pts)
lines = code.split('\n')
well_formatted = all(line.strip().endswith(';') or
line.strip().endswith('{') or
line.strip().endswith('}') or
line.strip() == "" or
line.strip().startswith('//')
for line in lines if line.strip())
if well_formatted:
score += 10
feedback.append("✓ Código bem formatado e pontuado")
# Determinar nível
if score >= 40:
level = "Excelente"
elif score >= 30:
level = "Bom"
elif score >= 20:
level = "Regular"
except Exception as e:
feedback.append(f"⚠ Erro de sintaxe: {str(e)}")
return score, level, feedback
def evaluate_competencies(self, code: str) -> Tuple[float, str, List[str]]:
"""Avalia competências práticas"""
score = 0
level = "Fraco"
feedback = []
try:
tree = javalang.parse.parse(code)
# 1. Seleção de estruturas (15 pts)
structures = {
'if': list(tree.filter(javalang.tree.IfStatement)),
'for': list(tree.filter(javalang.tree.ForStatement)),
'while': list(tree.filter(javalang.tree.WhileStatement))
}
struct_score = 0
for struct_type, instances in structures.items():
if instances:
struct_score += 5
if struct_type == 'for' and any('length' in str(inst) for inst in instances):
struct_score += 2
elif struct_type == 'while' and any('hasNext' in str(inst) for inst in instances):
struct_score += 2
score += min(15, struct_score)
if struct_score > 0:
feedback.append(f"✓ Uso apropriado de estruturas de controle")
# 2. Manipulação de dados (15 pts)
data_score = 0
operations = list(tree.filter(javalang.tree.BinaryOperation))
if operations:
if any(op.operator in ['*', '/', '+', '-'] for op in operations):
data_score += 5
if any(op.operator in ['>', '<', '>=', '<=', '=='] for op in operations):
data_score += 5
if any('=' in str(op) for op in operations):
data_score += 5
score += min(15, data_score)
if data_score > 0:
feedback.append("✓ Manipulação de dados adequada")
# 3. Clareza e organização (10 pts)
org_score = 0
if all(len(decl.declarators[0].name) > 1 for _, decl in tree.filter(javalang.tree.LocalVariableDeclaration)):
org_score += 5
lines = code.split('\n')
if any('//' in line or '/*' in line for line in lines):
org_score += 5
score += min(10, org_score)
if org_score > 0:
feedback.append("✓ Código bem organizado e documentado")
# 4. Resolução do problema (10 pts)
if 'Scanner' in code and 'System.out' in code and operations:
score += 10
feedback.append("✓ Solução completa com entrada, processamento e saída")
# Determinar nível
if score >= 40:
level = "Excelente"
elif score >= 30:
level = "Bom"
elif score >= 20:
level = "Regular"
except Exception as e:
feedback.append(f"⚠ Erro na análise de competências: {str(e)}")
return score, level, feedback
def evaluate_code(self, code: str) -> Dict:
"""Avalia o código Java usando todos os critérios"""
evaluation = {
"scores": {},
"levels": {},
"feedback": {},
"summary": {
"total_score": 0,
"proficiency": ""
}
}
# Avaliar cada critério
criteria_evaluations = {
"syntax": self.evaluate_syntax(code),
"competencies": self.evaluate_competencies(code)
}
# Compilar resultados
for criterion, (score, level, feedback) in criteria_evaluations.items():
evaluation["scores"][criterion] = score
evaluation["levels"][criterion] = level
evaluation["feedback"][criterion] = feedback
evaluation["summary"]["total_score"] += score
# Determinar proficiência geral
total_score = evaluation["summary"]["total_score"]
if total_score >= 90:
evaluation["summary"]["proficiency"] = "Excelente"
elif total_score >= 75:
evaluation["summary"]["proficiency"] = "Bom"
elif total_score >= 60:
evaluation["summary"]["proficiency"] = "Satisfatório"
else:
evaluation["summary"]["proficiency"] = "Necessita Melhorias"
return evaluation
# Interface Gradio
import gradio as gr
def process_java_files(files, evaluation_type: str) -> str:
"""Avalia arquivos Java usando o avaliador especificado"""
results = []
try:
# Criar avaliador apropriado
if evaluation_type == "structural":
evaluator = EnhancedJavaStructuralEvaluator()
else:
evaluator = EnhancedCompetencyEvaluator()
# Processar cada arquivo
for file in files:
with open(file.name, 'r', encoding='utf-8') as f:
code = f.read()
# Avaliar código
evaluation = evaluator.evaluate_code(code)
# Formatar resultado
result = f"\n{'='*50}\n"
result += f"Avaliação do arquivo: {file.name}\n"
result += f"{'='*50}\n\n"
# Pontuação e nível
result += f"Pontuação Total: {evaluation['summary']['total_score']:.1f}/100\n"
result += f"Nível de Proficiência: {evaluation['summary']['proficiency']}\n\n"
# Detalhamento por critério
result += "Avaliação Detalhada por Critério:\n"
result += "-" * 30 + "\n\n"
for criterion in evaluation["scores"].keys():
result += f"• {criterion.title()}:\n"
result += f" Nível: {evaluation['levels'][criterion]}\n"
result += f" Pontuação: {evaluation['scores'][criterion]:.1f}\n"
result += " Feedback:\n"
for fb in evaluation['feedback'][criterion]:
result += f" - {fb}\n"
result += "\n"
results.append(result)
return "\n".join(results)
except Exception as e:
return f"Erro ao processar arquivos: {str(e)}"
# Interface Gradio com abas
with gr.Blocks(title="Java-Judge: Avaliador de Sintaxe e Competencia Java") as demo:
gr.Markdown("# Java-Judge: Avaliador de Sintaxe e Competencia Java")
#
gr.HTML("""
<p>Java-Judge: Avaliador de Sintaxe e Competências em Java</p>
<p>Ramon Mayor Martins: <a href="https://rmayormartins.github.io/" target="_blank">Website</a> |
<a href="https://huggingface.co/rmayormartins" target="_blank">Spaces</a></p>
""")
gr.Markdown("""
Este avaliador analisa código Java em relação aos princípios de Programação Orientada a Objetos.
Critérios avaliados:
""")
#
gr.HTML("""
<p>
<a href="https://huggingface.co/spaces/rmayormartins/java-judge-syntax-competencies/blob/main/assets/rubric.pdf" target="_blank">📄 Visualizar Rubrica PDF</a>
</p>
<p>
<a href="https://huggingface.co/spaces/rmayormartins/java-judge-syntax-competencies/blob/main/assets/rubric_table.PNG" target="_blank">📊 Visualizar Tabela da Rubrica</a>
</p>
""")
gr.Markdown("""
# Avaliador de Código Java
Este avaliador analisa código Java usando duas perspectivas diferentes:
1. **Avaliação Estrutural**: Foca nos elementos fundamentais da linguagem
2. **Avaliação por Competências**: Analisa a qualidade técnica e boas práticas
""")
with gr.Tabs():
with gr.Tab("Avaliação Estrutural"):
upload_structural = gr.File(
file_count="multiple",
label="Upload dos arquivos Java",
file_types=[".java"]
)
evaluate_btn_structural = gr.Button("Avaliar Estruturas")
output_structural = gr.Textbox(
label="Resultado da Avaliação",
lines=25
)
evaluate_btn_structural.click(
fn=lambda x: process_java_files(x, "structural"),
inputs=upload_structural,
outputs=output_structural
)
with gr.Tab("Avaliação por Competências"):
upload_competency = gr.File(
file_count="multiple",
label="Upload dos arquivos Java",
file_types=[".java"]
)
evaluate_btn_competency = gr.Button("Avaliar Competências")
output_competency = gr.Textbox(
label="Resultado da Avaliação",
lines=25
)
evaluate_btn_competency.click(
fn=lambda x: process_java_files(x, "competency"),
inputs=upload_competency,
outputs=output_competency
)
if __name__ == "__main__":
demo.launch(debug=True)