ddas commited on
Commit
e79c8c3
Β·
unverified Β·
1 Parent(s): 4ce7d6f

better error messages

Browse files
Files changed (1) hide show
  1. app.py +206 -16
app.py CHANGED
@@ -36,6 +36,115 @@ MODEL_URL = "https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.b
36
  # Global counter for error modals to help with debugging
37
  _ERROR_MODAL_COUNTER = 0
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  def validate_english_only_windowed(text, model=None):
40
  """
41
  Validates that input text is English-only using sliding window approach.
@@ -652,10 +761,13 @@ def reset_to_initial_state():
652
  for i, email in enumerate(INBOX):
653
  reset_emails.append(format_single_email(email, i + 1))
654
 
 
 
 
655
  return (
656
  "", # Clear attack subject
657
  "", # Clear attack body
658
- "gpt-4o", # Reset model to default
659
  "", # Final output cleared
660
  "πŸ”„ Interface reset to initial state", # Trace message in accordion
661
  reset_emails[0], # Reset email 1
@@ -1112,31 +1224,33 @@ You achieve Attacker Goal 2 and user goal is also achieved and no information ab
1112
  with gr.Group(elem_id="defense-toggle-container"):
1113
  with gr.Row(elem_id="defense-toggle-row"):
1114
  with gr.Column(scale=2, min_width=200):
 
 
1115
  model_selector = gr.Dropdown(
1116
- choices=["claude-3-5-haiku-20241022", "gpt-4o", "claude-3-5-sonnet-20241022","gpt-5"],
1117
- value="gpt-4o",
1118
  label="Select Agent LLM",
1119
  elem_id="model-selector"
1120
  )
1121
  with gr.Column(scale=2, min_width=100):
1122
  defense_toggle = gr.Checkbox(label="Instruction Tagger Defense", value=True, elem_id="defense-toggle")
1123
 
1124
- system_display = gr.Textbox(
1125
- value=SYSTEM_PROMPT,
1126
  lines=2,
1127
- interactive=False,
1128
- show_copy_button=True,
1129
  label="System Prompt"
1130
- )
1131
-
1132
 
1133
- user_input_display = gr.Textbox(
1134
- value=USER_INPUT,
1135
  lines=1,
1136
- interactive=False,
1137
- show_copy_button=True,
1138
  label="User Query (Fixed)"
1139
- )
1140
 
1141
  # (Moved defense toggle to top; removed previous placement)
1142
 
@@ -1376,7 +1490,24 @@ You achieve Attacker Goal 2 and user goal is also achieved and no information ab
1376
  except Exception as e:
1377
  validation_errors.append(f"EMAIL BODY: Validation failed - {str(e)}")
1378
 
1379
- # If there are validation errors, show them all in the popup
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1380
  if validation_errors:
1381
  error_timestamp = int(time.time() * 1000)
1382
  print(f"🚨 VALIDATION ERRORS FOUND: {len(validation_errors)} errors at {error_timestamp}")
@@ -1402,7 +1533,66 @@ You achieve Attacker Goal 2 and user goal is also achieved and no information ab
1402
  "subject_confidence_scores": subject_confidence_scores,
1403
  "body_confidence_scores": body_confidence_scores
1404
  }
1405
- exec_log, final_out = submit_attack(from_addr.strip(), subject, body, model, defense_enabled, user_info.strip(), confidence_scores)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1406
 
1407
  # Build a formatted results summary extracted from exec_log
1408
  def build_results_html(log_text: str) -> str:
 
36
  # Global counter for error modals to help with debugging
37
  _ERROR_MODAL_COUNTER = 0
38
 
39
+ def get_available_api_keys():
40
+ """
41
+ Check which API keys are available in environment variables.
42
+
43
+ Returns:
44
+ dict: Dictionary with 'openai', 'anthropic', and 'invariant' boolean flags
45
+ """
46
+ return {
47
+ 'openai': bool(os.getenv('OPENAI_API_KEY')),
48
+ 'anthropic': bool(os.getenv('ANTHROPIC_API_KEY')),
49
+ 'invariant': bool(os.getenv('INVARIANT_API_KEY'))
50
+ }
51
+
52
+ def get_available_models():
53
+ """
54
+ Get list of available models based on API keys present.
55
+
56
+ Returns:
57
+ tuple: (choices_list, default_model)
58
+ """
59
+ api_keys = get_available_api_keys()
60
+
61
+ choices = []
62
+
63
+ # OpenAI models
64
+ if api_keys['openai']:
65
+ choices.extend(["gpt-4o", "gpt-5"])
66
+
67
+ # Anthropic models
68
+ if api_keys['anthropic']:
69
+ choices.extend(["claude-3-5-haiku-20241022", "claude-3-5-sonnet-20241022"])
70
+
71
+ # Determine default model based on available keys
72
+ if api_keys['openai']:
73
+ default_model = "gpt-4o"
74
+ elif api_keys['anthropic']:
75
+ default_model = "claude-3-5-sonnet-20241022"
76
+ else:
77
+ # No API keys available - we'll handle this in submit function
78
+ choices = ["No models available"]
79
+ default_model = "No models available"
80
+
81
+ return choices, default_model
82
+
83
+ def validate_api_key_for_model(model_name):
84
+ """
85
+ Validate that the required API key is available for the selected model.
86
+
87
+ Args:
88
+ model_name (str): Selected model name
89
+
90
+ Returns:
91
+ tuple: (is_valid, error_message)
92
+ """
93
+ api_keys = get_available_api_keys()
94
+
95
+ if model_name.startswith("gpt"):
96
+ if not api_keys['openai']:
97
+ return False, "OpenAI API key is required for GPT models. Please add OPENAI_API_KEY to your environment variables."
98
+
99
+ elif model_name.startswith("claude"):
100
+ if not api_keys['anthropic']:
101
+ return False, "Anthropic API key is required for Claude models. Please add ANTHROPIC_API_KEY to your environment variables."
102
+
103
+ elif model_name == "No models available":
104
+ return False, "No API keys found. Please add either OPENAI_API_KEY or ANTHROPIC_API_KEY to your environment variables to use this application."
105
+
106
+ return True, ""
107
+
108
+ def validate_invariant_api_key():
109
+ """
110
+ Validate that INVARIANT_API_KEY is available for trace collection.
111
+
112
+ Returns:
113
+ tuple: (is_valid, error_message)
114
+ """
115
+ api_keys = get_available_api_keys()
116
+
117
+ if not api_keys['invariant']:
118
+ return False, "Invariant Labs API key is required for trace collection and analysis. Please add INVARIANT_API_KEY to your environment variables. You can get an API key from https://invariantlabs.ai/"
119
+
120
+ return True, ""
121
+
122
+ def validate_model_dependencies():
123
+ """
124
+ Validate that critical models can be loaded.
125
+
126
+ Returns:
127
+ tuple: (is_valid, error_message)
128
+ """
129
+ try:
130
+ # Test FastText model loading
131
+ model = load_fasttext_model()
132
+ if model is None:
133
+ return False, "FastText language detection model failed to load. This is required for input validation."
134
+ except Exception as e:
135
+ return False, f"FastText model loading error: {str(e)}. Language detection is required for the application to function."
136
+
137
+ try:
138
+ # Test instruction classifier loading (only if defense would be enabled)
139
+ from instruction_classifier import get_sanitizer
140
+ sanitizer = get_sanitizer()
141
+ if sanitizer is None:
142
+ return False, "Instruction classifier model failed to load. This is required for defense system functionality."
143
+ except Exception as e:
144
+ return False, f"Instruction classifier loading error: {str(e)}. Defense system requires this model to function properly."
145
+
146
+ return True, ""
147
+
148
  def validate_english_only_windowed(text, model=None):
149
  """
150
  Validates that input text is English-only using sliding window approach.
 
761
  for i, email in enumerate(INBOX):
762
  reset_emails.append(format_single_email(email, i + 1))
763
 
764
+ # Get current default model based on available API keys
765
+ _, default_model = get_available_models()
766
+
767
  return (
768
  "", # Clear attack subject
769
  "", # Clear attack body
770
+ default_model, # Reset model to current default
771
  "", # Final output cleared
772
  "πŸ”„ Interface reset to initial state", # Trace message in accordion
773
  reset_emails[0], # Reset email 1
 
1224
  with gr.Group(elem_id="defense-toggle-container"):
1225
  with gr.Row(elem_id="defense-toggle-row"):
1226
  with gr.Column(scale=2, min_width=200):
1227
+ # Get available models based on API keys
1228
+ available_choices, default_model = get_available_models()
1229
  model_selector = gr.Dropdown(
1230
+ choices=available_choices,
1231
+ value=default_model,
1232
  label="Select Agent LLM",
1233
  elem_id="model-selector"
1234
  )
1235
  with gr.Column(scale=2, min_width=100):
1236
  defense_toggle = gr.Checkbox(label="Instruction Tagger Defense", value=True, elem_id="defense-toggle")
1237
 
1238
+ system_display = gr.Textbox(
1239
+ value=SYSTEM_PROMPT,
1240
  lines=2,
1241
+ interactive=False,
1242
+ show_copy_button=True,
1243
  label="System Prompt"
1244
+ )
1245
+
1246
 
1247
+ user_input_display = gr.Textbox(
1248
+ value=USER_INPUT,
1249
  lines=1,
1250
+ interactive=False,
1251
+ show_copy_button=True,
1252
  label="User Query (Fixed)"
1253
+ )
1254
 
1255
  # (Moved defense toggle to top; removed previous placement)
1256
 
 
1490
  except Exception as e:
1491
  validation_errors.append(f"EMAIL BODY: Validation failed - {str(e)}")
1492
 
1493
+
1494
+
1495
+ # 4. Validate API key for selected model
1496
+ is_api_valid, api_error_msg = validate_api_key_for_model(model)
1497
+ if not is_api_valid:
1498
+ validation_errors.append(f"API CONFIGURATION: {api_error_msg}")
1499
+
1500
+ # 5. Validate Invariant API key for trace collection
1501
+ is_invariant_valid, invariant_error_msg = validate_invariant_api_key()
1502
+ if not is_invariant_valid:
1503
+ validation_errors.append(f"TRACE COLLECTION: {invariant_error_msg}")
1504
+
1505
+ # 6. Validate critical model dependencies
1506
+ is_models_valid, models_error_msg = validate_model_dependencies()
1507
+ if not is_models_valid:
1508
+ validation_errors.append(f"MODEL LOADING: {models_error_msg}")
1509
+
1510
+ # If there are validation errors (including API key), show them all in the popup
1511
  if validation_errors:
1512
  error_timestamp = int(time.time() * 1000)
1513
  print(f"🚨 VALIDATION ERRORS FOUND: {len(validation_errors)} errors at {error_timestamp}")
 
1533
  "subject_confidence_scores": subject_confidence_scores,
1534
  "body_confidence_scores": body_confidence_scores
1535
  }
1536
+
1537
+ try:
1538
+ exec_log, final_out = submit_attack(from_addr.strip(), subject, body, model, defense_enabled, user_info.strip(), confidence_scores)
1539
+ except Exception as e:
1540
+ # Handle any setup or execution errors with detailed messages
1541
+ error_str = str(e).lower()
1542
+ original_error = str(e)
1543
+
1544
+ # Categorize errors and provide specific guidance
1545
+ if "fasttext" in error_str or "lid.176.bin" in error_str:
1546
+ setup_error_msg = f"LANGUAGE MODEL ERROR: FastText language detection model failed to load. {original_error}"
1547
+ setup_error_msg += " This could be due to corrupted model file, insufficient memory, or missing dependencies. Try refreshing the page or contact support if the issue persists."
1548
+
1549
+ elif "instruction_classifier" in error_str or "instruction classifier" in error_str or "sanitizer" in error_str:
1550
+ setup_error_msg = f"DEFENSE MODEL ERROR: Instruction classifier model failed to load. {original_error}"
1551
+ setup_error_msg += " The defense system requires a working instruction classifier. This could be due to model file corruption, insufficient GPU memory, or missing dependencies."
1552
+
1553
+ elif "api_key" in error_str or "api key" in error_str or "authentication" in error_str or "unauthorized" in error_str:
1554
+ setup_error_msg = f"API AUTHENTICATION ERROR: {original_error}"
1555
+ setup_error_msg += " Please verify your API keys are correct and have sufficient credits/permissions."
1556
+
1557
+ elif "model" in error_str and ("not found" in error_str or "unavailable" in error_str or "invalid" in error_str):
1558
+ setup_error_msg = f"MODEL AVAILABILITY ERROR: {original_error}"
1559
+ setup_error_msg += " The selected model may be temporarily unavailable or you may not have access to it. Try a different model."
1560
+
1561
+ elif "network" in error_str or "connection" in error_str or "timeout" in error_str or "dns" in error_str:
1562
+ setup_error_msg = f"NETWORK ERROR: {original_error}"
1563
+ setup_error_msg += " Please check your internet connection and try again. If the problem persists, the service may be temporarily unavailable."
1564
+
1565
+ elif "memory" in error_str or "oom" in error_str or "cuda" in error_str or "gpu" in error_str:
1566
+ setup_error_msg = f"RESOURCE ERROR: {original_error}"
1567
+ setup_error_msg += " Insufficient system resources (memory/GPU). Try using a smaller model or refreshing the page."
1568
+
1569
+ elif "import" in error_str or "module" in error_str or "dependency" in error_str:
1570
+ setup_error_msg = f"DEPENDENCY ERROR: {original_error}"
1571
+ setup_error_msg += " Missing required dependencies. Please ensure all required packages are installed."
1572
+
1573
+ elif "permission" in error_str or "access" in error_str or "denied" in error_str:
1574
+ setup_error_msg = f"PERMISSION ERROR: {original_error}"
1575
+ setup_error_msg += " File system permission issue. Contact administrator if running on shared system."
1576
+
1577
+ else:
1578
+ # Generic catch-all with enhanced information
1579
+ setup_error_msg = f"RUNTIME ERROR: {original_error}"
1580
+ setup_error_msg += " An unexpected error occurred during execution. Please try again, and if the problem persists, check the browser console for more details or contact support."
1581
+
1582
+ error_timestamp = int(time.time() * 1000)
1583
+ print(f"🚨 RUNTIME ERROR: {original_error} at {error_timestamp}")
1584
+ print(f"πŸ” Error category: {setup_error_msg.split(':')[0]}")
1585
+
1586
+ modal_html = create_error_modal_html([setup_error_msg])
1587
+ return (
1588
+ gr.update(), # final_output_display - no change
1589
+ gr.update(), # results_display - no change
1590
+ gr.update(), # trace_display - no change
1591
+ gr.update(), # email1_display - no change
1592
+ gr.update(), # email2_display - no change
1593
+ gr.update(), # email3_display - no change
1594
+ gr.update(value=modal_html, visible=True) # error_modal_html
1595
+ )
1596
 
1597
  # Build a formatted results summary extracted from exec_log
1598
  def build_results_html(log_text: str) -> str: