Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -2,37 +2,45 @@ import os, json, shutil
|
|
| 2 |
import pandas as pd
|
| 3 |
import gradio as gr
|
| 4 |
from agent import chat_with_agent
|
| 5 |
-
from tools import CSV_PATH, OUT_DIR, PDF_DIR, _embed, HEADERS
|
| 6 |
|
| 7 |
try: _embed()
|
| 8 |
except Exception as e: print(f">>> WARNING: Embedding pre-load failed: {e}")
|
| 9 |
|
| 10 |
-
IS_PERSISTENT = PERSISTENT_BASE == "/data"
|
| 11 |
-
STATUS_TAG = '<span style="background:#0ea5e8;color:white;padding:2px 6px;border-radius:4px;font-size:0.5em;vertical-align:middle;margin-left:8px">PERSISTENT</span>' if IS_PERSISTENT else ""
|
| 12 |
-
|
| 13 |
CSS = """
|
| 14 |
-
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=
|
| 15 |
-
:root { --primary: #0f172a; --secondary: #
|
| 16 |
-
body, .gradio-container { font-family: 'Inter', sans-serif !important; background-color: var(--
|
| 17 |
-
.hdr { font-family: '
|
| 18 |
-
.sub-hdr { font-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
button.
|
| 22 |
-
button.
|
| 23 |
-
.
|
| 24 |
-
.
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
.
|
| 28 |
-
|
|
|
|
| 29 |
"""
|
| 30 |
-
HDR =
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
PHASE_FILE = {"CODES": "_labels.json", "THEMES": "_themes.json", "PAJAIS": "_taxonomy.json"}
|
| 34 |
NEXT_PHASE = {"CODES": "THEMES", "THEMES": "PAJAIS", "PAJAIS": "REPORT"}
|
| 35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
def init_analysis(query, csv_file, chat_hist):
|
| 37 |
# 1. Clear old outputs
|
| 38 |
if os.path.exists(OUT_DIR):
|
|
@@ -91,7 +99,7 @@ def init_analysis(query, csv_file, chat_hist):
|
|
| 91 |
feedback = (f"Detected Mode: {mode}\nSources:\n{source_lines}\nTotal: {total_papers} papers\n\n👉 Preparing dataset... Proceeding to Phase 2")
|
| 92 |
|
| 93 |
new_hist = chat_hist + [{"role":"user","content": f"Init {mode}"}, {"role":"assistant","content": feedback + "\n\n" + res}]
|
| 94 |
-
return "", new_hist, _load_table("abstract", "CODES")
|
| 95 |
|
| 96 |
def handle_pdf_upload(files):
|
| 97 |
if not files: return "No files selected."
|
|
@@ -153,12 +161,13 @@ def _show_chart(m, t):
|
|
| 153 |
path = os.path.join(OUT_DIR, f"{m}_{t}.html")
|
| 154 |
return f'<iframe srcdoc="{open(path, encoding="utf-8").read().replace(chr(34),""")}" width="100%" height="450"></iframe>' if os.path.exists(path) else "Run Phase 2 first."
|
| 155 |
|
| 156 |
-
with gr.Blocks(
|
| 157 |
with gr.Row():
|
| 158 |
# LEFT SIDEBAR
|
| 159 |
with gr.Column(scale=1, elem_classes="sidebar"):
|
| 160 |
gr.HTML(HDR)
|
| 161 |
-
gr.HTML(
|
|
|
|
| 162 |
input_box = gr.Textbox(placeholder="Enter research topic...", label="Research Query")
|
| 163 |
start_btn = gr.Button("Execute Discovery", variant="primary")
|
| 164 |
|
|
@@ -178,8 +187,6 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue="violet", neutral_hue="slate"),
|
|
| 178 |
|
| 179 |
# RIGHT MAIN WORKSPACE
|
| 180 |
with gr.Column(scale=3, elem_classes="main-content"):
|
| 181 |
-
gr.HTML(PRG)
|
| 182 |
-
|
| 183 |
with gr.Tabs(elem_classes="tab-nav"):
|
| 184 |
with gr.Tab("💬 Agent Copilot"):
|
| 185 |
chatbot = gr.Chatbot([], height=500, label="Research Assistant")
|
|
@@ -215,7 +222,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue="violet", neutral_hue="slate"),
|
|
| 215 |
btn_refresh_files.click(_get_files, [], [dl])
|
| 216 |
|
| 217 |
# Event Bindings
|
| 218 |
-
start_btn.click(init_analysis, [input_box, csv_up, chatbot], [input_box, chatbot, tbl])
|
| 219 |
send_btn.click(handle_chat, [msg_in, chatbot, mode_btn, ph_state], [msg_in, chatbot, tbl])
|
| 220 |
btn_ingest.click(handle_chat, [gr.State("Ingest all uploaded PDFs and Word documents into the system."), chatbot, gr.State("abstract"), gr.State("CODES")], [msg_in, chatbot, tbl])
|
| 221 |
btn_scratch.click(handle_chat, [gr.State("Check the local scratch folder and import any papers found there."), chatbot, gr.State("abstract"), gr.State("CODES")], [msg_in, chatbot, tbl])
|
|
@@ -223,5 +230,4 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue="violet", neutral_hue="slate"),
|
|
| 223 |
sub_btn.click(submit_review, [tbl, chatbot, mode_btn, ph_state], [chatbot, ph_state, tbl]).then(_get_report, [], [report_box])
|
| 224 |
|
| 225 |
if __name__ == "__main__":
|
| 226 |
-
server_port
|
| 227 |
-
demo.launch(server_name="0.0.0.0", server_port=server_port)
|
|
|
|
| 2 |
import pandas as pd
|
| 3 |
import gradio as gr
|
| 4 |
from agent import chat_with_agent
|
| 5 |
+
from tools import CSV_PATH, OUT_DIR, PDF_DIR, _embed, HEADERS
|
| 6 |
|
| 7 |
try: _embed()
|
| 8 |
except Exception as e: print(f">>> WARNING: Embedding pre-load failed: {e}")
|
| 9 |
|
|
|
|
|
|
|
|
|
|
| 10 |
CSS = """
|
| 11 |
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Plus+Jakarta+Sans:wght@600;700&display=swap');
|
| 12 |
+
:root { --primary: #0f172a; --secondary: #6366f1; --accent: #8b5cf6; --bg: #f8fafc; }
|
| 13 |
+
body, .gradio-container { font-family: 'Inter', sans-serif !important; background-color: var(--bg) !important; color: var(--primary) !important; }
|
| 14 |
+
.hdr { font-family: 'Plus Jakarta Sans', sans-serif !important; font-size: 2.25rem !important; font-weight: 700; color: var(--primary) !important; letter-spacing: -0.04em; margin-bottom: 2px !important; }
|
| 15 |
+
.sub-hdr { font-size: 0.875rem !important; color: #64748b !important; margin-bottom: 24px !important; }
|
| 16 |
+
.sidebar { background: white !important; border-right: 1px solid rgba(15,23,42,0.08) !important; padding: 24px !important; }
|
| 17 |
+
.main-content { background: white !important; border-radius: 12px !important; border: 1px solid rgba(15,23,42,0.05) !important; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05) !important; }
|
| 18 |
+
button.primary { background: var(--primary) !important; color: white !important; border-radius: 8px !important; font-weight: 600 !important; transition: all 0.2s; }
|
| 19 |
+
button.primary:hover { background: #1e293b !important; transform: translateY(-1px); }
|
| 20 |
+
.phase-orb { display: flex; align-items: center; gap: 8px; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: #94a3b8; margin-bottom: 12px; }
|
| 21 |
+
.phase-orb.active { color: var(--secondary); }
|
| 22 |
+
.phase-dot { width: 8px; height: 8px; border-radius: 50%; background: #e2e8f0; }
|
| 23 |
+
.phase-orb.active .phase-dot { background: var(--secondary); box-shadow: 0 0 8px var(--secondary); }
|
| 24 |
+
input, textarea, .gr-box, .gr-form, label, span, p, .markdown-text { color: #0f172a !important; }
|
| 25 |
+
input, textarea { border-radius: 8px !important; border: 1px solid #e2e8f0 !important; background: white !important; }
|
| 26 |
+
input:focus { border-color: var(--secondary) !important; ring: 2px var(--secondary) !important; }
|
| 27 |
"""
|
| 28 |
+
HDR = '<div class="hdr">Digital Curator</div><div class="sub-hdr">Enterprise Agentic Research Platform</div>'
|
| 29 |
+
PRG_TPL = '<div style="display: flex; flex-direction: column; gap: 4px;">' \
|
| 30 |
+
'<div class="phase-orb {a1}"><div class="phase-dot"></div>1. Ingestion</div>' \
|
| 31 |
+
'<div class="phase-orb {a2}"><div class="phase-dot"></div>2. Algorithmic Coding</div>' \
|
| 32 |
+
'<div class="phase-orb {a3}"><div class="phase-dot"></div>3. Thematic Abstraction</div>' \
|
| 33 |
+
'<div class="phase-orb {a4}"><div class="phase-dot"></div>4. Report Narration</div>' \
|
| 34 |
+
'</div>'
|
| 35 |
|
| 36 |
PHASE_FILE = {"CODES": "_labels.json", "THEMES": "_themes.json", "PAJAIS": "_taxonomy.json"}
|
| 37 |
NEXT_PHASE = {"CODES": "THEMES", "THEMES": "PAJAIS", "PAJAIS": "REPORT"}
|
| 38 |
|
| 39 |
+
def get_phase_html(current_phase):
|
| 40 |
+
mapping = {"INGEST": "a1", "CODES": "a2", "THEMES": "a3", "PAJAIS": "a3", "REPORT": "a4"}
|
| 41 |
+
active = mapping.get(current_phase, "a1")
|
| 42 |
+
return PRG_TPL.format(**{k: "active" if k == active else "" for k in ["a1", "a2", "a3", "a4"]})
|
| 43 |
+
|
| 44 |
def init_analysis(query, csv_file, chat_hist):
|
| 45 |
# 1. Clear old outputs
|
| 46 |
if os.path.exists(OUT_DIR):
|
|
|
|
| 99 |
feedback = (f"Detected Mode: {mode}\nSources:\n{source_lines}\nTotal: {total_papers} papers\n\n👉 Preparing dataset... Proceeding to Phase 2")
|
| 100 |
|
| 101 |
new_hist = chat_hist + [{"role":"user","content": f"Init {mode}"}, {"role":"assistant","content": feedback + "\n\n" + res}]
|
| 102 |
+
return "", new_hist, _load_table("abstract", "CODES"), get_phase_html("CODES")
|
| 103 |
|
| 104 |
def handle_pdf_upload(files):
|
| 105 |
if not files: return "No files selected."
|
|
|
|
| 161 |
path = os.path.join(OUT_DIR, f"{m}_{t}.html")
|
| 162 |
return f'<iframe srcdoc="{open(path, encoding="utf-8").read().replace(chr(34),""")}" width="100%" height="450"></iframe>' if os.path.exists(path) else "Run Phase 2 first."
|
| 163 |
|
| 164 |
+
with gr.Blocks() as demo:
|
| 165 |
with gr.Row():
|
| 166 |
# LEFT SIDEBAR
|
| 167 |
with gr.Column(scale=1, elem_classes="sidebar"):
|
| 168 |
gr.HTML(HDR)
|
| 169 |
+
prg_display = gr.HTML(get_phase_html("INGEST"))
|
| 170 |
+
gr.HTML('<div style="height: 24px; border-top: 1px solid #f1f5f9; margin-top: 24px;"></div>')
|
| 171 |
input_box = gr.Textbox(placeholder="Enter research topic...", label="Research Query")
|
| 172 |
start_btn = gr.Button("Execute Discovery", variant="primary")
|
| 173 |
|
|
|
|
| 187 |
|
| 188 |
# RIGHT MAIN WORKSPACE
|
| 189 |
with gr.Column(scale=3, elem_classes="main-content"):
|
|
|
|
|
|
|
| 190 |
with gr.Tabs(elem_classes="tab-nav"):
|
| 191 |
with gr.Tab("💬 Agent Copilot"):
|
| 192 |
chatbot = gr.Chatbot([], height=500, label="Research Assistant")
|
|
|
|
| 222 |
btn_refresh_files.click(_get_files, [], [dl])
|
| 223 |
|
| 224 |
# Event Bindings
|
| 225 |
+
start_btn.click(init_analysis, [input_box, csv_up, chatbot], [input_box, chatbot, tbl, prg_display])
|
| 226 |
send_btn.click(handle_chat, [msg_in, chatbot, mode_btn, ph_state], [msg_in, chatbot, tbl])
|
| 227 |
btn_ingest.click(handle_chat, [gr.State("Ingest all uploaded PDFs and Word documents into the system."), chatbot, gr.State("abstract"), gr.State("CODES")], [msg_in, chatbot, tbl])
|
| 228 |
btn_scratch.click(handle_chat, [gr.State("Check the local scratch folder and import any papers found there."), chatbot, gr.State("abstract"), gr.State("CODES")], [msg_in, chatbot, tbl])
|
|
|
|
| 230 |
sub_btn.click(submit_review, [tbl, chatbot, mode_btn, ph_state], [chatbot, ph_state, tbl]).then(_get_report, [], [report_box])
|
| 231 |
|
| 232 |
if __name__ == "__main__":
|
| 233 |
+
demo.launch(server_port=7861, theme=gr.themes.Base(primary_hue="violet", neutral_hue="slate"), css=CSS)
|
|
|