feat(vida): jeito de gente e console com o porquê de cada decisão
Console (console.py + tela Console no painel):
- cada parte registra o que fez e o motivo: modo vida (com necessidades
e humor), sentidos, celular (ordens e o que o rosto fez), IA local,
aprendizado e ideias do dia; últimas 400 linhas, ao vivo pelo SSE;
- tela com o "agora" (humor, necessidades, o que está fazendo, próxima
decisão, última decisão, jeito), filtros, detalhes, pausa e busca.
Jeito de gente:
- saudade: a festa cresce com o tempo fora (aceno, "Oi! Você voltou!",
"Senti sua falta!"); bom dia lembrando de ontem;
- pedidos com motivo ("Brinca comigo?", "Me faz um carinho?", mostrar a
figurinha nova), no máximo 1 a cada 20 min;
- larga atividade no meio quando fica chato; personalidade (curiosidade,
brincadeira, timidez) que pesa nos gestos e amadurece com o convívio;
- no rosto: acordar grogue, sonhar com algo do dia (balão no motor),
hesitar antes de gestos, errar na atividade e ficar sem graça, olhar
nos olhos e desviar, sorrir de volta (FaceLandmarker no rastreador do
painel) e reagir à luz (sensor de luz no app 0.10.0);
- ordem "dizer" com legenda e voz de robô.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+28
-3
@@ -45,6 +45,7 @@ from vida import Vida
|
||||
from criacao import Criacao
|
||||
from inspiracao import Inspiracao
|
||||
from aprendizado import Aprendizado
|
||||
from console import Console
|
||||
|
||||
TRAVA = threading.Lock()
|
||||
|
||||
@@ -73,12 +74,13 @@ ARQUIVO_APARENCIA = "aparencia.json"
|
||||
# Arquivos servidos como estão: o rosto do celular e o rastreamento do painel.
|
||||
ESTATICOS = {"/carinha.html", "/camera.html", "/reacoes-render.js", "/rastreador-worker.js", "/rosto-motor.js", "/voz-robo.js",
|
||||
"/vendor/mediapipe/vision_bundle.mjs", "/vendor/mediapipe/face.tflite", "/vendor/mediapipe/hands.task",
|
||||
"/vendor/mediapipe/expressao.task",
|
||||
"/vendor/mediapipe/wasm/vision_wasm_internal.js", "/vendor/mediapipe/wasm/vision_wasm_internal.wasm",
|
||||
"/vendor/mediapipe/wasm/vision_wasm_nosimd_internal.js", "/vendor/mediapipe/wasm/vision_wasm_nosimd_internal.wasm"}
|
||||
|
||||
# Rotas que não exigem token: só o necessário para a página do rosto abrir e o app se achar.
|
||||
PUBLICAS_GET = {"/app/health", "/faces", "/gestos", "/config", "/ia/modelo", "/app.apk"}
|
||||
PREFIXOS_API = ("/eventos", "/estado", "/fila", "/rtc/", "/conversa/", "/treinamento/", "/historico/", "/vida/", "/aprendizado/", "/criacao/",
|
||||
PREFIXOS_API = ("/eventos", "/console", "/estado", "/fila", "/rtc/", "/conversa/", "/treinamento/", "/historico/", "/vida/", "/aprendizado/", "/criacao/",
|
||||
"/app/", "/braco/", "/servos/", "/ia/", "/api/", "/gesto/", "/face/", "/diag/")
|
||||
|
||||
|
||||
@@ -122,10 +124,26 @@ EVENTOS = Eventos()
|
||||
ESTOP = {"ativo": False, "desde": None}
|
||||
|
||||
|
||||
CONSOLE = Console()
|
||||
# ordens que se repetem (o modo vida reenvia o humor a cada minuto): no console, só em "detalhes"
|
||||
ORDENS_DETALHE = ("humor ", "ritmo ", "zanga ", "sono ")
|
||||
|
||||
|
||||
def enfileirar(ordem):
|
||||
"""Caminho único de uma ordem para o rosto: fila do celular + evento para os painéis."""
|
||||
FILA.adicionar(ordem)
|
||||
EVENTOS.publicar("expressao", {"ordem": ordem})
|
||||
if ordem.startswith("dizer "):
|
||||
CONSOLE.registrar("celular", "Falou: " + ordem[6:])
|
||||
elif ordem.startswith(("atividade_criada ", "expressao_criada ")):
|
||||
try:
|
||||
nome = json.loads(ordem.split(" ", 1)[1]).get("nome", "?")
|
||||
except ValueError:
|
||||
nome = "?"
|
||||
CONSOLE.registrar("celular", "Mandou ao rosto a criação: " + nome)
|
||||
elif not ordem.startswith("aprendi "):
|
||||
CONSOLE.registrar("celular", "Mandou ao rosto: " + ordem,
|
||||
nivel="detalhe" if ordem.startswith(ORDENS_DETALHE) else "info")
|
||||
|
||||
|
||||
def carregar_aparencia():
|
||||
@@ -264,7 +282,7 @@ class Handler(SimpleHTTPRequestHandler):
|
||||
|
||||
def modulos(self):
|
||||
s = self.server
|
||||
return [getattr(s, nome) for nome in ("api_config", "historico", "vida", "aprendizado", "inspiracao", "criacao", "treinamento", "conversa", "cerebro",
|
||||
return [getattr(s, nome) for nome in ("console", "api_config", "historico", "vida", "aprendizado", "inspiracao", "criacao", "treinamento", "conversa", "cerebro",
|
||||
"braco", "servos", "controle") if hasattr(s, nome)]
|
||||
|
||||
def estado(self):
|
||||
@@ -486,7 +504,8 @@ class Servidor(ThreadingHTTPServer):
|
||||
|
||||
|
||||
def ligar_eventos(servidor):
|
||||
for nome in ("controle", "servos", "cerebro", "conversa", "treinamento", "historico", "vida", "criacao", "inspiracao", "aprendizado"):
|
||||
for nome in ("controle", "servos", "cerebro", "conversa", "treinamento", "historico", "vida", "criacao", "inspiracao", "aprendizado",
|
||||
"console"):
|
||||
if hasattr(servidor, nome):
|
||||
getattr(servidor, nome).publicar = EVENTOS.publicar
|
||||
|
||||
@@ -560,6 +579,12 @@ def main():
|
||||
def nome_criada(ident):
|
||||
return next((a['nome'] for a in servidor.criacao.atividades() if a['id'] == ident), None)
|
||||
servidor.aprendizado = aprendizado = Aprendizado(Path.cwd() / 'aprendizado.json', nome_criada)
|
||||
# Console: tudo o que ele faz e por quê (cada parte registra o motivo da decisão)
|
||||
servidor.console = CONSOLE
|
||||
for parte in (vida, aprendizado, inspiracao, servidor.cerebro, servidor.historico, servidor.controle):
|
||||
parte.console = CONSOLE.registrar
|
||||
vida.dia_anterior = lambda: aprendizado.historico[-1] if aprendizado.historico else None
|
||||
CONSOLE.registrar("sistema", "Servidor iniciado", "versão " + versao())
|
||||
aprendizado.anotar = lambda tipo, texto, agora=None: (vida.anotar(tipo, texto, agora), vida.avisar())
|
||||
vida.aprendizado = aprendizado
|
||||
# a análise da semana usa a mesma IA do estúdio (Gemini, IA local ou o S10)
|
||||
|
||||
Reference in New Issue
Block a user