feat: horizonte de 35 dias y histograma real en /perfil
El cambio de perfil funcionaba, pero con 13 dias planificados por delante la diferencia entre perfiles no se apreciaba: la variedad es una propiedad estadistica y con esa muestra un 51% y un 29% se ven casi igual. - Horizonte de 21 a 35 dias naturales (~22 laborables). Con esa muestra el histograma ya se corresponde con lo anunciado: disperso da 6 horas distintas con la mas repetida al 27%, frente al 29% medido sobre el año entero. - /perfil enseña ahora el histograma REAL de lo que hay sorteado, no solo las cifras teoricas del perfil. Asi se ve el efecto del cambio en el momento, que era justo lo que faltaba para poder decidir. Verificado que los cinco perfiles siguen dando exactamente las cifras documentadas tras el refactor a perfiles por tramo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
22
app/bot.py
22
app/bot.py
@@ -291,8 +291,30 @@ class BotUI:
|
|||||||
lines.append(f" <i>{profiles.resumen(n)}</i>")
|
lines.append(f" <i>{profiles.resumen(n)}</i>")
|
||||||
lines.append("\n<i>madrugón = de esos minutos, los que te levantas antes "
|
lines.append("\n<i>madrugón = de esos minutos, los que te levantas antes "
|
||||||
"por la entrada de la mañana. Tu histórico real: 4 minutos, moda 38%.</i>")
|
"por la entrada de la mañana. Tu histórico real: 4 minutos, moda 38%.</i>")
|
||||||
|
real = self._histograma_real()
|
||||||
|
if real:
|
||||||
|
lines.append("\n" + real)
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
def _histograma_real(self) -> str:
|
||||||
|
"""Lo que hay sorteado ahora mismo, para poder ver el efecto del cambio."""
|
||||||
|
from collections import Counter
|
||||||
|
hoy = self.svc.today()
|
||||||
|
c: Counter = Counter()
|
||||||
|
for i in range(60):
|
||||||
|
for r in self.svc.store.get_plan(hoy + timedelta(days=i)):
|
||||||
|
t = datetime.fromisoformat(r["target"])
|
||||||
|
if r["typ"] == ENTRADA and (t.hour, t.minute) == (9, 0):
|
||||||
|
c[datetime.fromisoformat(r["planned_at"]).strftime("%H:%M")] += 1
|
||||||
|
if not c:
|
||||||
|
return ""
|
||||||
|
tot = sum(c.values())
|
||||||
|
filas = "\n".join(
|
||||||
|
f" <code>{h}</code> {'█' * n} {n}" for h, n in sorted(c.items()))
|
||||||
|
return (f"<b>Tus próximos {tot} días ya sorteados</b> (entrada de la mañana)\n"
|
||||||
|
f"{filas}\n <i>{len(c)} horas distintas · la más repetida "
|
||||||
|
f"{max(c.values())} de {tot} ({round(100 * max(c.values()) / tot)}%)</i>")
|
||||||
|
|
||||||
def _perfil_teclado(self) -> InlineKeyboardMarkup:
|
def _perfil_teclado(self) -> InlineKeyboardMarkup:
|
||||||
actual = self.svc.store.get("perfil", profiles.DEFECTO)
|
actual = self.svc.store.get("perfil", profiles.DEFECTO)
|
||||||
botones = [InlineKeyboardButton(
|
botones = [InlineKeyboardButton(
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ logger = logging.getLogger(__name__)
|
|||||||
ANNOUNCE_LEAD = timedelta(minutes=12) # cuanta antelacion tiene el killswitch
|
ANNOUNCE_LEAD = timedelta(minutes=12) # cuanta antelacion tiene el killswitch
|
||||||
MAX_SLEEP = 60.0
|
MAX_SLEEP = 60.0
|
||||||
REPLAN_HOUR = 4 # hora a la que se planifica el dia
|
REPLAN_HOUR = 4 # hora a la que se planifica el dia
|
||||||
HORIZON_DAYS = 21 # dias que se planifican por adelantado
|
HORIZON_DAYS = 35 # dias que se planifican por adelantado
|
||||||
|
|
||||||
|
|
||||||
class Service:
|
class Service:
|
||||||
|
|||||||
Reference in New Issue
Block a user