AsyncCoder-10 commited on
Commit
97a30d4
·
verified ·
1 Parent(s): 9b737c5

Update app/main.py

Browse files
Files changed (1) hide show
  1. app/main.py +13 -116
app/main.py CHANGED
@@ -1,145 +1,42 @@
1
- import os
2
- os.environ.setdefault("NUMBA_DISABLE_CUDA", "1")
3
-
4
- import spaces # must come before torch/transformers
5
-
6
- import re
7
- import torch
8
  from fastapi import FastAPI
9
  from pydantic import BaseModel
10
- from transformers import pipeline, AutoModelForCausalLM, AutoTokenizer
11
  from glin_profanity import Filter
12
 
13
- # ---- CPU-only toxicity classifier (runs outside @spaces.GPU) ----
14
- toxicity_pipe = pipeline(
15
- "text-classification",
16
- model="textdetox/twitter-xlmr-toxicity-classifier",
17
- device=-1, # force CPU
18
- )
19
  profanity_filter = Filter({"languages": ["english", "spanish", "french"], "replace_with": "***"})
20
 
21
- # ---- Phi-3 loaded once on CPU; moved to GPU only inside the GPU function ----
22
- PHI_ID = "microsoft/Phi-3-mini-4k-instruct"
23
- phi_tokenizer = AutoTokenizer.from_pretrained(PHI_ID, trust_remote_code=True)
24
- phi_model = AutoModelForCausalLM.from_pretrained(
25
- PHI_ID,
26
- trust_remote_code=True,
27
- attn_implementation="eager",
28
- torch_dtype=torch.float16,
29
- )
30
-
31
  app = FastAPI(title="Multilingual Moderation API")
32
 
33
-
34
  class TextRequest(BaseModel):
35
  text: str
36
 
37
-
38
  class ModerationResponse(BaseModel):
39
  original_text: str
40
  detected_categories: dict
41
  is_flagged: bool
42
- rewritten_text: list[str] | None
43
-
44
-
45
- THREAT_KEYWORDS = [
46
- r"\bguns?\b", r"\bweapons?\b", r"\bbombs?\b", r"\bexplosives?\b",
47
- r"\bkill\b", r"\bmurder\b", r"\bshoot\b", r"\bstab\b",
48
- r"\bdie\b", r"\bdeath\b", r"\bhurt\b",
49
- ]
50
- threat_pattern = re.compile("|".join(THREAT_KEYWORDS), re.IGNORECASE)
51
-
52
-
53
- @spaces.GPU
54
- def generate_suggestions(text: str) -> list[str]:
55
- """Generate 5 polite rewrites on GPU."""
56
- phi_model.to("cuda")
57
-
58
- messages = [
59
- {
60
- "role": "system",
61
- "content": (
62
- "You are a helpful, polite assistant. Rewrite the user's toxic message "
63
- "into exactly 5 different safe, polite, and non-threatening sentences. "
64
- "Number them 1 to 5. Do not include any other text in your response."
65
- ),
66
- },
67
- {"role": "user", "content": text},
68
- ]
69
-
70
- prompt = phi_tokenizer.apply_chat_template(
71
- messages, tokenize=False, add_generation_prompt=True
72
- )
73
- inputs = phi_tokenizer(prompt, return_tensors="pt").to("cuda")
74
-
75
- with torch.no_grad():
76
- outputs = phi_model.generate(
77
- **inputs,
78
- max_new_tokens=200,
79
- do_sample=True,
80
- temperature=0.7,
81
- )
82
-
83
- new_tokens = outputs[0][inputs["input_ids"].shape[1]:]
84
- generated_text = phi_tokenizer.decode(new_tokens, skip_special_tokens=True).strip()
85
-
86
- rewritten = []
87
- for line in generated_text.split("\n"):
88
- line = line.strip()
89
- if line and line[0].isdigit():
90
- clean = re.sub(r"^\d+[\.\-\)]\s*", "", line).strip().strip("\"'")
91
- if clean:
92
- rewritten.append(clean)
93
-
94
- rewritten = list(dict.fromkeys(rewritten))[:5]
95
- return rewritten if rewritten else ["[AI could not generate a rewrite, please revise manually]"]
96
-
97
 
98
  @app.post("/moderate", response_model=ModerationResponse)
99
  async def moderate_text(request: TextRequest):
100
  text = request.text
101
-
102
  profanity_result = profanity_filter.check_profanity(text)
103
- # tox_result = toxicity_pipe(text)[0]
104
- # raw_result = toxicity_pipe(text)
105
- # tox_result = raw_result[0][0] if isinstance(raw_result[0], list) else raw_result[0]
106
-
107
- # is_toxic_by_model = (
108
- # tox_result["label"].lower() in ["toxic", "label_1"] and tox_result["score"] > 0.5
109
- # )
110
- raw_result = toxicity_pipe(text)
111
- # Handle both nested list [[{...}]] and flat list [{...}] outputs safely
112
- if isinstance(raw_result, list) and len(raw_result) > 0:
113
- tox_result = raw_result[0][0] if isinstance(raw_result[0], list) else raw_result[0]
114
- else:
115
- tox_result = {"label": "neutral", "score": 0.0}
116
-
117
- is_toxic_by_model = (
118
- isinstance(tox_result, dict)
119
- and tox_result.get("label", "").lower() in ["toxic", "label_1"]
120
- and tox_result.get("score", 0.0) > 0.5
121
- )
122
 
123
- is_threat_by_keyword = bool(threat_pattern.search(text))
124
-
125
- is_flagged = bool(
126
- profanity_result["contains_profanity"] or is_toxic_by_model or is_threat_by_keyword
127
- )
128
-
129
- rewritten = generate_suggestions(text) if is_flagged else None
130
-
131
  return ModerationResponse(
132
  original_text=text,
133
- detected_categories={
134
- "profanity": profanity_result["contains_profanity"],
135
- "ai_toxicity": is_toxic_by_model,
136
- "threat_keyword": is_threat_by_keyword,
137
- },
138
  is_flagged=is_flagged,
139
- rewritten_text=rewritten,
140
  )
141
 
142
-
143
  @app.get("/health")
144
  async def health_check():
145
  return {"status": "ok"}
 
 
 
 
 
 
 
 
1
  from fastapi import FastAPI
2
  from pydantic import BaseModel
3
+ from transformers import pipeline
4
  from glin_profanity import Filter
5
 
6
+ # Initialize your models
7
+ toxicity_pipe = pipeline("text-classification", model="textdetox/twitter-xlmr-toxicity-classifier")
8
+ detox_pipe = pipeline("text2text-generation", model="s-nlp/mt0-xl-detox-orpo")
 
 
 
9
  profanity_filter = Filter({"languages": ["english", "spanish", "french"], "replace_with": "***"})
10
 
 
 
 
 
 
 
 
 
 
 
11
  app = FastAPI(title="Multilingual Moderation API")
12
 
 
13
  class TextRequest(BaseModel):
14
  text: str
15
 
 
16
  class ModerationResponse(BaseModel):
17
  original_text: str
18
  detected_categories: dict
19
  is_flagged: bool
20
+ rewritten_text: str | None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  @app.post("/moderate", response_model=ModerationResponse)
23
  async def moderate_text(request: TextRequest):
24
  text = request.text
 
25
  profanity_result = profanity_filter.check_profanity(text)
26
+ toxicity_scores = toxicity_pipe(text)[0]
27
+
28
+ is_flagged = profanity_result["contains_profanity"] or toxicity_scores['score'] > 0.5
29
+ rewritten = None
30
+ if is_flagged:
31
+ rewritten = detox_pipe(text, max_length=100)[0]['generated_text']
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
 
 
 
 
 
 
 
 
33
  return ModerationResponse(
34
  original_text=text,
35
+ detected_categories={"profanity": profanity_result["contains_profanity"], "toxicity_model": toxicity_scores},
 
 
 
 
36
  is_flagged=is_flagged,
37
+ rewritten_text=rewritten
38
  )
39
 
 
40
  @app.get("/health")
41
  async def health_check():
42
  return {"status": "ok"}