Skip to content

Commit 39e21b6

Browse files
refactor detector management to store multiple detector types
1 parent db210ad commit 39e21b6

File tree

6 files changed

+42
-15
lines changed

6 files changed

+42
-15
lines changed

detectors/built_in/app.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from fastapi import HTTPException
2-
2+
from contextlib import asynccontextmanager
33
from base_detector_registry import BaseDetectorRegistry
44
from regex_detectors import RegexDetectorRegistry
55
from file_type_detectors import FileTypeDetectorRegistry
@@ -8,21 +8,31 @@
88
from detectors.common.scheme import ContentAnalysisHttpRequest, ContentsAnalysisResponse
99
from detectors.common.app import DetectorBaseAPI as FastAPI
1010

11-
app = FastAPI()
11+
@asynccontextmanager
12+
async def lifespan(app: FastAPI):
13+
app.set_detector(RegexDetectorRegistry(), "regex")
14+
app.set_detector(FileTypeDetectorRegistry(), "file_type")
15+
yield
16+
17+
app.cleanup_detector()
18+
19+
20+
app = FastAPI(lifespan=lifespan)
1221
Instrumentator().instrument(app).expose(app)
1322

1423

15-
registry : dict[str, BaseDetectorRegistry] = {
16-
"regex": RegexDetectorRegistry(),
17-
"file_type": FileTypeDetectorRegistry(),
18-
}
24+
# registry : dict[str, BaseDetectorRegistry] = {
25+
# "regex": RegexDetectorRegistry(),
26+
# "file_type": FileTypeDetectorRegistry(),
27+
# }
1928

2029
@app.post("/api/v1/text/contents", response_model=ContentsAnalysisResponse)
2130
def detect_content(request: ContentAnalysisHttpRequest):
2231
detections = []
2332
for content in request.contents:
2433
message_detections = []
25-
for detector_kind, detector_registry in registry.items():
34+
for detector_kind, detector_registry in app.get_all_detectors().items():
35+
assert isinstance(detector_registry, BaseDetectorRegistry), f"Detector {detector_kind} is not a valid BaseDetectorRegistry"
2636
if detector_kind in request.detector_params:
2737
try:
2838
message_detections += detector_registry.handle_request(content, request.detector_params)
@@ -37,7 +47,8 @@ def detect_content(request: ContentAnalysisHttpRequest):
3747
@app.get("/registry")
3848
def get_registry():
3949
result = {}
40-
for detector_type, detector_registry in registry.items():
50+
for detector_type, detector_registry in app.get_all_detectors().items():
51+
assert isinstance(detector_registry, BaseDetectorRegistry), f"Detector {detector_type} is not a valid BaseDetectorRegistry"
4152
result[detector_type] = {}
4253
for detector_name, detector_fn in detector_registry.get_registry().items():
4354
result[detector_type][detector_name] = detector_fn.__doc__

detectors/common/app.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
class DetectorBaseAPI(FastAPI):
3535
def __init__(self, *args, **kwargs):
3636
super().__init__(*args, **kwargs)
37+
self.state.detectors = {}
3738
self.add_exception_handler(
3839
RequestValidationError, self.validation_exception_handler
3940
)
@@ -94,17 +95,21 @@ async def http_exception_handler(self, request, exc):
9495
content={"code": exc.status_code, "message": exc.detail},
9596
)
9697

97-
def set_detector(self, detector) -> None:
98+
def set_detector(self, detector, detector_name="default") -> None:
9899
"""Store detector in app.state"""
99-
self.state.detector = detector
100+
self.state.detectors[detector_name] = detector
100101

101-
def get_detector(self):
102+
def get_detector(self, detector_name="default"):
102103
"""Retrieve detector from app.state"""
103-
return getattr(self.state, 'detector', None)
104+
return self.state.detectors.get(detector_name)
105+
106+
def get_all_detectors(self) -> dict:
107+
"""Retrieve all detectors from app.state"""
108+
return self.state.detectors
104109

105110
def cleanup_detector(self) -> None:
106111
"""Clean up detector resources"""
107-
self.state.detector = None
112+
self.state.detectors.clear()
108113

109114
async def health():
110115
return "ok"

detectors/llm_judge/app.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from contextlib import asynccontextmanager
22
from typing import Annotated, Dict
33

4-
from fastapi import Header
4+
from fastapi import Header, HTTPException
55
from prometheus_fastapi_instrumentator import Instrumentator
66

77
from detectors.common.app import DetectorBaseAPI as FastAPI
@@ -48,6 +48,8 @@ async def detector_unary_handler(
4848
):
4949
"""Analyze content using LLM-as-Judge evaluation."""
5050
detector: LLMJudgeDetector = app.get_detector()
51+
if not detector:
52+
raise HTTPException(status_code=404, detail="Detector not found")
5153
return ContentsAnalysisResponse(root=await detector.run(request))
5254

5355

@@ -63,7 +65,7 @@ async def list_metrics():
6365
"""List all available evaluation metrics."""
6466
detector: LLMJudgeDetector = app.get_detector()
6567
if not detector:
66-
return {"metrics": [], "total": 0}
68+
raise HTTPException(status_code=404, detail="Detector not found")
6769

6870
metrics = detector.list_available_metrics()
6971
return MetricsListResponse(metrics=metrics, total=len(metrics))

tests/detectors/builtIn/test_filetype.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ class TestFileTypeDetectors:
77
@pytest.fixture
88
def client(self):
99
from detectors.built_in.app import app
10+
from detectors.built_in.file_type_detectors import FileTypeDetectorRegistry
11+
12+
app.set_detector(FileTypeDetectorRegistry(), "file_type")
13+
1014
return TestClient(app)
1115

1216
@pytest.fixture

tests/detectors/builtIn/test_regex.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ class TestRegexDetectors:
55
@pytest.fixture
66
def client(self):
77
from detectors.built_in.app import app
8+
from detectors.built_in.regex_detectors import RegexDetectorRegistry
9+
10+
app.set_detector(RegexDetectorRegistry(), "regex")
11+
812
return TestClient(app)
913

1014
@pytest.mark.parametrize(

tox.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ deps =
1010
-r{toxinidir}/detectors/huggingface/requirements.txt
1111
-r{toxinidir}/detectors/common/requirements.txt
1212
-r{toxinidir}/detectors/llm_judge/requirements.txt
13+
-r{toxinidir}/detectors/built_in/requirements.txt
1314
setenv =
1415
PYTHONPATH = {toxinidir}/detectors/huggingface:{toxinidir}/detectors/llm_judge:{toxinidir}/detectors:{toxinidir}
1516
commands =

0 commit comments

Comments
 (0)