Junaidb commited on
Commit
db45716
·
verified ·
1 Parent(s): 6010f03

Update ui.py

Browse files
Files changed (1) hide show
  1. ui.py +134 -270
ui.py CHANGED
@@ -1,291 +1,155 @@
1
  import streamlit as st
2
  import requests
3
  import os
4
- from gliner import GLiNER
5
- from streamlit_autorefresh import st_autorefresh
6
  import time
 
7
 
8
  tok = os.getenv("TOK")
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
 
12
- #st_autorefresh(interval=10000, key="volter")
13
-
14
- st.write(tok)
15
  def Target_Identification(userinput):
16
  model = GLiNER.from_pretrained("Ihor/gliner-biomed-bi-small-v1.0")
17
- labels = ["Protein","Mutation"]
18
  entities = model.predict_entities(userinput, labels, threshold=0.5)
19
-
20
  for entity in entities:
21
  if entity["label"] == "Protein":
22
  return entity["text"]
23
 
24
 
25
  def APP():
26
- tab_map = {
27
- 0: "BIO ENGINEERING LAB @newMATTER",
28
- }
29
-
30
- tab_selection = st.pills(
31
- "TABS",
32
- options=tab_map.keys(),
33
- format_func=lambda option: tab_map[option],
34
- selection_mode="single",
35
- )
36
-
37
- def SHOWTABS():
38
- if tab_selection == 0:
39
- # Two-column split
40
- left_col, right_col = st.columns([0.3, 0.7],vertical_alignment="center",border=True)
41
-
42
- # CSS to make right column sticky
43
- st.markdown("""
44
- <style>
45
- [data-testid="column"]:nth-of-type(2) {
46
- position: sticky;
47
- top: 0;
48
- align-self: flex-start;
49
- height: 100vh;
50
- overflow-y: auto;
51
- background-color: #0E1117;
52
- padding: 10px;
53
- border-left: 1px solid rgba(255,255,255,0.1);
54
- }
55
- </style>
56
- """, unsafe_allow_html=True)
57
-
58
- with left_col:
59
- option_map = {
60
- 0: "@OriginAI Nanobody Engineering:",
61
- }
62
- selection = st.pills(
63
- "BIOLOGICS",
64
- options=option_map.keys(),
65
- format_func=lambda option: option_map[option],
66
- selection_mode="single",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  )
 
68
 
69
- if selection == 0:
70
- st.markdown(
71
- "<p style='color:white;background-color:orange;font-weight:bold'> Nanobody [CANCER targeted]</p>",
72
- unsafe_allow_html=True,
73
- )
74
-
75
- # Get projects with error handling and caching
76
- @st.cache_data(ttl=20) # Cache for 5 minutes to reduce API calls
77
- def scan_for_project_availability_cached(user_id):
78
- try:
79
- request_url = f"https://thexforce-combat-backend.hf.space/{user_id}/projects"
80
- response = requests.get(
81
- request_url,
82
- headers={
83
- "Content-Type": "application/json",
84
- "Authorization": f"Bearer {tok}",
85
- },
86
- timeout=10 # Add timeout to prevent hanging
87
- )
88
-
89
- if response.status_code == 200:
90
- response_json = response.json()
91
- pros = response_json.get("projects", []) # Default to empty list if no projects key
92
-
93
- project_list = []
94
- if pros: # Check if pros is not None or empty
95
- for pro in pros:
96
- if isinstance(pro, dict):
97
- project_name = pro.get("project")
98
- if project_name: # Only add if project name exists
99
- project_list.append(project_name)
100
- else:
101
- if pro: # Only add if pro is not None or empty
102
- project_list.append(str(pro))
103
-
104
- return project_list
105
- else:
106
- st.error(f"Failed to fetch projects. Status code: {response.status_code}")
107
- return []
108
-
109
- except requests.exceptions.RequestException as e:
110
- st.error(f"Error fetching projects: {str(e)}")
111
- return []
112
- except Exception as e:
113
- st.error(f"Unexpected error: {str(e)}")
114
- return []
115
-
116
- projects = scan_for_project_availability_cached(st.user.email)
117
- projectname = None
118
-
119
- if len(projects) > 0:
120
- agree = st.checkbox("new project ?")
121
- if agree:
122
- #projectname = st.selectbox("Select Project", projects)
123
- projectname = st.text_input("Enter project name:")
124
- else:
125
- projectname = st.selectbox("Select Project", projects)
126
-
127
- else:
128
- projectname = st.text_input("Enter project name:")
129
-
130
- st.session_state.projectname = projectname
131
-
132
- with right_col:
133
- bio_input = st.chat_input(" Ready for Action ! ")
134
-
135
- # FIXED: Removed caching and added force_refresh parameter
136
- def fetch_ops(force_refresh=False):
137
- # Clear cache if force_refresh is True
138
- if force_refresh and 'ops_cache' in st.session_state:
139
- del st.session_state.ops_cache
140
-
141
- fetch_url=f"https://thexforce-combat-backend.hf.space/{st.user.email}/{st.session_state.projectname}/individual/experiment"
142
-
143
- response = requests.get(
144
- fetch_url,
145
- headers={
146
- "Content-Type": "application/json",
147
- "Authorization": f"Bearer {tok}",
148
- },
149
- )
150
- return response.json()
151
-
152
- if "messages" not in st.session_state:
153
- st.session_state.messages = []
154
-
155
- if len(st.session_state.messages) > 0:
156
- for msg in st.session_state.messages:
157
- with st.chat_message(msg["role"]):
158
- st.markdown(msg["content"])
159
-
160
- if bio_input:
161
- st.session_state.messages.append({"role": "user", "content": bio_input})
162
- with st.chat_message("user"):
163
- st.markdown(bio_input)
164
-
165
- if st.session_state.projectname in [None, ""]:
166
- st.markdown(":orange-badge[⚠️ Set Projectname]")
167
- else:
168
- identified_target = Target_Identification(bio_input)
169
- st.warning(f"TARGET IDENTIFIED IS : {identified_target}")
170
-
171
- payload = {
172
- "uid": st.user.email,
173
- "pid": st.session_state.projectname,
174
- "target": identified_target or None,
175
- "high_level_bio_query": bio_input,
176
- }
177
-
178
- response = requests.post(
179
- "https://thexforce-combat-backend.hf.space/application_layer_agent",
180
- json=payload,
181
- headers={
182
- "Content-Type": "application/json",
183
- "Authorization":f"Bearer {tok}",
184
- },
185
- )
186
-
187
- plan_response = response.json()
188
-
189
- with st.chat_message("assistant"):
190
- st.markdown(plan_response)
191
-
192
- # FIXED: Use animations while waiting for backend processing
193
- with st.spinner("🧬 Processing biological data..."):
194
- # Try multiple times with short delays between attempts
195
- fetch_ops_response = None
196
- max_attempts = 6
197
-
198
- for attempt in range(max_attempts):
199
- fetch_ops_response = fetch_ops(force_refresh=True)
200
-
201
- # Check if we got data
202
- if fetch_ops_response and fetch_ops_response.get("exp"):
203
- break
204
-
205
- # Short delay before next attempt (non-blocking)
206
- if attempt < max_attempts - 1: # Don't sleep on last attempt
207
- import time
208
- time.sleep(0.5) # Much shorter sleep between retries
209
-
210
- # Show completion animation
211
- if fetch_ops_response and fetch_ops_response.get("exp"):
212
- st.success("✅complete!")
213
- else:
214
- st.info("⏳ Operations are still being processed...")
215
-
216
- # FIXED: Better error handling with animations
217
- if fetch_ops_response:
218
- #st.write("Debug - Full response:", fetch_ops_response) # Debug line - remove in production
219
-
220
- exp_data = fetch_ops_response.get("exp")
221
- if exp_data is not None and len(exp_data) > 0:
222
- # Animated success message
223
- st.balloons() # Celebratory animation
224
- st.success(f"🔬 Found {len(exp_data)} experimental operations!")
225
-
226
- #for i, op in enumerate(exp_data):
227
- with st.chat_message("assistant"):
228
- # Add animated typing effect with progress
229
- progress_placeholder = st.empty()
230
- progress_placeholder.info(f"📊 Loading operation")
231
-
232
- #operation_text = op.get("operation", "No operation text")
233
- #output_text = op.get("output", "No output text")
234
-
235
- # Clear progress and show content
236
- progress_placeholder.empty()
237
-
238
- with st.container(border=True):
239
- #st.markdown(f"**🧪 Operation:** {operation_text}")
240
- #st.markdown(f"**📈 Output:** {output_text}")
241
- st.write(exp_data)
242
-
243
-
244
-
245
- # Small delay between operations for visual flow
246
- import time
247
- time.sleep(0.2)
248
- else:
249
- # Animated waiting message
250
- st.info("🔄 No experimental data found yet. Operations may still be processing...")
251
- with st.container():
252
- st.markdown("""
253
- <div style="text-align: center;">
254
- <div class="spinner"></div>
255
- </div>
256
- <style>
257
- .spinner {
258
- border: 4px solid #f3f3f3;
259
- border-top: 4px solid #ff6b35;
260
- border-radius: 50%;
261
- width: 30px;
262
- height: 30px;
263
- animation: spin 1s linear infinite;
264
- margin: 10px auto;
265
- }
266
- @keyframes spin {
267
- 0% { transform: rotate(0deg); }
268
- 100% { transform: rotate(360deg); }
269
- }
270
- </style>
271
- """, unsafe_allow_html=True)
272
- else:
273
- st.error("❌ Failed to fetch operations data")
274
- st.markdown("🔄 **Tip:** Try refreshing or submitting your query again.")
275
-
276
- st.session_state.messages.append(
277
- {"role": "assistant", "content": str(plan_response)}
278
- )
279
-
280
- if st.user.is_logged_in:
281
- if st.button("🚪 Logout"):
282
- st.logout()
283
- st.rerun()
284
 
285
- st.markdown(f"## {st.user.email}")
286
- SHOWTABS()
287
- else:
288
- st.info("Please log in to access the Bio Lab")
289
- if st.button("Log in"):
290
- st.login("auth0")
291
- st.stop()
 
1
  import streamlit as st
2
  import requests
3
  import os
 
 
4
  import time
5
+ from gliner import GLiNER
6
 
7
  tok = os.getenv("TOK")
8
 
9
+ st.set_page_config(page_title="Bio Lab @newMATTER", layout="wide")
10
+
11
+ # Cohere-like CSS styling
12
+ st.markdown("""
13
+ <style>
14
+ body {background-color: #0E1117; color: #EAEAEA;}
15
+ .chat-bubble-user {
16
+ background-color: #3A3F47;
17
+ color: white;
18
+ padding: 10px 14px;
19
+ border-radius: 16px;
20
+ max-width: 75%;
21
+ margin: 6px 0;
22
+ margin-left: auto;
23
+ box-shadow: 0 2px 6px rgba(0,0,0,0.4);
24
+ animation: fadeIn 0.3s ease-in;
25
+ }
26
+ .chat-bubble-assistant {
27
+ background-color: #23272F;
28
+ color: #EAEAEA;
29
+ padding: 10px 14px;
30
+ border-radius: 16px;
31
+ max-width: 75%;
32
+ margin: 6px 0;
33
+ margin-right: auto;
34
+ box-shadow: 0 2px 6px rgba(0,0,0,0.4);
35
+ animation: fadeIn 0.3s ease-in;
36
+ }
37
+ .typing-dots {
38
+ display: inline-block;
39
+ width: 4px; height: 4px;
40
+ margin: 0 2px;
41
+ background: #aaa;
42
+ border-radius: 50%;
43
+ animation: blink 1.2s infinite both;
44
+ }
45
+ .typing-dots:nth-child(2) { animation-delay: 0.2s; }
46
+ .typing-dots:nth-child(3) { animation-delay: 0.4s; }
47
+ @keyframes blink { 0%,80%,100%{opacity:0;} 40%{opacity:1;} }
48
+ @keyframes fadeIn { from {opacity:0; transform: translateY(5px);} to {opacity:1; transform: translateY(0);} }
49
+ </style>
50
+ """, unsafe_allow_html=True)
51
 
52
 
 
 
 
53
  def Target_Identification(userinput):
54
  model = GLiNER.from_pretrained("Ihor/gliner-biomed-bi-small-v1.0")
55
+ labels = ["Protein", "Mutation"]
56
  entities = model.predict_entities(userinput, labels, threshold=0.5)
 
57
  for entity in entities:
58
  if entity["label"] == "Protein":
59
  return entity["text"]
60
 
61
 
62
  def APP():
63
+ st.title("🧬 BIO ENGINEERING LAB @newMATTER")
64
+
65
+ # Sidebar (projects and session)
66
+ with st.sidebar:
67
+ st.header("📂 Project Manager")
68
+
69
+ @st.cache_data(ttl=30)
70
+ def fetch_projects(user_id):
71
+ try:
72
+ url = f"https://thexforce-combat-backend.hf.space/{user_id}/projects"
73
+ response = requests.get(url, headers={"Authorization": f"Bearer {tok}"}, timeout=8)
74
+ if response.status_code == 200:
75
+ return response.json().get("projects", [])
76
+ return []
77
+ except:
78
+ return []
79
+
80
+ if st.user.is_logged_in:
81
+ projects = fetch_projects(st.user.email)
82
+ if projects:
83
+ choice = st.radio("Select or create project:", ["New Project"] + projects)
84
+ if choice == "New Project":
85
+ projectname = st.text_input("Enter new project name")
86
+ else:
87
+ projectname = choice
88
+ else:
89
+ projectname = st.text_input("Enter project name")
90
+
91
+ st.session_state.projectname = projectname
92
+ st.markdown(f"👤 Logged in as **{st.user.email}**")
93
+ if st.button("🚪 Logout"):
94
+ st.logout()
95
+ st.rerun()
96
+ else:
97
+ st.info("🔑 Please log in")
98
+ if st.button("Log in"):
99
+ st.login("auth0")
100
+ st.stop()
101
+
102
+ # Main chat interface
103
+ if st.user.is_logged_in:
104
+ st.subheader("💬 Research Dialogue")
105
+ if "messages" not in st.session_state:
106
+ st.session_state.messages = []
107
+
108
+ # Render chat history
109
+ for msg in st.session_state.messages:
110
+ role_class = "chat-bubble-user" if msg["role"] == "user" else "chat-bubble-assistant"
111
+ st.markdown(f"<div class='{role_class}'>{msg['content']}</div>", unsafe_allow_html=True)
112
+
113
+ user_input = st.chat_input("Type your biological query...")
114
+
115
+ if user_input:
116
+ st.session_state.messages.append({"role": "user", "content": user_input})
117
+ st.markdown(f"<div class='chat-bubble-user'>{user_input}</div>", unsafe_allow_html=True)
118
+
119
+ if not st.session_state.projectname:
120
+ st.warning("⚠️ Please set a project first!")
121
+ return
122
+
123
+ with st.spinner("Identifying targets..."):
124
+ target = Target_Identification(user_input)
125
+ time.sleep(0.5)
126
+
127
+ payload = {
128
+ "uid": st.user.email,
129
+ "pid": st.session_state.projectname,
130
+ "target": target or None,
131
+ "high_level_bio_query": user_input,
132
+ }
133
+
134
+ response = requests.post(
135
+ "https://thexforce-combat-backend.hf.space/application_layer_agent",
136
+ json=payload,
137
+ headers={"Authorization": f"Bearer {tok}"}
138
+ )
139
+
140
+ plan_response = response.json()
141
+
142
+ # Assistant typing animation
143
+ with st.container():
144
+ st.markdown(
145
+ "<div class='chat-bubble-assistant'>"
146
+ "<span class='typing-dots'></span><span class='typing-dots'></span><span class='typing-dots'></span>"
147
+ "</div>",
148
+ unsafe_allow_html=True,
149
  )
150
+ time.sleep(1.2)
151
 
152
+ st.session_state.messages.append({"role": "assistant", "content": str(plan_response)})
153
+ st.markdown(f"<div class='chat-bubble-assistant'>{plan_response}</div>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
+ APP()