mirror of
https://github.com/jiaxiaojunQAQ/OmniSafeBench-MM.git
synced 2026-08-25 12:43:06 +02:00
refactor: consolidate duplicate code and fix deadlock bug
- Extract duplicate attack/defense config merging into _merge_component_configs() - Extract duplicate lazy loading logic into _get_component() - Move content policy detection to BaseModel base class - Fix BatchSaveManager deadlock by splitting flush logic - Add TypeError to ValueError conversion for consistent config errors - Move _determine_load_model() to BaseComponent (explicit field only)
This commit is contained in:
+10
-27
@@ -7,6 +7,11 @@ class AnthropicModel(BaseModel):
|
||||
|
||||
default_output = "I'm sorry, but I cannot assist with that request."
|
||||
|
||||
# Anthropic-specific content policy keywords
|
||||
PROVIDER_SPECIFIC_KEYWORDS = [
|
||||
"output blocked by content filtering policy",
|
||||
]
|
||||
|
||||
def __init__(self, model_name: str, api_key: str) -> None:
|
||||
super().__init__(model_name, api_key)
|
||||
|
||||
@@ -53,15 +58,8 @@ class AnthropicModel(BaseModel):
|
||||
)
|
||||
return response
|
||||
except Exception as e:
|
||||
error_str = str(e).lower()
|
||||
if "Output blocked by content filtering policy" in str(e):
|
||||
return self.API_CONTENT_REJECTION_OUTPUT
|
||||
# Handle BadRequestError specifically
|
||||
if (
|
||||
"badrequesterror" in error_str
|
||||
and "data_inspection_failed" in error_str
|
||||
):
|
||||
return self.API_CONTENT_REJECTION_OUTPUT
|
||||
if self._is_content_policy_rejection(e):
|
||||
return self._handle_content_rejection()
|
||||
raise
|
||||
|
||||
return self._retry_with_backoff(_api_call)
|
||||
@@ -100,23 +98,8 @@ class AnthropicModel(BaseModel):
|
||||
)
|
||||
return stream
|
||||
except Exception as e:
|
||||
error_str = str(e).lower()
|
||||
if "Output blocked by content filtering policy" in str(e):
|
||||
# Return a generator that yields the content rejection placeholder
|
||||
def error_generator():
|
||||
yield self.API_CONTENT_REJECTION_OUTPUT
|
||||
|
||||
return error_generator()
|
||||
# Handle BadRequestError specifically
|
||||
if (
|
||||
"badrequesterror" in error_str
|
||||
and "data_inspection_failed" in error_str
|
||||
):
|
||||
|
||||
def error_generator():
|
||||
yield self.API_CONTENT_REJECTION_OUTPUT
|
||||
|
||||
return error_generator()
|
||||
if self._is_content_policy_rejection(e):
|
||||
return self._handle_content_rejection_stream()
|
||||
raise
|
||||
|
||||
try:
|
||||
@@ -128,4 +111,4 @@ class AnthropicModel(BaseModel):
|
||||
elif hasattr(chunk, "completion") and chunk.completion:
|
||||
yield chunk.completion
|
||||
except Exception:
|
||||
yield self.API_ERROR_OUTPUT
|
||||
yield self._handle_api_error()
|
||||
|
||||
@@ -18,6 +18,21 @@ class BaseModel(CoreBaseModel):
|
||||
API_MAX_RETRY = 3
|
||||
API_TIMEOUT = 600
|
||||
|
||||
# Content policy detection keywords (common across providers)
|
||||
CONTENT_POLICY_KEYWORDS = [
|
||||
"content policy",
|
||||
"safety",
|
||||
"harmful",
|
||||
"unsafe",
|
||||
"violation",
|
||||
"moderation",
|
||||
"data_inspection_failed",
|
||||
"inappropriate content",
|
||||
]
|
||||
|
||||
# Provider-specific additional keywords (subclasses can override)
|
||||
PROVIDER_SPECIFIC_KEYWORDS = []
|
||||
|
||||
def __init__(self, model_name: str, api_key: str = None, base_url: str = None):
|
||||
# Call parent class __init__, pass empty configuration
|
||||
super().__init__(config={})
|
||||
@@ -76,6 +91,46 @@ class BaseModel(CoreBaseModel):
|
||||
else:
|
||||
return "local"
|
||||
|
||||
def _is_content_policy_rejection(self, error: Exception) -> bool:
|
||||
"""Check if an exception represents a content policy rejection.
|
||||
|
||||
Args:
|
||||
error: The exception to check
|
||||
|
||||
Returns:
|
||||
True if the error indicates content policy rejection
|
||||
"""
|
||||
error_str = str(error).lower()
|
||||
|
||||
# Combine common and provider-specific keywords
|
||||
all_keywords = self.CONTENT_POLICY_KEYWORDS + self.PROVIDER_SPECIFIC_KEYWORDS
|
||||
|
||||
return any(keyword in error_str for keyword in all_keywords)
|
||||
|
||||
def _handle_content_rejection(self) -> str:
|
||||
"""Return the standard content rejection output."""
|
||||
return self.API_CONTENT_REJECTION_OUTPUT
|
||||
|
||||
def _handle_content_rejection_stream(self):
|
||||
"""Return a generator that yields the content rejection placeholder."""
|
||||
|
||||
def error_generator():
|
||||
yield self.API_CONTENT_REJECTION_OUTPUT
|
||||
|
||||
return error_generator()
|
||||
|
||||
def _handle_api_error(self) -> str:
|
||||
"""Return the standard API error output."""
|
||||
return self.API_ERROR_OUTPUT
|
||||
|
||||
def _handle_api_error_stream(self):
|
||||
"""Return a generator that yields the API error placeholder."""
|
||||
|
||||
def error_generator():
|
||||
yield self.API_ERROR_OUTPUT
|
||||
|
||||
return error_generator()
|
||||
|
||||
def _retry_with_backoff(self, func, *args, **kwargs):
|
||||
"""Execute function with retry logic and exponential backoff using backoff library."""
|
||||
|
||||
|
||||
+5
-43
@@ -33,20 +33,8 @@ class DoubaoModel(BaseModel):
|
||||
)
|
||||
return response
|
||||
except Exception as e:
|
||||
# Check for content policy violations in ByteDance models
|
||||
error_str = str(e).lower()
|
||||
content_keywords = [
|
||||
"content policy",
|
||||
"safety",
|
||||
"harmful",
|
||||
"unsafe",
|
||||
"violation",
|
||||
"moderation",
|
||||
"data_inspection_failed",
|
||||
"inappropriate content",
|
||||
]
|
||||
if any(keyword in error_str for keyword in content_keywords):
|
||||
return self.API_CONTENT_REJECTION_OUTPUT
|
||||
if self._is_content_policy_rejection(e):
|
||||
return self._handle_content_rejection()
|
||||
raise
|
||||
|
||||
return self._retry_with_backoff(_api_call)
|
||||
@@ -68,34 +56,8 @@ class DoubaoModel(BaseModel):
|
||||
)
|
||||
return stream
|
||||
except Exception as e:
|
||||
# Check for content policy violations in ByteDance models
|
||||
error_str = str(e).lower()
|
||||
content_keywords = [
|
||||
"content policy",
|
||||
"safety",
|
||||
"harmful",
|
||||
"unsafe",
|
||||
"violation",
|
||||
"moderation",
|
||||
"data_inspection_failed",
|
||||
"inappropriate content",
|
||||
]
|
||||
if any(keyword in error_str for keyword in content_keywords):
|
||||
# Return a generator that yields the content rejection placeholder
|
||||
def error_generator():
|
||||
yield self.API_CONTENT_REJECTION_OUTPUT
|
||||
|
||||
return error_generator()
|
||||
# Handle BadRequestError specifically
|
||||
if (
|
||||
"badrequesterror" in error_str
|
||||
and "data_inspection_failed" in error_str
|
||||
):
|
||||
|
||||
def error_generator():
|
||||
yield self.API_CONTENT_REJECTION_OUTPUT
|
||||
|
||||
return error_generator()
|
||||
if self._is_content_policy_rejection(e):
|
||||
return self._handle_content_rejection_stream()
|
||||
raise
|
||||
|
||||
try:
|
||||
@@ -104,4 +66,4 @@ class DoubaoModel(BaseModel):
|
||||
if chunk.choices[0].delta.content is not None:
|
||||
yield chunk.choices[0].delta.content
|
||||
except Exception:
|
||||
yield self.API_ERROR_OUTPUT
|
||||
yield self._handle_api_error()
|
||||
|
||||
+8
-22
@@ -7,6 +7,11 @@ class GoogleModel(BaseModel):
|
||||
|
||||
default_output = "I'm sorry, but I cannot assist with that request."
|
||||
|
||||
# Google-specific content policy keywords
|
||||
PROVIDER_SPECIFIC_KEYWORDS = [
|
||||
"blocked",
|
||||
]
|
||||
|
||||
def __init__(self, model_name: str, api_key: str, base_url: str = None) -> None:
|
||||
super().__init__(model_name=model_name, api_key=api_key, base_url=base_url)
|
||||
|
||||
@@ -37,27 +42,8 @@ class GoogleModel(BaseModel):
|
||||
)
|
||||
return response
|
||||
except Exception as e:
|
||||
# Check for content policy violations in Gemini models
|
||||
error_str = str(e).lower()
|
||||
content_keywords = [
|
||||
"content policy",
|
||||
"safety",
|
||||
"harmful",
|
||||
"unsafe",
|
||||
"violation",
|
||||
"moderation",
|
||||
"blocked",
|
||||
"data_inspection_failed",
|
||||
"inappropriate content",
|
||||
]
|
||||
if any(keyword in error_str for keyword in content_keywords):
|
||||
return self.API_CONTENT_REJECTION_OUTPUT
|
||||
# Handle BadRequestError specifically
|
||||
if (
|
||||
"badrequesterror" in error_str
|
||||
and "data_inspection_failed" in error_str
|
||||
):
|
||||
return self.API_CONTENT_REJECTION_OUTPUT
|
||||
if self._is_content_policy_rejection(e):
|
||||
return self._handle_content_rejection()
|
||||
raise
|
||||
|
||||
return self._retry_with_backoff(_api_call)
|
||||
@@ -86,4 +72,4 @@ class GoogleModel(BaseModel):
|
||||
if chunk.text:
|
||||
yield chunk.text
|
||||
except Exception:
|
||||
yield self.API_ERROR_OUTPUT
|
||||
yield self._handle_api_error()
|
||||
|
||||
+5
-49
@@ -47,26 +47,8 @@ class MistralModel(BaseModel):
|
||||
)
|
||||
return chat_response
|
||||
except Exception as e:
|
||||
# Check for content policy violations in Mistral models
|
||||
error_str = str(e).lower()
|
||||
content_keywords = [
|
||||
"content policy",
|
||||
"safety",
|
||||
"harmful",
|
||||
"unsafe",
|
||||
"violation",
|
||||
"moderation",
|
||||
"data_inspection_failed",
|
||||
"inappropriate content",
|
||||
]
|
||||
if any(keyword in error_str for keyword in content_keywords):
|
||||
return self.API_CONTENT_REJECTION_OUTPUT
|
||||
# Handle BadRequestError specifically
|
||||
if (
|
||||
"badrequesterror" in error_str
|
||||
and "data_inspection_failed" in error_str
|
||||
):
|
||||
return self.API_CONTENT_REJECTION_OUTPUT
|
||||
if self._is_content_policy_rejection(e):
|
||||
return self._handle_content_rejection()
|
||||
raise
|
||||
|
||||
return self._retry_with_backoff(_api_call)
|
||||
@@ -99,34 +81,8 @@ class MistralModel(BaseModel):
|
||||
)
|
||||
return stream
|
||||
except Exception as e:
|
||||
# Check for content policy violations in Mistral models
|
||||
error_str = str(e).lower()
|
||||
content_keywords = [
|
||||
"content policy",
|
||||
"safety",
|
||||
"harmful",
|
||||
"unsafe",
|
||||
"violation",
|
||||
"moderation",
|
||||
"data_inspection_failed",
|
||||
"inappropriate content",
|
||||
]
|
||||
if any(keyword in error_str for keyword in content_keywords):
|
||||
# Return a generator that yields the content rejection placeholder
|
||||
def error_generator():
|
||||
yield self.API_CONTENT_REJECTION_OUTPUT
|
||||
|
||||
return error_generator()
|
||||
# Handle BadRequestError specifically
|
||||
if (
|
||||
"badrequesterror" in error_str
|
||||
and "data_inspection_failed" in error_str
|
||||
):
|
||||
|
||||
def error_generator():
|
||||
yield self.API_CONTENT_REJECTION_OUTPUT
|
||||
|
||||
return error_generator()
|
||||
if self._is_content_policy_rejection(e):
|
||||
return self._handle_content_rejection_stream()
|
||||
raise
|
||||
|
||||
try:
|
||||
@@ -136,4 +92,4 @@ class MistralModel(BaseModel):
|
||||
if chunk.choices[0].delta.content is not None:
|
||||
yield chunk.choices[0].delta.content
|
||||
except Exception:
|
||||
yield self.API_ERROR_OUTPUT
|
||||
yield self._handle_api_error()
|
||||
|
||||
+16
-50
@@ -5,6 +5,14 @@ from .base_model import BaseModel
|
||||
class OpenAIModel(BaseModel):
|
||||
"""OpenAI model implementation using OpenAI API."""
|
||||
|
||||
# OpenAI-specific content policy keywords
|
||||
PROVIDER_SPECIFIC_KEYWORDS = [
|
||||
"invalid",
|
||||
"inappropriate",
|
||||
"invalid_prompt",
|
||||
"limited access",
|
||||
]
|
||||
|
||||
def __init__(self, model_name: str, api_key: str, base_url: Optional[str] = None):
|
||||
super().__init__(model_name=model_name, api_key=api_key, base_url=base_url)
|
||||
|
||||
@@ -41,27 +49,11 @@ class OpenAIModel(BaseModel):
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
# Check for content policy violations in GPT models
|
||||
error_str = str(e).lower()
|
||||
print("Error during API call:", error_str)
|
||||
content_keywords = [
|
||||
"content policy",
|
||||
"invalid",
|
||||
"safety",
|
||||
"harmful",
|
||||
"unsafe",
|
||||
"violation",
|
||||
"moderation",
|
||||
"data_inspection_failed",
|
||||
"inappropriate",
|
||||
"invalid_prompt",
|
||||
"limited access",
|
||||
]
|
||||
if any(keyword in error_str for keyword in content_keywords):
|
||||
print("✓ Content rejection triggered")
|
||||
return self.API_CONTENT_REJECTION_OUTPUT
|
||||
print("✗ No content keywords matched, raising exception")
|
||||
raise e
|
||||
print("Error during API call:", str(e).lower())
|
||||
if self._is_content_policy_rejection(e):
|
||||
print("Content rejection triggered")
|
||||
return self._handle_content_rejection()
|
||||
raise
|
||||
|
||||
return self._retry_with_backoff(_api_call)
|
||||
|
||||
@@ -86,34 +78,8 @@ class OpenAIModel(BaseModel):
|
||||
)
|
||||
return stream
|
||||
except Exception as e:
|
||||
# Check for content policy violations in GPT models
|
||||
error_str = str(e).lower()
|
||||
content_keywords = [
|
||||
"content policy",
|
||||
"safety",
|
||||
"harmful",
|
||||
"unsafe",
|
||||
"violation",
|
||||
"moderation",
|
||||
"data_inspection_failed",
|
||||
"inappropriate content",
|
||||
]
|
||||
if any(keyword in error_str for keyword in content_keywords):
|
||||
# Return a generator that yields the content rejection placeholder
|
||||
def error_generator():
|
||||
yield self.API_CONTENT_REJECTION_OUTPUT
|
||||
|
||||
return error_generator()
|
||||
# Handle BadRequestError specifically
|
||||
if (
|
||||
"badrequesterror" in error_str
|
||||
and "data_inspection_failed" in error_str
|
||||
):
|
||||
|
||||
def error_generator():
|
||||
yield self.API_CONTENT_REJECTION_OUTPUT
|
||||
|
||||
return error_generator()
|
||||
if self._is_content_policy_rejection(e):
|
||||
return self._handle_content_rejection_stream()
|
||||
raise
|
||||
|
||||
try:
|
||||
@@ -122,4 +88,4 @@ class OpenAIModel(BaseModel):
|
||||
if chunk.choices[0].delta.content is not None:
|
||||
yield chunk.choices[0].delta.content
|
||||
except Exception:
|
||||
yield self.API_ERROR_OUTPUT
|
||||
yield self._handle_api_error()
|
||||
|
||||
Reference in New Issue
Block a user