Pular para o conteúdo

Conversas e estado

A máquina de estados por chat, a validação passo a passo, e onde o estado mora.

Guardar "em que passo este chat está" num vault solto é o que todo bot faz errado: funciona até o segundo usuário, os dois se misturam, e um bot reiniciado esquece todo mundo.

Uma conversa#

dataforge
action e_email(texto):
    yield "@" in texto and "." in texto

cadastro := app.conversa("cadastro", [
    {"pergunta": "Qual e o seu nome?", "guarda": "nome"},
    {"pergunta": "E o seu e-mail?", "guarda": "email",
     "valida": e_email, "erro": "Isso nao parece um e-mail."}
])

mark @cadastro.ao_terminar()
action terminou(ctx, respostas):
    salvar(respostas["nome"], respostas["email"])
    ctx.responder($"Pronto, {respostas['nome']}!")

mark @app.comando("cadastro")
action abrir(ctx):
    cadastro.comecar(ctx)

Cada passo pergunta, espera, valida e guarda. O estado fica no chat, então duas pessoas conversando ao mesmo tempo não se atrapalham.

O estado deste chat#

dataforge
mark @app.comando("lembrar")
action lembrar(ctx):
    ctx.guardar("ultima_busca", ctx.args[0] ?? "")
    ctx.responder($"Anotei: {ctx.lembrar('ultima_busca', 'nada')}")
OndeSobrevive aQuando usar
Tg.estado_em_memoria()nada — some ao reiniciardesenvolvimento, e bots sem memória
Tg.estado_em_arquivo(pasta)o reinício do processoum bot só, num servidor só

O nome do arquivo sai do id do chat, e ele é conferido: um id que chegasse com ../ escreveria fora da pasta. O id vem do Telegram e é sempre numérico — mas "sempre" é uma suposição sobre um sistema de terceiros, e é barato não depender dela.

dataforge
app := Tg.app(Tg.segredo_do_ambiente(),
              estado := Tg.estado_em_arquivo(".telegram/estado"))