import javalang from typing import Dict, List, Tuple from dataclasses import dataclass import gradio as gr @dataclass class RubricCriterion: name: str description: str weight: int is_essential: bool levels: Dict[str, Dict[str, float]] class EnhancedJavaPOOEvaluator: """Avaliador POO com rubrica detalhada""" def __init__(self): self.rubric = { "classes_objects": RubricCriterion( name="Classes e Objetos", description="Avalia a definição e uso de classes e objetos", weight=20, is_essential=True, levels={ "Fraco": {"threshold": 0, "description": "Nenhuma ou poucas classes/objetos"}, "Regular": {"threshold": 10, "description": "Classes básicas sem organização clara"}, "Bom": {"threshold": 15, "description": "Classes bem estruturadas e objetos adequados"}, "Excelente": {"threshold": 20, "description": "Excelente uso de classes e objetos"} } ), "methods": RubricCriterion( name="Métodos", description="Avalia métodos e sua organização", weight=20, is_essential=True, levels={ "Fraco": {"threshold": 0, "description": "Poucos métodos ou mal estruturados"}, "Regular": {"threshold": 10, "description": "Métodos básicos sem sobrecarga"}, "Bom": {"threshold": 15, "description": "Boa organização e alguns métodos sobrecarregados"}, "Excelente": {"threshold": 20, "description": "Excelente organização e uso de sobrecarga"} } ), "attributes": RubricCriterion( name="Atributos", description="Avalia atributos e sua organização", weight=20, is_essential=True, levels={ "Fraco": {"threshold": 0, "description": "Poucos atributos ou mal organizados"}, "Regular": {"threshold": 10, "description": "Atributos básicos sem encapsulamento"}, "Bom": {"threshold": 15, "description": "Boa organização de atributos"}, "Excelente": {"threshold": 20, "description": "Excelente organização e encapsulamento"} } ), "encapsulation": RubricCriterion( name="Encapsulamento", description="Avalia uso de modificadores e getters/setters", weight=10, is_essential=False, levels={ "Ausente": {"threshold": 0, "description": "Sem encapsulamento"}, "Parcial": {"threshold": 5, "description": "Encapsulamento básico"}, "Bom": {"threshold": 7.5, "description": "Bom uso de encapsulamento"}, "Excelente": {"threshold": 10, "description": "Encapsulamento completo e correto"} } ), "inheritance": RubricCriterion( name="Herança", description="Avalia uso de herança", weight=10, is_essential=False, levels={ "Ausente": {"threshold": 0, "description": "Sem uso de herança"}, "Parcial": {"threshold": 5, "description": "Uso básico de herança"}, "Bom": {"threshold": 7.5, "description": "Bom uso de herança"}, "Excelente": {"threshold": 10, "description": "Uso avançado e apropriado de herança"} } ), "polymorphism": RubricCriterion( name="Polimorfismo", description="Avalia uso de polimorfismo", weight=10, is_essential=False, levels={ "Ausente": {"threshold": 0, "description": "Sem uso de polimorfismo"}, "Parcial": {"threshold": 5, "description": "Uso básico de sobrescrita"}, "Bom": {"threshold": 7.5, "description": "Bom uso de polimorfismo"}, "Excelente": {"threshold": 10, "description": "Uso avançado de polimorfismo"} } ), "abstraction": RubricCriterion( name="Abstração", description="Avalia uso de abstrações", weight=10, is_essential=False, levels={ "Ausente": {"threshold": 0, "description": "Sem uso de abstração"}, "Parcial": {"threshold": 5, "description": "Uso básico de interfaces/classes abstratas"}, "Bom": {"threshold": 7.5, "description": "Bom uso de abstração"}, "Excelente": {"threshold": 10, "description": "Uso completo de abstrações"} } ) } def evaluate_criterion(self, criterion: RubricCriterion, analysis_result: Dict) -> Tuple[float, str, str]: """Avalia um critério específico baseado nos resultados da análise""" score = 0 level = list(criterion.levels.keys())[0] # Nível mais baixo por padrão feedback = [] if criterion.name == "Classes e Objetos": num_classes = len(analysis_result.get("classes", [])) num_objects = len(analysis_result.get("objects", [])) if num_classes >= 3 and num_objects >= 5: score = criterion.weight level = "Excelente" elif num_classes >= 2 and num_objects >= 3: score = criterion.weight * 0.75 level = "Bom" elif num_classes >= 1 and num_objects >= 1: score = criterion.weight * 0.5 level = "Regular" feedback.append(f"Encontradas {num_classes} classes e {num_objects} objetos") elif criterion.name == "Métodos": methods = analysis_result.get("methods", []) method_names = [m.name for m in methods] overloaded = len([name for name in method_names if method_names.count(name) > 1]) if len(methods) >= 5 and overloaded >= 2: score = criterion.weight level = "Excelente" elif len(methods) >= 3 and overloaded >= 1: score = criterion.weight * 0.75 level = "Bom" elif len(methods) >= 1: score = criterion.weight * 0.5 level = "Regular" feedback.append(f"Encontrados {len(methods)} métodos, sendo {overloaded} sobrecarregados") elif criterion.name == "Atributos": attributes = analysis_result.get("attributes", []) num_private = analysis_result["encapsulation"]["private_count"] if len(attributes) >= 5 and num_private >= 3: score = criterion.weight level = "Excelente" elif len(attributes) >= 3 and num_private >= 1: score = criterion.weight * 0.75 level = "Bom" elif len(attributes) >= 1: score = criterion.weight * 0.5 level = "Regular" feedback.append(f"Encontrados {len(attributes)} atributos, sendo {num_private} privados") elif criterion.name == "Encapsulamento": num_private = analysis_result["encapsulation"]["private_count"] num_getters_setters = analysis_result["encapsulation"]["getters_setters"] if num_private >= 3 and num_getters_setters >= 4: score = criterion.weight level = "Excelente" elif num_private >= 2 and num_getters_setters >= 3: score = criterion.weight * 0.75 level = "Bom" elif num_private >= 1 and num_getters_setters >= 2: score = criterion.weight * 0.5 level = "Parcial" feedback.append(f"Encontrados {num_private} atributos privados e {num_getters_setters} getters/setters") elif criterion.name == "Herança": subclasses = analysis_result["inheritance"]["subclasses"] if len(subclasses) >= 3: score = criterion.weight level = "Excelente" elif len(subclasses) >= 2: score = criterion.weight * 0.75 level = "Bom" elif len(subclasses) >= 1: score = criterion.weight * 0.5 level = "Parcial" feedback.append(f"Encontradas {len(subclasses)} classes que usam herança") elif criterion.name == "Polimorfismo": overridden = len(analysis_result["polymorphism"]["overridden_methods"]) if overridden >= 3: score = criterion.weight level = "Excelente" elif overridden >= 2: score = criterion.weight * 0.75 level = "Bom" elif overridden >= 1: score = criterion.weight * 0.5 level = "Parcial" feedback.append(f"Encontrados {overridden} métodos sobrescritos") elif criterion.name == "Abstração": abstract_classes = len(analysis_result["abstraction"]["abstract_classes"]) interfaces = len(analysis_result["abstraction"]["interfaces"]) if abstract_classes >= 1 and interfaces >= 1: score = criterion.weight level = "Excelente" elif abstract_classes >= 1 and interfaces >= 0: score = criterion.weight * 0.75 level = "Bom" elif abstract_classes >= 1 or interfaces >= 1: score = criterion.weight * 0.5 level = "Parcial" feedback.append(f"Encontradas {abstract_classes} classes abstratas e {interfaces} interfaces") return score, level, ". ".join(feedback) def analyze_code(self, code: str) -> Dict: """Analisa o código Java e retorna dados brutos""" analysis = { "classes": [], "objects": [], "methods": [], "attributes": [], "encapsulation": {"private_count": 0, "getters_setters": 0}, "inheritance": {"subclasses": []}, "polymorphism": {"overridden_methods": []}, "abstraction": {"abstract_classes": [], "interfaces": []} } try: tree = javalang.parse.parse(code) # Análise de classes e objetos analysis["classes"] = [node for _, node in tree.filter(javalang.tree.ClassDeclaration)] analysis["objects"] = [node for _, node in tree.filter(javalang.tree.VariableDeclarator) if isinstance(node.initializer, javalang.tree.ClassCreator)] # Análise de métodos analysis["methods"] = [node for _, node in tree.filter(javalang.tree.MethodDeclaration)] # Análise de atributos e encapsulamento fields = [node for _, node in tree.filter(javalang.tree.FieldDeclaration)] analysis["attributes"] = fields analysis["encapsulation"]["private_count"] = sum(1 for field in fields if "private" in field.modifiers) # Contagem de getters e setters methods = analysis["methods"] getters_setters = sum(1 for method in methods if method.name.startswith('get') or method.name.startswith('set')) analysis["encapsulation"]["getters_setters"] = getters_setters # Análise de herança analysis["inheritance"]["subclasses"] = [cls for cls in analysis["classes"] if cls.extends is not None] # Análise de polimorfismo analysis["polymorphism"]["overridden_methods"] = [method for method in methods if any(ann.name == "Override" for ann in (method.annotations or []))] # Análise de abstração analysis["abstraction"]["abstract_classes"] = [cls for cls in analysis["classes"] if "abstract" in cls.modifiers] analysis["abstraction"]["interfaces"] = [node for _, node in tree.filter(javalang.tree.InterfaceDeclaration)] except Exception as e: print(f"Erro na análise: {str(e)}") return analysis def evaluate_code(self, code: str) -> Dict: """Avalia o código Java usando a rubrica detalhada""" analysis = self.analyze_code(code) evaluation = { "scores": {}, "levels": {}, "feedback": {}, "summary": { "essential_score": 0, "bonus_score": 0, "total_score": 0 } } # Avalia cada critério for criterion_key, criterion in self.rubric.items(): score, level, feedback = self.evaluate_criterion(criterion, analysis) evaluation["scores"][criterion_key] = score evaluation["levels"][criterion_key] = level evaluation["feedback"][criterion_key] = feedback if criterion.is_essential: evaluation["summary"]["essential_score"] += score else: evaluation["summary"]["bonus_score"] += score evaluation["summary"]["total_score"] = min(100, evaluation["summary"]["essential_score"] + evaluation["summary"]["bonus_score"]) # Determina nível geral if evaluation["summary"]["total_score"] >= 90: evaluation["summary"]["proficiency"] = "Excelente" elif evaluation["summary"]["total_score"] >= 75: evaluation["summary"]["proficiency"] = "Bom" elif evaluation["summary"]["total_score"] >= 60: evaluation["summary"]["proficiency"] = "Satisfatório" else: evaluation["summary"]["proficiency"] = "Necessita Melhorias" return evaluation # Interface Gradio with gr.Blocks(title="Avaliador de POO em Java") as demo: gr.Markdown("# Avaliador de POO em Java") gr.Markdown(""" Este avaliador analisa código Java em relação aos princípios de Programação Orientada a Objetos. Critérios avaliados: """) # Links usando caminho completo do Hugging Face gr.HTML(f"""

📄 Visualizar Rubrica PDF

📊 Visualizar Tabela da Rubrica

""") upload = gr.File(label="Carregue arquivos Java para avaliação", file_types=[".java"], file_count="multiple") evaluate_button = gr.Button("Avaliar Código") output = gr.Textbox(label="Resultado da Avaliação", lines=25) def evaluate_code_files(files) -> str: """Função para avaliar múltiplos arquivos Java""" evaluator = EnhancedJavaPOOEvaluator() results = [] for file in files: with open(file.name, 'r', encoding='utf-8') as f: code = f.read() evaluation = evaluator.evaluate_code(code) # Formatar resultado por arquivo result = f"\n{'='*50}\nAvaliação do arquivo: {file.name}\n{'='*50}\n\n" # Pontuação e nível geral result += f"Pontuação Total: {evaluation['summary']['total_score']:.1f}/100\n" result += f"Nível de Proficiência: {evaluation['summary']['proficiency']}\n" result += f"Pontuação Essencial: {evaluation['summary']['essential_score']:.1f}/60\n" result += f"Pontuação Bônus: {evaluation['summary']['bonus_score']:.1f}/40\n\n" # Detalhamento por critério result += "Avaliação Detalhada por Critério:\n" result += "-" * 30 + "\n\n" for criterion_key, criterion in evaluator.rubric.items(): result += f"• {criterion.name}:\n" result += f" Nível: {evaluation['levels'][criterion_key]}\n" result += f" Pontuação: {evaluation['scores'][criterion_key]:.1f}/{criterion.weight}\n" if evaluation['feedback'][criterion_key]: result += f" Feedback: {evaluation['feedback'][criterion_key]}\n" result += "\n" results.append(result) return "\n".join(results) evaluate_button.click(fn=evaluate_code_files, inputs=upload, outputs=output) if __name__ == "__main__": demo.launch(debug=True)