milindkamat0507 commited on
Commit
735a008
·
verified ·
1 Parent(s): 51622f2

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -158
app.py DELETED
@@ -1,158 +0,0 @@
1
- """app.py — Compact Gradio + Mistral + BERTopic. Version 2.1.0 | 4 April 2026. ZERO for/while/if.
2
-
3
- FUNCTIONS IN THIS FILE:
4
- _latest_output() — Scans /tmp for newest rq4_* file → feeds download button
5
- respond() — Core chat handler: takes message + history + file → yields agent response
6
- gr.Blocks() — One-page UI: header + upload + chatbot + input + download
7
- """
8
- import os
9
- import glob
10
- import gradio as gr
11
- from langchain_mistralai import ChatMistralAI
12
- from langgraph.prebuilt import create_react_agent
13
- from langgraph.checkpoint.memory import MemorySaver
14
- from agent import SYSTEM_PROMPT, get_local_tools
15
-
16
- print(">>> app.py: imports complete")
17
-
18
- # ═══════════════════════════════════════════════
19
- # AGENT SETUP — Mistral brain + 5 BERTopic tools
20
- # ═══════════════════════════════════════════════
21
- llm = ChatMistralAI(model="mistral-small-latest", temperature=0, timeout=300)
22
- tools = get_local_tools()
23
- agent = create_react_agent(model=llm, tools=tools, prompt=SYSTEM_PROMPT, checkpointer=MemorySaver())
24
- print(f">>> app.py: agent ready ({len(tools)} tools, Mistral Large)")
25
-
26
- _msg_count = 0
27
- _uploaded = {"path": ""}
28
-
29
- # ═══════════════════════════════════════════════
30
- # COMPACT HEADER — fits in ~60px
31
- # ═══════════════════════════════════════════════
32
- HEADER_HTML = """
33
- <style>
34
- @import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap');
35
- .gradio-container {max-width: 900px !important; margin: 0 auto !important; font-family: 'DM Sans', sans-serif !important; padding: 8px !important;}
36
- footer {display: none !important;}
37
- </style>
38
- <div style="background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #334155 100%); border-radius: 10px; padding: 12px 20px; margin-bottom: 8px; color: white;">
39
- <div style="display: flex; align-items: center; gap: 12px;">
40
- <span style="font-size: 1.5em;">🔬</span>
41
- <div>
42
- <div style="font-size: 1.1em; font-weight: 700; color: #e0e0ff;">BERTopic Research Discovery Agent</div>
43
- <div style="font-size: 0.7em; color: #94a3b8;">Mistral Large 🇫🇷 · BERTopic HDBSCAN · 384d Embeddings · 5 Nearest Centroid · 4 Plotly Charts</div>
44
- </div>
45
- </div>
46
- </div>
47
- """
48
-
49
- # ═══════════════════════════════════════════════
50
- # FUNCTION 1: Find latest output for download
51
- # ═══════════════════════════════════════════════
52
- def _latest_output():
53
- """Scan /tmp for most recent rq4_* file (CSV, HTML, or TXT).
54
- Returns filepath string or None. Fed to gr.File download component."""
55
- files = sorted(glob.glob("/tmp/rq4_*.csv") + glob.glob("/tmp/rq4_*.html") + glob.glob("/tmp/rq4_*.txt"), key=os.path.getmtime)
56
- return (files and files[-1]) or None
57
-
58
-
59
- # ═══════════════════════════════════════════════
60
- # FUNCTION 2: Chat handler — core of the app
61
- # ═══════════════════════════════════════════════
62
- def respond(message, chat_history, uploaded_file):
63
- """Handle one chat turn:
64
- 1. Store uploaded file path (if new upload)
65
- 2. Append file context to message so agent knows where CSV is
66
- 3. Show progress bubble immediately (user sees instant feedback)
67
- 4. Invoke agent (Mistral brain decides which tools to call)
68
- 5. Replace progress bubble with agent's actual response
69
- 6. Update download link to latest output file
70
-
71
- Uses per-message thread_id to prevent context overflow. State persists via disk checkpoints.
72
- Agent asks clarification FIRST (via SYSTEM_PROMPT) before running heavy tools."""
73
- global _msg_count
74
- _msg_count += 1
75
-
76
- # Store file path — no if/else, uses `or` short-circuit
77
- _uploaded["path"] = uploaded_file or _uploaded.get("path", "")
78
- file_note = f"\n[CSV file at: {_uploaded['path']}]" * bool(_uploaded["path"])
79
- text = ((message or "").strip() or "Analyze my Scopus CSV") + file_note
80
- print(f"\n{'='*60}\n>>> MSG #{_msg_count}: '{text[:100]}'\n{'='*60}")
81
-
82
- # Yield progress bubble immediately — user sees instant response
83
- chat_history = chat_history + [
84
- {"role": "user", "content": (message or "").strip()},
85
- {"role": "assistant", "content": "🔬 **Working...** _Agent is thinking..._"},
86
- ]
87
- yield chat_history, "", _latest_output()
88
-
89
- # Per-message thread_id to prevent context window overflow.
90
- # WHY: MemorySaver accumulates ALL previous messages + tool outputs.
91
- # After 3 turns with 100 topic labels each → 300K tokens → exceeds 262K limit.
92
- # Tools save state to DISK (labels.json, themes.json, taxonomy_map.json).
93
- # Agent reads from disk checkpoints, NOT conversation memory.
94
- # Multi-turn works because disk state persists across messages.
95
- result = agent.invoke(
96
- {"messages": [("human", text)]},
97
- config={"configurable": {"thread_id": f"t{_msg_count}"}},
98
- )
99
- response = result["messages"][-1].content
100
- print(f">>> Response ({len(response)} chars)")
101
-
102
- # Replace progress bubble with actual response
103
- chat_history[-1] = {"role": "assistant", "content": response}
104
- yield chat_history, "", _latest_output()
105
-
106
-
107
- # ═══════════════════════════════════════════════
108
- # UI LAYOUT — Everything fits ONE screen (~500px)
109
- #
110
- # ┌────────────────────────────────────┐
111
- # │ 🔬 BERTopic Agent (compact) │ ~55px
112
- # ├────────────────────────────────────┤
113
- # │ [📂 Upload CSV] │ ~35px
114
- # ├────────────────────────────────────┤
115
- # │ 💬 Chat bubbles (cloud style) │
116
- # │ User: "Analyze my data" │ ~320px
117
- # │ Agent: "I found 1390 papers. │
118
- # │ Which config? All 3?" │
119
- # ├────────────────────────────────────┤
120
- # │ [Type message... ] [⏎] │ ~35px
121
- # ├────────────────────────────────────┤
122
- # │ 📥 Download │ ~35px
123
- # └────────────────────────────────────┘
124
- # TOTAL: ~480px — fits any screen
125
- # ═══════════════════════════════════════════════
126
- print(">>> Building UI...")
127
- with gr.Blocks(title="BERTopic Research Discovery Agent") as demo:
128
- gr.HTML(HEADER_HTML)
129
-
130
- upload = gr.File(label="📂 Upload Scopus CSV", file_types=[".csv"], height=35)
131
-
132
- chatbot = gr.Chatbot(height=300, show_label=False, placeholder="Upload CSV ↑ then click a quick action or type below")
133
-
134
- with gr.Row():
135
- msg = gr.Textbox(
136
- placeholder="Or type: group 0 1 5 · re-run 15 · topic 2 looks wrong · approve",
137
- show_label=False, scale=9, lines=1, max_lines=1, container=False)
138
- send = gr.Button("⏎", variant="primary", scale=1, min_width=45)
139
-
140
- gr.Examples(
141
- examples=[
142
- ["Run abstract only"],
143
- ["Run all columns (title + keywords + abstract)"],
144
- ["Run both configs"],
145
- ["approve"],
146
- ["Generate narrative"],
147
- ],
148
- inputs=msg,
149
- label="⚡ Quick actions (click to populate textbox, then press ⏎)",
150
- )
151
-
152
- download = gr.File(label="📥 Download", visible=True, height=35)
153
-
154
- msg.submit(respond, [msg, chatbot, upload], [chatbot, msg, download])
155
- send.click(respond, [msg, chatbot, upload], [chatbot, msg, download])
156
-
157
- print(">>> Launching...")
158
- demo.launch(server_name="0.0.0.0", server_port=7860)