feat(vida): aprendizado com o dia a dia (gosto, rotina da casa e sono)
O Carinha passa a melhorar as interações com o que vive em casa, sem IA e sem internet (aprendizado.py): - gosto: gesto ou atividade feito com alguém por perto é uma tentativa; carinho, brincadeira ou conversa até 60 s depois contam como "gostaram" (cutucada vale meio). A chance de cada ato vai de 0,5x a 2x, relativa à média, e só depois de 3 tentativas; - rotina: fração de minutos com gente em cada hora (média móvel entre dias). Antes de uma hora movimentada, acorda do cochilo 15 min antes; sono pesado e madrugada continuam respeitados; - sono: PIR acordou e ninguém ficou nem interagiu em 3 min = à toa. Se repete na mesma hora, ali pede 1 ou 2 disparos a mais para acordar; - à meia-noite fecha o dia: lições em primeira pessoa no diário e o passado pesa 15% menos a cada dia (o gosto muda); - rotas /aprendizado/status|config|esquecer e SSE 'aprendizado'; - painel: cartão "O que ele aprendeu" no Ao vivo (rotina em 24 barras, faz mais / faz menos, lições, esquecer com confirmação) e tópico no guia. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -112,6 +112,7 @@ PERIODOS = [(5, 12, 'de manhã', ['um sol nascendo', 'um pãozinho', 'uma xícar
|
||||
(0, 5, 'de madrugada', ['uma lua', 'uma vela', 'uma coruja'])]
|
||||
|
||||
MAX_DIARIO = 60
|
||||
GESTOS_VIDA = {g for atos in ATOS.values() for g, _, _ in atos}
|
||||
|
||||
|
||||
def _limitar(v):
|
||||
@@ -147,6 +148,7 @@ class Vida:
|
||||
self.do_dia = lambda: [] # ids das ideias de hoje
|
||||
self.aprendi_pendente = lambda: None # curiosidade de hoje que ainda dá para contar
|
||||
self.contar_aprendi = lambda ident, agora=None: None
|
||||
self.aprendizado = None # o que ele aprende com o dia a dia (aprendizado.py)
|
||||
|
||||
agora = time.time()
|
||||
self.config = dict(PADRAO)
|
||||
@@ -319,6 +321,8 @@ class Vida:
|
||||
self.anotar('cuidado', CUIDADOS[tipo], agora)
|
||||
if tipo in CUIDADOS or tipo == 'conversa':
|
||||
self.interagiu_em = agora # alguém quis ele acordado (sensor não conta)
|
||||
if self.aprendizado:
|
||||
self.aprendizado.resposta(tipo, agora)
|
||||
if gesto and not self.bloqueado():
|
||||
if self.dormindo():
|
||||
self.acordar(agora, None)
|
||||
@@ -369,7 +373,10 @@ class Vida:
|
||||
else:
|
||||
lista = ATIVAS + CRIATIVAS * 2 + CALMAS
|
||||
opcoes = [a for a in lista if a != self.ultima_atividade] or lista
|
||||
return self.rng.choice(opcoes)
|
||||
pesos = [self.gosto(a) for a in opcoes]
|
||||
if all(p == 1.0 for p in pesos):
|
||||
return self.rng.choice(opcoes)
|
||||
return self.rng.choices(opcoes, weights=pesos)[0] # as que agradam saem mais
|
||||
|
||||
def comecar_atividade(self, agora, nome, segundos):
|
||||
if nome.startswith('criado:'):
|
||||
@@ -394,8 +401,12 @@ class Vida:
|
||||
agora = agora or time.time()
|
||||
self.pir_eventos = [t for t in self.pir_eventos if agora - t < 120] + [agora]
|
||||
precisa = PIR_ACORDAR[self.config['ritmo']] if self.config['ligado'] else 1
|
||||
if self.aprendizado and self.config['ligado']:
|
||||
precisa += self.aprendizado.extra_pir(agora) # nesta hora já acordou à toa outras vezes
|
||||
if len(self.pir_eventos) >= precisa:
|
||||
self.pir_eventos = []
|
||||
if self.aprendizado and self.config['ligado']:
|
||||
self.aprendizado.acordou_pelo_sensor(agora)
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -406,7 +417,12 @@ class Vida:
|
||||
return hora >= ini or hora < fim
|
||||
|
||||
# ------------------------------------------------------------------ decidir o que fazer
|
||||
def gosto(self, nome):
|
||||
"""Quanto o aprendizado multiplica a chance de um ato (1 = sem opinião)."""
|
||||
return self.aprendizado.peso(nome) if self.aprendizado else 1.0
|
||||
|
||||
def escolher(self, opcoes):
|
||||
opcoes = [(g, p * self.gosto(g), t) for g, p, t in opcoes]
|
||||
total = sum(p for _, p, _ in opcoes)
|
||||
x = self.rng.uniform(0, total)
|
||||
for gesto, peso, texto in opcoes:
|
||||
@@ -473,6 +489,11 @@ class Vida:
|
||||
if n['energia'] >= DESCANSADO and not self.madrugada(agora):
|
||||
self.acordar(agora, 'Acordou descansado')
|
||||
return 'acordar'
|
||||
# aprendeu a rotina: acorda do cochilo um pouco antes da hora em que costuma ter gente
|
||||
if (self.aprendizado and not self.sono_profundo and not self.madrugada(agora) and n['energia'] >= 50
|
||||
and self.aprendizado.chega_logo(agora)):
|
||||
self.acordar(agora, 'Acordou: daqui a pouco costuma chegar alguém')
|
||||
return 'acordar'
|
||||
return None
|
||||
if self.config['noite'] and self.madrugada(agora) and agora - self.interagiu_em > PEDIU_ATENCAO:
|
||||
self.dormir(agora, 'Ficou tarde, foi dormir')
|
||||
@@ -529,11 +550,25 @@ class Vida:
|
||||
self.anotar('acao', texto, agora)
|
||||
return gesto
|
||||
|
||||
def aprender_ato(self, ato, agora):
|
||||
"""Gestos e atividades feitos com plateia entram no aprendizado (para ver se agradam)."""
|
||||
if not self.aprendizado or not ato:
|
||||
return
|
||||
if ato.startswith('atividade '):
|
||||
nome = ato[len('atividade '):]
|
||||
elif ato in GESTOS_VIDA:
|
||||
nome = ato
|
||||
else:
|
||||
return
|
||||
self.aprendizado.ato(nome, agora, self.alguem_perto())
|
||||
|
||||
def tick(self, agora=None):
|
||||
agora = agora or time.time()
|
||||
self.passar_tempo(agora)
|
||||
if not self.config['ligado']:
|
||||
return None
|
||||
if self.aprendizado:
|
||||
self.aprendizado.observar(agora, self.alguem_perto())
|
||||
ato = None
|
||||
humor = self.humor()
|
||||
# acordaram ele de propósito (toque, painel) antes de descansar: o sono pesado acaba aqui
|
||||
@@ -554,6 +589,7 @@ class Vida:
|
||||
self.zanga_enviada = zanga
|
||||
if agora >= self.proximo_ato:
|
||||
ato = self.agir(agora)
|
||||
self.aprender_ato(ato, agora)
|
||||
lo, hi = RITMOS[self.config['ritmo']]
|
||||
self.proximo_ato = agora + self.rng.uniform(lo, hi)
|
||||
if ato or agora - self.publicado_em > 30 or humor != self.humor():
|
||||
|
||||
Reference in New Issue
Block a user