Text Classification
Keras
English
Azerbaijani
prompt-injection
security
llm-security
document-security
retvec
cnn
tensorflow
fastapi
Eval Results (legacy)
Instructions to use MegrurNiftiyev/MyGuard-Prompt-Injection-Detector with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Keras
How to use MegrurNiftiyev/MyGuard-Prompt-Injection-Detector with Keras:
# Available backend options are: "jax", "torch", "tensorflow". import os os.environ["KERAS_BACKEND"] = "jax" import keras model = keras.saving.load_model("hf://MegrurNiftiyev/MyGuard-Prompt-Injection-Detector") - Notebooks
- Google Colab
- Kaggle
| """ | |
| Tests for the /classify endpoint with fullText schema & chunk prediction. | |
| """ | |
| import pytest | |
| from unittest.mock import AsyncMock, patch | |
| from httpx import AsyncClient, ASGITransport | |
| from app.main import app | |
| from app.ml.serving.registry import DummyModel | |
| def auth_headers(): | |
| """Valid internal service auth headers.""" | |
| return {"X-Internal-Token": "test-secret"} | |
| async def test_classify_returns_prediction(auth_headers): | |
| """POST /classify should return a valid ClassifyResponse for fullText.""" | |
| dummy = DummyModel() | |
| with patch( | |
| "app.api.routes.classify.load_active_model", | |
| new_callable=AsyncMock, | |
| return_value=dummy, | |
| ): | |
| transport = ASGITransport(app=app) | |
| async with AsyncClient(transport=transport, base_url="http://test") as client: | |
| response = await client.post( | |
| "/analyze-injection", | |
| json={ | |
| "documentId": "doc-123", | |
| "fullText": "This is a normal corporate document with standard operational content.", | |
| }, | |
| headers=auth_headers, | |
| ) | |
| assert response.status_code == 200 | |
| data = response.json() | |
| assert data["label"] in ("safe", "suspicious", "injection") | |
| assert 0.0 <= data["confidence"] <= 1.0 | |
| async def test_classify_without_document_id(auth_headers): | |
| """POST /analyze-injection should work even if documentId is omitted.""" | |
| dummy = DummyModel() | |
| with patch( | |
| "app.api.routes.classify.load_active_model", | |
| new_callable=AsyncMock, | |
| return_value=dummy, | |
| ): | |
| transport = ASGITransport(app=app) | |
| async with AsyncClient(transport=transport, base_url="http://test") as client: | |
| response = await client.post( | |
| "/analyze-injection", | |
| json={ | |
| "fullText": "This is a normal corporate document with standard operational content.", | |
| }, | |
| headers=auth_headers, | |
| ) | |
| assert response.status_code == 200 | |
| data = response.json() | |
| assert data["label"] in ("safe", "suspicious", "injection") | |
| assert 0.0 <= data["confidence"] <= 1.0 | |
| async def test_classify_rejects_missing_auth(): | |
| """POST /classify without X-Internal-Token should return 401 or 422.""" | |
| dummy = DummyModel() | |
| with patch( | |
| "app.api.routes.classify.load_active_model", | |
| new_callable=AsyncMock, | |
| return_value=dummy, | |
| ): | |
| transport = ASGITransport(app=app) | |
| async with AsyncClient(transport=transport, base_url="http://test") as client: | |
| response = await client.post( | |
| "/analyze-injection", | |
| json={ | |
| "documentId": "doc-123", | |
| "fullText": "Sample text for testing authentication validation.", | |
| }, | |
| ) | |
| assert response.status_code in (401, 422) | |
| async def test_classify_rejects_wrong_token(): | |
| """POST /classify with wrong token should return 401.""" | |
| dummy = DummyModel() | |
| with patch( | |
| "app.api.routes.classify.load_active_model", | |
| new_callable=AsyncMock, | |
| return_value=dummy, | |
| ): | |
| transport = ASGITransport(app=app) | |
| async with AsyncClient(transport=transport, base_url="http://test") as client: | |
| response = await client.post( | |
| "/analyze-injection", | |
| json={ | |
| "documentId": "doc-123", | |
| "fullText": "Sample text for testing invalid token handling.", | |
| }, | |
| headers={"X-Internal-Token": "wrong-secret"}, | |
| ) | |
| assert response.status_code == 401 | |
| async def test_classify_rejects_insufficient_text(auth_headers): | |
| """Verify that fullText under 5 words raises 503 insufficient_text.""" | |
| transport = ASGITransport(app=app) | |
| async with AsyncClient(transport=transport, base_url="http://test") as client: | |
| response = await client.post( | |
| "/analyze-injection", | |
| json={ | |
| "documentId": "doc-short", | |
| "fullText": "One two three four", # 4 words | |
| }, | |
| headers=auth_headers, | |
| ) | |
| assert response.status_code == 503 | |
| assert response.json()["message"] == "insufficient_text" | |
| async def test_classify_rejects_extra_legacy_fields(auth_headers): | |
| """Verify that extra legacy fields (text, ocrText, hiddenText) are rejected (422).""" | |
| transport = ASGITransport(app=app) | |
| async with AsyncClient(transport=transport, base_url="http://test") as client: | |
| response = await client.post( | |
| "/analyze-injection", | |
| json={ | |
| "documentId": "doc-legacy", | |
| "fullText": "This is valid text containing enough words for test.", | |
| "text": "Legacy text field that should be forbidden", | |
| }, | |
| headers=auth_headers, | |
| ) | |
| assert response.status_code == 422 | |
| async def test_classify_passes_raw_full_text(auth_headers): | |
| """Verify raw fullText is passed directly to run_prediction.""" | |
| dummy = DummyModel() | |
| captured_texts = [] | |
| def capturing_run_prediction(model, text): | |
| captured_texts.append(text) | |
| return ("safe", 0.99) | |
| raw_input_text = " Hello WORLD\nLine two of document.\nLine three of document text." | |
| with patch( | |
| "app.api.routes.classify.load_active_model", | |
| new_callable=AsyncMock, | |
| return_value=dummy, | |
| ), patch( | |
| "app.api.routes.classify.run_prediction", | |
| side_effect=capturing_run_prediction, | |
| ): | |
| transport = ASGITransport(app=app) | |
| async with AsyncClient(transport=transport, base_url="http://test") as client: | |
| res = await client.post( | |
| "/analyze-injection", | |
| json={ | |
| "documentId": "doc-raw", | |
| "fullText": raw_input_text, | |
| }, | |
| headers=auth_headers, | |
| ) | |
| assert res.status_code == 200 | |
| assert captured_texts[0] == raw_input_text | |