"""Interactive Gradio demo for the encoder-on-LFM2.5 transaction model. Three-tab structure (Demo / Why Liquid / Integration). Demo is the landing tab so a customer immediately sees what the model does; Why Liquid is the architectural pitch; Integration is the build-it-yourself playbook. Same Gradio theme + CSS as the rest of Liquid's customer- facing demos for visual consistency. The demo is intentionally self-contained: no side-by-side comparison against an alternative architecture, no per-tab references to other work. The argument is the architecture pattern itself — encoder + frozen LFM2.5 backbone + LoRA + multi-head — and the reader gets a clean read of it. Usage: python -m encoder.src.demo.app \\ --checkpoint encoder/experiments/.../step_004999.pt \\ --model-config encoder/configs/model_nocompress.yaml \\ --schema data/schema.yaml \\ --data-dir data/synthetic \\ --port 7860 """ from __future__ import annotations import argparse import time from pathlib import Path import gradio as gr import torch from src.data.schema import load_schema from src.demo.app import DemoData # reuse parent's curated-test-set loader from src.demo.decode import TransactionDecoder from src.demo.merchant_catalog import DemoMerchantCatalog from src.demo.profile_inference import format_profile_html, infer_profile from encoder.src.demo.cold_start import render_cold_start from encoder.src.demo.inference import EncoderDemoModel from encoder.src.demo.render import ( format_amount_predictions, format_fraud_score, format_mcc_predictions, format_merchant_predictions, format_timeline, render_encoder_integration, render_why_encoder, ) # --------------------------------------------------------------------------- # Header # --------------------------------------------------------------------------- _HEADER_HTML = """

Encoder on LFM2.5 — Transaction Foundation Model

Liquid AI · LFM2.5-350M base · Encoder + LoRA + multi-head

""" # Container width applied to every tab's content so the three surfaces # read at the same width. Kept in sync with render.py's _CONTAINER_WIDTH. _CONTAINER_WIDTH = "1180px" # --------------------------------------------------------------------------- # Demo tab intro — standalone, no comparison framing # --------------------------------------------------------------------------- _DEMO_INTRO_HTML = f"""
Live multi-head inference on a frozen LFM2.5-350M backbone
Pick a curated customer archetype, click Run Inference, watch four task heads predict in parallel from one shared backbone — fraud probability, next-merchant, amount bucket, and merchant category (MCC). The encoder turns the 64-transaction history into 960 pseudo-tokens; the frozen LFM2.5-350M backbone with LoRA processes them; per-task heads pool the hidden states. For the architectural rationale see Why Liquid; for the build-it-yourself playbook see Integration.
""" # --------------------------------------------------------------------------- # CSS — scoped to the encoder demo # --------------------------------------------------------------------------- _CSS = f""" /* Force light mode regardless of system preference */ :root, .dark {{ color-scheme: light !important; }} .gradio-container {{ background: #f5f5f5 !important; max-width: 1280px !important; margin: auto !important; padding: 1.5rem !important; }} /* Tabs: pill-style matching the rest of Liquid's customer-facing demos */ .tabs {{ background: transparent !important; }} .tab-nav {{ background: #f5f5f5 !important; border: none !important; border-bottom: 1px solid rgba(0,0,0,0.1) !important; gap: 4px !important; padding: 4px 0 !important; }} .tab-nav button {{ font-weight: 500 !important; font-size: 14px !important; color: #737373 !important; background: transparent !important; border: none !important; border-bottom: 2px solid transparent !important; padding: 8px 16px !important; border-radius: 0 !important; transition: all 0.15s ease !important; }} .tab-nav button:hover {{ color: #171717 !important; background: rgba(0,0,0,0.03) !important; }} .tab-nav button.selected {{ color: #171717 !important; font-weight: 600 !important; border-bottom: 2px solid #171717 !important; background: transparent !important; }} /* Run button: pill style, dark fill. Scoped by elem_id so it does not bleed into Gradio's internal radio/checkbox