import logging from fastapi import FastAPI, HTTPException from pydantic import BaseModel from contextlib import asynccontextmanager import uvicorn import api_logic # Importa nosso módulo com a lógica principal # Configuração de Logging (opcional, mas útil) logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # --- Modelos Pydantic para Validação de Entrada/Saída --- class ChatMessage(BaseModel): message: str # Poderíamos adicionar mais campos como user_id se necessário no futuro class ChatResponse(BaseModel): reply: str # --- Lifespan: Carregar modelos na inicialização, liberar na finalização --- # Esta é a forma moderna e recomendada no FastAPI para carregar recursos pesados @asynccontextmanager async def lifespan(app: FastAPI): logger.info("Executando startup do lifespan...") # Carrega os modelos e a memória definidos em api_logic.py try: api_logic.load_models_and_memory() logger.info("Modelos e memória carregados com sucesso.") except Exception as e: logger.exception("Falha crítica ao carregar modelos na inicialização!") # Se falhar aqui, a API provavelmente não funcionará corretamente. # Poderíamos impedir o startup, mas vamos deixar iniciar e os endpoints falharão. yield # Código de limpeza (shutdown) - opcional para este caso logger.info("Executando shutdown do lifespan...") # Poderia salvar o estado final aqui, mas já salvamos em add_to_memory # api_logic.save_state() # --- Inicialização do App FastAPI --- # Passamos o lifespan para gerenciar o carregamento dos modelos app = FastAPI(lifespan=lifespan, title="RPG API Backend", version="0.1.0") # --- Endpoints da API --- @app.get("/", summary="Endpoint de Verificação") async def read_root(): """Verifica se a API está online.""" logger.info("Endpoint '/' acessado.") return {"status": "RPG API Online", "message": "Use o endpoint POST /chat para interagir."} @app.post("/chat", response_model=ChatResponse, summary="Processa uma mensagem de chat") async def process_chat_message(chat_message: ChatMessage): """ Recebe uma mensagem do usuário, processa usando a lógica de IA e retorna a resposta do narrador. """ logger.info(f"Endpoint '/chat' recebido: {chat_message.message}") try: # Chama a função principal da nossa lógica reply_text = api_logic.run_chat_logic(chat_message.message) if reply_text is None or not isinstance(reply_text, str): logger.error(f"run_chat_logic retornou um tipo inesperado: {type(reply_text)}") raise HTTPException(status_code=500, detail="Erro interno: A IA não retornou um texto válido.") logger.info(f"Resposta gerada: {reply_text[:100]}...") # Loga parte da resposta return ChatResponse(reply=reply_text) except HTTPException as http_exc: # Re-levanta exceções HTTP que já foram tratadas raise http_exc except Exception as e: # Captura qualquer outro erro inesperado logger.exception(f"Erro inesperado ao processar /chat para a mensagem: {chat_message.message}") raise HTTPException(status_code=500, detail=f"Erro interno no servidor ao processar a mensagem: {e}") # --- Execução (se rodar localmente, não usado diretamente no Space) --- # O Hugging Face Space usará o Dockerfile para iniciar o Uvicorn if __name__ == "__main__": # Esta parte é útil para testes locais, mas não será usada no deploy do Space print("Iniciando servidor Uvicorn localmente para teste...") # Carrega modelos antes de iniciar o servidor localmente # api_logic.load_models_and_memory() # Já chamado pelo lifespan uvicorn.run(app, host="0.0.0.0", port=7860)