"""Onboarding, help and diagnostics. Registered last so /help sees everything.""" from __future__ import annotations from typing import Sequence from .. import render from ..analytics import month_bounds from .base import BotContext, CommandSpec, Reply, SimpleFeature _WELCOME = """Hello ๐Ÿ‘‹ Just tell me what you spent and I'll keep track. Log it 250 coffee โ‚น1,240 groceries at bigbasket 45.50 lunch yesterday 320 uber #transport Send me things ๐Ÿ“ท a receipt photo โ€” I'll read the total ๐Ÿ“„ a bank statement (PDF, CSV, XLSX) โ€” I'll pull out the transactions and ask before saving See it back /today ยท /week ยท /month ยท /recurring ยท /advice /help for everything.""" class CoreFeature(SimpleFeature): name = "core" description = "โš™๏ธ General" priority = 90 def commands(self) -> Sequence[CommandSpec]: return ( CommandSpec("start", "What this bot does"), CommandSpec("help", "All commands"), CommandSpec("status", "Configuration and storage health"), CommandSpec("whoami", "Your Telegram user ID", hidden=True), ) def cmd_start(self, ctx: BotContext) -> Reply: return Reply(_WELCOME) def cmd_help(self, ctx: BotContext) -> Reply: body = ctx.services.registry.help_text() tail = ( "\n\nPlain text with a number is logged as an expense. " "Add #category to override the guess." ) return Reply(body + tail) def cmd_whoami(self, ctx: BotContext) -> Reply: return Reply(f"Your Telegram user ID is {ctx.user_id}.") def cmd_status(self, ctx: BotContext) -> Reply: settings = ctx.settings store = ctx.store start, _ = month_bounds(ctx.today) month_count = len(ctx.store.list_expenses(ctx.user_id, start, ctx.today)) lines = [ "Status", f"Transactions logged: {store.count(ctx.user_id)} ({month_count} this month)", f"Today (in {render.escape(settings.timezone)}): {ctx.today.isoformat()}", "", "Inference", ] llm = ctx.services.llm if llm.enabled: lines.append(f"โœ… {render.escape(llm.describe())}") else: lines.append(f"โš ๏ธ {render.escape(llm.describe())}") lines.append(" Receipts, statements and written advice are off.") lines.append(" Typed expenses, summaries and budgets still work.") lines.append("") lines.append("Access") if settings.open_access: cap = settings.uploads_per_user_per_day lines.append("๐ŸŒ Open โ€” anyone on Telegram can use this bot.") lines.append(" Each person's ledger is separate; nobody sees yours.") lines.append( f" Uploads capped at {cap}/user/day." if cap > 0 else " โš ๏ธ Uploads uncapped โ€” strangers can spend your inference credits." ) else: lines.append(f"๐Ÿ”’ Allowlist โ€” {len(settings.allowed_user_ids)} user(s).") lines.append("") lines.append("Storage") if settings.sync_enabled: lines.append(f"โœ… {render.escape(store.sync_status)}") else: lines.append( "๐Ÿ”ด Local only โ€” Space disk is ephemeral.\n" " Your data will be lost on the next restart or sleep.\n" " Set HF_DATASET_REPO to fix this." ) if gaps := settings.missing_required(): lines.append("") lines.append("Not configured") lines.extend(f"โ€ข {render.escape(gap)}" for gap in gaps) return Reply("\n".join(lines))