Junaidb commited on
Commit
fd7ea58
·
verified ·
1 Parent(s): 1a16865

Update ui.py

Browse files
Files changed (1) hide show
  1. ui.py +269 -159
ui.py CHANGED
@@ -1,181 +1,291 @@
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
 
10
- import uuid
11
- #Generate a standard random UUID and convert it to a string
12
- def ider():
13
- long_uuid = str(uuid.uuid4())
14
- short_uuid = long_uuid[:5]
15
- return str(short_uuid)
16
-
17
-
18
-
19
-
20
-
21
-
22
- st.set_page_config(page_title="Bio Lab @newMATTER", layout="wide")
23
-
24
- # Cohere-like CSS styling
25
- st.markdown("""
26
- <style>
27
- body {background-color: #0E1117; color: #EAEAEA;}
28
- .chat-bubble-user {
29
- background-color: #3A3F47;
30
- color: white;
31
- padding: 10px 14px;
32
- border-radius: 16px;
33
- max-width: 75%;
34
- margin: 6px 0;
35
- margin-left: auto;
36
- box-shadow: 0 2px 6px rgba(0,0,0,0.4);
37
- animation: fadeIn 0.3s ease-in;
38
- }
39
- .chat-bubble-assistant {
40
- background-color: #23272F;
41
- color: #EAEAEA;
42
- padding: 10px 14px;
43
- border-radius: 16px;
44
- max-width: 75%;
45
- margin: 6px 0;
46
- margin-right: auto;
47
- box-shadow: 0 2px 6px rgba(0,0,0,0.4);
48
- animation: fadeIn 0.3s ease-in;
49
- }
50
- .typing-dots {
51
- display: inline-block;
52
- width: 4px; height: 4px;
53
- margin: 0 2px;
54
- background: #aaa;
55
- border-radius: 50%;
56
- animation: blink 1.2s infinite both;
57
- }
58
- .typing-dots:nth-child(2) { animation-delay: 0.2s; }
59
- .typing-dots:nth-child(3) { animation-delay: 0.4s; }
60
- @keyframes blink { 0%,80%,100%{opacity:0;} 40%{opacity:1;} }
61
- @keyframes fadeIn { from {opacity:0; transform: translateY(5px);} to {opacity:1; transform: translateY(0);} }
62
- </style>
63
- """, unsafe_allow_html=True)
64
 
 
65
 
 
66
  def Target_Identification(userinput):
67
  model = GLiNER.from_pretrained("Ihor/gliner-biomed-bi-small-v1.0")
68
- labels = ["Protein", "Mutation"]
69
  entities = model.predict_entities(userinput, labels, threshold=0.5)
 
70
  for entity in entities:
71
  if entity["label"] == "Protein":
72
  return entity["text"]
73
 
74
 
75
  def APP():
76
- st.title("🧬 BIO ENGINEERING LAB @newMATTER")
77
-
78
- # Sidebar (projects and session)
79
- with st.sidebar:
80
- st.header("📂 Project Manager")
81
-
82
- @st.cache_data(ttl=30)
83
- def fetch_projects(user_id):
84
- try:
85
- url = f"https://thexforce-combat-backend.hf.space/{user_id}/projects"
86
- response = requests.get(url, headers={"Authorization": f"Bearer {tok}"}, timeout=8)
87
- if response.status_code == 200:
88
- return response.json().get("projects", [])
89
- return []
90
- except:
91
- return []
92
-
93
- if st.user.is_logged_in:
94
- projects = fetch_projects(st.user.email)
95
- projectname=None
96
-
97
- skey1=ider()
98
- neww=st.selectbox("new project ?",["yes","no"],key=skey1)
99
-
100
- if projects:
101
- skey2=ider()
102
-
103
- choice = st.selectbox("select project",projects,key=skey2)
104
- projectname=choice
105
-
106
- if neww== "yes":
107
- tkey1=ider()
108
- projectname = st.text_input("Enter new project name",key=tkey1)
109
- #else:
110
- #projectname = choice
111
- #else:
112
- #projectname = st.text_input("Enter project name")
113
-
114
- st.session_state.projectname = projectname
115
- st.markdown(f"👤 Logged in as **{st.user.email}**")
116
- bkey1=ider()
117
- if st.button("🚪 Logout",key=bkey1):
118
- st.logout()
119
- st.rerun()
120
- else:
121
- st.info("🔑 Please log in")
122
- bkey2=ider()
123
- if st.button("Log in",key=bkey2):
124
- st.login("auth0")
125
- st.stop()
126
-
127
- # Main chat interface
128
- if st.user.is_logged_in:
129
- st.subheader("💬 Research Dialogue")
130
- if "messages" not in st.session_state:
131
- st.session_state.messages = []
132
-
133
- # Render chat history
134
- for msg in st.session_state.messages:
135
- role_class = "chat-bubble-user" if msg["role"] == "user" else "chat-bubble-assistant"
136
- st.markdown(f"<div class='{role_class}'>{msg['content']}</div>", unsafe_allow_html=True)
137
-
138
- ckey1=ider()
139
- user_input = st.chat_input("Type your biological query...",key=ckey1)
140
-
141
- if user_input:
142
- st.session_state.messages.append({"role": "user", "content": user_input})
143
- st.markdown(f"<div class='chat-bubble-user'>{user_input}</div>", unsafe_allow_html=True)
144
-
145
- if not st.session_state.projectname:
146
- st.warning("⚠️ Please set a project first!")
147
- return
148
-
149
- with st.spinner("Identifying targets..."):
150
- target = Target_Identification(user_input)
151
- time.sleep(0.5)
152
-
153
- payload = {
154
- "uid": st.user.email,
155
- "pid": st.session_state.projectname,
156
- "target": target or None,
157
- "high_level_bio_query": user_input,
158
- }
159
-
160
- response = requests.post(
161
- "https://thexforce-combat-backend.hf.space/application_layer_agent",
162
- json=payload,
163
- headers={"Authorization": f"Bearer {tok}"}
164
- )
165
-
166
- plan_response = response.json()
167
-
168
- # Assistant typing animation
169
- with st.container():
170
- st.markdown(
171
- "<div class='chat-bubble-assistant'>"
172
- "<span class='typing-dots'></span><span class='typing-dots'></span><span class='typing-dots'></span>"
173
- "</div>",
174
- unsafe_allow_html=True,
175
  )
176
- time.sleep(1.2)
177
 
178
- st.session_state.messages.append({"role": "assistant", "content": str(plan_response)})
179
- st.markdown(f"<div class='chat-bubble-assistant'>{plan_response}</div>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
- APP()
 
 
 
 
 
 
 
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()