Spaces:
Sleeping
Sleeping
Create main.py
Browse files
main.py
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import logging
|
2 |
+
from fastapi import FastAPI, HTTPException
|
3 |
+
from pydantic import BaseModel
|
4 |
+
from contextlib import asynccontextmanager
|
5 |
+
import uvicorn
|
6 |
+
import api_logic # Importa nosso módulo com a lógica principal
|
7 |
+
|
8 |
+
# Configuração de Logging (opcional, mas útil)
|
9 |
+
logging.basicConfig(level=logging.INFO)
|
10 |
+
logger = logging.getLogger(__name__)
|
11 |
+
|
12 |
+
# --- Modelos Pydantic para Validação de Entrada/Saída ---
|
13 |
+
class ChatMessage(BaseModel):
|
14 |
+
message: str
|
15 |
+
# Poderíamos adicionar mais campos como user_id se necessário no futuro
|
16 |
+
|
17 |
+
class ChatResponse(BaseModel):
|
18 |
+
reply: str
|
19 |
+
|
20 |
+
# --- Lifespan: Carregar modelos na inicialização, liberar na finalização ---
|
21 |
+
# Esta é a forma moderna e recomendada no FastAPI para carregar recursos pesados
|
22 |
+
@asynccontextmanager
|
23 |
+
async def lifespan(app: FastAPI):
|
24 |
+
logger.info("Executando startup do lifespan...")
|
25 |
+
# Carrega os modelos e a memória definidos em api_logic.py
|
26 |
+
try:
|
27 |
+
api_logic.load_models_and_memory()
|
28 |
+
logger.info("Modelos e memória carregados com sucesso.")
|
29 |
+
except Exception as e:
|
30 |
+
logger.exception("Falha crítica ao carregar modelos na inicialização!")
|
31 |
+
# Se falhar aqui, a API provavelmente não funcionará corretamente.
|
32 |
+
# Poderíamos impedir o startup, mas vamos deixar iniciar e os endpoints falharão.
|
33 |
+
yield
|
34 |
+
# Código de limpeza (shutdown) - opcional para este caso
|
35 |
+
logger.info("Executando shutdown do lifespan...")
|
36 |
+
# Poderia salvar o estado final aqui, mas já salvamos em add_to_memory
|
37 |
+
# api_logic.save_state()
|
38 |
+
|
39 |
+
# --- Inicialização do App FastAPI ---
|
40 |
+
# Passamos o lifespan para gerenciar o carregamento dos modelos
|
41 |
+
app = FastAPI(lifespan=lifespan, title="RPG API Backend", version="0.1.0")
|
42 |
+
|
43 |
+
# --- Endpoints da API ---
|
44 |
+
|
45 |
+
@app.get("/", summary="Endpoint de Verificação")
|
46 |
+
async def read_root():
|
47 |
+
"""Verifica se a API está online."""
|
48 |
+
logger.info("Endpoint '/' acessado.")
|
49 |
+
return {"status": "RPG API Online", "message": "Use o endpoint POST /chat para interagir."}
|
50 |
+
|
51 |
+
@app.post("/chat", response_model=ChatResponse, summary="Processa uma mensagem de chat")
|
52 |
+
async def process_chat_message(chat_message: ChatMessage):
|
53 |
+
"""
|
54 |
+
Recebe uma mensagem do usuário, processa usando a lógica de IA
|
55 |
+
e retorna a resposta do narrador.
|
56 |
+
"""
|
57 |
+
logger.info(f"Endpoint '/chat' recebido: {chat_message.message}")
|
58 |
+
try:
|
59 |
+
# Chama a função principal da nossa lógica
|
60 |
+
reply_text = api_logic.run_chat_logic(chat_message.message)
|
61 |
+
|
62 |
+
if reply_text is None or not isinstance(reply_text, str):
|
63 |
+
logger.error(f"run_chat_logic retornou um tipo inesperado: {type(reply_text)}")
|
64 |
+
raise HTTPException(status_code=500, detail="Erro interno: A IA não retornou um texto válido.")
|
65 |
+
|
66 |
+
logger.info(f"Resposta gerada: {reply_text[:100]}...") # Loga parte da resposta
|
67 |
+
return ChatResponse(reply=reply_text)
|
68 |
+
|
69 |
+
except HTTPException as http_exc:
|
70 |
+
# Re-levanta exceções HTTP que já foram tratadas
|
71 |
+
raise http_exc
|
72 |
+
except Exception as e:
|
73 |
+
# Captura qualquer outro erro inesperado
|
74 |
+
logger.exception(f"Erro inesperado ao processar /chat para a mensagem: {chat_message.message}")
|
75 |
+
raise HTTPException(status_code=500, detail=f"Erro interno no servidor ao processar a mensagem: {e}")
|
76 |
+
|
77 |
+
# --- Execução (se rodar localmente, não usado diretamente no Space) ---
|
78 |
+
# O Hugging Face Space usará o Dockerfile para iniciar o Uvicorn
|
79 |
+
if __name__ == "__main__":
|
80 |
+
# Esta parte é útil para testes locais, mas não será usada no deploy do Space
|
81 |
+
print("Iniciando servidor Uvicorn localmente para teste...")
|
82 |
+
# Carrega modelos antes de iniciar o servidor localmente
|
83 |
+
# api_logic.load_models_and_memory() # Já chamado pelo lifespan
|
84 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|