Spaces:
Sleeping
Sleeping
File size: 5,500 Bytes
971e38a 86b948e 335600f 971e38a e3c954b 971e38a 335600f e3c954b 86b948e e3c954b 86b948e e3c954b 86b948e e3c954b 86b948e 971e38a 86b948e 971e38a 335600f 86b948e e3c954b 86b948e 971e38a 86b948e 971e38a 86b948e 971e38a 86b948e 971e38a 86b948e 335600f 971e38a e3c954b 335600f e3c954b 971e38a 335600f e3c954b 971e38a e3c954b 335600f 971e38a 335600f 86b948e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
from __future__ import annotations
import os
import json
import tempfile
import gradio as gr
from dotenv import load_dotenv
load_dotenv()
from genesis.pipeline import research_once
from genesis.providers import postprocess_summary, synthesize_tts
from genesis.graph import build_preview_graph_html
from genesis.graphdb import write_topic_and_papers
APP_TITLE = "GENESIS-AI β Synthetic Biology Deep Research (Safety-First)"
APP_DESC = (
"High-level synthetic biology literature synthesis with citations. "
"This app NEVER produces operational protocols."
)
DEFAULT_POST = os.getenv("POSTPROCESSOR_DEFAULT", "none").lower()
DEFAULT_RERANK_MODEL = os.getenv("RERANK_MODEL", "mixedbread-ai/mxbai-rerank-large-v1")
async def run_pipeline(
query: str,
fast: bool,
postprocessor: str,
want_graph: bool,
state: dict,
) -> tuple[str, str, str, str | None, dict]:
"""
Orchestrates deep research + optional post-processing + optional graph preview.
Returns: (final_markdown, citations_markdown, json_blob, graph_html, state)
"""
out = await research_once(query, fast=fast, rerank_model=DEFAULT_RERANK_MODEL)
# Optional polish (Gemini/DeepSeek) β never add lab steps
if postprocessor and postprocessor != "none":
out["final_output"] = await postprocess_summary(
base_text=out.get("final_output") or "",
citations=out.get("citations", []),
engine=postprocessor,
)
# Keep state for TTS / graph writer
state = state or {}
state["final_text"] = out.get("final_output") or ""
state["citations"] = out.get("citations", [])
state["query"] = query
# Graph preview HTML
graph_html = build_preview_graph_html(state["citations"]) if want_graph else None
# Report
final_md = state["final_text"] if state["final_text"] else "_No output_"
# Citations list (robust string building)
cite_lines: list[str] = []
for c in state["citations"]:
title = c.get("title") or "link"
url = c.get("url") or ""
cite_lines.append(f"- [{title}]({url})")
cites_md = "\n".join(cite_lines) if cite_lines else "_None detected_"
# JSON export
json_blob = json.dumps(out, indent=2)
return final_md, cites_md, json_blob, graph_html, state
async def do_tts(state: dict) -> tuple[str | None, str]:
"""Narrate the high-level summary via ElevenLabs."""
text = (state or {}).get("final_text") or ""
if not text.strip():
return None, "Nothing to narrate yet β run research first."
audio_bytes, mime = await synthesize_tts(text)
if not audio_bytes:
return None, "TTS not configured or failed. Ensure ELEVEN_LABS_API_KEY/VOICE_ID are set."
suffix = ".mp3" if (mime or "").find("mpeg") >= 0 else ".wav"
with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as f:
f.write(audio_bytes)
path = f.name
return path, "Narration ready."
async def do_graph_write(state: dict) -> str:
"""Write Topic -> Paper knowledge graph into Neo4j."""
topic = (state or {}).get("query") or "Untitled Topic"
citations = (state or {}).get("citations") or []
if not citations:
return "No citations present β run research first."
counts = await write_topic_and_papers(topic, citations)
return f"Wrote to Neo4j: nodes={counts.get('nodes',0)}, rels={counts.get('rels',0)}"
with gr.Blocks(theme=gr.themes.Soft(), fill_height=True) as demo:
gr.Markdown(f"# {APP_TITLE}")
gr.Markdown(APP_DESC)
state = gr.State({"final_text": "", "citations": [], "query": ""})
with gr.Row():
query = gr.Textbox(
label="Your high-level research request",
lines=5,
placeholder=(
"e.g., High-level synthesis of CRISPR base-editing trends in oncology (last 2 years). "
"Summarize mechanisms, targets, ethics, and provide citations."
),
)
with gr.Row():
fast = gr.Checkbox(label="Fast mode (o4-mini-deep-research)", value=False)
post = gr.Dropdown(
label="Post-processor",
choices=["none", "gemini", "deepseek"],
value=DEFAULT_POST,
allow_custom_value=False,
)
want_graph = gr.Checkbox(label="Build graph preview", value=False)
go = gr.Button("Run Deep Research", variant="primary")
with gr.Tabs():
with gr.Tab("Research Report"):
report = gr.Markdown()
with gr.Tab("Citations"):
citations = gr.Markdown()
with gr.Tab("JSON Export"):
json_out = gr.Code(language="json")
with gr.Tab("Graph Preview"):
graph_html = gr.HTML()
with gr.Tab("Graph Writer (Neo4j)"):
write_btn = gr.Button("Write Topic & Papers to Neo4j", variant="secondary")
write_status = gr.Markdown()
with gr.Tab("Narration (ElevenLabs)"):
tts_btn = gr.Button("Narrate Summary", variant="secondary")
tts_audio = gr.Audio(label="Narration", autoplay=False)
tts_status = gr.Markdown()
go.click(
fn=run_pipeline,
inputs=[query, fast, post, want_graph, state],
outputs=[report, citations, json_out, graph_html, state],
)
tts_btn.click(fn=do_tts, inputs=[state], outputs=[tts_audio, tts_status])
write_btn.click(fn=do_graph_write, inputs=[state], outputs=[write_status])
if __name__ == "__main__":
demo.launch()
|