Spaces:
Runtime error
Runtime error
File size: 8,368 Bytes
cc51976 6952db2 cc51976 ffa0c53 9eab4dd c9a085a 2fe6001 cc51976 5019432 9eab4dd cc51976 9eab4dd 0614e7d cc51976 0614e7d cc51976 78222a9 9eab4dd 78222a9 9eab4dd ffa0c53 cc51976 9eab4dd 4e991ba c9a085a 9eab4dd 2fe6001 9eab4dd 4e991ba 9eab4dd 3c016be 9eab4dd 4e991ba 9eab4dd 4e991ba 9eab4dd 4e991ba 9eab4dd 0614e7d cc51976 be75c7f cc51976 be75c7f cc51976 be75c7f 5019432 be75c7f c9a085a ffa0c53 9eab4dd 4e991ba 6952db2 4e991ba 6952db2 4e991ba 5019432 78222a9 ffa0c53 be75c7f 5019432 ffa0c53 5019432 78222a9 6952db2 5019432 6952db2 be75c7f cc51976 be75c7f 2fe6001 78222a9 4e991ba 2fe6001 78222a9 ffa0c53 be75c7f 4e991ba be75c7f 9d17108 be75c7f 9d17108 be75c7f 4e991ba be75c7f 4e991ba be75c7f 4e991ba 9d17108 4e991ba be75c7f 4e991ba 0614e7d cc51976 ffa0c53 0614e7d 9d17108 be75c7f ffa0c53 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
from fastapi import FastAPI, HTTPException
from transformers import AutoTokenizer, T5ForConditionalGeneration
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
import json
import os
import logging
import time
import gc
import re
import psutil # Para monitorar uso de recursos
# Configura logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI()
app.mount("/", StaticFiles(directory="static", html=True), name="static")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Carrega questions.json
try:
with open("questions.json", "r", encoding="utf-8") as f:
examples = json.load(f)
logger.info("questions.json carregado com sucesso.")
except FileNotFoundError:
examples = []
logger.warning("questions.json não encontrado, usando lista vazia.")
# Função para carregar modelo e tokenizer
def get_model():
if not hasattr(get_model, "model_data"):
logger.info("Iniciando carregamento de modelo e tokenizer...")
start_time = time.time()
try:
tokenizer = AutoTokenizer.from_pretrained(
"unicamp-dl/ptt5-small-portuguese-vocab",
legacy=False,
clean_up_tokenization_spaces=True
)
logger.info(f"Tokenizer baixado e carregado em {time.time() - start_time:.2f} segundos.")
model = T5ForConditionalGeneration.from_pretrained(
"unicamp-dl/ptt5-small-portuguese-vocab"
)
logger.info(f"Modelo baixado e carregado em {time.time() - start_time:.2f} segundos.")
get_model.model_data = {"tokenizer": tokenizer, "model": model}
logger.info("Modelo e tokenizer armazenados com sucesso em model_data.")
except Exception as e:
logger.error(f"Erro ao carregar modelo ou tokenizer: {e}")
get_model.model_data = None
logger.debug(f"Retornando model_data: {get_model.model_data is not None}")
return get_model.model_data
def parse_model_output(response):
logger.debug(f"Saída bruta do modelo: {response}")
pattern = r"Enunciado clínico: (.*?)(?:\s*Alternativas: (.*?))?(?:\s*Gabarito: (.*?))?(?:\s*Explicação: (.*?))?"
match = re.match(pattern, response, re.DOTALL)
if match:
question = match.group(1).strip() if match.group(1) else response[:200]
options = [opt.strip() for opt in (match.group(2) or "").split(",") if opt.strip()] if match.group(2) else []
answer = match.group(3).strip() if match.group(3) else ""
explanation = match.group(4).strip() if match.group(4) else "Sem explicação ou parsing incompleto"
if len(options) >= 4:
return {
"question": f"Enunciado clínico: {question}",
"options": [f"A) {options[0]}", f"B) {options[1]}", f"C) {options[2]}", f"D) {options[3]}"],
"answer": answer,
"explanation": explanation
}
logger.warning(f"Parsing falhou para: {response[:200]}")
# Fallback para tentar extrair algo útil
if "Enunciado clínico" in response:
return {"question": response[:200], "options": [], "answer": "", "explanation": "Formato parcial detectado"}
return {"question": response[:200] if len(response) > 200 else response, "options": [], "answer": "", "explanation": "Erro no parsing ou formato inválido"}
def generate_question_from_prompt(theme, difficulty, example_question=None):
model_data = get_model()
logger.debug(f"Verificando model_data: {model_data is not None}")
if not model_data or not model_data["tokenizer"] or not model_data["model"]:
logger.error("Modelo ou tokenizer não disponível.")
return {"question": "Erro: Modelo ou tokenizer não carregado.", "options": [], "answer": "", "explanation": "Por favor, verifique os logs."}
tokenizer = model_data["tokenizer"]
model = model_data["model"]
logger.info(f"Gerando questão com tema: {theme}, dificuldade: {difficulty}")
logger.debug(f"Uso de CPU: {psutil.cpu_percent()}%, Memória: {psutil.virtual_memory().percent}%")
if example_question:
example_text = example_question.get("question", "") + " " + ", ".join(example_question.get("options", []))
prompt = f"Usando '{example_text[:100]}' como exemplo, gere uma NOVA questão curta sobre '{theme}', dificuldade '{difficulty}', estilo USP. Responda SOMENTE: 'Enunciado clínico: [texto]. Alternativas: A) [opção], B) [opção], C) [opção], D) [opção]. Gabarito: [letra]. Explicação: [texto].'"
else:
prompt = f"Gere uma NOVA questão curta sobre '{theme}', dificuldade '{difficulty}', estilo USP. Responda SOMENTE: 'Enunciado clínico: [texto]. Alternativas: A) [opção], B) [opção], C) [opção], D) [opção]. Gabarito: [letra]. Explicação: [texto].'"
try:
inputs = tokenizer(prompt, return_tensors="pt", padding=True, truncation=True, max_length=512)
outputs = model.generate(**inputs, max_new_tokens=512, do_sample=True, temperature=0.7, top_p=0.9)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
logger.debug(f"Resposta bruta: {response}")
result = parse_model_output(response)
logger.debug(f"Questão processada: {result}")
gc.collect()
return result
except Exception as e:
logger.error(f"Erro na geração da questão: {e}")
gc.collect()
return {"question": f"Erro na geração: {e}", "options": [], "answer": "", "explanation": "Tente novamente."}
# Função para exibir perguntas do JSON e gerar adicionais
def generate_simulado():
logger.info("Iniciando geração de simulado...")
# Exibe as 3 primeiras perguntas do JSON
max_json_questions = min(3, len(examples))
for i in range(max_json_questions):
question_data = examples[i]
logger.info(f"Questão do JSON {i + 1}: {question_data['question']}")
for opt in question_data['options']:
logger.info(f" {opt}")
logger.info(f" Gabarito: {question_data['answer']}")
logger.info(f" Explicação: {question_data['explanation']}")
# Gera 3 perguntas adicionais com o modelo
for i in range(3):
logger.debug(f"Gerando pergunta adicional {i + 1}")
example = examples[i % len(examples)] if examples else None
question_data = generate_question_from_prompt("clinica medica", "medio", example)
logger.info(f"Questão Gerada {max_json_questions + i + 1}: {question_data['question']}")
for opt in question_data['options']:
logger.info(f" {opt}")
logger.info(f" Gabarito: {question_data['answer']}")
logger.info(f" Explicação: {question_data['explanation']}")
logger.info("Geração de simulado concluída.")
return {"simulado": examples[:3] + [generate_question_from_prompt("clinica medica", "medio") for _ in range(3)]}
# Força carregamento inicial
logger.info("Testando carregamento inicial do modelo...")
start_time = time.time()
model_data = get_model()
if model_data:
logger.info(f"Modelo e tokenizer inicializados em {time.time() - start_time:.2f} segundos.")
time.sleep(1) # Delay para estabilidade
generate_simulado()
else:
logger.error("Falha na inicialização do modelo.")
@app.get("/generate")
async def generate_question(theme: str, difficulty: str):
valid_difficulties = ["fácil", "médio", "difícil"]
if not theme or difficulty.lower() not in valid_difficulties:
raise HTTPException(status_code=400, detail="Tema inválido ou dificuldade deve ser 'fácil', 'médio' ou 'difícil'.")
example = examples[0] if examples else None
return generate_question_from_prompt(theme, difficulty, example)
@app.get("/simulado")
async def get_simulado(num_questions: int = 6): # 3 do JSON + 3 geradas
simulado = examples[:min(3, len(examples))] # Até 3 do JSON
for _ in range(min(3, num_questions - len(simulado))): # Gera até 3 adicionais
example = examples[0] if examples else None
question_data = generate_question_from_prompt("clinica medica", "medio", example)
simulado.append(question_data)
return {"simulado": simulado} |