Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9d72fac
backup
Feb 28, 2025
c403640
Merge branch 'dev' into dev-yujing
Feb 28, 2025
5b12757
update test_unsafe_words_detector
Feb 28, 2025
c9853ca
update test_unsafe_words_detector
Feb 28, 2025
6e23df8
update test_unsafe_words_detector
Feb 28, 2025
4102ca1
add test_domain_safety_detector
Feb 28, 2025
c93186d
add test_domain_safety_detector
Feb 28, 2025
4af08da
fix: 修复文件锁定机制,确保锁文件在异常情况下被正确删除
darkrush Feb 28, 2025
0a6f21d
feat: 添加基于模型的安全模块,支持内容安全检测和处理
darkrush Mar 3, 2025
6b00770
Merge branch 'dev' of github.com:ccprocessor/llm-webkit-mirror into z…
darkrush Mar 3, 2025
8af2e9b
Merge branch 'zh_en_political' into dev-yujing
Mar 3, 2025
d201836
test rule-based-safety-module
Mar 3, 2025
9040a7f
test rule-based-safety-module
Mar 3, 2025
47a8f06
test rule-based-safety-module
Mar 3, 2025
abd2320
test rule-based-safety-module
Mar 3, 2025
992b4d5
test rule-based-safety-module
Mar 3, 2025
928feff
test rule-based-safety-module
Mar 3, 2025
972a39a
model_based_safety_module
Mar 4, 2025
ed7e141
model_based_safety_module
Mar 5, 2025
7e8adec
merge dev
Mar 12, 2025
3463dfc
part merge https://github.com/yogacc33/llm-webkit-mirror/blob/feature…
Mar 12, 2025
a5a0d8f
feat: 添加 ModelRuntimeException 异常处理,优化模型资源管理
darkrush Mar 12, 2025
222db58
refactor: 优化模型加载和资源配置,调整类属性以增强可读性
darkrush Mar 13, 2025
b6ff7f2
add top readme of models
Mar 13, 2025
7ba7a08
backup tests
Mar 18, 2025
e906ba5
backup tests
Mar 18, 2025
55712d6
lint code
Mar 18, 2025
ba5e353
lint readme
Mar 18, 2025
65f7700
lint all code
Mar 18, 2025
c889c09
merge dev
Mar 18, 2025
725f6cb
add error code
Mar 18, 2025
e9c55ef
bug fix
Mar 19, 2025
930d5b3
roll back end of html
Mar 19, 2025
e41766d
roll back end of html
Mar 19, 2025
3413fd7
roll back end of jsonl
Mar 19, 2025
c942af0
clean unused code
Mar 19, 2025
8dbb66b
clean unused code
Mar 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Empty file.
21 changes: 21 additions & 0 deletions docs/llm_web_kit/model/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# 面向用户的接口

## html分类

html_simplify_classify.md

## 语言检测

lang_id.md

## 清洗模型

clean_module.md

## 安全规则

rule_based_safety_module.md

## 安全模型

model_interface.md
Empty file.
4 changes: 4 additions & 0 deletions llm_web_kit/exception/exception.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@
"CleanModelUnsupportedLanguageException": {
"code": 46100000,
"message": "Clean model unsupported language exception"
},
"ModelRuntimeException": {
"code": 47000000,
"message": "Model runtime exception"
}
}
}
8 changes: 8 additions & 0 deletions llm_web_kit/exception/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,14 @@ def __init__(self, custom_message: str | None = None, error_code: int | None = N
super().__init__(custom_message, error_code)


class ModelRuntimeException(ModelBaseException):
"""Exception raised for model input data format."""
def __init__(self, custom_message: str | None = None, error_code: int | None = None):
if error_code is None:
error_code = ErrorMsg.get_error_code('Model', 'ModelRuntimeException')
super().__init__(custom_message, error_code)


class ModelOutputException(ModelBaseException):
"""Exception raised for model output data format."""
def __init__(self, custom_message: str | None = None, error_code: int | None = None):
Expand Down
13 changes: 13 additions & 0 deletions llm_web_kit/model/domain_safety_detector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class DomainFilter:
def __init__(self):
pass

def filter(
self,
content_str: str,
language: str,
url: str,
language_details: str,
content_style: str,
) -> dict:
return True, {}
289 changes: 289 additions & 0 deletions llm_web_kit/model/model_impl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
from abc import abstractmethod
from enum import Enum
from typing import Dict, List, Type

from llm_web_kit.exception.exception import (ModelInitException,
ModelInputException,
ModelRuntimeException)
from llm_web_kit.model.model_interface import (BatchProcessConfig,
ModelPredictor, ModelResource,
ModelResponse, PoliticalRequest,
PoliticalResponse, PornRequest,
PornResponse,
ResourceRequirement)
from llm_web_kit.model.policical import (get_singleton_political_detect,
update_political_by_str)


class ModelType(Enum):
"""模型类型枚举."""

POLITICAL = 'political' # 涉政模型
PORN = 'porn' # 色情模型


class DeviceType(Enum):
"""设备类型枚举."""

CPU = 'cpu'
GPU = 'gpu'


class BaseModelResource(ModelResource):
"""基础模型资源类."""

def __init__(self):
self.model = None

def initialize(self) -> None:
self.model = self._load_model()

@abstractmethod
def _load_model(self):
pass

Check warning on line 43 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L43

Added line #L43 was not covered by tests

@abstractmethod
def convert_result_to_response(self, result: dict) -> ModelResponse:
pass

Check warning on line 47 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L47

Added line #L47 was not covered by tests

def cleanup(self) -> None:
if self.model:
self._cleanup_model()
self.model = None

Check warning on line 52 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L50-L52

Added lines #L50 - L52 were not covered by tests

def _cleanup_model(self):
pass

Check warning on line 55 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L55

Added line #L55 was not covered by tests


class BasePredictor(ModelPredictor):
"""基础预测器类."""

def __init__(self, language: str):
self.language = language
self.model = self._create_model(language)

# 初始化模型
self.model.initialize()

@abstractmethod
def _create_model(self, language) -> ModelResource:
pass

Check warning on line 70 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L70

Added line #L70 was not covered by tests

def get_resource_requirement(self):
return self.model.get_resource_requirement()

Check warning on line 73 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L73

Added line #L73 was not covered by tests


# 涉政模型实现
class PoliticalCPUModel(BaseModelResource):
"""涉政检测CPU模型."""

def _load_model(self):
try:
model = get_singleton_political_detect()
if model is None:
raise RuntimeError('Failed to load political model')
return model
except Exception as e:
raise RuntimeError(f'Failed to load political CPU model: {e}')

Check warning on line 87 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L81-L87

Added lines #L81 - L87 were not covered by tests

def get_resource_requirement(self):
return ResourceRequirement(num_cpus=1, memory_GB=4, num_gpus=0)

def get_batch_config(self) -> BatchProcessConfig:
return BatchProcessConfig(
max_batch_size=1000, optimal_batch_size=512, min_batch_size=8
)

def predict_batch(self, contents: List[str]) -> List[dict]:
if not self.model:
raise RuntimeError('Model not initialized')

Check warning on line 99 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L99

Added line #L99 was not covered by tests
try:
# 批量处理
results = []
for content in contents:
result = update_political_by_str(content)
results.append(result)

return results
except Exception as e:
raise RuntimeError(f'Prediction failed: {e}')

Check warning on line 109 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L108-L109

Added lines #L108 - L109 were not covered by tests

def convert_result_to_response(self, result: dict) -> ModelResponse:
# raise NotImplementedError
# TODO convert result to response ensure the threshold
return PoliticalResponse(
is_remained=result['political_prob'] > 0.99, details=result
)


class PoliticalPredictorImpl(BasePredictor):
"""涉政检测预测器实现."""

def _create_model(self, language: str) -> ModelResource:

if language in ['zh', 'en']:
return PoliticalCPUModel()
raise ModelInitException(

Check warning on line 126 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L124-L126

Added lines #L124 - L126 were not covered by tests
f'Poltical model does not support language: {language}'
)

def predict_batch(
self, requests: List[PoliticalRequest]
) -> List[PoliticalResponse]:
"""批量预测接口."""

try:

Check warning on line 135 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L135

Added line #L135 was not covered by tests
# 收集所有请求内容
batch_contents = []

Check warning on line 137 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L137

Added line #L137 was not covered by tests

for req in requests:

Check warning on line 139 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L139

Added line #L139 was not covered by tests
# 验证语言支持
if req.language != self.language:
raise ModelInputException(

Check warning on line 142 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L141-L142

Added lines #L141 - L142 were not covered by tests
f'Language mismatch: {req.language} vs {self.language}'
)
batch_contents.append(req.content)

Check warning on line 145 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L145

Added line #L145 was not covered by tests

if batch_contents:

Check warning on line 147 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L147

Added line #L147 was not covered by tests
# 批量处理
probs = self.model.predict_batch(batch_contents)
responses = [self.model.convert_result_to_response(prob) for prob in probs]
except Exception as e:
raise ModelRuntimeException(f'Political prediction failed: {e}')

Check warning on line 152 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L149-L152

Added lines #L149 - L152 were not covered by tests

return responses

Check warning on line 154 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L154

Added line #L154 was not covered by tests


# 色情模型实现
class PornEnGPUModel(BaseModelResource):
"""英文色情检测GPU模型."""

def _load_model(self):
try:
from llm_web_kit.model.porn_detector import \
BertModel as PornEnModel

return PornEnModel()
except Exception as e:
raise ModelInitException(f'Failed to init the en porn model: {e}')

Check warning on line 168 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L167-L168

Added lines #L167 - L168 were not covered by tests

def get_resource_requirement(self):
# S2 cluster has 96 CPUs, 1TB memory, 8 GPUs
# so we can use 12 CPUs, 64GB memory, 1 GPU for this model
return ResourceRequirement(num_cpus=12, memory_GB=64, num_gpus=1)

def get_batch_config(self) -> BatchProcessConfig:
return BatchProcessConfig(
max_batch_size=1000, optimal_batch_size=512, min_batch_size=8
)

def predict_batch(self, contents: List[str]) -> List[dict]:
if not self.model:
raise RuntimeError('Model not initialized')
try:
# 色情模型本身支持批处理
results = self.model.predict(contents)
return [
{'porn_prob': result[self.model.get_output_key('prob')]}
for result in results
]
except Exception as e:
raise RuntimeError(f'Prediction failed: {e}')

Check warning on line 191 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L190-L191

Added lines #L190 - L191 were not covered by tests

def convert_result_to_response(self, result: dict) -> ModelResponse:
# raise NotImplementedError
# TODO convert result to response ensure the threshold
return PornResponse(is_remained=result['porn_prob'] < 0.2, details=result)


class PornZhGPUModel(BaseModelResource):
"""中文色情检测GPU模型."""

def _load_model(self):
try:
from llm_web_kit.model.porn_detector import \
XlmrModel as PornZhModel

return PornZhModel()
except Exception as e:
raise ModelInitException(f'Failed to init the zh porn model: {e}')

Check warning on line 209 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L208-L209

Added lines #L208 - L209 were not covered by tests

def get_resource_requirement(self):
# S2 cluster has at least 96 CPUs, 1TB memory, 8 GPUs
# so we can use 12 CPUs, 64GB memory, 1 GPU for this model
return ResourceRequirement(num_cpus=12, memory_GB=64, num_gpus=1)

def get_batch_config(self) -> BatchProcessConfig:
return BatchProcessConfig(
max_batch_size=300, optimal_batch_size=256, min_batch_size=8
)

def predict_batch(self, contents: List[str]) -> List[dict]:
if not self.model:
raise RuntimeError('Model not initialized')
try:
# 色情模型本身支持批处理
results = self.model.predict(contents)
return [
{'porn_prob': result[self.model.get_output_key('prob')]}
for result in results
]
except Exception as e:
raise RuntimeError(f'Prediction failed: {e}')

Check warning on line 232 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L231-L232

Added lines #L231 - L232 were not covered by tests

def convert_result_to_response(self, result: dict) -> ModelResponse:
# raise NotImplementedError
# TODO convert result to response ensure the threshold
return PornResponse(is_remained=result['porn_prob'] > 0.95, details=result)


class PornPredictorImpl(BasePredictor):
"""色情检测预测器实现."""

def _create_model(self, language: str) -> ModelResource:
if language == 'en':
return PornEnGPUModel()
elif language == 'zh':
return PornZhGPUModel()
raise ModelInitException(f'Porn model does not support language: {language}')

Check warning on line 248 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L246-L248

Added lines #L246 - L248 were not covered by tests

def predict_batch(self, requests: List[PornRequest]) -> List[PornResponse]:
"""批量预测接口."""
try:
# 收集所有请求内容
batch_contents = []

for req in requests:
# 验证语言支持
if req.language != self.language:
raise ModelInputException(
f'Language mismatch: {req.language} vs {self.language}'
)
batch_contents.append(req.content)

if batch_contents:
# 批量处理
probs = self.model.predict_batch(batch_contents)
responses = [self.model.convert_result_to_response(prob) for prob in probs]
except Exception as e:
raise ModelRuntimeException(f'Porn prediction failed: {e}')
return responses


# 模型工厂
class ModelFactory:
"""模型工厂类."""

_predictor_registry: Dict[ModelType, Type[BasePredictor]] = {
ModelType.POLITICAL: PoliticalPredictorImpl,
ModelType.PORN: PornPredictorImpl,
}

@classmethod
def create_predictor(cls, model_type: ModelType, language: str) -> BasePredictor:
"""创建预测器实例."""
predictor_class = cls._predictor_registry.get(model_type)
print(predictor_class)
if not predictor_class:
raise ValueError(f'No predictor registered for type: {model_type}')

Check warning on line 288 in llm_web_kit/model/model_impl.py

View check run for this annotation

Codecov / codecov/patch

llm_web_kit/model/model_impl.py#L288

Added line #L288 was not covered by tests
return predictor_class(language=language)
Loading