Spaces:
Sleeping
Sleeping
| """ | |
| DVNC.AI β root app.py | |
| Fixed: all internal module imports now use correct underscore names | |
| matching the actual function/constant names in dvnc_ai_v2_hf/. | |
| """ | |
| # ββ Standard library ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| import html | |
| import random | |
| import re | |
| import sys | |
| from pathlib import Path | |
| from typing import Dict, List, Optional | |
| # Ensure the repository root is on sys.path so the package is importable | |
| ROOT = Path(__file__).resolve().parent | |
| if str(ROOT) not in sys.path: | |
| sys.path.insert(0, str(ROOT)) | |
| # ββ Third-party βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| import gradio as gr | |
| # ββ Internal modules ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| from dvnc_ai_v2_hf.agent_route_cards import build_agent_route_cards_html | |
| from dvnc_ai_v2_hf.discovery_app_bridge import ( | |
| get_default_route_state, | |
| get_discovery_css, | |
| get_initial_discovery_timeline_html, | |
| ) | |
| from dvnc_ai_v2_hf.dvnc_ui_layout import get_dvnc_layout_css | |
| from dvnc_ai_v2_hf.graph_canvas_patch import render_graph_canvas_html | |
| from dvnc_ai_v2_hf.self_learning_graph import ( | |
| DEFAULT_SOURCES, | |
| SEARCH_MODES, | |
| SOURCE_OPTIONS, | |
| build_journal_html, | |
| ingest_selected_papers, | |
| parse_uploaded_pdf, | |
| render_parse_result, | |
| run_paper_discovery, | |
| safe_text, | |
| ) | |
| # ββ Constants βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| MODELS = [ | |
| { | |
| "name": "DVNC Sovereign", | |
| "tag": "flagship", | |
| "desc": "Maximum depth orchestration for frontier discovery", | |
| }, | |
| { | |
| "name": "DVNC Atlas", | |
| "tag": "research", | |
| "desc": "Balanced reasoning, graph traversal, and synthesis", | |
| }, | |
| { | |
| "name": "DVNC Curie", | |
| "tag": "lab", | |
| "desc": "Experimental hypothesis generation for anomalous signals", | |
| }, | |
| ] | |
| AGENTS = [ | |
| "Query Interpreter", | |
| "Graph Divergence Mapper", | |
| "Evidence Harvester", | |
| "Analogy Engine", | |
| "Hypothesis Composer", | |
| "Adversarial Critic", | |
| "Experimental Program Designer", | |
| ] | |
| NODES = [ | |
| {"id": "seed", "label": "Seed Query", "group": "core", "x": 10, "y": 0, "z": 0}, | |
| {"id": "bio", "label": "Biomaterials", "group": "domain", "x": 24, "y": 12, "z": -8}, | |
| {"id": "card", "label": "Cardiac Repair", "group": "domain", "x": 38, "y": 3, "z": 14}, | |
| {"id": "nano", "label": "Nanostructure", "group": "bridge", "x": 24, "y": -18, "z": 16}, | |
| {"id": "selfasm", "label": "Self-Assembly", "group": "bridge", "x": 40, "y": -16, "z": -16}, | |
| {"id": "electro", "label": "Electro-signalling", "group": "mechanism", "x": 58, "y": 10, "z": -10}, | |
| {"id": "immune", "label": "Immune Modulation", "group": "mechanism", "x": 64, "y": -8, "z": 10}, | |
| {"id": "trial", "label": "Validation Path", "group": "outcome", "x": 80, "y": 0, "z": 0}, | |
| {"id": "alt1", "label": "Piezoelectric Scaffold", "group": "candidate", "x": 56, "y": 26, "z": 14}, | |
| {"id": "alt2", "label": "Peptide Mesh", "group": "candidate", "x": 54, "y": -27, "z": -14}, | |
| ] | |
| EDGES = [ | |
| ("seed", "bio"), ("seed", "nano"), ("bio", "card"), ("nano", "selfasm"), | |
| ("selfasm", "electro"), ("card", "immune"), ("electro", "trial"), | |
| ("immune", "trial"), ("card", "alt1"), ("selfasm", "alt2"), | |
| ("alt1", "trial"), ("alt2", "trial"), | |
| ] | |
| DEFAULT_PATH = ["seed", "nano", "selfasm", "electro", "trial"] | |
| CANDIDATES = [ | |
| { | |
| "title": "Piezoelectric Scaffold Cascade", | |
| "front": "Use mechano-electric scaffolds to convert cardiac strain into micro-current signalling.", | |
| "back": "Discovery path: anomalous healing signal -> piezoelectric analog -> ion-channel entrainment -> tissue regeneration. Risk: power density and fibrosis coupling.", | |
| "score": 92, | |
| "novelty": "High", | |
| "agent": "Hypothesis Composer", | |
| }, | |
| { | |
| "title": "Peptide Self-Assembly Mesh", | |
| "front": "Deploy dynamic peptide meshes that self-assemble around damaged myocardium and guide repair.", | |
| "back": "Discovery path: self-assembly -> local immune choreography -> regenerative substrate formation. Risk: degradation timing and targeting specificity.", | |
| "score": 88, | |
| "novelty": "High", | |
| "agent": "Analogy Engine", | |
| }, | |
| { | |
| "title": "Immune-Tuned Conductive Hydrogel", | |
| "front": "Blend conductivity with macrophage-state modulation to reduce scarring and restore conduction.", | |
| "back": "Discovery path: inflammation mismatch -> conductive medium -> macrophage polarization -> synchronized healing. Risk: persistence and biocompatibility.", | |
| "score": 85, | |
| "novelty": "Medium-High", | |
| "agent": "Adversarial Critic", | |
| }, | |
| ] | |
| ACADEMIC_INSIGHTS = [ | |
| { | |
| "hypothesis": "Implementation of mechano-electric scaffolds to transduce cardiac strain into localized micro-current signalling for myocardial regeneration.", | |
| "metrics": { | |
| "Novelty": 92, | |
| "Mechanistic clarity": 85, | |
| "Experimental tractability": 78, | |
| "Cross-domain distance": 94, | |
| }, | |
| "outline": ( | |
| "1. Synthesize candidate piezoelectric biomaterial scaffolds with tunable strain-electric coupling.\n" | |
| "2. Evaluate in vitro electromechanical transduction and subsequent ion-channel entrainment.\n" | |
| "3. Conduct in vivo comparative models to assess regenerative efficacy against gold-standard substrates.\n" | |
| "4. Rigorously validate to exclude pathological fibrosis and power-density toxicity." | |
| ), | |
| "path": ["seed", "bio", "card", "alt1", "trial"], | |
| }, | |
| { | |
| "hypothesis": "Deployment of dynamic peptide networks that self-assemble post-infarction to orchestrate local immunological responses and guide substrate regeneration.", | |
| "metrics": { | |
| "Novelty": 88, | |
| "Mechanistic clarity": 82, | |
| "Experimental tractability": 86, | |
| "Cross-domain distance": 85, | |
| }, | |
| "outline": ( | |
| "1. Formulate peptide sequences programmed for triggered in situ self-assembly within the myocardial infarct zone.\n" | |
| "2. Quantify macrophage polarization and local immune choreography post-deployment.\n" | |
| "3. Map the temporospatial degradation profile against de novo tissue formation.\n" | |
| "4. Falsify against off-target aggregation and delayed clearance risks." | |
| ), | |
| "path": ["seed", "nano", "selfasm", "alt2", "trial"], | |
| }, | |
| { | |
| "hypothesis": "Integration of conductive hydrogels with immunomodulatory properties to simultaneously bridge electrical uncoupling and mitigate adverse fibrotic scarring.", | |
| "metrics": { | |
| "Novelty": 85, | |
| "Mechanistic clarity": 90, | |
| "Experimental tractability": 88, | |
| "Cross-domain distance": 79, | |
| }, | |
| "outline": ( | |
| "1. Fabricate biocompatible hydrogels featuring precisely tuned electrical conductivity and immunomodulatory motifs.\n" | |
| "2. Monitor electrophysiological synchronization across the scaffold-tissue interface.\n" | |
| "3. Assess macrophage state transitions and suppression of adverse fibrotic remodelling.\n" | |
| "4. Validate long-term persistence, hemocompatibility, and mechanical integration." | |
| ), | |
| "path": ["seed", "bio", "card", "immune", "trial"], | |
| }, | |
| ] | |
| # ββ Utility helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def norm_text(x: Optional[str]) -> str: | |
| return re.sub(r"\s+", " ", (x or "")).strip() | |
| def build_learning_graph_html(nodes, edges, title="Self-Learning Knowledge Graph"): | |
| return render_graph_canvas_html( | |
| { | |
| "status": "ok" if (nodes or edges) else "empty", | |
| "nodes": nodes or [], | |
| "edges": edges or [], | |
| }, | |
| title=title, | |
| height=780, | |
| ) | |
| # ββ HTML builders βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def build_connectome_html(path_ids: List[str]) -> str: | |
| active = set(path_ids) | |
| node_map = {n["id"]: n for n in NODES} | |
| path_pairs = { | |
| pair | |
| for i in range(len(path_ids) - 1) | |
| for pair in [(path_ids[i], path_ids[i + 1]), (path_ids[i + 1], path_ids[i])] | |
| } | |
| baselines, activelines, circles, labels = [], [], [], [] | |
| for a, b in EDGES: | |
| na, nb = node_map[a], node_map[b] | |
| x1, y1 = na["x"] * 8 + 80, na["y"] * 6 + 280 | |
| x2, y2 = nb["x"] * 8 + 80, nb["y"] * 6 + 280 | |
| baselines.append(f'e class="edge" x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}"/>') | |
| if (a, b) in path_pairs: | |
| activelines.append(f'e class="edge active" x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}"/>') | |
| for n in NODES: | |
| cx, cy = n["x"] * 8 + 80, n["y"] * 6 + 280 | |
| is_active = n["id"] in active | |
| state = "chosen" if is_active else "idle" | |
| halo_cls = "halo active" if is_active else "halo" | |
| lbl_cls = "label active" if is_active else "label" | |
| radius = 18 if is_active else 13 | |
| halo_r = 30 if is_active else 0 | |
| circles.append( | |
| f'ircle class="{halo_cls}" cx="{cx}" cy="{cy}" r="{halo_r}"/>' | |
| f'ircle class="node {state}" cx="{cx}" cy="{cy}" r="{radius}"/>' | |
| f'<title>{safe_text(n["label"])}</title>' | |
| f'<text class="{lbl_cls}" x="{cx}" y="{cy + radius + 14}" text-anchor="middle">{safe_text(n["label"][:18])}</text>' | |
| ) | |
| return f"""<div class="brain-shell panel"> | |
| <div class="brain-header"> | |
| <div><p class="eyebrow">Connectome</p><h3>3D Connectome</h3></div> | |
| <div class="brain-legend"> | |
| <span><span class="dot dot-live"></span>lit path</span> | |
| <span><span class="dot dot-chosen"></span>chosen node</span> | |
| <span><span class="dot dot-idle"></span>available node</span> | |
| </div></div> | |
| <div class="brain-stage"> | |
| <svg class="brain-svg" viewBox="0 0 880 560"> | |
| {''.join(baselines)} {''.join(activelines)} {''.join(circles)} | |
| </svg></div></div>""" | |
| def build_cards_html(cards: List[Dict]) -> str: | |
| items = [] | |
| for i, c in enumerate(cards): | |
| items.append( | |
| f"""<div class="candidate-card" tabindex="0"> | |
| <div class="candidate-card-inner"> | |
| <div class="candidate-face"> | |
| <div class="candidate-top"><span class="chip">{safe_text(c["agent"])}</span><span class="score">{safe_text(c["score"])}</span></div> | |
| <h4>{safe_text(c["title"])}</h4> | |
| <p>{safe_text(c["front"])}</p> | |
| <div class="meta-row"><span>Novelty <strong>{safe_text(c["novelty"])}</strong></span></div> | |
| <button class="mini" onclick="triggerRouteSwap({i})">Use as main insight</button> | |
| </div> | |
| <div class="candidate-face candidate-back"> | |
| <div class="candidate-top"><span class="chip alt">Alternative path</span><span class="score">{safe_text(c["score"])}</span></div> | |
| <h4>{safe_text(c["title"])}</h4> | |
| <p>{safe_text(c["back"])}</p> | |
| <div class="meta-row"><span>Swap into route <strong>Enabled</strong></span></div> | |
| <button class="mini" onclick="triggerRouteSwap({i})">Use as main insight</button> | |
| </div> | |
| </div></div>""" | |
| ) | |
| return '<div class="candidate-grid">' + "".join(items) + "</div>" | |
| def build_chat_html(query: str, result: Dict) -> str: | |
| return f"""<div class="chat-panel panel"><div class="chat-thread"> | |
| <div class="bubble bubble-user"><span class="role">You</span><p>{safe_text(query)}</p></div> | |
| <div class="bubble bubble-ai"><span class="role">DVNC Sovereign</span><p>{safe_text(result["summary"])}</p></div> | |
| <div class="bubble bubble-system"><span class="role">Discovery Signal</span> | |
| <p><strong>Primary hypothesis:</strong> {safe_text(result["primary_hypothesis"])}</p> | |
| </div></div></div>""" | |
| def build_models_html(selected: str) -> str: | |
| items = [] | |
| for m in MODELS: | |
| active = "active" if m["name"] == selected else "" | |
| items.append( | |
| f'<div class="model-pill {active}"><span class="model-name">{safe_text(m["name"])}</span>' | |
| f'<span class="model-tag">{safe_text(m["tag"])}</span>' | |
| f'<small>{safe_text(m["desc"])}</small></div>' | |
| ) | |
| return '<div class="model-switcher">' + "".join(items) + "</div>" | |
| # ββ Discovery logic βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def run_discovery(query: str, model_name: str): | |
| random.seed(len(query or "") + len(model_name or "")) | |
| if "curie" in (query or "").lower() or "einstein" in (query or "").lower(): | |
| primary = "Map the anomaly first, then force a distant analogy before composing the experimental programme." | |
| path = ["seed", "bio", "card", "immune", "trial"] | |
| else: | |
| primary = ( | |
| "Utilization of a self-assembling conductive scaffold to transduce mechanical " | |
| "strain into localized regenerative signalling pathways." | |
| ) | |
| path = DEFAULT_PATH | |
| summaries = [ | |
| "Normalises the user prompt into a graph-searchable seed and isolates the tension inside the question.", | |
| "Finds remote conceptual bridges instead of staying near the starting domain cluster.", | |
| "Pulls evidence packets and conflict signals required for grounded hypothesis formation.", | |
| "Generates cross-domain analogies with a bias toward mechanism transfer rather than keyword similarity.", | |
| "Composes the lead hypothesis and two structurally different variants.", | |
| "Attacks weak assumptions, hidden confounders, and feasibility gaps.", | |
| "Produces a staged validation plan with measurable falsification criteria.", | |
| ] | |
| tags = ["input", "graph", "evidence", "analogy", "compose", "critique", "experiment"] | |
| reasoning = [ | |
| {"step": i + 1, "agent": AGENTS[i], "tag": tags[i], "summary": summaries[i]} | |
| for i in range(7) | |
| ] | |
| result = { | |
| "summary": ( | |
| "A deeper route was chosen through the connectome, with live alternatives preserved " | |
| "as swappable cards so the reasoning path can be inspected rather than hidden." | |
| ), | |
| "primary_hypothesis": primary, | |
| "reasoning": reasoning, | |
| "cards": CANDIDATES, | |
| "path": path, | |
| "metrics": { | |
| "Novelty": 93, | |
| "Mechanistic clarity": 89, | |
| "Experimental tractability": 82, | |
| "Cross-domain distance": 91, | |
| }, | |
| } | |
| chat_html = build_chat_html(query, result) | |
| connectome_html = build_connectome_html(path) | |
| timeline_html = build_agent_route_cards_html(reasoning) | |
| metrics_md = "\n".join(f"- {k}: {v}/100" for k, v in result["metrics"].items()) | |
| hypothesis_md = ( | |
| "# Discovery Output\n\n" | |
| f"**Model:** {model_name}\n\n" | |
| f"**Primary hypothesis:** {result['primary_hypothesis']}\n\n" | |
| "## Scoring\n" | |
| f"{metrics_md}\n\n" | |
| "## Experimental outline\n" | |
| "1. Construct the candidate material or protocol.\n" | |
| "2. Test mechanistic signal expression under controlled conditions.\n" | |
| "3. Compare against baseline and nearest-neighbour alternatives.\n" | |
| "4. Falsify using the adversarial risk criteria surfaced in the reasoning path.\n" | |
| ) | |
| cards_html = build_cards_html(CANDIDATES) | |
| route_state = get_default_route_state() | |
| return ( | |
| chat_html, | |
| connectome_html, | |
| timeline_html, | |
| cards_html, | |
| hypothesis_md, | |
| build_models_html(model_name), | |
| route_state, | |
| ) | |
| def apply_route_swap(query: str, model_name: str, route_swap_payload: str, route_state): | |
| try: | |
| idx = int(route_swap_payload) | |
| except Exception: | |
| idx = 0 | |
| if not (0 <= idx < len(ACADEMIC_INSIGHTS)): | |
| idx = 0 | |
| academic = ACADEMIC_INSIGHTS[idx] | |
| connectome_html = build_connectome_html(academic["path"]) | |
| result = { | |
| "summary": ( | |
| "Main insight formally adopted. The connectome pathway and validation protocol " | |
| "have been realigned to the selected candidate methodology." | |
| ), | |
| "primary_hypothesis": academic["hypothesis"], | |
| } | |
| chat_html = build_chat_html(query, result) | |
| metrics_md = "\n".join(f"- {k}: {v}/100" for k, v in academic["metrics"].items()) | |
| hypothesis_md = ( | |
| "# Discovery Output\n\n" | |
| f"**Model:** {model_name}\n\n" | |
| f"**Primary hypothesis:** {academic['hypothesis']}\n\n" | |
| "## Scoring\n" | |
| f"{metrics_md}\n\n" | |
| "## Experimental outline\n" | |
| f"{academic['outline']}\n" | |
| ) | |
| return chat_html, connectome_html, gr.update(), hypothesis_md, route_state | |
| # ββ Example loaders ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def load_example() -> str: | |
| return "How could a self-assembling conductive biomaterial improve cardiac tissue regeneration by converting mechanical strain into repair signalling?" | |
| def load_paper_topic() -> str: | |
| return "self-assembling conductive biomaterials for cardiac repair" | |
| # ββ CSS / HEAD ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| BASE_CSS = r""" | |
| :root { | |
| --bg:#ffffff; --panel:#ffffff; --line:rgba(0,0,0,.12); --text:#111111; | |
| --muted:#5b5b5b; --soft:rgba(0,0,0,.62); --gold:#ff6600; --teal:#17b8a6; | |
| --blue:#628dff; --chosen:#ff7a1a; --idle:#b8d8ff; --idle-stroke:#5e8fe6; | |
| --query-node:#ffd8b3; --paper-node:#d7f6f2; --upload-node:#e7defe; | |
| --shadow:0 16px 40px rgba(0,0,0,.12); | |
| } | |
| html,body,.gradio-container{background:#ffffff !important;font-family:Inter,ui-sans-serif,system-ui,sans-serif;} | |
| .gradio-container{max-width:1640px !important;padding:20px !important;} | |
| #dvnc-shell{border:1px solid var(--line);border-radius:28px;overflow:hidden;background:#ffffff;box-shadow:var(--shadow);padding:20px 22px 22px;} | |
| .hero-bar{display:flex;justify-content:space-between;align-items:center;gap:16px;padding-bottom:12px;border-bottom:1px solid rgba(0,0,0,.06);margin-bottom:16px;} | |
| .brand{display:flex;align-items:center;gap:14px;} | |
| .logo{width:42px;height:42px;border-radius:14px;display:grid;place-items:center;color:var(--gold);background:linear-gradient(135deg,rgba(255,122,26,.12),rgba(23,184,166,.10));border:1px solid rgba(0,0,0,.08);} | |
| .brand h1{font-size:1.05rem;margin:0;font-weight:700;letter-spacing:.12em;text-transform:uppercase;} | |
| .brand p{margin:3px 0 0;color:var(--muted);font-size:.84rem;} | |
| .status{display:flex;gap:10px;align-items:center;color:var(--soft);font-size:.85rem;} | |
| .status-dot{width:10px;height:10px;border-radius:50%;background:var(--teal);box-shadow:0 0 0 6px rgba(23,184,166,.10),0 0 14px rgba(23,184,166,.25);} | |
| .panel{background:#ffffff;border:1px solid var(--line);border-radius:22px;box-shadow:inset 0 1px 0 rgba(255,255,255,. |