diff --git a/Guia1/src/__pycache__/__init__.cpython-313.pyc b/Guia1/src/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..b41715e Binary files /dev/null and b/Guia1/src/__pycache__/__init__.cpython-313.pyc differ diff --git a/Guia1/src/__pycache__/main.cpython-313.pyc b/Guia1/src/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000..aeeb9fb Binary files /dev/null and b/Guia1/src/__pycache__/main.cpython-313.pyc differ diff --git a/Guia1/src/config/__pycache__/__init__.cpython-313.pyc b/Guia1/src/config/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..d0b4b84 Binary files /dev/null and b/Guia1/src/config/__pycache__/__init__.cpython-313.pyc differ diff --git a/Guia1/src/config/__pycache__/settings.cpython-313.pyc b/Guia1/src/config/__pycache__/settings.cpython-313.pyc new file mode 100644 index 0000000..f276473 Binary files /dev/null and b/Guia1/src/config/__pycache__/settings.cpython-313.pyc differ diff --git a/Guia1/src/models/__pycache__/__init__.cpython-313.pyc b/Guia1/src/models/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..678fa76 Binary files /dev/null and b/Guia1/src/models/__pycache__/__init__.cpython-313.pyc differ diff --git a/Guia1/src/models/__pycache__/record.cpython-313.pyc b/Guia1/src/models/__pycache__/record.cpython-313.pyc new file mode 100644 index 0000000..157ad2d Binary files /dev/null and b/Guia1/src/models/__pycache__/record.cpython-313.pyc differ diff --git a/Guia1/src/repositories/__pycache__/__init__.cpython-313.pyc b/Guia1/src/repositories/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..1d22921 Binary files /dev/null and b/Guia1/src/repositories/__pycache__/__init__.cpython-313.pyc differ diff --git a/Guia1/src/repositories/__pycache__/abstract_repository.cpython-313.pyc b/Guia1/src/repositories/__pycache__/abstract_repository.cpython-313.pyc new file mode 100644 index 0000000..bc6646b Binary files /dev/null and b/Guia1/src/repositories/__pycache__/abstract_repository.cpython-313.pyc differ diff --git a/Guia1/src/repositories/__pycache__/record_repository.cpython-313.pyc b/Guia1/src/repositories/__pycache__/record_repository.cpython-313.pyc new file mode 100644 index 0000000..83b0a73 Binary files /dev/null and b/Guia1/src/repositories/__pycache__/record_repository.cpython-313.pyc differ diff --git a/Guia1/src/repositories/record_repository.py b/Guia1/src/repositories/record_repository.py index bded279..bafe4ec 100644 --- a/Guia1/src/repositories/record_repository.py +++ b/Guia1/src/repositories/record_repository.py @@ -1,6 +1,7 @@ from src.repositories.abstract_repository import AbstractRepository from src.models.record import Record from src.utils.file_loader import FileLoader +from unidecode import unidecode class RecordRepository(AbstractRepository): @@ -10,15 +11,25 @@ def __init__(self, file_path: str): def load_all(self): data = FileLoader.load_csv(self._file_path) - self._records = [ - Record(int(row["id"]), row["name"], row["address"]) - for row in data - ] + for row in data: + try: + id = int(row['id']) + if row['name'].strip() == '' or row['address'].strip() == '' or id < 0: + raise ValueError() + else: + self._records.append(Record(id, row['name'], row['address'])) + except: + print(f"Registro inválido ignorado {row}") + return self._records def search(self, term: str): - term = term.lower() - return [ - r for r in self._records - if term in r.name.lower() or term in r.address.lower() - ] \ No newline at end of file + terms = unidecode(term).lower().split() + results = [] + + for r in self._records: + nome = unidecode(r.name).lower() + add = unidecode(r.address).lower() + if all(palavra in nome or palavra in add for palavra in terms): + results.append(r) + return results \ No newline at end of file diff --git a/Guia1/src/services/__pycache__/__init__.cpython-313.pyc b/Guia1/src/services/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..7e17034 Binary files /dev/null and b/Guia1/src/services/__pycache__/__init__.cpython-313.pyc differ diff --git a/Guia1/src/services/__pycache__/record_service.cpython-313.pyc b/Guia1/src/services/__pycache__/record_service.cpython-313.pyc new file mode 100644 index 0000000..aab02d5 Binary files /dev/null and b/Guia1/src/services/__pycache__/record_service.cpython-313.pyc differ diff --git a/Guia1/src/utils/__pycache__/__init__.cpython-313.pyc b/Guia1/src/utils/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..84bd6ee Binary files /dev/null and b/Guia1/src/utils/__pycache__/__init__.cpython-313.pyc differ diff --git a/Guia1/src/utils/__pycache__/file_loader.cpython-313.pyc b/Guia1/src/utils/__pycache__/file_loader.cpython-313.pyc new file mode 100644 index 0000000..d06aef0 Binary files /dev/null and b/Guia1/src/utils/__pycache__/file_loader.cpython-313.pyc differ diff --git a/Guia1/tests/__pycache__/__init__.cpython-313.pyc b/Guia1/tests/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..6400053 Binary files /dev/null and b/Guia1/tests/__pycache__/__init__.cpython-313.pyc differ diff --git a/Guia1/tests/__pycache__/test_runner.cpython-313-pytest-9.0.3.pyc b/Guia1/tests/__pycache__/test_runner.cpython-313-pytest-9.0.3.pyc new file mode 100644 index 0000000..6a14eba Binary files /dev/null and b/Guia1/tests/__pycache__/test_runner.cpython-313-pytest-9.0.3.pyc differ diff --git a/Guia1/tests/__pycache__/test_runner.cpython-313.pyc b/Guia1/tests/__pycache__/test_runner.cpython-313.pyc new file mode 100644 index 0000000..9d76f5e Binary files /dev/null and b/Guia1/tests/__pycache__/test_runner.cpython-313.pyc differ diff --git a/Guia1/tests/test_runner.py b/Guia1/tests/test_runner.py index f8004a8..005ea34 100644 --- a/Guia1/tests/test_runner.py +++ b/Guia1/tests/test_runner.py @@ -61,7 +61,7 @@ def test_search_multiple_terms(self): for r in results: text = (r.name + " " + r.address).lower() - if "joao" not in text or "rua" not in text or "a" not in text: + if "joão" not in text or "rua" not in text or "a" not in text: print("FALHA: Resultado incorreto na busca") return diff --git a/Guia2/src/__pycache__/__init__.cpython-313.pyc b/Guia2/src/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..13a46a2 Binary files /dev/null and b/Guia2/src/__pycache__/__init__.cpython-313.pyc differ diff --git a/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-313.pyc b/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..b23a162 Binary files /dev/null and b/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-313.pyc differ diff --git a/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-313.pyc b/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-313.pyc new file mode 100644 index 0000000..a39269b Binary files /dev/null and b/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-313.pyc differ diff --git a/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-313.pyc b/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-313.pyc new file mode 100644 index 0000000..456b628 Binary files /dev/null and b/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-313.pyc differ diff --git a/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-313.pyc b/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-313.pyc new file mode 100644 index 0000000..81b44c1 Binary files /dev/null and b/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-313.pyc differ diff --git a/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-313.pyc b/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-313.pyc new file mode 100644 index 0000000..6c90997 Binary files /dev/null and b/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-313.pyc differ diff --git a/Guia2/src/folha_pagamento/desenvolvedor.py b/Guia2/src/folha_pagamento/desenvolvedor.py index 5c5d3c9..8bb9801 100644 --- a/Guia2/src/folha_pagamento/desenvolvedor.py +++ b/Guia2/src/folha_pagamento/desenvolvedor.py @@ -2,5 +2,37 @@ # Desenvolva a classe Desenvolvedor aqui. -class Desenvolvedor: - pass \ No newline at end of file +class Desenvolvedor(Funcionario): + def __init__(self, nome, matricula, salario_base, linguagem, senioridade): + super().__init__(nome, matricula, salario_base) + if not linguagem: + raise ValueError("Sem valor") + if not senioridade: + raise ValueError("Sem valor") + self.linguagem = linguagem.strip() + self.senioridade = senioridade.strip() + + def calcular_bonus(self): + if self.senioridade == "junior": + return self.salario_base * 0.05 + elif self.senioridade == "pleno": + return self.salario_base * 0.1 + elif self.senioridade == "senior": + return self.salario_base * 0.15 + + def calcular_descontos(self): + return self.salario_base * 0.08 + + def calcular_adicionais(self): + if self.linguagem == "Python": + return 500 + elif self.linguagem == "Java": + return 400 + elif self.linguagem == "JavaScript": + return 350 + else: + return 200 + + + + \ No newline at end of file diff --git a/Guia2/src/folha_pagamento/estagiario.py b/Guia2/src/folha_pagamento/estagiario.py index d50a433..0e543c2 100644 --- a/Guia2/src/folha_pagamento/estagiario.py +++ b/Guia2/src/folha_pagamento/estagiario.py @@ -2,5 +2,26 @@ # Desenvolva a classe Estagiario aqui. -class Estagiario: - pass \ No newline at end of file +class Estagiario(Funcionario): + def __init__(self, nome, matricula, salario_base, curso, carga_horaria): + super().__init__(nome, matricula, salario_base) + if not curso: + raise ValueError("Sem valor") + if not carga_horaria or carga_horaria <= 0: + raise ValueError("Sem valor ou valor incorreto") + self.curso = curso + self.carga_horaria = carga_horaria + + def calcular_bonus(self): + return self.salario_base * 0.03 + + def calcular_descontos(self): + return self.salario_base * 0.02 + + def calcular_adicionais(self): + if self.carga_horaria <= 20: + return 150 + elif self.carga_horaria <= 30: + return 250 + elif self.carga_horaria <= 40: + return 350 \ No newline at end of file diff --git a/Guia2/src/folha_pagamento/gerente.py b/Guia2/src/folha_pagamento/gerente.py index 31819a1..af03325 100644 --- a/Guia2/src/folha_pagamento/gerente.py +++ b/Guia2/src/folha_pagamento/gerente.py @@ -2,5 +2,32 @@ # Desenvolva a classe Gerente aqui. -class Gerente: - pass \ No newline at end of file +class Gerente(Funcionario): + def __init__(self, nome, matricula, salario_base, setor, qtd_equipe): + super().__init__(nome, matricula, salario_base) + if not setor: + raise ValueError("Sem valor") + if not qtd_equipe or qtd_equipe <= 0: + raise ValueError("Sem valor ou valor incorreto") + self.setor = setor + self.qtd_equipe = qtd_equipe + + def calcular_bonus(self): + if self.qtd_equipe <= 5: + return self.salario_base * 0.1 + elif self.qtd_equipe > 5 and self.qtd_equipe <= 10: + return self.salario_base * 0.15 + elif self.qtd_equipe > 10: + return self.salario_base * 0.2 + + def calcular_descontos(self): + return self.salario_base * 0.12 + + def calcular_adicionais(self): + + if self.qtd_equipe > 10: + return 2000 + elif self.qtd_equipe > 5: + return 1000 + else: + return 500 diff --git a/Guia2/tests/__pycache__/__init__.cpython-313.pyc b/Guia2/tests/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..acdf758 Binary files /dev/null and b/Guia2/tests/__pycache__/__init__.cpython-313.pyc differ diff --git a/Guia2/tests/__pycache__/integrity.cpython-313.pyc b/Guia2/tests/__pycache__/integrity.cpython-313.pyc new file mode 100644 index 0000000..e833617 Binary files /dev/null and b/Guia2/tests/__pycache__/integrity.cpython-313.pyc differ diff --git a/Guia2/tests/__pycache__/test_desenvolvedor.cpython-313-pytest-9.0.3.pyc b/Guia2/tests/__pycache__/test_desenvolvedor.cpython-313-pytest-9.0.3.pyc new file mode 100644 index 0000000..3c88159 Binary files /dev/null and b/Guia2/tests/__pycache__/test_desenvolvedor.cpython-313-pytest-9.0.3.pyc differ diff --git a/Guia2/tests/__pycache__/test_estagiario.cpython-313-pytest-9.0.3.pyc b/Guia2/tests/__pycache__/test_estagiario.cpython-313-pytest-9.0.3.pyc new file mode 100644 index 0000000..a3a5d37 Binary files /dev/null and b/Guia2/tests/__pycache__/test_estagiario.cpython-313-pytest-9.0.3.pyc differ diff --git a/Guia2/tests/__pycache__/test_gerente.cpython-313-pytest-9.0.3.pyc b/Guia2/tests/__pycache__/test_gerente.cpython-313-pytest-9.0.3.pyc new file mode 100644 index 0000000..4a6b471 Binary files /dev/null and b/Guia2/tests/__pycache__/test_gerente.cpython-313-pytest-9.0.3.pyc differ diff --git a/Guia2/tests/integrity.py b/Guia2/tests/integrity.py index 6d3ebd9..0e2fbc5 100644 --- a/Guia2/tests/integrity.py +++ b/Guia2/tests/integrity.py @@ -1,3 +1,6 @@ + + + from pathlib import Path import hashlib diff --git a/Guia3/src/alternativa.py b/Guia3/src/alternativa.py index 4dde61f..f2caa32 100644 --- a/Guia3/src/alternativa.py +++ b/Guia3/src/alternativa.py @@ -1,4 +1,10 @@ from typing import List, Tuple, Dict class Alternativa: - pass \ No newline at end of file + def __init__(self, texto, correta, explicacao = None): + self.texto = texto + self.correta = correta + self.explicacao = explicacao + + def get_correta(self): + return self.correta \ No newline at end of file diff --git a/Guia3/src/pergunta.py b/Guia3/src/pergunta.py index 5b3763d..4f00f88 100644 --- a/Guia3/src/pergunta.py +++ b/Guia3/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, explicacao_geral=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/Guia3/src/perguntadiscursiva.py b/Guia3/src/perguntadiscursiva.py index f4c26af..ac82262 100644 --- a/Guia3/src/perguntadiscursiva.py +++ b/Guia3/src/perguntadiscursiva.py @@ -1,4 +1,17 @@ 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, resposta_esperada=None, case_sensitive=True): + super().__init__(texto) + self.resposta_esperada = resposta_esperada + self.case_sensitive = case_sensitive + + def validar_resposta(self, res): + if res == self.resposta_esperada: + return True + else: + return False + + def get_tipo(self): + return "discursiva" \ No newline at end of file diff --git a/Guia3/src/perguntamultiplaescolha.py b/Guia3/src/perguntamultiplaescolha.py index bcbe94d..a37ec0b 100644 --- a/Guia3/src/perguntamultiplaescolha.py +++ b/Guia3/src/perguntamultiplaescolha.py @@ -1,4 +1,23 @@ 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, alternativas, explicacao_geral=None): + super().__init__(texto, explicacao_geral) + self.alternativas = alternativas + + def validar_resposta(self, indice): + resposta = self.alternativas[indice] + return resposta.get_correta() + + def get_alternativa_correta(self): + for res in self.alternativas: + if res.get_correta() == True: + return res + + def get_tipo(self): + return "multipla_escolha" + + def get_explicacao(self): + return self.explicacao_geral + \ No newline at end of file diff --git a/Guia3/src/questionario.py b/Guia3/src/questionario.py index 7525582..b8abb92 100644 --- a/Guia3/src/questionario.py +++ b/Guia3/src/questionario.py @@ -1,4 +1,14 @@ from typing import List, Tuple, Dict +from .tentativaquestionario import TentativaQuestionario class Questionario: - pass + def __init__(self, titulo): + self.titulo = titulo + self.perguntas = [] + + def adicionar_pergunta(self, pergunta): + self.perguntas.append(pergunta) + + def criar_attempt(self, usuario): + return TentativaQuestionario(self, usuario) + diff --git a/Guia3/src/resposta.py b/Guia3/src/resposta.py index 846d771..f5add9a 100644 --- a/Guia3/src/resposta.py +++ b/Guia3/src/resposta.py @@ -1,4 +1,15 @@ 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 + + @property + @abstractmethod + def esta_correta(self): + pass + + @abstractmethod + def calcular_pontuacao(self): + pass \ No newline at end of file diff --git a/Guia3/src/respostadiscursiva.py b/Guia3/src/respostadiscursiva.py index 4ea6dbb..2939504 100644 --- a/Guia3/src/respostadiscursiva.py +++ b/Guia3/src/respostadiscursiva.py @@ -1,4 +1,14 @@ 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): + super().__init__(pergunta) + self.texto_resposta = texto_resposta + + @property + def esta_correta(self): + return self.pergunta.validar_resposta(self.texto_resposta) + + def calcular_pontuacao(self): + return 1.0 if self.esta_correta else 0.0 \ No newline at end of file diff --git a/Guia3/src/respostaobjetiva.py b/Guia3/src/respostaobjetiva.py index 72ed2d0..d96d7c1 100644 --- a/Guia3/src/respostaobjetiva.py +++ b/Guia3/src/respostaobjetiva.py @@ -1,4 +1,14 @@ 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): + super().__init__(pergunta) + self.indice_escolhido = indice_escolhido + + @property + def esta_correta(self): + return self.pergunta.validar_resposta(self.indice_escolhido) + + def calcular_pontuacao(self): + return 1.0 if self.esta_correta else 0.0 \ No newline at end of file diff --git a/Guia3/src/tentativaquestionario.py b/Guia3/src/tentativaquestionario.py index 9947dd1..bd752f2 100644 --- a/Guia3/src/tentativaquestionario.py +++ b/Guia3/src/tentativaquestionario.py @@ -1,4 +1,33 @@ -from typing import List, Tuple, Dict +from datetime import datetime +from .respostaobjetiva import RespostaObjetiva +from .respostadiscursiva import RespostaDiscursiva +from .perguntamultiplaescolha import PerguntaMultiplaEscolha +from .perguntadiscursiva import PerguntaDiscursiva class TentativaQuestionario: - pass \ No newline at end of file + def __init__(self, questionario, usuario): + self.questionario = questionario + self.usuario = usuario + self.data_inicio = datetime.now() + self.data_fim = None + self.respostas = [] + + def registrar_resposta(self, indice_pergunta, valor): + pergunta = self.questionario.perguntas[indice_pergunta] + if isinstance(pergunta, PerguntaMultiplaEscolha): + resposta = RespostaObjetiva(pergunta, valor) + else: + resposta = RespostaDiscursiva(pergunta, valor) + self.respostas.append(resposta) + + def calcular_pontuacao(self): + return sum(r.calcular_pontuacao() for r in self.respostas) + + def finalizar(self): + self.data_fim = datetime.now() + pontuacao = self.calcular_pontuacao() + feedback = f"Pontuação final: {pontuacao}" + return pontuacao, feedback + + def is_finalizado(self): + return self.data_fim is not None \ No newline at end of file diff --git a/Guia4.zip b/Guia4.zip new file mode 100644 index 0000000..41e2bd2 Binary files /dev/null and b/Guia4.zip differ diff --git a/Guia4/main.py b/Guia4/main.py index e9e667d..258a8f0 100644 --- a/Guia4/main.py +++ b/Guia4/main.py @@ -1,7 +1,76 @@ -from Guia3.src import * +from dotenv import load_dotenv +load_dotenv() + +from src.alternativa import Alternativa +from src.perguntamultiplaescolha import PerguntaMultiplaEscolha +from src.perguntadiscursiva import PerguntaDiscursiva +from src.questionario import Questionario +from src.correcao import Correcao + def main(): - pass + # 1. Criar o questionário (quiz) + quiz = Questionario("Quiz de Programação") + + # 2. Pergunta de múltipla escolha + p1 = PerguntaMultiplaEscolha( + texto="Qual linguagem é interpretada?", + alternativas=[ + Alternativa("Java", False), + Alternativa("Python", True, explicacao="Python é interpretada por padrão."), + Alternativa("C", False), + ], + explicacao_geral="Python normalmente é interpretada." + ) + quiz.adicionar_pergunta(p1) + + # 3. Pergunta discursiva + p2 = PerguntaDiscursiva( + texto="O que significa CPU?", + resposta_esperada="Central Processing Unit" + ) + quiz.adicionar_pergunta(p2) + + print(f"Quiz criado: '{quiz.titulo}' com {len(quiz.perguntas)} perguntas.\n") + + # 4. Criar tentativa + tentativa = quiz.criar_attempt("valter") + print(f"Tentativa criada para usuário: {tentativa.usuario}") + print(f"Finalizada? {tentativa.is_finalizado()}\n") + + # 5. Registrar respostas + print("--- Registrando respostas ---") + tentativa.registrar_resposta(0, 1) # "Python" -> correta + tentativa.registrar_resposta(1, "Central Processing Unit") # discursiva correta + + print(f"Total de respostas registradas: {len(tentativa.respostas)}\n") + + # 6. Pontuação parcial + print(f"Pontuação atual: {tentativa.calcular_pontuacao()}\n") + + # 7. Finalizar + pontuacao, feedback = tentativa.finalizar() + print("--- Resultado Final ---") + print(f"Pontuação: {pontuacao}") + print(f"Feedback: {feedback}") + print(f"Finalizada? {tentativa.is_finalizado()}\n") + + # 8. Correção discursiva via LLM (Groq) + print("--- Teste de Correção Discursiva via LLM ---") + pergunta_discursiva = PerguntaDiscursiva( + texto="O que é encapsulamento em POO?", + resposta_esperada="É o princípio que esconde os detalhes internos de um objeto, " + "expondo apenas o necessário através de uma interface." + ) + + resposta_aluno = "É quando você protege os atributos da classe e só permite acesso via métodos." + + resultado = Correcao.corrigir_discursiva(pergunta_discursiva, resposta_aluno) + + print(f"Correta: {resultado['correta']}") + print(f"Pontuação: {resultado['pontuacao']}") + print(f"Feedback: {resultado['feedback']}") + print(f"Explicação: {resultado['explicacao']}") if __name__ == "__main__": diff --git a/Guia4/src/alternativa.py b/Guia4/src/alternativa.py index 4dde61f..f2caa32 100644 --- a/Guia4/src/alternativa.py +++ b/Guia4/src/alternativa.py @@ -1,4 +1,10 @@ from typing import List, Tuple, Dict class Alternativa: - pass \ No newline at end of file + def __init__(self, texto, correta, explicacao = None): + self.texto = texto + self.correta = correta + self.explicacao = explicacao + + def get_correta(self): + return self.correta \ No newline at end of file diff --git a/Guia4/src/correcao.py b/Guia4/src/correcao.py index bdf2fa4..c5e998b 100644 --- a/Guia4/src/correcao.py +++ b/Guia4/src/correcao.py @@ -1,4 +1,16 @@ from typing import List, Tuple, Dict +from .llmservice import LLMService + class Correcao: - pass \ No newline at end of file + @staticmethod + def criar_prompt_correcao(pergunta, resposta_aluno): + service = LLMService() + return service._criar_prompt(pergunta, resposta_aluno) + + @staticmethod + def corrigir_discursiva(pergunta, resposta_aluno, service=None): + if service is None: + service = LLMService() + + return service.corrigir_resposta(pergunta, resposta_aluno) \ No newline at end of file diff --git a/Guia4/src/llmservice.py b/Guia4/src/llmservice.py index e6e91b5..168b041 100644 --- a/Guia4/src/llmservice.py +++ b/Guia4/src/llmservice.py @@ -1,4 +1,72 @@ from typing import List, Tuple, Dict +import os +import json +from groq import Groq + + class LLMService: - pass \ No newline at end of file + def __init__(self, api_key=None, model="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" + self._client = None + + if self.api_key: + try: + self._client = Groq(api_key=self.api_key) + except Exception as e: + self._tratar_erro(e) + + def corrigir_resposta(self, pergunta, resposta_aluno): + if not self._client: + return { + "correta": False, + "pontuacao": 0.0, + "feedback": "Serviço de correção indisponível (API key não configurada).", + "explicacao": pergunta.get_explicacao() or "" + } + + prompt = self._criar_prompt(pergunta, resposta_aluno) + + try: + resposta_texto = self._fazer_chamada_api(prompt) + resultado = json.loads(resposta_texto) + + return { + "correta": bool(resultado.get("correta", False)), + "pontuacao": float(resultado.get("pontuacao", 0.0)), + "feedback": str(resultado.get("feedback", "")), + "explicacao": str(resultado.get("explicacao", pergunta.get_explicacao() or "")) + } + except Exception as e: + return self._tratar_erro(e) + + def _criar_prompt(self, pergunta, resposta_aluno): + return ( + "Você é um corretor de provas. Avalie a resposta do aluno.\n\n" + f"Pergunta: {pergunta.texto}\n" + f"Resposta esperada: {pergunta.resposta_esperada}\n" + f"Resposta do aluno: {resposta_aluno}\n\n" + "Responda APENAS em JSON, sem texto adicional, no formato:\n" + '{"correta": true ou false, "pontuacao": número de 0.0 a 1.0, ' + '"feedback": "comentário curto sobre a resposta", ' + '"explicacao": "explicação da resposta correta"}' + ) + + def _fazer_chamada_api(self, prompt): + completion = self._client.chat.completions.create( + model=self.model, + messages=[{"role": "user", "content": prompt}], + temperature=0, + response_format={"type": "json_object"}, + ) + return completion.choices[0].message.content + + def _tratar_erro(self, e): + return { + "correta": False, + "pontuacao": 0.0, + "feedback": f"Não foi possível corrigir automaticamente (erro: {type(e).__name__}).", + "explicacao": "" + } \ No newline at end of file diff --git a/Guia4/src/pergunta.py b/Guia4/src/pergunta.py index 5b3763d..4f00f88 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, explicacao_geral=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..ac82262 100644 --- a/Guia4/src/perguntadiscursiva.py +++ b/Guia4/src/perguntadiscursiva.py @@ -1,4 +1,17 @@ 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, resposta_esperada=None, case_sensitive=True): + super().__init__(texto) + self.resposta_esperada = resposta_esperada + self.case_sensitive = case_sensitive + + def validar_resposta(self, res): + if res == self.resposta_esperada: + return True + else: + return False + + 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..a37ec0b 100644 --- a/Guia4/src/perguntamultiplaescolha.py +++ b/Guia4/src/perguntamultiplaescolha.py @@ -1,4 +1,23 @@ 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, alternativas, explicacao_geral=None): + super().__init__(texto, explicacao_geral) + self.alternativas = alternativas + + def validar_resposta(self, indice): + resposta = self.alternativas[indice] + return resposta.get_correta() + + def get_alternativa_correta(self): + for res in self.alternativas: + if res.get_correta() == True: + return res + + def get_tipo(self): + return "multipla_escolha" + + def get_explicacao(self): + return self.explicacao_geral + \ No newline at end of file diff --git a/Guia4/src/questionario.py b/Guia4/src/questionario.py index 7525582..b8abb92 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): + self.titulo = titulo + self.perguntas = [] + + def adicionar_pergunta(self, pergunta): + self.perguntas.append(pergunta) + + def criar_attempt(self, usuario): + return TentativaQuestionario(self, usuario) + diff --git a/Guia4/src/resposta.py b/Guia4/src/resposta.py index 846d771..f5add9a 100644 --- a/Guia4/src/resposta.py +++ b/Guia4/src/resposta.py @@ -1,4 +1,15 @@ 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 + + @property + @abstractmethod + def esta_correta(self): + pass + + @abstractmethod + def calcular_pontuacao(self): + pass \ No newline at end of file diff --git a/Guia4/src/respostadiscursiva.py b/Guia4/src/respostadiscursiva.py index 4ea6dbb..2939504 100644 --- a/Guia4/src/respostadiscursiva.py +++ b/Guia4/src/respostadiscursiva.py @@ -1,4 +1,14 @@ 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): + super().__init__(pergunta) + self.texto_resposta = texto_resposta + + @property + def esta_correta(self): + return self.pergunta.validar_resposta(self.texto_resposta) + + def calcular_pontuacao(self): + return 1.0 if self.esta_correta else 0.0 \ No newline at end of file diff --git a/Guia4/src/respostaobjetiva.py b/Guia4/src/respostaobjetiva.py index 72ed2d0..d96d7c1 100644 --- a/Guia4/src/respostaobjetiva.py +++ b/Guia4/src/respostaobjetiva.py @@ -1,4 +1,14 @@ 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): + super().__init__(pergunta) + self.indice_escolhido = indice_escolhido + + @property + def esta_correta(self): + return self.pergunta.validar_resposta(self.indice_escolhido) + + def calcular_pontuacao(self): + return 1.0 if self.esta_correta else 0.0 \ No newline at end of file diff --git a/Guia4/src/tentativaquestionario.py b/Guia4/src/tentativaquestionario.py index 9947dd1..bd752f2 100644 --- a/Guia4/src/tentativaquestionario.py +++ b/Guia4/src/tentativaquestionario.py @@ -1,4 +1,33 @@ -from typing import List, Tuple, Dict +from datetime import datetime +from .respostaobjetiva import RespostaObjetiva +from .respostadiscursiva import RespostaDiscursiva +from .perguntamultiplaescolha import PerguntaMultiplaEscolha +from .perguntadiscursiva import PerguntaDiscursiva class TentativaQuestionario: - pass \ No newline at end of file + def __init__(self, questionario, usuario): + self.questionario = questionario + self.usuario = usuario + self.data_inicio = datetime.now() + self.data_fim = None + self.respostas = [] + + def registrar_resposta(self, indice_pergunta, valor): + pergunta = self.questionario.perguntas[indice_pergunta] + if isinstance(pergunta, PerguntaMultiplaEscolha): + resposta = RespostaObjetiva(pergunta, valor) + else: + resposta = RespostaDiscursiva(pergunta, valor) + self.respostas.append(resposta) + + def calcular_pontuacao(self): + return sum(r.calcular_pontuacao() for r in self.respostas) + + def finalizar(self): + self.data_fim = datetime.now() + pontuacao = self.calcular_pontuacao() + feedback = f"Pontuação final: {pontuacao}" + return pontuacao, feedback + + def is_finalizado(self): + return self.data_fim is not None \ No newline at end of file