import os
import hashlib
from datetime import datetime, timezone
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
DEFAULT_MODEL = "gpt-3.5-turbo"
DEFAULT_TEMPERATURE = 0.7
memoria_sessoes = {}
PROMPT_TEMPLATE = ChatPromptTemplate.from_messages(
[
(
"system",
"Você é o 'GeoAI Mentor', um assistente especializado em ajudar geocientistas a migrar para a área de Ciência de Dados. Seja amigável e didático.",
),
("placeholder", "{historico}"),
("human", "{query}"),
]
)
def build_model() -> ChatOpenAI:
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
raise RuntimeError(
"OPENAI_API_KEY no está configurada. Agrégala a tu archivo .env."
)
model_name = os.getenv("OPENAI_MODEL", DEFAULT_MODEL)
temperature = float(os.getenv("OPENAI_TEMPERATURE", str(DEFAULT_TEMPERATURE)))
return ChatOpenAI(
api_key=api_key,
model=model_name,
temperature=temperature,
)
def obter_historico_por_sessao(session_id: str) -> InMemoryChatMessageHistory:
if not isinstance(session_id, str) or not session_id.strip():
raise ValueError("session_id deve ser uma string não vazia.")
try:
if session_id not in memoria_sessoes:
memoria_sessoes[session_id] = InMemoryChatMessageHistory()
return memoria_sessoes[session_id]
except Exception as exc:
raise RuntimeError(
f"Falha ao obter/criar histórico para a sessão '{session_id}'."
) from exc
def gerar_session_id() -> str:
agora = datetime.now(timezone.utc).isoformat()
return hashlib.sha256(agora.encode("utf-8")).hexdigest()[:16]
def chat(pergunta: str, session_id: str) -> None:
llm = build_model()
cadeia = PROMPT_TEMPLATE | llm | StrOutputParser()
cadeia_com_memoria = RunnableWithMessageHistory(
cadeia,
obter_historico_por_sessao,
input_messages_key="query",
history_messages_key="historico",
)
print(f"Usuario: {pergunta}\n")
if pergunta:
response = cadeia_com_memoria.invoke(
{"query": pergunta},
config={"configurable": {"session_id": session_id}},
)
print(f"Mentor: {response}\n")
else:
print("Chat mentor listo. Escribe 'salir' para terminar.")
while True:
user_message = input("Usuario: ").strip()
if not user_message:
continue
if user_message.lower() in {"salir", "exit", "quit"}:
print("Fin.")
break
response = cadeia_com_memoria.invoke(
{"query": user_message},
config={"configurable": {"session_id": session_id}},
)
print(f"Mentor: {response}\n")
# pra executar o chat interativo, basta rodar o script sem argumentos. Para perguntas rápidas, passe a pergunta como argumento.
if __name__ == "__main__":
perguntas = [
"Eu sou geofísico e quero migrar para a área de dados. Qual linguagem de programação devo aprender primeiro?",
"E que tipo de projeto de portfólio eu poderia criar usando essa linguagem?",
]
session_id = gerar_session_id()
try:
for pergunta in perguntas:
try:
chat(pergunta, session_id)
except Exception as e:
print(f"Erro ao processar pergunta: {e}\n")
except RuntimeError as e:
print(f"Erro de configuração: {e}")
except Exception as e:
print(f"Erro inesperado: {e}")