daqc commited on
Commit
cd7d11f
ยท
verified ยท
1 Parent(s): b1ced03

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +145 -168
app.py CHANGED
@@ -4,6 +4,7 @@ import os
4
  import re
5
  import shutil
6
  import threading
 
7
  from typing import Optional
8
  from loguru import logger
9
  from datetime import datetime
@@ -85,65 +86,20 @@ if os.getenv("HF_TOKEN"):
85
  logger.warning(f"Failed to login with HF_TOKEN from environment: {e}")
86
  logger.info("You can still use the application by providing a valid API key in the interface")
87
 
88
- append_answer_lock = threading.Lock()
89
-
90
- custom_role_conversions = {"tool-call": "assistant", "tool-response": "user"}
91
-
92
- user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0"
93
-
94
- BROWSER_CONFIG = {
95
- "viewport_size": 1024 * 5,
96
- "downloads_folder": "downloads_folder",
97
- "request_kwargs": {
98
- "headers": {"User-Agent": user_agent},
99
- "timeout": 300,
100
- },
101
- "serpapi_key": os.getenv("SERPAPI_API_KEY"),
102
- }
103
-
104
- os.makedirs(f"./{BROWSER_CONFIG['downloads_folder']}", exist_ok=True)
105
 
106
- # Default Hugging Face model configuration
107
- model_id = os.getenv("MODEL_ID", "Qwen/Qwen2.5-Coder-32B-Instruct")
108
- logger.info(f"Default Hugging Face model: {model_id}")
109
 
110
- # Define text_limit before using it
111
- text_limit = 20000
112
 
113
- # Default model (will be overridden by session-specific models)
114
- # Note: This model may not work without a valid API key
115
- default_model = None
116
- ti_tool = None
117
 
118
- # Only try to create default model if we have a valid token
119
- if os.getenv("HF_TOKEN"):
120
- try:
121
- # Test if the token is valid
122
- api = HfApi(token=os.getenv("HF_TOKEN"))
123
- api.whoami() # This will raise an exception if token is invalid
124
- # If we get here, token is valid
125
- default_model = InferenceClientModel(
126
- model_id,
127
- custom_role_conversions={
128
- "tool-call": "assistant",
129
- "tool-response": "user"
130
- },
131
- token=os.getenv("HF_TOKEN")
132
- )
133
- ti_tool = TextInspectorTool(default_model, text_limit)
134
- logger.info("Default model created successfully with valid token")
135
- except Exception as e:
136
- logger.warning(f"Failed to create default model: {e}")
137
- default_model = None
138
- ti_tool = None
139
- else:
140
- logger.info("No HF_TOKEN provided, default model will be created when user provides API key")
141
-
142
- browser = SimpleTextBrowser(**BROWSER_CONFIG)
143
-
144
- # Tool configuration
145
  cvedb_tool = CVEDBTool()
146
- report_generator = ReportGeneratorTool()
147
  epss_tool = EpsTool()
148
  nvd_tool = NvdTool()
149
  kevin_tool = KevinTool()
@@ -186,50 +142,22 @@ def validate_hf_api_key(api_key: str) -> tuple[bool, str]:
186
  return False, f"โŒ Invalid API key: {str(e)}"
187
 
188
  def create_model_with_api_key(hf_token: str, model_id: str = None) -> InferenceClientModel:
189
- """Create a new InferenceClientModel instance with the provided HF_TOKEN."""
190
  if not model_id:
191
- model_id = os.getenv("MODEL_ID", "Qwen/Qwen2.5-Coder-32B-Instruct")
192
-
193
- logger.info(f"Creating model {model_id} with token: {hf_token[:10]}...")
194
 
195
- # First, try to login with the token to ensure it's properly set
196
- try:
197
- login(hf_token)
198
- logger.info("Successfully logged in with token")
199
- except Exception as e:
200
- logger.warning(f"Login failed: {e}")
201
-
202
- # Create the model with explicit token
203
- model = InferenceClientModel(
204
- model_id,
205
- custom_role_conversions={
206
- "tool-call": "assistant",
207
- "tool-response": "user"
208
- },
209
- token=hf_token
210
  )
211
-
212
- # Verify the token is set correctly
213
- if hasattr(model, 'token'):
214
- logger.info(f"Model token attribute: {model.token[:10] if model.token else 'None'}...")
215
- else:
216
- logger.warning("Model does not have token attribute")
217
-
218
- # Test the model with a simple request to verify token works
219
- try:
220
- logger.info("Testing model with simple request...")
221
- # This is a simple test to see if the model can be accessed
222
- test_response = model.generate("Hello", max_new_tokens=5)
223
- logger.info("Model test successful")
224
- except Exception as e:
225
- logger.error(f"Model test failed: {e}")
226
- # Don't raise the exception, just log it
227
-
228
- logger.info(f"Model created successfully with token")
229
- return model
230
 
231
- def create_tools_with_model(model: InferenceClientModel) -> list:
232
- """Create tools list with the provided model."""
 
 
 
233
  return [
234
  web_search, # duckduckgo
235
  VisitTool(browser),
@@ -238,7 +166,7 @@ def create_tools_with_model(model: InferenceClientModel) -> list:
238
  FinderTool(browser),
239
  FindNextTool(browser),
240
  ArchiveSearchTool(browser),
241
- TextInspectorTool(model, text_limit),
242
  cvedb_tool, # CVEDB Tool
243
  # report_generator, # Report generation tool - COMMENTED: Only works locally
244
  epss_tool, # EPSS Tool
@@ -270,11 +198,60 @@ def create_agent(hf_token: str = None, model_id: str = None, max_steps: int = 10
270
  logger.info("Agent created successfully")
271
  return agent
272
 
273
- # Only create document_inspection_tool if default_model is available
274
- if default_model:
275
- document_inspection_tool = TextInspectorTool(default_model, 20000)
276
- else:
277
- document_inspection_tool = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
 
279
  class GradioUI:
280
  """A one-line interface to launch your agent in Gradio"""
@@ -308,59 +285,60 @@ class GradioUI:
308
  else:
309
  return message, "error"
310
 
311
- def interact_with_agent(self, prompt, messages, session_state):
312
- # Clear any stale session data at the beginning
313
- if "hf_token" in session_state and not session_state.get("hf_token"):
314
- del session_state["hf_token"]
315
- if "agent" in session_state and not session_state.get("agent"):
316
- del session_state["agent"]
 
317
 
318
- # Get or create session-specific agent
319
- if "agent" not in session_state:
320
  # Check if we have a valid HF_TOKEN in session
321
- hf_token = session_state.get("hf_token")
322
 
323
  # If no token in session, try to get it from .env file
324
  if not hf_token:
325
  env_token = os.getenv("HF_TOKEN")
326
  if env_token:
327
  hf_token = env_token
328
- session_state["hf_token"] = env_token
329
- session_state["max_steps"] = 10 # Default max_steps
330
- logger.info(f"Using HF_TOKEN from .env file: {env_token[:10]}...")
331
  else:
332
- logger.warning("No API key found in session state or .env file")
333
  error_msg = "โŒ No API key provided. Please enter your Hugging Face API key in the API Configuration section above or set HF_TOKEN in your .env file."
334
  messages.append(gr.ChatMessage(role="assistant", content=error_msg))
335
  yield messages
336
  return
337
 
338
- logger.info(f"Agent not in session, checking for token: {hf_token[:10] if hf_token else 'None'}...")
339
 
340
  if hf_token:
341
  try:
342
- max_steps = session_state.get("max_steps", 10)
343
- session_state["agent"] = create_agent(hf_token, max_steps=max_steps)
344
- logger.info("Agent created successfully in interact_with_agent")
345
  except Exception as e:
346
- logger.error(f"Failed to create agent in interact_with_agent: {e}")
347
  error_msg = f"โŒ Failed to create agent with provided API key: {str(e)}"
348
  messages.append(gr.ChatMessage(role="assistant", content=error_msg))
349
  yield messages
350
  return
351
  else:
352
- logger.info("Agent already exists in session")
353
 
354
  # Adding monitoring
355
  try:
356
  # log the existence of agent memory
357
- has_memory = hasattr(session_state["agent"], "memory")
358
  print(f"Agent has memory: {has_memory}")
359
  if has_memory:
360
- print(f"Memory type: {type(session_state['agent'].memory)}")
361
 
362
  # Prepare the system prompt
363
- system_prompt = f"""You are a Vulnerability Intelligence Analyst. Complete the user request in {session_state.get('max_steps', 10)} steps maximum.
364
 
365
  AVAILABLE TOOLS: nvd_search, web_search, cvedb_search, kevin_search, epss_search
366
 
@@ -428,9 +406,9 @@ User Query: """
428
  messages.append(gr.ChatMessage(role="user", content=prompt))
429
  yield messages
430
 
431
- logger.info("Starting agent interaction...")
432
  for msg in stream_to_gradio(
433
- session_state["agent"], task=full_prompt, reset_agent_memory=False
434
  ):
435
  # If the message contains an HTML report, we save it and update the message
436
  if isinstance(msg.content, str) and msg.content.startswith("<!DOCTYPE html>"):
@@ -441,24 +419,25 @@ User Query: """
441
  yield messages
442
 
443
  # Clear sensitive data from session after interaction (AUTOMATIC)
444
- if "hf_token" in session_state:
445
- del session_state["hf_token"]
446
- if "agent" in session_state:
447
- del session_state["agent"]
448
- if "HF_TOKEN" in os.environ:
449
- del os.environ["HF_TOKEN"]
450
- logger.info("Session automatically cleared after interaction")
451
 
452
  yield messages
453
  except Exception as e:
454
- logger.error(f"Error in interaction: {str(e)}")
455
  print(f"Error in interaction: {str(e)}")
456
  error_msg = f"โŒ Error during interaction: {str(e)}"
457
  messages.append(gr.ChatMessage(role="assistant", content=error_msg))
458
  yield messages
459
 
460
- def setup_api_key(self, api_key: str, max_steps: int, session_state) -> str:
461
- """Setup API key for the session."""
 
 
 
 
 
 
462
  # Check if API key is provided from interface
463
  if api_key and api_key.strip():
464
  # Use the API key from interface
@@ -477,30 +456,24 @@ User Query: """
477
  is_valid, message = validate_hf_api_key(token_to_use)
478
 
479
  if is_valid:
480
- # Store HF_TOKEN in session state (but will be cleared after use)
481
- session_state["hf_token"] = token_to_use
482
- session_state["max_steps"] = max_steps
483
- logger.info(f"API key stored in session from {source}: {token_to_use[:10]}...")
484
  logger.info(f"Max steps set to: {max_steps}")
485
 
486
- # Also set the environment variable for smolagents
487
- os.environ["HF_TOKEN"] = token_to_use
488
- logger.info("HF_TOKEN environment variable set")
489
-
490
  # Create new agent with the HF_TOKEN and max_steps
491
  try:
492
- session_state["agent"] = create_agent(token_to_use, max_steps=max_steps)
493
- logger.info("Agent created successfully in setup_api_key")
494
  return f"โœ… API key from {source} validated and agent created successfully! {message.split('!')[1] if '!' in message else ''}"
495
  except Exception as e:
496
- logger.error(f"Failed to create agent in setup_api_key: {e}")
497
  return f"โŒ Failed to create agent with API key from {source}: {str(e)}"
498
  else:
499
- logger.warning(f"Invalid API key from {source}: {token_to_use[:10] if token_to_use else 'None'}...")
500
  return f"โŒ Invalid API key from {source}: {message}"
501
 
502
-
503
-
504
  def upload_file(
505
  self,
506
  file,
@@ -693,7 +666,7 @@ This AI agent specializes in automated vulnerability research and analysis, buil
693
  # API Key Configuration Section
694
  with gr.Accordion("๐Ÿ”‘ API Configuration", open=False):
695
  gr.Markdown("**Configure your Hugging Face API Key**")
696
- gr.Markdown("๐Ÿ”’ **Security**: API keys are automatically cleared after each interaction for your privacy.")
697
  gr.Markdown("Get your API key from: https://huggingface.co/settings/tokens")
698
 
699
  api_key_input = gr.Textbox(
@@ -742,10 +715,7 @@ This AI agent specializes in automated vulnerability research and analysis, buil
742
  <a target="_blank" href="https://github.com/huggingface/smolagents"><b>hf/smolagents</b></a>
743
  </div>""")
744
 
745
- # Add session state to store session-specific data
746
- session_state = gr.State(
747
- {}
748
- ) # Initialize empty state for each session
749
  stored_messages = gr.State([])
750
  chatbot = gr.Chatbot(
751
  label="open-Deep-Research",
@@ -765,7 +735,7 @@ This AI agent specializes in automated vulnerability research and analysis, buil
765
  # API Key setup event
766
  setup_api_btn.click(
767
  self.setup_api_key,
768
- [api_key_input, max_steps_slider, session_state],
769
  [api_key_status]
770
  )
771
 
@@ -777,8 +747,7 @@ This AI agent specializes in automated vulnerability research and analysis, buil
777
  [stored_messages, text_input, launch_research_btn],
778
  ).then(
779
  self.interact_with_agent,
780
- # Include session_state in function calls
781
- [stored_messages, chatbot, session_state],
782
  [chatbot],
783
  ).then(
784
  lambda: (
@@ -797,8 +766,7 @@ This AI agent specializes in automated vulnerability research and analysis, buil
797
  [stored_messages, text_input, launch_research_btn],
798
  ).then(
799
  self.interact_with_agent,
800
- # Include session_state in function calls
801
- [stored_messages, chatbot, session_state],
802
  [chatbot],
803
  ).then(
804
  lambda: (
@@ -846,7 +814,7 @@ This AI agent specializes in automated vulnerability research and analysis, buil
846
  # API Key Configuration Section for Mobile
847
  with gr.Accordion("๐Ÿ”‘ API Configuration", open=False):
848
  gr.Markdown("**Configure your Hugging Face API Key**")
849
- gr.Markdown("๐Ÿ”’ **Security**: API keys are automatically cleared after each interaction for your privacy.")
850
  gr.Markdown("Get your API key from: https://huggingface.co/settings/tokens")
851
 
852
  mobile_api_key_input = gr.Textbox(
@@ -874,10 +842,7 @@ This AI agent specializes in automated vulnerability research and analysis, buil
874
 
875
  mobile_setup_api_btn = gr.Button("Setup API Key", variant="secondary")
876
 
877
- # Add session state to store session-specific data
878
- session_state = gr.State(
879
- {}
880
- ) # Initialize empty state for each session
881
  stored_messages = gr.State([])
882
  file_uploads_log = gr.State([])
883
  chatbot = gr.Chatbot(
@@ -894,7 +859,7 @@ This AI agent specializes in automated vulnerability research and analysis, buil
894
  # Mobile API Key setup event
895
  mobile_setup_api_btn.click(
896
  self.setup_api_key,
897
- [mobile_api_key_input, mobile_max_steps_slider, session_state],
898
  [mobile_api_key_status]
899
  )
900
 
@@ -977,8 +942,7 @@ This AI agent specializes in automated vulnerability research and analysis, buil
977
  [stored_messages, text_input, launch_research_btn],
978
  ).then(
979
  self.interact_with_agent,
980
- # Include session_state in function calls
981
- [stored_messages, chatbot, session_state],
982
  [chatbot],
983
  ).then(
984
  lambda: (
@@ -997,8 +961,7 @@ This AI agent specializes in automated vulnerability research and analysis, buil
997
  [stored_messages, text_input, launch_research_btn],
998
  ).then(
999
  self.interact_with_agent,
1000
- # Include session_state in function calls
1001
- [stored_messages, chatbot, session_state],
1002
  [chatbot],
1003
  ).then(
1004
  lambda: (
@@ -1012,6 +975,20 @@ This AI agent specializes in automated vulnerability research and analysis, buil
1012
  [text_input, launch_research_btn],
1013
  )
1014
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1015
  demo.launch(debug=True, **kwargs)
1016
 
1017
  # can this fix ctrl-c no response? no
 
4
  import re
5
  import shutil
6
  import threading
7
+ import uuid
8
  from typing import Optional
9
  from loguru import logger
10
  from datetime import datetime
 
86
  logger.warning(f"Failed to login with HF_TOKEN from environment: {e}")
87
  logger.info("You can still use the application by providing a valid API key in the interface")
88
 
89
+ # Global session storage for independent user sessions
90
+ user_sessions = {}
91
+ session_lock = threading.Lock()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
+ append_answer_lock = threading.Lock()
 
 
94
 
95
+ # Initialize browser
96
+ browser = SimpleTextBrowser()
97
 
98
+ # Initialize tools
99
+ ti_tool = TextInspectorTool(None, 20000) # Will be updated with session-specific model
 
 
100
 
101
+ # Initialize vulnerability tools
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  cvedb_tool = CVEDBTool()
 
103
  epss_tool = EpsTool()
104
  nvd_tool = NvdTool()
105
  kevin_tool = KevinTool()
 
142
  return False, f"โŒ Invalid API key: {str(e)}"
143
 
144
  def create_model_with_api_key(hf_token: str, model_id: str = None) -> InferenceClientModel:
145
+ """Create a model instance with the provided API key."""
146
  if not model_id:
147
+ model_id = "Qwen/Qwen2.5-Coder-32B-Instruct"
 
 
148
 
149
+ return InferenceClientModel(
150
+ model_id=model_id,
151
+ hf_token=hf_token,
152
+ temperature=0.1,
153
+ max_tokens=4000,
 
 
 
 
 
 
 
 
 
 
154
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
+ def create_tools_with_model(model: InferenceClientModel):
157
+ """Create tools with the provided model."""
158
+ # Update text inspector tool with the model
159
+ ti_tool = TextInspectorTool(model, 20000)
160
+
161
  return [
162
  web_search, # duckduckgo
163
  VisitTool(browser),
 
166
  FinderTool(browser),
167
  FindNextTool(browser),
168
  ArchiveSearchTool(browser),
169
+ ] + ([ti_tool] if ti_tool else []) + [
170
  cvedb_tool, # CVEDB Tool
171
  # report_generator, # Report generation tool - COMMENTED: Only works locally
172
  epss_tool, # EPSS Tool
 
198
  logger.info("Agent created successfully")
199
  return agent
200
 
201
+ # Document inspection tool will be created per session
202
+ document_inspection_tool = None
203
+
204
+ def get_user_session(request: gr.Request) -> str:
205
+ """Get or create a unique session ID for the user."""
206
+ if not request:
207
+ return str(uuid.uuid4())
208
+
209
+ # Try to get session from headers or create new one
210
+ session_id = request.headers.get("x-session-id")
211
+ if not session_id:
212
+ session_id = str(uuid.uuid4())
213
+
214
+ return session_id
215
+
216
+ def get_session_data(session_id: str) -> dict:
217
+ """Get session data for a specific user."""
218
+ with session_lock:
219
+ if session_id not in user_sessions:
220
+ user_sessions[session_id] = {
221
+ "hf_token": None,
222
+ "agent": None,
223
+ "max_steps": 10,
224
+ "created_at": datetime.now()
225
+ }
226
+ return user_sessions[session_id]
227
+
228
+ def clear_session_data(session_id: str):
229
+ """Clear session data for a specific user."""
230
+ with session_lock:
231
+ if session_id in user_sessions:
232
+ # Clear sensitive data
233
+ user_sessions[session_id]["hf_token"] = None
234
+ user_sessions[session_id]["agent"] = None
235
+ logger.info(f"Session {session_id[:8]}... cleared")
236
+
237
+ def cleanup_old_sessions():
238
+ """Clean up sessions older than 1 hour."""
239
+ with session_lock:
240
+ current_time = datetime.now()
241
+ sessions_to_remove = []
242
+
243
+ for session_id, session_data in user_sessions.items():
244
+ if session_data.get("created_at"):
245
+ time_diff = current_time - session_data["created_at"]
246
+ if time_diff.total_seconds() > 3600: # 1 hour
247
+ sessions_to_remove.append(session_id)
248
+
249
+ for session_id in sessions_to_remove:
250
+ del user_sessions[session_id]
251
+ logger.info(f"Removed old session {session_id[:8]}...")
252
+
253
+ if sessions_to_remove:
254
+ logger.info(f"Cleaned up {len(sessions_to_remove)} old sessions")
255
 
256
  class GradioUI:
257
  """A one-line interface to launch your agent in Gradio"""
 
285
  else:
286
  return message, "error"
287
 
288
+ def interact_with_agent(self, prompt, messages, request: gr.Request):
289
+ """Handle agent interaction with proper session management."""
290
+ # Get unique session ID for this user
291
+ session_id = get_user_session(request)
292
+ session_data = get_session_data(session_id)
293
+
294
+ logger.info(f"Processing request for session {session_id[:8]}...")
295
 
296
+ # Check if we have a valid agent for this session
297
+ if not session_data.get("agent"):
298
  # Check if we have a valid HF_TOKEN in session
299
+ hf_token = session_data.get("hf_token")
300
 
301
  # If no token in session, try to get it from .env file
302
  if not hf_token:
303
  env_token = os.getenv("HF_TOKEN")
304
  if env_token:
305
  hf_token = env_token
306
+ session_data["hf_token"] = env_token
307
+ session_data["max_steps"] = 10 # Default max_steps
308
+ logger.info(f"Using HF_TOKEN from .env file for session {session_id[:8]}...")
309
  else:
310
+ logger.warning(f"No API key found for session {session_id[:8]}...")
311
  error_msg = "โŒ No API key provided. Please enter your Hugging Face API key in the API Configuration section above or set HF_TOKEN in your .env file."
312
  messages.append(gr.ChatMessage(role="assistant", content=error_msg))
313
  yield messages
314
  return
315
 
316
+ logger.info(f"Creating agent for session {session_id[:8]}...")
317
 
318
  if hf_token:
319
  try:
320
+ max_steps = session_data.get("max_steps", 10)
321
+ session_data["agent"] = create_agent(hf_token, max_steps=max_steps)
322
+ logger.info(f"Agent created successfully for session {session_id[:8]}...")
323
  except Exception as e:
324
+ logger.error(f"Failed to create agent for session {session_id[:8]}: {e}")
325
  error_msg = f"โŒ Failed to create agent with provided API key: {str(e)}"
326
  messages.append(gr.ChatMessage(role="assistant", content=error_msg))
327
  yield messages
328
  return
329
  else:
330
+ logger.info(f"Agent already exists for session {session_id[:8]}...")
331
 
332
  # Adding monitoring
333
  try:
334
  # log the existence of agent memory
335
+ has_memory = hasattr(session_data["agent"], "memory")
336
  print(f"Agent has memory: {has_memory}")
337
  if has_memory:
338
+ print(f"Memory type: {type(session_data['agent'].memory)}")
339
 
340
  # Prepare the system prompt
341
+ system_prompt = f"""You are a Vulnerability Intelligence Analyst. Complete the user request in {session_data.get('max_steps', 10)} steps maximum.
342
 
343
  AVAILABLE TOOLS: nvd_search, web_search, cvedb_search, kevin_search, epss_search
344
 
 
406
  messages.append(gr.ChatMessage(role="user", content=prompt))
407
  yield messages
408
 
409
+ logger.info(f"Starting agent interaction for session {session_id[:8]}...")
410
  for msg in stream_to_gradio(
411
+ session_data["agent"], task=full_prompt, reset_agent_memory=False
412
  ):
413
  # If the message contains an HTML report, we save it and update the message
414
  if isinstance(msg.content, str) and msg.content.startswith("<!DOCTYPE html>"):
 
419
  yield messages
420
 
421
  # Clear sensitive data from session after interaction (AUTOMATIC)
422
+ clear_session_data(session_id)
423
+ logger.info(f"Session {session_id[:8]}... automatically cleared after interaction")
 
 
 
 
 
424
 
425
  yield messages
426
  except Exception as e:
427
+ logger.error(f"Error in interaction for session {session_id[:8]}: {str(e)}")
428
  print(f"Error in interaction: {str(e)}")
429
  error_msg = f"โŒ Error during interaction: {str(e)}"
430
  messages.append(gr.ChatMessage(role="assistant", content=error_msg))
431
  yield messages
432
 
433
+ def setup_api_key(self, api_key: str, max_steps: int, request: gr.Request) -> str:
434
+ """Setup API key for the user's session."""
435
+ # Get unique session ID for this user
436
+ session_id = get_user_session(request)
437
+ session_data = get_session_data(session_id)
438
+
439
+ logger.info(f"Setting up API key for session {session_id[:8]}...")
440
+
441
  # Check if API key is provided from interface
442
  if api_key and api_key.strip():
443
  # Use the API key from interface
 
456
  is_valid, message = validate_hf_api_key(token_to_use)
457
 
458
  if is_valid:
459
+ # Store HF_TOKEN in session data
460
+ session_data["hf_token"] = token_to_use
461
+ session_data["max_steps"] = max_steps
462
+ logger.info(f"API key stored in session {session_id[:8]}... from {source}")
463
  logger.info(f"Max steps set to: {max_steps}")
464
 
 
 
 
 
465
  # Create new agent with the HF_TOKEN and max_steps
466
  try:
467
+ session_data["agent"] = create_agent(token_to_use, max_steps=max_steps)
468
+ logger.info(f"Agent created successfully for session {session_id[:8]}...")
469
  return f"โœ… API key from {source} validated and agent created successfully! {message.split('!')[1] if '!' in message else ''}"
470
  except Exception as e:
471
+ logger.error(f"Failed to create agent for session {session_id[:8]}: {e}")
472
  return f"โŒ Failed to create agent with API key from {source}: {str(e)}"
473
  else:
474
+ logger.warning(f"Invalid API key for session {session_id[:8]}... from {source}")
475
  return f"โŒ Invalid API key from {source}: {message}"
476
 
 
 
477
  def upload_file(
478
  self,
479
  file,
 
666
  # API Key Configuration Section
667
  with gr.Accordion("๐Ÿ”‘ API Configuration", open=False):
668
  gr.Markdown("**Configure your Hugging Face API Key**")
669
+ gr.Markdown("๐Ÿ”’ **Security**: Each user has an independent session. API keys are automatically cleared after each interaction for your privacy.")
670
  gr.Markdown("Get your API key from: https://huggingface.co/settings/tokens")
671
 
672
  api_key_input = gr.Textbox(
 
715
  <a target="_blank" href="https://github.com/huggingface/smolagents"><b>hf/smolagents</b></a>
716
  </div>""")
717
 
718
+ # Chat interface
 
 
 
719
  stored_messages = gr.State([])
720
  chatbot = gr.Chatbot(
721
  label="open-Deep-Research",
 
735
  # API Key setup event
736
  setup_api_btn.click(
737
  self.setup_api_key,
738
+ [api_key_input, max_steps_slider],
739
  [api_key_status]
740
  )
741
 
 
747
  [stored_messages, text_input, launch_research_btn],
748
  ).then(
749
  self.interact_with_agent,
750
+ [stored_messages, chatbot],
 
751
  [chatbot],
752
  ).then(
753
  lambda: (
 
766
  [stored_messages, text_input, launch_research_btn],
767
  ).then(
768
  self.interact_with_agent,
769
+ [stored_messages, chatbot],
 
770
  [chatbot],
771
  ).then(
772
  lambda: (
 
814
  # API Key Configuration Section for Mobile
815
  with gr.Accordion("๐Ÿ”‘ API Configuration", open=False):
816
  gr.Markdown("**Configure your Hugging Face API Key**")
817
+ gr.Markdown("๐Ÿ”’ **Security**: Each user has an independent session. API keys are automatically cleared after each interaction for your privacy.")
818
  gr.Markdown("Get your API key from: https://huggingface.co/settings/tokens")
819
 
820
  mobile_api_key_input = gr.Textbox(
 
842
 
843
  mobile_setup_api_btn = gr.Button("Setup API Key", variant="secondary")
844
 
845
+ # Chat interface for mobile
 
 
 
846
  stored_messages = gr.State([])
847
  file_uploads_log = gr.State([])
848
  chatbot = gr.Chatbot(
 
859
  # Mobile API Key setup event
860
  mobile_setup_api_btn.click(
861
  self.setup_api_key,
862
+ [mobile_api_key_input, mobile_max_steps_slider],
863
  [mobile_api_key_status]
864
  )
865
 
 
942
  [stored_messages, text_input, launch_research_btn],
943
  ).then(
944
  self.interact_with_agent,
945
+ [stored_messages, chatbot],
 
946
  [chatbot],
947
  ).then(
948
  lambda: (
 
961
  [stored_messages, text_input, launch_research_btn],
962
  ).then(
963
  self.interact_with_agent,
964
+ [stored_messages, chatbot],
 
965
  [chatbot],
966
  ).then(
967
  lambda: (
 
975
  [text_input, launch_research_btn],
976
  )
977
 
978
+ # Start periodic cleanup of old sessions
979
+ def periodic_cleanup():
980
+ import time
981
+ while True:
982
+ try:
983
+ cleanup_old_sessions()
984
+ time.sleep(300) # Run every 5 minutes
985
+ except Exception as e:
986
+ logger.error(f"Error in periodic cleanup: {e}")
987
+ time.sleep(300)
988
+
989
+ cleanup_thread = threading.Thread(target=periodic_cleanup, daemon=True)
990
+ cleanup_thread.start()
991
+
992
  demo.launch(debug=True, **kwargs)
993
 
994
  # can this fix ctrl-c no response? no