Quazim0t0's picture
Upload app.py with huggingface_hub
b91dd05 verified
Raw
History Blame Contribute Delete
28.8 kB
"""
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 = """<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600&family=JetBrains+Mono:wght@400;500;700&display=swap');
:root{--paper:#f7f5ee;--paper2:#f2efe2;--ink:#1f1f1d;--muted:#8c918b;--hairline:#d6d3c4;
--green:#317f3f;--green2:#2a5931;--gold:#c79a2e;--gold2:#9c7714}
.dcx{font-family:"Inter","Helvetica Neue",sans-serif;font-weight:300;color:var(--ink);
font-size:13px;line-height:1.7;margin:4px 0}
.dcx .mono{font-family:"JetBrains Mono",ui-monospace,monospace}
.dcx .note{background:var(--paper2);border:1px solid var(--hairline);border-radius:4px;
padding:12px 14px;color:#5a5a55;font-size:13px}
.dcx .h{font-family:"JetBrains Mono",ui-monospace,monospace;font-size:12px;font-weight:500;
letter-spacing:.16em;text-transform:uppercase;color:var(--ink);margin:6px 0 12px;
padding-bottom:8px;border-bottom:1px solid var(--hairline)}
.dcx .p{color:var(--muted)}
.dcx .g{color:var(--green2);font-weight:600}
.dcx .chain{display:flex;gap:0;align-items:stretch;flex-wrap:wrap;margin:8px 0}
.dcx .link{align-self:center;color:var(--hairline);font-size:18px;margin:0 2px 22px;font-weight:700}
.dcx .card{flex:1;min-width:180px;background:var(--paper);border:1px solid var(--hairline);
border-radius:4px;padding:12px 13px;position:relative;overflow:hidden;transition:box-shadow .3s,border-color .3s}
.dcx .card .nm{font-family:"JetBrains Mono",ui-monospace,monospace;font-weight:500;font-size:12px;
letter-spacing:.06em;text-transform:uppercase}
.dcx .card .meta{color:var(--muted);font-size:11px;margin-top:4px;min-height:28px;line-height:1.45}
.dcx .card .bar{height:6px;background:var(--paper2);border:1px solid var(--hairline);border-radius:99px;margin-top:9px;overflow:hidden}
.dcx .card .fill{height:100%;border-radius:99px;animation:dcxw .7s ease}
.dcx .card .pct{font-size:10px;color:var(--muted);margin-top:5px;letter-spacing:.04em;text-transform:uppercase;font-family:"JetBrains Mono",monospace}
.dcx .badge{position:absolute;top:9px;right:10px;font-family:"JetBrains Mono",monospace;font-size:9px;
font-weight:700;letter-spacing:.12em;padding:3px 8px;border-radius:99px;color:var(--paper);background:var(--green)}
@keyframes dcxw{from{width:0}}
.dcx .gen{background:var(--paper2);border:1px solid var(--hairline);border-radius:4px;padding:13px 15px;
margin:12px 0;font-size:14px;line-height:1.8;font-family:"JetBrains Mono",ui-monospace,monospace;word-break:break-all}
.dcx .caret{display:inline-block;width:8px;height:16px;border-radius:1px;background:var(--green);
margin-left:2px;vertical-align:text-bottom;animation:dcxb .8s steps(1) infinite}
@keyframes dcxb{50%{opacity:0}}
.dcx .sub{color:var(--muted);font-size:12px;line-height:1.6;margin-top:10px}
.dcx .stats{display:flex;gap:0;flex-wrap:wrap;margin:12px 0;border:1px solid var(--hairline);border-radius:4px;overflow:hidden}
.dcx .stat{flex:1;min-width:120px;text-align:center;background:var(--paper);padding:16px 10px;border-right:1px solid var(--hairline)}
.dcx .stat:last-child{border-right:none}
.dcx .stat .v{font-family:"JetBrains Mono",monospace;font-size:26px;font-weight:700;line-height:1;color:var(--green2)}
.dcx .stat .l{font-size:10px;color:var(--muted);margin-top:8px;letter-spacing:.06em;text-transform:uppercase;line-height:1.4}
.dcx table{border-collapse:collapse;width:100%;margin:10px 0;font-size:12.5px}
.dcx th,.dcx td{border:1px solid var(--hairline);padding:8px 11px;text-align:left}
.dcx th{background:var(--paper2);color:var(--ink);font-family:"JetBrains Mono",monospace;font-weight:500;
font-size:10px;letter-spacing:.1em;text-transform:uppercase}
.dcx td.n{text-align:right;font-variant-numeric:tabular-nums;font-family:"JetBrains Mono",monospace}
/* --- live 2D double-helix (our own take on a base-by-base DNA viz) --- */
.dcx .helixwrap{background:var(--paper2);border:1px solid var(--hairline);border-radius:4px;padding:8px 12px;margin:12px 0;overflow-x:auto}
.dcx .helix-svg{display:block;margin:1px 0}
.dcx .hx-strand{fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;opacity:.5}
.dcx .hx-strand.back{opacity:.24}
.dcx .hx-rung{stroke:var(--hairline);stroke-width:1}
.dcx .hx-rung.user{stroke:#e6e3d6}
.dcx .hx-base{font-family:"JetBrains Mono",monospace;font-size:9px;font-weight:700;text-anchor:middle;dominant-baseline:central}
.dcx .hx-legend{display:flex;gap:13px;flex-wrap:wrap;font-family:"JetBrains Mono",monospace;font-size:9px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);margin:2px 0 4px}
.dcx .hx-dot{display:inline-block;width:8px;height:8px;border-radius:2px;margin-right:5px;vertical-align:middle}
/* --- tokenization tracks (our take on carbon-tokenization-02): per-base + 6-mer --- */
.dcx .seqtrack{font-family:"JetBrains Mono",monospace;font-size:11px;background:var(--paper);border:1px solid var(--hairline);border-radius:4px;padding:8px 10px;display:flex;flex-wrap:wrap;gap:1px;margin:8px 0 2px}
.dcx .seqb{display:inline-flex;align-items:center;justify-content:center;width:18px;height:20px;border-radius:2px;color:#fff;font-weight:500}
.dcx .seqb.A{background:#1A7A40}.dcx .seqb.T{background:#b00020}.dcx .seqb.C{background:#2c5aa0}.dcx .seqb.G{background:#b8862c}
.dcx .tkrow{display:flex;gap:14px;align-items:baseline;margin:12px 0 2px;flex-wrap:wrap}
.dcx .tklabel{font-family:"JetBrains Mono",monospace;font-size:9.5px;font-weight:500;color:#5b5b56;text-transform:uppercase;letter-spacing:1.6px}
.dcx .tkstat{font-family:"JetBrains Mono",monospace;font-size:10px;color:var(--muted);letter-spacing:.5px}
.dcx .tkstat .n{font-weight:600;color:var(--green2)}
.dcx .tokrow{display:flex;flex-wrap:wrap;align-items:center;gap:0}
.dcx .tok{display:inline-flex;align-items:center;font-family:"JetBrains Mono",monospace;font-size:11px;letter-spacing:.5px;padding:4px 8px;margin:2px;border:1px solid #ccc;border-radius:3px;background:#fff;color:var(--ink)}
.dcx .tok.kmer{background:rgba(49,127,63,.10);border-color:rgba(49,127,63,.5);color:var(--green2);font-weight:500}
/* --- editorial hero banner (dotted texture + faint green edge stripes) --- */
.dc-banner{position:relative;overflow:hidden;border:1px solid var(--hairline);border-radius:6px;margin:2px 0 6px;
background:radial-gradient(circle at 22% 32%,rgba(0,0,0,.06),transparent 1px),
radial-gradient(circle at 78% 64%,rgba(0,0,0,.055),transparent 1px),
linear-gradient(90deg,rgba(49,127,63,.04),transparent 32%,transparent 68%,rgba(199,154,46,.05)),
var(--paper);
background-size:7px 7px,11px 11px,auto,auto}
.dc-binner{position:relative;padding:22px 26px;font-family:"JetBrains Mono",ui-monospace,monospace}
.dc-ident{display:flex;align-items:center;gap:11px;margin-bottom:16px}
.dc-mark{font-size:30px;line-height:1}
.dc-title{font-size:13px;font-weight:700;letter-spacing:.2em;text-transform:uppercase;color:var(--ink)}
.dc-path{font-size:10px;font-weight:400;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);margin-top:2px}
.dc-word{font-family:"JetBrains Mono",monospace;font-size:40px;font-weight:700;letter-spacing:-.01em;color:var(--ink);line-height:1.05;margin:4px 0 6px}
.dc-word .dot{color:var(--gold)}
.dc-tag{font-family:"Inter",sans-serif;font-weight:300;font-size:13px;color:#5a5a55;max-width:560px;line-height:1.6}
.dc-motif{display:flex;align-items:center;gap:4px;flex-wrap:wrap;margin-top:18px}
.dc-chip{font-family:"JetBrains Mono",monospace;font-size:10px;letter-spacing:.06em;text-transform:uppercase;
background:var(--paper2);border:1px solid var(--hairline);border-radius:99px;padding:5px 11px;color:var(--ink)}
.dc-tie{color:var(--green);font-size:13px;font-weight:700}
.dc-rule{height:1px;background:var(--hairline);margin:14px 0}
</style>"""
def _wrap(body):
return _CSS + "<div class='dcx'>" + body + "</div>"
def _esc(s):
return _h.escape(s or "").replace("\n", "<br>")
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"<div class='note'>⏳ Loading the four ~74M specialists + {action.lower()}… "
"first run can take ~20–40s on CPU; every run after is fast.</div>")
return _wrap(f"<div class='note'>⏳ {action}…</div>")
def _msg(title, body):
return _wrap(f"<div class='note'><b>{title}</b><br>{body}</div>")
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"<span class='badge' style='background:{c}'>ROUTED βœ“</span>" if win else ""
meta = (f"{DESC.get(n,'')}<br>{v:.3f} bits/base (lower = more at home)"
if v is not None else f"{DESC.get(n,'')}<br>…")
bar = (f"<div class='bar'><div class='fill' style='width:{conf*100:.1f}%;background:{c}'></div></div>"
f"<div class='pct'>confidence {conf*100:.0f}%</div>") if v is not None else \
"<div class='bar'></div><div class='pct'>…</div>"
cells.append(
f"<div class='card' style='{style}'>{badge}"
f"<div class='nm' style='color:{c}'>{EMOJI.get(n, n)}</div>"
f"<div class='meta'>{meta}</div>{bar}</div>")
if i < len(doms) - 1:
cells.append("<div class='link'>β¬­</div>")
return "<div class='chain'>" + "".join(cells) + "</div>"
def _gen_box(prompt, gen, live=False):
caret = "<span class='caret'></span>" if live else ""
return (f"<div class='gen'><span class='p'>{_esc(prompt)}</span>"
f"<span class='g'>{_esc(gen)}</span>{caret}</div>")
# ---- 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"<svg class='helix-svg' width='{w}' height='{_HX_ROWH}' "
f"viewBox='0 0 {w} {_HX_ROWH}' xmlns='http://www.w3.org/2000/svg'>",
f"<polyline class='hx-strand' style='stroke:{accent}' points='{_hx_strand(n,1)}'/>",
f"<polyline class='hx-strand back' style='stroke:{accent}' points='{_hx_strand(n,-1)}'/>"]
for i in range(n):
x = i * _HX_SP + _HX_SP / 2
ang = (i + 0.5) * 2 * math.pi / _HX_TURN
yt = _HX_YC + _HX_AMP * math.sin(ang); yb = _HX_YC - _HX_AMP * math.sin(ang)
kind = "user" if start + i < user_len else "gen"
out.append(f"<line class='hx-rung {kind}' x1='{x:.1f}' y1='{yt:.1f}' x2='{x:.1f}' y2='{yb:.1f}'/>")
for i in range(n):
x = i * _HX_SP + _HX_SP / 2
ang = (i + 0.5) * 2 * math.pi / _HX_TURN
yt = _HX_YC + _HX_AMP * math.sin(ang); yb = _HX_YC - _HX_AMP * math.sin(ang)
b = bases[i]; comp = _COMP.get(b, "N")
gen = start + i >= user_len
col = _BASE_COL.get(b, "#999") if gen else _USER_COL
ccol = _BASE_COL.get(comp, "#999") if gen else _USER_COL
op = "1" if gen else ".6"
out.append(f"<text class='hx-base' x='{x:.1f}' y='{yt:.1f}' style='fill:{col};opacity:{op}'>{b}</text>")
out.append(f"<text class='hx-base' x='{x:.1f}' y='{yb:.1f}' style='fill:{ccol};opacity:{op}'>{comp}</text>")
out.append("</svg>")
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 = "<span class='caret'></span>" if live else ""
legend = ("<div class='hx-legend'>"
+ "".join(f"<span><span class='hx-dot' style='background:{_BASE_COL[b]}'></span>{b}</span>" for b in "ACGT")
+ f"<span><span class='hx-dot' style='background:{_USER_COL}'></span>your input</span></div>")
return f"<div class='helixwrap'>{''.join(rows) or '&nbsp;'}{caret}</div>{legend}"
def _seq_track(gen):
"""Per-base colored track of the generated bases (our take on the tokenization demo)."""
cells = "".join(f"<span class='seqb {c}'>{c}</span>" for c in gen if c in "ACGT")
return f"<div class='seqtrack'>{cells or '&nbsp;'}</div>"
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"<span class='tok kmer'>{t}</span>" for t in toks)
head = ("<div class='tkrow'><span class='tklabel'>6-mer tokens</span>"
f"<span class='tkstat'>tokens <span class='n'>{len(toks)}</span></span>"
f"<span class='tkstat'>bases <span class='n'>{len(s)}</span></span>"
"<span class='tkstat'>6 bases / token</span></div>")
return head + f"<div class='tokrow'>{chips}</div>"
FOOTER = ("Four ~74M DNA/RNA specialists (β‰ˆ295M total, <b>under Carbon-500M</b>), 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 <b>100.0%</b>. 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("<div class='h'>πŸ”— Sending the sequence down the chain…</div>" + _cards(bpb))
home, _ = dc.route(seq)
c = COLOR.get(home, "#9b59b6")
head = (f"<div class='h'>🧭 Routed to <span style='color:{c}'>{EMOJI.get(home, home)}</span>"
f" β€” the specialist most at home with your sequence</div>" + _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"<div class='h'>🧬 {EMOJI.get(home, home)} β€” building the strand base-by-base "
f"<span style='color:var(--muted)'>({mode})</span></div>")
rawhdr = "<div class='h'>raw sequence β€” select to copy</div>"
# 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 = ("<div class='sub'>πŸ§ͺ <b>Generation is exploratory</b> β€” 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 <b>routing</b> and per-base likelihood "
"are the result here, not Carbon-level generation.</div>")
yield _wrap(head + hxhead + _helix(ctx, gen, c, live=False)
+ _seq_track(gen) + _kmer_strip(gen)
+ rawhdr + _gen_box(ctx, gen, live=False)
+ gennote + f"<div class='sub'>{FOOTER}</div>")
else:
_WARMED["done"] = True
yield _wrap(head + f"<div class='sub'>{FOOTER}</div>")
STATS_HTML = _wrap(
"<div class='h'>πŸ“Š DaisyChain vs Carbon-500M β€” the fair baseline</div>"
"<div class='stats'>"
"<div class='stat'><div class='v' style='color:#37b24d'>100.0%</div>"
"<div class='l'>routing accuracy<br>(held-out)</div></div>"
"<div class='stat'><div class='v' style='color:#7c5cff'>β‰ˆ295M</div>"
"<div class='l'>total params<br>(4 Γ— ~74M) &lt; Carbon-500M</div></div>"
"<div class='stat'><div class='v' style='color:#22b8cf'>~7Γ—</div>"
"<div class='l'>cheaper per query<br>(one 74M specialist active)</div></div>"
"</div>"
"<table><tr><th>metric</th><th>DaisyChain</th><th>Carbon-500M</th></tr>"
"<tr><td>Likelihood β€” bits/base, base-pair FNS (↓ better)</td><td class='n'>1.88</td><td class='n'>1.79</td></tr>"
"<tr><td>Seq-recovery, eukaryote β€” FNS (↑ better)</td><td class='n'>31.5%</td><td class='n'>38.9%</td></tr>"
"<tr><td>Seq-recovery, bacteria β€” FNS (↑ better)</td><td class='n'>40.9%</td><td class='n'>54.1%</td></tr>"
"</table>"
"<div class='sub'>Four ~74M specialists (β‰ˆ295M total, <b>under Carbon-500M</b>); 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.</div>")
BANNER = _CSS + """
<div class='dcx'><div class='dc-banner'><div class='dc-binner'>
<div class='dc-ident'>
<span class='dc-mark'>🌼</span>
<div>
<div class='dc-title'>DAISYCHAIN</div>
<div class='dc-path'>DAISYCHAINAI / GENOMICS Β· ROUTED DNA SPECIALISTS</div>
</div>
</div>
<div class='dc-word'>DaisyChain<span class='dot'>.</span></div>
<div class='dc-tag'>A modular genomic mind. Four dense ~74M DNA/RNA specialists
(&approx;295M total, <b>under Carbon-500M</b>), each distilled per-domain from Carbon-500M.
A learned router reads how <i>surprised</i> each specialist is by your sequence
(bits/base) plus its hidden state, then hands the work to its home specialist β€”
held-out routing accuracy <b>100.0%</b>. Watch it route in real time.</div>
<div class='dc-motif'>
<span class='dc-chip'>🧬 Eukaryote</span><span class='dc-tie'>β€”</span>
<span class='dc-chip'>🦠 Prokaryote</span><span class='dc-tie'>β€”</span>
<span class='dc-chip'>πŸ“œ mRNA</span><span class='dc-tie'>β€”</span>
<span class='dc-chip'>βœ‚οΈ mRNA-splice</span>
</div>
</div></div></div>"""
# 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("<div class='h'>The chain Β· paste a sequence to light it up</div>"
+ _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()