From 7a3169bc4e5c5e8ac6e9d345e390f8cb4fe92b16 Mon Sep 17 00:00:00 2001 From: ZaionLuz Date: Fri, 12 Jun 2026 23:43:01 -0300 Subject: [PATCH 1/2] Finalizei Guia 4 mas ainda nao testei -Zaion --- Guia4/src/alternativa.py | 5 +++- Guia4/src/pergunta.py | 18 +++++++++++-- Guia4/src/perguntadiscursiva.py | 20 +++++++++++++-- Guia4/src/perguntamultiplaescolha.py | 21 +++++++++++++-- Guia4/src/questionario.py | 12 ++++++++- Guia4/src/resposta.py | 12 +++++++-- Guia4/src/respostadiscursiva.py | 12 +++++++-- Guia4/src/respostaobjetiva.py | 13 ++++++++-- Guia4/src/tentativaquestionario.py | 38 +++++++++++++++++++++++++++- 9 files changed, 136 insertions(+), 15 deletions(-) diff --git a/Guia4/src/alternativa.py b/Guia4/src/alternativa.py index 4dde61f..cdae2b5 100644 --- a/Guia4/src/alternativa.py +++ b/Guia4/src/alternativa.py @@ -1,4 +1,7 @@ from typing import List, Tuple, Dict class Alternativa: - pass \ No newline at end of file + def __init__(self, texto: str, correta: bool, explicacao: str = None): + self.texto = texto + self.correta = correta + self.explicacao = explicacao \ No newline at end of file diff --git a/Guia4/src/pergunta.py b/Guia4/src/pergunta.py index 5b3763d..9adaf46 100644 --- a/Guia4/src/pergunta.py +++ b/Guia4/src/pergunta.py @@ -1,4 +1,18 @@ from typing import List, Tuple, Dict +from abc import ABC, abstractmethod -class Pergunta: - pass \ No newline at end of file +class Pergunta(ABC): + def __init__(self, texto: str, explicacao_geral: str = None): + self.texto = texto + self.explicacao_geral = explicacao_geral + + @abstractmethod + def validar_resposta(self, resposta): + pass + + def get_explicacao(self): + return self.explicacao_geral + + @abstractmethod + def get_tipo(self): + pass \ No newline at end of file diff --git a/Guia4/src/perguntadiscursiva.py b/Guia4/src/perguntadiscursiva.py index f4c26af..be10e1e 100644 --- a/Guia4/src/perguntadiscursiva.py +++ b/Guia4/src/perguntadiscursiva.py @@ -1,4 +1,20 @@ from typing import List, Tuple, Dict +from .pergunta import Pergunta -class PerguntaDiscursiva: - pass \ No newline at end of file +class PerguntaDiscursiva(Pergunta): + def __init__(self, texto: str, resposta_esperada: str = None, case_sensitive: bool = False, explicacao_geral: str = None): + super().__init__(texto, explicacao_geral) + self.resposta_esperada = resposta_esperada + self.case_sensitive = case_sensitive + + def validar_resposta(self, texto: str) -> bool: + if self.resposta_esperada is None: + return False + + if self.case_sensitive: + return texto == self.resposta_esperada + + return texto.strip().lower() == self.resposta_esperada.strip().lower() + + def get_tipo(self): + return "discursiva" \ No newline at end of file diff --git a/Guia4/src/perguntamultiplaescolha.py b/Guia4/src/perguntamultiplaescolha.py index bcbe94d..715fb61 100644 --- a/Guia4/src/perguntamultiplaescolha.py +++ b/Guia4/src/perguntamultiplaescolha.py @@ -1,4 +1,21 @@ from typing import List, Tuple, Dict +from .pergunta import Pergunta -class PerguntaMultiplaEscolha: - pass \ No newline at end of file +class PerguntaMultiplaEscolha(Pergunta): + def __init__(self, texto: str, alternativas: list, explicacao_geral: str = None): + super().__init__(texto, explicacao_geral) + self.alternativas = alternativas + + def validar_resposta(self, indice: int) -> bool: + if indice < 0 or indice >= len(self.alternativas): + return False + return self.alternativas[indice].correta + + def get_alternativa_correta(self): + for alt in self.alternativas: + if alt.correta: + return alt + return None + + def get_tipo(self): + return "multipla_escolha" \ No newline at end of file diff --git a/Guia4/src/questionario.py b/Guia4/src/questionario.py index 7525582..d6da30c 100644 --- a/Guia4/src/questionario.py +++ b/Guia4/src/questionario.py @@ -1,4 +1,14 @@ from typing import List, Tuple, Dict +from .tentativaquestionario import TentativaQuestionario + class Questionario: - pass + def __init__(self, titulo: str, perguntas=None): + self.titulo = titulo + self.perguntas = perguntas if perguntas else [] + + def adicionar_pergunta(self, pergunta): + self.perguntas.append(pergunta) + + def criar_attempt(self, usuario: str): + return TentativaQuestionario(self, usuario) diff --git a/Guia4/src/resposta.py b/Guia4/src/resposta.py index 846d771..5a8f707 100644 --- a/Guia4/src/resposta.py +++ b/Guia4/src/resposta.py @@ -1,4 +1,12 @@ from typing import List, Tuple, Dict +from abc import ABC, abstractmethod -class Resposta: - pass \ No newline at end of file +class Resposta(ABC): + def __init__(self, pergunta): + self.pergunta = pergunta + self.esta_correta = False + self.pontuacao_obtida = 0.0 + + @abstractmethod + def calcular_pontuacao(self) -> float: + pass \ No newline at end of file diff --git a/Guia4/src/respostadiscursiva.py b/Guia4/src/respostadiscursiva.py index 4ea6dbb..9e15dac 100644 --- a/Guia4/src/respostadiscursiva.py +++ b/Guia4/src/respostadiscursiva.py @@ -1,4 +1,12 @@ from typing import List, Tuple, Dict +from .resposta import Resposta -class RespostaDiscursiva: - pass \ No newline at end of file +class RespostaDiscursiva(Resposta): + def __init__(self, pergunta, texto_resposta: str): + super().__init__(pergunta) + self.texto_resposta = texto_resposta + self.esta_correta = bool(self.pergunta.validar_resposta(self.texto_resposta)) + self.pontuacao_obtida = 1.0 if self.esta_correta else 0.0 + + def calcular_pontuacao(self) -> float: + return self.pontuacao_obtida \ No newline at end of file diff --git a/Guia4/src/respostaobjetiva.py b/Guia4/src/respostaobjetiva.py index 72ed2d0..e0d4426 100644 --- a/Guia4/src/respostaobjetiva.py +++ b/Guia4/src/respostaobjetiva.py @@ -1,4 +1,13 @@ from typing import List, Tuple, Dict +from .resposta import Resposta -class RespostaObjetiva: - pass \ No newline at end of file +class RespostaObjetiva(Resposta): + def __init__(self, pergunta, indice_escolhido: int): + super().__init__(pergunta) + self.indice_escolhido = indice_escolhido + self.alternativa_selecionada = None + self.esta_correta = self.pergunta.validar_resposta(self.indice_escolhido) + self.pontuacao_obtida = 1.0 if self.esta_correta else 0.0 + + def calcular_pontuacao(self) -> float: + return self.pontuacao_obtida \ No newline at end of file diff --git a/Guia4/src/tentativaquestionario.py b/Guia4/src/tentativaquestionario.py index 9947dd1..f01da3a 100644 --- a/Guia4/src/tentativaquestionario.py +++ b/Guia4/src/tentativaquestionario.py @@ -1,4 +1,40 @@ from typing import List, Tuple, Dict +from datetime import datetime +from .respostaobjetiva import RespostaObjetiva +from .respostadiscursiva import RespostaDiscursiva class TentativaQuestionario: - pass \ No newline at end of file + def __init__(self, questionario, usuario: str): + self.questionario = questionario + self.usuario = usuario + self.data_inicio = datetime.now() + self.data_fim = None + self.respostas = [] + self._finalizado = False + + def registrar_resposta(self, indice_pergunta: int, valor): + if self._finalizado: + return + + pergunta = self.questionario.perguntas[indice_pergunta] + + if hasattr(pergunta, "alternativas"): + resposta = RespostaObjetiva(pergunta, int(valor)) + else: + resposta = RespostaDiscursiva(pergunta, str(valor)) + + resposta.calcular_pontuacao() + self.respostas.append(resposta) + + def calcular_pontuacao(self): + return sum(r.pontuacao_obtida for r in self.respostas) + + def finalizar(self): + self.data_fim = datetime.now() + self._finalizado = True + pontuacao = self.calcular_pontuacao() + feedback = f"Usuário {self.usuario} fez {pontuacao} pontos" + return pontuacao, feedback + + def is_finalizado(self): + return self._finalizado \ No newline at end of file From 81cfab3c7107c29a84b22a7f2c0d624a27bbf771 Mon Sep 17 00:00:00 2001 From: ZaionLuz Date: Fri, 12 Jun 2026 23:49:13 -0300 Subject: [PATCH 2/2] Esqueci de adicionar correcao e llmservice --- Guia4/src/correcao.py | 29 ++++++++++++++- Guia4/src/llmservice.py | 82 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/Guia4/src/correcao.py b/Guia4/src/correcao.py index bdf2fa4..397813e 100644 --- a/Guia4/src/correcao.py +++ b/Guia4/src/correcao.py @@ -1,4 +1,31 @@ from typing import List, Tuple, Dict +from .perguntadiscursiva import PerguntaDiscursiva +from .llmservice import LLMService + + class Correcao: - pass \ No newline at end of file + + @staticmethod + def corrigir_discursiva( + pergunta: PerguntaDiscursiva, + resposta_aluno: str, + service: LLMService = None + ) -> Dict: + + if service is None: + service = LLMService() + + return service.corrigir_resposta(pergunta, resposta_aluno) + + @staticmethod + def criar_prompt_correcao( + pergunta: PerguntaDiscursiva, + resposta_aluno: str + ) -> str: + + return ( + f"Pergunta: {pergunta.texto} | " + f"Esperado: {pergunta.resposta_esperada} | " + f"Aluno: {resposta_aluno}" + ) \ No newline at end of file diff --git a/Guia4/src/llmservice.py b/Guia4/src/llmservice.py index e6e91b5..9a6168a 100644 --- a/Guia4/src/llmservice.py +++ b/Guia4/src/llmservice.py @@ -1,4 +1,84 @@ from typing import List, Tuple, Dict +import os +import json +from typing import Dict +from groq import Groq +from .perguntadiscursiva import PerguntaDiscursiva + + class LLMService: - pass \ No newline at end of file + def _init_(self, api_key: str = None, model: str = "llama3-70b-8192"): + self.api_key = api_key or os.getenv("GROQ_API_KEY") + + if model == "llama3-70b-8192": + self.model = "llama-3.3-70b-versatile" + else: + self.model = model + + self.base_url = "https://api.groq.com" + + self.client = Groq(api_key=self.api_key) if self.api_key else None + + def corrigir_resposta(self, pergunta: PerguntaDiscursiva, resposta_aluno: str) -> Dict: + prompt = f""" +Você é um professor avaliador rigoroso. + +Pergunta: {pergunta.texto} +Resposta Esperada: {pergunta.resposta_esperada} +Resposta do Aluno: {resposta_aluno} + +Responda APENAS JSON: +{{ + "correta": true, + "pontuacao": 0.0, + "feedback": "", + "explicacao": "" +}} +""" + + try: + resposta_texto = self._fazer_chamada_api(prompt) + return json.loads(resposta_texto) + + except Exception as e: + return self._tratar_erro(e, pergunta, resposta_aluno) + + def _fazer_chamada_api(self, prompt: str) -> str: + if not self.client: + raise ValueError("API Key do Groq não configurada.") + + chat_completion = self.client.chat.completions.create( + model=self.model, + temperature=0.1, + response_format={"type": "json_object"}, + messages=[ + { + "role": "system", + "content": "Você responde apenas JSON válido." + }, + { + "role": "user", + "content": prompt + } + ] + ) + + return chat_completion.choices[0].message.content + + def _tratar_erro(self, e: Exception, pergunta: PerguntaDiscursiva, resposta_aluno: str) -> Dict: + print(f"[LLMService Error]: {e}") + + resposta_esperada = pergunta.resposta_esperada or "" + + eh_correto = ( + str(resposta_aluno).strip().lower() + == str(resposta_esperada).strip().lower() + ) + + return { + "correta": eh_correto, + "pontuacao": 1.0 if eh_correto else 0.0, + "feedback": f"Fallback (erro API): {str(e)}", + "explicacao": pergunta.get_explicacao() or "Sem explicação" + } \ No newline at end of file