Spaces:
Running on Zero
Running on Zero
Update app/main.py
Browse files- app/main.py +28 -14
app/main.py
CHANGED
|
@@ -4,8 +4,12 @@ from transformers import pipeline
|
|
| 4 |
from glin_profanity import Filter
|
| 5 |
import re
|
| 6 |
|
|
|
|
| 7 |
toxicity_pipe = pipeline("text-classification", model="textdetox/twitter-xlmr-toxicity-classifier")
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
| 9 |
profanity_filter = Filter({"languages": ["english", "spanish", "french"], "replace_with": "***"})
|
| 10 |
|
| 11 |
app = FastAPI(title="Multilingual Moderation API")
|
|
@@ -19,30 +23,23 @@ class ModerationResponse(BaseModel):
|
|
| 19 |
is_flagged: bool
|
| 20 |
rewritten_text: list[str] | None
|
| 21 |
|
| 22 |
-
# 1. Define explicit threat keywords (You can expand this list)
|
| 23 |
THREAT_KEYWORDS = [
|
| 24 |
r"\bguns?\b", r"\bweapons?\b", r"\bbombs?\b", r"\bexplosives?\b",
|
| 25 |
r"\bkill\b", r"\bmurder\b", r"\bshoot\b", r"\bstab\b",
|
| 26 |
r"\bdie\b", r"\bdeath\b", r"\bhurt\b"
|
| 27 |
]
|
| 28 |
-
# Compile the regex pattern for fast matching
|
| 29 |
threat_pattern = re.compile("|".join(THREAT_KEYWORDS), re.IGNORECASE)
|
| 30 |
|
| 31 |
@app.post("/moderate", response_model=ModerationResponse)
|
| 32 |
async def moderate_text(request: TextRequest):
|
| 33 |
text = request.text
|
| 34 |
|
| 35 |
-
# Check 1: Profanity filter
|
| 36 |
profanity_result = profanity_filter.check_profanity(text)
|
| 37 |
-
|
| 38 |
-
# Check 2: AI Toxicity model
|
| 39 |
tox_result = toxicity_pipe(text)[0]
|
| 40 |
-
is_toxic_by_model = (tox_result['label'].lower() in ['toxic', 'label_1']) and (tox_result['score'] > 0.5)
|
| 41 |
|
| 42 |
-
|
| 43 |
is_threat_by_keyword = bool(threat_pattern.search(text))
|
| 44 |
|
| 45 |
-
# Final Decision: Flag if ANY check is true
|
| 46 |
is_flagged = (
|
| 47 |
profanity_result["contains_profanity"] or
|
| 48 |
is_toxic_by_model or
|
|
@@ -51,16 +48,33 @@ async def moderate_text(request: TextRequest):
|
|
| 51 |
|
| 52 |
rewritten = None
|
| 53 |
if is_flagged:
|
|
|
|
|
|
|
|
|
|
| 54 |
outputs = detox_pipe(
|
| 55 |
-
|
| 56 |
-
max_length=
|
| 57 |
num_return_sequences=5,
|
| 58 |
do_sample=True,
|
| 59 |
-
temperature=0.
|
| 60 |
top_p=0.9
|
| 61 |
)
|
| 62 |
-
|
| 63 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
return ModerationResponse(
|
| 65 |
original_text=text,
|
| 66 |
detected_categories={
|
|
|
|
| 4 |
from glin_profanity import Filter
|
| 5 |
import re
|
| 6 |
|
| 7 |
+
# 1. Keep the toxicity classifier
|
| 8 |
toxicity_pipe = pipeline("text-classification", model="textdetox/twitter-xlmr-toxicity-classifier")
|
| 9 |
+
|
| 10 |
+
# 2. SWAP to an Instruction-following model for rewriting
|
| 11 |
+
detox_pipe = pipeline("text2text-generation", model="google/flan-t5-base")
|
| 12 |
+
|
| 13 |
profanity_filter = Filter({"languages": ["english", "spanish", "french"], "replace_with": "***"})
|
| 14 |
|
| 15 |
app = FastAPI(title="Multilingual Moderation API")
|
|
|
|
| 23 |
is_flagged: bool
|
| 24 |
rewritten_text: list[str] | None
|
| 25 |
|
|
|
|
| 26 |
THREAT_KEYWORDS = [
|
| 27 |
r"\bguns?\b", r"\bweapons?\b", r"\bbombs?\b", r"\bexplosives?\b",
|
| 28 |
r"\bkill\b", r"\bmurder\b", r"\bshoot\b", r"\bstab\b",
|
| 29 |
r"\bdie\b", r"\bdeath\b", r"\bhurt\b"
|
| 30 |
]
|
|
|
|
| 31 |
threat_pattern = re.compile("|".join(THREAT_KEYWORDS), re.IGNORECASE)
|
| 32 |
|
| 33 |
@app.post("/moderate", response_model=ModerationResponse)
|
| 34 |
async def moderate_text(request: TextRequest):
|
| 35 |
text = request.text
|
| 36 |
|
|
|
|
| 37 |
profanity_result = profanity_filter.check_profanity(text)
|
|
|
|
|
|
|
| 38 |
tox_result = toxicity_pipe(text)[0]
|
|
|
|
| 39 |
|
| 40 |
+
is_toxic_by_model = (tox_result['label'].lower() in ['toxic', 'label_1']) and (tox_result['score'] > 0.5)
|
| 41 |
is_threat_by_keyword = bool(threat_pattern.search(text))
|
| 42 |
|
|
|
|
| 43 |
is_flagged = (
|
| 44 |
profanity_result["contains_profanity"] or
|
| 45 |
is_toxic_by_model or
|
|
|
|
| 48 |
|
| 49 |
rewritten = None
|
| 50 |
if is_flagged:
|
| 51 |
+
# 3. Create a prompt that tells the AI exactly how to rewrite it
|
| 52 |
+
prompt = f"Rewrite this sentence to be completely safe, polite, and non-threatening: '{text}'"
|
| 53 |
+
|
| 54 |
outputs = detox_pipe(
|
| 55 |
+
prompt,
|
| 56 |
+
max_length=50,
|
| 57 |
num_return_sequences=5,
|
| 58 |
do_sample=True,
|
| 59 |
+
temperature=0.9,
|
| 60 |
top_p=0.9
|
| 61 |
)
|
| 62 |
+
|
| 63 |
+
# Clean up the outputs to make sure they are unique
|
| 64 |
+
suggestions = set()
|
| 65 |
+
for out in outputs:
|
| 66 |
+
clean_text = out['generated_text'].strip()
|
| 67 |
+
# Only add if it actually changed the text
|
| 68 |
+
if clean_text.lower() != text.lower() and clean_text:
|
| 69 |
+
suggestions.add(clean_text)
|
| 70 |
+
|
| 71 |
+
# Convert the set back to a list
|
| 72 |
+
rewritten = list(suggestions)
|
| 73 |
+
|
| 74 |
+
# Fallback if the AI failed to generate anything different
|
| 75 |
+
if not rewritten:
|
| 76 |
+
rewritten = ["[AI could not generate a safe rewrite, please revise manually]"]
|
| 77 |
+
|
| 78 |
return ModerationResponse(
|
| 79 |
original_text=text,
|
| 80 |
detected_categories={
|