Spaces:
Sleeping
Sleeping
| """ | |
| model_guard.py | |
| Wraps the protectai/deberta-v3-base-prompt-injection-v2 model behind the | |
| same simple interface as pattern_guard.check(), so the two approaches can | |
| be compared apples-to-apples in the UI. | |
| Model card: https://huggingface.co/protectai/deberta-v3-base-prompt-injection-v2 | |
| License: Apache 2.0 (underlying training data may carry additional terms — | |
| see model card "Limitations" section) | |
| Known limitations of this model (stated on its model card): | |
| - Does not reliably detect jailbreak-style attacks (only injection) | |
| - English only | |
| - Not recommended for scanning system prompts (produces false positives) | |
| These limitations are intentionally surfaced in the UI — they are the | |
| basis for the "defense in depth" argument: pattern matching catches | |
| jailbreak phrasing that this model misses, and vice versa for novel | |
| phrasings of instruction override that no static pattern anticipated. | |
| """ | |
| import time | |
| from dataclasses import dataclass | |
| from functools import lru_cache | |
| from transformers import pipeline | |
| MODEL_ID = "protectai/deberta-v3-base-prompt-injection-v2" | |
| class ModelGuardResult: | |
| blocked: bool | |
| label: str | |
| confidence: float | |
| latency_ms: float | |
| def _get_classifier(): | |
| """ | |
| Lazily load the model once per process and cache it. | |
| Cold start will be slow (model download + load); subsequent calls | |
| are fast. This is loaded on CPU — no GPU required for this model size. | |
| """ | |
| return pipeline( | |
| task="text-classification", | |
| model=MODEL_ID, | |
| truncation=True, | |
| max_length=512, | |
| ) | |
| def check(text: str) -> ModelGuardResult: | |
| """ | |
| Run the DeBERTa-v3 prompt injection classifier on `text`. | |
| Returns label "INJECTION" (1) or "SAFE" (0) along with the model's | |
| confidence score and wall-clock latency for this call. | |
| """ | |
| if not text or not text.strip(): | |
| return ModelGuardResult( | |
| blocked=False, label="SAFE", confidence=1.0, latency_ms=0.0 | |
| ) | |
| classifier = _get_classifier() | |
| start = time.perf_counter() | |
| result = classifier(text)[0] | |
| elapsed = (time.perf_counter() - start) * 1000 | |
| # protectai model outputs LABEL_0 (safe) / LABEL_1 (injection) or | |
| # "SAFE"/"INJECTION" depending on model version — normalize both. | |
| raw_label = result["label"].upper() | |
| is_injection = raw_label in ("LABEL_1", "INJECTION", "1") | |
| return ModelGuardResult( | |
| blocked=is_injection, | |
| label="INJECTION" if is_injection else "SAFE", | |
| confidence=round(result["score"], 4), | |
| latency_ms=round(elapsed, 2), | |
| ) | |
| def warm_up(): | |
| """Call once at Space startup to pay the model-load cost up front, | |
| rather than on the first user request.""" | |
| _get_classifier() | |
| check("warm up") | |