Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions Guia4/main.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,37 @@
from Guia3.src import *
import os
from src.perguntadiscursiva import PerguntaDiscursiva
from src.correcao import Correcao

def main():
pass
print("=== Iniciando Teste do Sistema de Quiz com LLM (Guia 4) ===")


if not os.environ.get("GROQ_API_KEY"):
print("\n⚠️ AVISO: A variável de ambiente GROQ_API_KEY não foi detectada.")
print("Defina-a no terminal antes de rodar: set GROQ_API_KEY=sua_chave\n")


pergunta = PerguntaDiscursiva()
pergunta.texto = "Explique o que é Encapsulamento em Programação Orientada a Objetos."
pergunta.resposta_esperada = "É o mecanismo que esconde os detalhes internos de uma classe e protege os dados usando modificadores de acesso (privado/protegido) e métodos getters/setters."


resposta_do_aluno = "Serve para esconder os dados do código lá dentro da classe usando private para ninguém mexer direto e usar métodos para acessar."

print(f"\nQuestão: {pergunta.texto}")
print(f"Resposta do Aluno: '{resposta_do_aluno}'")
print("\nEnviando para correção na API do Groq (Llama 3)... Aguarde...")

# 4. Executando a correção através da classe utilitária
resultado = Correcao.corrigir_discursiva(pergunta, resposta_do_aluno)

# 5. Exibindo o veredito da Inteligência Artificial
print("\n================ RESULTADO DA CORREÇÃO ================")
print(f"Acertou? : {resultado.get('correta')}")
print(f"Pontuação (0-1): {resultado.get('pontuacao')}")
print(f"Feedback : {resultado.get('feedback')}")
print(f"Explicação : {resultado.get('explicacao')}")
print("=======================================================")

if __name__ == "__main__":
main()
10 changes: 2 additions & 8 deletions Guia4/src/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
from .alternativa import Alternativa

from .pergunta import Pergunta
from .perguntadiscursiva import PerguntaDiscursiva
from .perguntamultiplaescolha import PerguntaMultiplaEscolha
from .questionario import Questionario
from .resposta import Resposta
from .respostadiscursiva import RespostaDiscursiva
from .respostaobjetiva import RespostaObjetiva
from .tentativaquestionario import TentativaQuestionario
from .perguntadiscursiva import PerguntaDiscursiva
7 changes: 4 additions & 3 deletions Guia4/src/alternativa.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import List, Tuple, Dict

class Alternativa:
pass
def __init__(self, texto: str, correta: bool, explicacao: str = None):
self.texto = texto
self.correta = correta
self.explicacao = explicacao
22 changes: 20 additions & 2 deletions Guia4/src/correcao.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
from typing import List, Tuple, Dict
from typing import Dict, Any, Optional
from src.perguntadiscursiva import PerguntaDiscursiva

class Correcao:
pass
@staticmethod
def criar_prompt_correcao(pergunta: PerguntaDiscursiva, resposta_aluno: str) -> str:
resposta_esperada = getattr(pergunta, "resposta_esperada", 'não informada')
return (
f"Enunciado da Questão: {pergunta.texto}\n"
f"Gabarito/Resposta Esperada: {resposta_esperada}\n"
f"Resposta submetida pelo Aluno: {resposta_aluno}\n\n"
f"Avalie se a resposta do aluno é conceitualmente equivalente ao gabarito. "
f"Determine a pontuação (de 0.0 a 1.0), se está correta (True/False) e gere um feedback estruturado."
)

@staticmethod
def corrigir_discursiva(pergunta: PerguntaDiscursiva, resposta_aluno: str, service=None) -> Dict[str, Any]:
if service is None:
from src.llmservice import LLMService
service = LLMService()

return service.corrigir_resposta(pergunta, resposta_aluno)
65 changes: 63 additions & 2 deletions Guia4/src/llmservice.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,65 @@
from typing import List, Tuple, Dict
import os
import json
from typing import Dict, Any
import requests

class LLMService:
pass
def __init__(self, api_key: str = None, model: str = "llama-3.3-70b-versatile"):

self.api_key = api_key or os.environ.get("GROQ_API_KEY", "")
self.model = model
self.base_url = "https://api.groq.com/openai/v1/chat/completions"

def corrigir_resposta(self, pergunta, resposta_aluno: str) -> Dict[str, Any]:

from src.correcao import Correcao
prompt = Correcao.criar_prompt_correcao(pergunta, resposta_aluno)

try:
return json.loads(self._fazer_chamada_api(prompt))
except Exception as e:

self._tratar_erro(e)
return {
"correta": False,
"pontuacao": 0.0,
"feedback": "Erro temporário na comunicação com o avaliador de IA.",
"explicacao": "A requisição falhou ou retornou um formato inválido."
}

def _fazer_chamada_api(self, prompt: str) -> str:
if not self.api_key:
raise ValueError("Chave de API GROQ_API_KEY não configurada no ambiente.")

headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
}

payload = {
"model": self.model,
"messages": [
{
"role": "system",
"content": "Você é um professor avaliador rigoroso. Você DEVE responder exclusivamente em formato JSON com as chaves: 'correta' (boolean), 'pontuacao' (float de 0.0 a 1.0), 'feedback' (string) e 'explicacao' (string)."
},
{
"role": "user",
"content": prompt
}
],
"response_format": {"type": "json_object"},
"temperature": 0.0
}

response = requests.post(self.base_url, headers=headers, json=payload, timeout=10)

if response.status_code != 200:
raise RuntimeError(f"Erro na API Groq ({response.status_code}): {response.text}")

dados = response.json()
return dados["choices"][0]["message"]["content"]

def _tratar_erro(self, e: Exception) -> None:

print(f"[LLMService Error]: {str(e)}")
8 changes: 5 additions & 3 deletions Guia4/src/pergunta.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from typing import List, Tuple, Dict
from abc import ABC, abstractmethod

class Pergunta:
pass
class Pergunta(ABC):
def __init__(self, texto: str, pontuacao: float = 0.0):
self.texto = texto
self.pontuacao = pontuacao
8 changes: 5 additions & 3 deletions Guia4/src/perguntadiscursiva.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from typing import List, Tuple, Dict
from src.pergunta import Pergunta

class PerguntaDiscursiva:
pass
class PerguntaDiscursiva(Pergunta):
def __init__(self, texto: str, pontuacao: float = 0.0, resposta_correta: str = ""):
super().__init__(texto, pontuacao)
self.resposta_correta = resposta_correta
53 changes: 50 additions & 3 deletions Guia4/src/perguntamultiplaescolha.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,51 @@
from typing import List, Tuple, Dict
from src.alternativa import Alternativa
from src.perguntamultiplaescolha import PerguntaMultiplaEscolha

class PerguntaMultiplaEscolha:
pass

def criar_pergunta():
alternativas = [
Alternativa("Java", False),
Alternativa("Python", True),
Alternativa("C", False),
]

return PerguntaMultiplaEscolha(
texto="Qual linguagem é interpretada?",
alternativas=alternativas,
explicacao_geral="Python normalmente é interpretada."
)


def test_validar_resposta_correta():
pergunta = criar_pergunta()

assert pergunta.validar_resposta(1) is True


def test_validar_resposta_errada():
pergunta = criar_pergunta()

assert pergunta.validar_resposta(0) is False


def test_get_alternativa_correta():
pergunta = criar_pergunta()

correta = pergunta.get_alternativa_correta()

assert correta.texto == "Python"
assert correta.correta is True


def test_get_tipo():
pergunta = criar_pergunta()

assert pergunta.get_tipo() == "multipla_escolha"


def test_get_explicacao():
pergunta = criar_pergunta()

assert pergunta.get_explicacao() == (
"Python normalmente é interpretada."
)
29 changes: 26 additions & 3 deletions Guia4/src/questionario.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
from typing import List, Tuple, Dict
import pytest

from src.questionario import Questionario
from src.perguntadiscursiva import PerguntaDiscursiva
from src.tentativaquestionario import TentativaQuestionario


def test_adicionar_pergunta():
questionario = Questionario("Quiz POO")

pergunta = PerguntaDiscursiva(
texto="O que é encapsulamento?"
)

questionario.adicionar_pergunta(pergunta)

assert len(questionario.perguntas) == 1


def test_criar_attempt():
questionario = Questionario("Quiz Redes")

tentativa = questionario.criar_attempt("valter")

assert isinstance(tentativa, TentativaQuestionario)
assert tentativa.usuario == "valter"

class Questionario:
pass
10 changes: 7 additions & 3 deletions Guia4/src/resposta.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from typing import List, Tuple, Dict
import pytest

class Resposta:
pass
from src.resposta import Resposta


def test_nao_instanciar_resposta_abstract():
with pytest.raises(TypeError):
Resposta(None)
44 changes: 41 additions & 3 deletions Guia4/src/respostadiscursiva.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,42 @@
from typing import List, Tuple, Dict
from src.perguntadiscursiva import PerguntaDiscursiva
from src.respostadiscursiva import RespostaDiscursiva

class RespostaDiscursiva:
pass

def criar_pergunta():
return PerguntaDiscursiva(
texto="O que significa CPU?",
resposta_esperada="Central Processing Unit"
)


def test_resposta_discursiva_correta():
pergunta = criar_pergunta()

resposta = RespostaDiscursiva(
pergunta=pergunta,
texto_resposta="Central Processing Unit"
)

assert resposta.esta_correta is True


def test_resposta_discursiva_errada():
pergunta = criar_pergunta()

resposta = RespostaDiscursiva(
pergunta=pergunta,
texto_resposta="Memória RAM"
)

assert resposta.esta_correta is False


def test_calcular_pontuacao():
pergunta = criar_pergunta()

resposta = RespostaDiscursiva(
pergunta=pergunta,
texto_resposta="Central Processing Unit"
)

assert resposta.calcular_pontuacao() == 1.0
Loading