"""
DaisyChain β interactive routing demo (HuggingFace Space).
Paste DNA; the learned router reads how *surprised* each ~74M specialist is (bits/base)
plus its hidden state and hands the sequence to its home specialist β then that specialist
streams a continuation live. Styled after the Modular-Mind panel: animated routing cards,
a first-run loading notice, live token streaming. Every handler is a generator.
"""
import html as _h
import os
import json
import math
import gradio as gr
# ZeroGPU: @spaces.GPU allocates a GPU only for the decorated call. Falls back to a no-op
# decorator when `spaces` isn't installed (local / plain CPU).
try:
import spaces
_gpu = spaces.GPU
except Exception:
def _gpu(fn=None, **kw):
return fn if callable(fn) else (lambda f: f)
from daisychain import DaisyChain
HERE = os.path.dirname(os.path.abspath(__file__))
MODEL_REPO = os.environ.get("DAISYCHAIN_REPO", "DaisyChainAI/daisychain-genomics")
DEVICE = os.environ.get("DAISYCHAIN_DEVICE", "cpu")
# code + tokenizer + router are bundled here; pull the big specialist weights from the
# (gated) model repo on first launch using the HF_TOKEN Space secret. No silent
# swallow β if the download fails we want a visible error, not a broken-but-running app.
if not os.path.exists(os.path.join(HERE, "eukaryote", "model.safetensors")):
from huggingface_hub import snapshot_download
snapshot_download(MODEL_REPO, local_dir=HERE,
token=os.environ.get("HF_TOKEN"),
allow_patterns=["*/model.safetensors", "tokenizer.json", "router2.pt"])
_DC = {"m": None} # lazy-loaded so CUDA is never touched at import
_WARMED = {"done": False} # so the "loading" notice only shows on the first run
EMOJI = {"eukaryote": "𧬠Eukaryote", "prokaryote": "π¦ Prokaryote",
"mrna": "π mRNA", "mrna_splice": "βοΈ mRNA-splice"}
# deeper, paper-friendly tones (vs the old neon dark-theme hues)
COLOR = {"eukaryote": "#5b4bb0", "prokaryote": "#1f7a99",
"mrna": "#b03a63", "mrna_splice": "#317f3f"}
DESC = DaisyChain.DESCRIPTIONS
def _moe():
if _DC["m"] is None:
_DC["m"] = DaisyChain(root=HERE, device=DEVICE)
return _DC["m"]
# ---- HTML rendering ----------------------------------------------------------------
# Editorial "scientific-paper" aesthetic borrowed from Carbon's demo (cream paper, ink,
# green accent, mono uppercase headers) but made our own: a daisy-gold second accent and
# the chain-of-specialists motif. Tokens live in :root so the cards/bars all stay in sync.
_CSS = """"""
def _wrap(body):
return _CSS + "
" + body + "
"
def _esc(s):
return _h.escape(s or "").replace("\n", " ")
def _notice(action="Routing"):
if not _WARMED["done"]:
try:
gr.Info("First run β loading the four ~74M specialists (~20β40s on CPU). After this it's quick.")
except Exception:
pass
return _wrap(f"
β³ Loading the four ~74M specialists + {action.lower()}β¦ "
"first run can take ~20β40s on CPU; every run after is fast.
")
return _wrap(f"
β³ {action}β¦
")
def _msg(title, body):
return _wrap(f"
{title} {body}
")
def _cards(bpb, winner=None):
"""One animated card per specialist: surprise (bits/base), confidence bar, winner badge + glow.
bpb values may be None (not computed yet). Lower bits/base = more 'at home' = fuller bar."""
cells = []
doms = list(bpb.keys())
for i, n in enumerate(doms):
c = COLOR.get(n, "#9b59b6")
v = bpb[n]
win = (n == winner)
conf = max(0.0, min(1.0, (2.02 - v) / 0.5)) if v is not None else 0.0 # ~1.52..2.02 -> 1..0
style = f"border-color:{c};box-shadow:0 0 16px {c}40" if win else ""
badge = f"ROUTED β" if win else ""
meta = (f"{DESC.get(n,'')} {v:.3f} bits/base (lower = more at home)"
if v is not None else f"{DESC.get(n,'')} β¦")
bar = (f"
"
f"
confidence {conf*100:.0f}%
") if v is not None else \
"
β¦
"
cells.append(
f"
{badge}"
f"
{EMOJI.get(n, n)}
"
f"
{meta}
{bar}
")
if i < len(doms) - 1:
cells.append("
β¬
")
return "
" + "".join(cells) + "
"
def _gen_box(prompt, gen, live=False):
caret = "" if live else ""
return (f"
{_esc(prompt)}"
f"{_esc(gen)}{caret}
")
# ---- live 2D double-helix --------------------------------------------------------
# A base-by-base SVG double-helix (two sine-wave backbones + per-base rungs, each base
# letter on the top strand with its WatsonβCrick complement on the bottom). Built in
# Python so it streams inside our existing generator; ours = cream palette, our own
# nucleotide colors, strands tinted by the routed specialist's accent.
_COMP = {"A": "T", "T": "A", "C": "G", "G": "C", "N": "N"}
# shared nucleotide palette (matches our tokenization track): A green, T red, C blue, G amber
_BASE_COL = {"A": "#1A7A40", "T": "#b00020", "C": "#2c5aa0", "G": "#b8862c"}
_USER_COL = "#bdbaa9"
_HX_SP, _HX_AMP, _HX_YC, _HX_ROWH, _HX_TURN, _HX_PERROW = 14, 12, 22, 48, 10.5, 46
def _hx_strand(n, sign):
pts = []
for s in range(n * 4 + 1):
t = s / 4
x = t * _HX_SP + _HX_SP / 2
ang = (t + 0.5) * 2 * math.pi / _HX_TURN
y = _HX_YC + sign * _HX_AMP * math.sin(ang)
pts.append(f"{x:.1f},{y:.1f}")
return " ".join(pts)
def _hx_row(bases, start, user_len, accent):
n = len(bases)
w = n * _HX_SP + 6
out = [f"")
return "".join(out)
def _helix(prompt, gen, accent, live=False):
bases = [c for c in (prompt + gen) if c in "ACGTN"]
user_len = len([c for c in prompt if c in "ACGTN"])
rows, i = [], 0
while i < len(bases):
rows.append(_hx_row(bases[i:i + _HX_PERROW], i, user_len, accent))
i += _HX_PERROW
caret = "" if live else ""
legend = ("
"
+ "".join(f"{b}" for b in "ACGT")
+ f"your input
")
return f"
{''.join(rows) or ' '}{caret}
{legend}"
def _seq_track(gen):
"""Per-base colored track of the generated bases (our take on the tokenization demo)."""
cells = "".join(f"{c}" for c in gen if c in "ACGT")
return f"
{cells or ' '}
"
def _kmer_strip(gen):
"""The generated sequence cut into our model's actual non-overlapping 6-mer tokens."""
s = "".join(c for c in gen if c in "ACGTN")
toks = [s[i:i + 6] for i in range(0, len(s) - len(s) % 6, 6)]
chips = "".join(f"{t}" for t in toks)
head = ("
"
FOOTER = ("Four ~74M DNA/RNA specialists (β295M total, under Carbon-500M), each distilled "
"per-domain from Carbon-500M. A learned router reads every specialist's surprise + hidden "
"state and routes to the home specialist β held-out routing accuracy 100.0%. Only one "
"specialist runs per query (~7Γ cheaper than the 500M monolith).")
# ---- handler ----------------------------------------------------------------------
@_gpu(duration=120)
def route_run(seq, n_bases, do_gen, decode="auto"):
yield _notice("Routing & generating")
seq = (seq or "").strip()
if len(seq) < 18:
yield _msg("𧬠Enter a DNA sequence", "Paste at least 18 bases (A/C/G/T) β try an example below.")
return
dc = _moe()
doms = dc.domains
bpb = {d: None for d in doms}
# progressively reveal each specialist's surprise (the chain lighting up)
sc, hd = dc._scores_hidden(seq)
for d in doms:
bpb[d] = sc[d] / 6 / 0.6931
yield _wrap("
π Sending the sequence down the chainβ¦
" + _cards(bpb))
home, _ = dc.route(seq)
c = COLOR.get(home, "#9b59b6")
head = (f"
π§ Routed to {EMOJI.get(home, home)}"
f" β the specialist most at home with your sequence
" + _cards(bpb, winner=home))
if do_gen:
# decoding: default = base-pair (FNS) β marginalize the 6-mer softmax to six 4-way base
# distributions and sample each base, the same factorization Carbon uses. "argmax" forces
# the deterministic 6-mer best-guess (matches the recovery metric; collapses over long spans).
dl = (decode or "").lower()
greedy = "argmax" in dl
feed_ctx = seq # FULL context to the specialist (it frame-aligns + caps)
ctx = seq[-48:] # short context shown in the helix / text box
mode = "base-pair Β· FNS argmax" if greedy else "base-pair Β· FNS sampled"
hxhead = (f"
𧬠{EMOJI.get(home, home)} β building the strand base-by-base "
f"({mode})
")
rawhdr = "
raw sequence β select to copy
"
# both modes use Carbon's FNS base-level decoder; greedy=argmax per base (recovery metric),
# else top-p sampled per base.
stream = dc.generate_baselevel_stream(home, length=int(n_bases), temperature=1.0,
top_p=0.9, prompt=feed_ctx, greedy=greedy)
for gen in stream:
yield _wrap(head + hxhead + _helix(ctx, gen, c, live=True)
+ _seq_track(gen) + _kmer_strip(gen)
+ rawhdr + _gen_box(ctx, gen, live=True))
_WARMED["done"] = True
gennote = ("
π§ͺ Generation is exploratory β these ~74M specialists are "
"trained on a slice of the corpus, so sampled DNA is low-complexity (and splice / "
"bacterial domains are genuinely AT-rich). The routing and per-base likelihood "
"are the result here, not Carbon-level generation.
Four ~74M specialists (β295M total, under Carbon-500M); only one runs per "
"query, so it's ~7Γ cheaper per token. Behind the 500M / 1T-token monolith but within striking "
"distance β the gap is concentrated in the structured domains (mRNA, bacteria) and keeps closing "
"with more per-domain training. Same protocols as Carbon's eval suite (sequence recovery; per-base "
"likelihood). Carbon-500M is the right yardstick for a sub-500M modular set, not the 3B flagship.
")
BANNER = _CSS + """
πΌ
DAISYCHAIN
DAISYCHAINAI / GENOMICS Β· ROUTED DNA SPECIALISTS
DaisyChain.
A modular genomic mind. Four dense ~74M DNA/RNA specialists
(≈295M total, under Carbon-500M), each distilled per-domain from Carbon-500M.
A learned router reads how surprised each specialist is by your sequence
(bits/base) plus its hidden state, then hands the work to its home specialist β
held-out routing accuracy 100.0%. Watch it route in real time.
"""
# Light editorial chrome for the Gradio shell so the cream paper extends to the whole page.
# We pin Gradio's theme CSS variables (for BOTH light and .dark) to the paper palette so the
# text never renders white-on-cream when a visitor's browser/Space defaults to dark mode.
_PAGE_CSS = """
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600&family=JetBrains+Mono:wght@400;500;700&display=swap');
.gradio-container, .gradio-container.dark, .dark, body, body.dark{
--body-background-fill:#f7f5ee!important;
--background-fill-primary:#f7f5ee!important;
--background-fill-secondary:#f2efe2!important;
--block-background-fill:#fbfaf4!important;
--block-label-background-fill:#f2efe2!important;
--input-background-fill:#fffdf6!important;
--body-text-color:#1f1f1d!important;
--body-text-color-subdued:#5a5a55!important;
--block-title-text-color:#1f1f1d!important;
--block-label-text-color:#5a5a55!important;
--block-info-text-color:#5a5a55!important;
--border-color-primary:#d6d3c4!important;
--neutral-50:#f7f5ee!important;
--table-even-background-fill:#fbfaf4!important;
--table-odd-background-fill:#f2efe2!important;
--table-row-focus:#eef3e9!important;
--table-text-color:#1f1f1d!important;
background:#f7f5ee!important;
color:#1f1f1d!important;
}
/* Examples dataset table rows (were rendering black in dark mode) */
.gradio-container .gr-samples-table, .gradio-container [class*='dataset'] table,
.gradio-container [class*='dataset'] td, .gradio-container [class*='dataset'] tr,
.gradio-container [class*='dataset'] tbody{background:#fbfaf4!important;color:#1f1f1d!important}
.gradio-container [class*='dataset'] tr:nth-child(even) td{background:#f2efe2!important}
/* Radio / checkbox options (were rendering black in dark mode) */
.gradio-container [class*='radio'] label, .gradio-container fieldset label,
.gradio-container [class*='checkbox'] label, .gradio-container .wrap label{
background:#fbfaf4!important;color:#1f1f1d!important;border:1px solid #d6d3c4!important}
.gradio-container [class*='radio'] label *, .gradio-container fieldset label *,
.gradio-container [class*='checkbox'] label *{color:#1f1f1d!important}
.gradio-container input[type=radio],.gradio-container input[type=checkbox]{accent-color:#317f3f!important}
.gradio-container{font-family:"Inter","Helvetica Neue",sans-serif!important;max-width:1080px!important}
/* force any Gradio-rendered label / markdown / example text to ink, never white */
.gradio-container label, .gradio-container .prose, .gradio-container p,
.gradio-container span, .gradio-container td, .gradio-container th,
.gradio-container .gr-text-input, .gradio-container input, .gradio-container textarea{color:#1f1f1d!important}
.gradio-container input::placeholder, .gradio-container textarea::placeholder{color:#9c9989!important}
footer{display:none!important}
.gr-button-primary, button.primary{background:#317f3f!important;border:1px solid #2a5931!important;color:#f7f5ee!important;
font-family:"JetBrains Mono",monospace!important;letter-spacing:.08em!important;text-transform:uppercase!important;font-size:12px!important}
.gr-button-primary:hover, button.primary:hover{background:#2a5931!important}
.gr-button-primary *, button.primary *{color:#f7f5ee!important}
"""
def build():
theme = gr.themes.Default(primary_hue="green", neutral_hue="stone",
font=[gr.themes.GoogleFont("Inter"), "sans-serif"],
font_mono=[gr.themes.GoogleFont("JetBrains Mono"), "monospace"])
# force the light palette so text is never white-on-cream if a visitor defaults to dark mode
_force_light = ("() => { const u = new URL(window.location.href);"
" if (u.searchParams.get('__theme') !== 'light') {"
" u.searchParams.set('__theme','light'); window.location.replace(u.href); } }")
with gr.Blocks(title="DaisyChain β modular genomic mind", theme=theme, css=_PAGE_CSS,
js=_force_light) as demo:
gr.HTML(BANNER)
with gr.Row():
seq = gr.Textbox(label="DNA SEQUENCE", lines=3, scale=4,
placeholder="ACGT⦠(eukaryotic, bacterial, mRNA, or splice-site DNA)")
n = gr.Slider(60, 300, value=90, step=30, label="GENERATE BASES", scale=1)
with gr.Row():
gen_ck = gr.Checkbox(value=True, label="stream a continuation from the routed specialist")
decode = gr.Radio(["base-pair (FNS)", "greedy (argmax)"], value="base-pair (FNS)",
label="DECODING", scale=1,
info="base-pair (FNS) = Carbon-style: each base sampled from the marginalized per-position distribution (base-pair control, no 6-mer repeat loops); argmax = deterministic best guess (matches recovery, collapses over long spans)")
btn = gr.Button("π Route through the DaisyChain", variant="primary")
out = gr.HTML(_wrap("
The chain Β· paste a sequence to light it up
"
+ _cards({d: None for d in DaisyChain.DESCRIPTIONS})))
btn.click(route_run, [seq, n, gen_ck, decode], out)
try:
ex = json.load(open(os.path.join(HERE, "examples.json")))
gr.Examples([[v, 90, True, "base-pair (FNS)"] for v in ex.values()],
inputs=[seq, n, gen_ck, decode],
label="Example sequences (one per domain)")
except Exception:
pass
gr.HTML(STATS_HTML)
return demo
if __name__ == "__main__":
build().launch()