Mustafa Öztürk commited on
Commit
b2e6438
·
1 Parent(s): ddd2daa

Add early-exit and Detoxify call counters to moderation logs

Browse files
Files changed (1) hide show
  1. app/services/moderation_service.py +78 -4
app/services/moderation_service.py CHANGED
@@ -64,6 +64,12 @@ ACTION_MAP = {
64
  }
65
 
66
 
 
 
 
 
 
 
67
  def _extract_blacklist_hits(cleaned_text: str, dil: str):
68
  pure_text = re.sub(r"[^a-zA-ZçğıöşüÇĞİÖŞÜ0-9\s]", "", cleaned_text).lower()
69
  words_in_pure_text = set(pure_text.split())
@@ -125,8 +131,10 @@ def _tr_off_scores_batched(text_list, state, batch_size: int = 8):
125
 
126
  def _tr_result_with_off_score(cleaned_text: str, profanity_hits, insult_hits, off_score: float, state, dil: str):
127
  # Only run Detoxify on uncertain content to reduce inference cost.
 
128
  if off_score < 0.60:
129
  raw_threat_res = state["D_MULTI"].predict(cleaned_text)
 
130
  else:
131
  raw_threat_res = {
132
  "toxicity": off_score,
@@ -158,16 +166,20 @@ def _tr_result_with_off_score(cleaned_text: str, profanity_hits, insult_hits, of
158
  },
159
  )
160
  detail.update({"action": ACTION_MAP.get(verdict["risk_level"], "MONITOR")})
161
- return verdict["decision"], verdict["reason"], verdict["risk_level"], dil, cleaned_text, detail
162
 
163
 
164
  def run_moderation(text: str, platform_dil: str = "tr"):
165
  state = _ensure_runtime_ready()
 
 
166
 
167
  temiz = clean_text_nfkc(text)
168
  dil = "en" if platform_dil == "en" else "tr"
169
 
170
  if is_spam(temiz, dil):
 
 
171
  return (
172
  "🗑️ SPAM/GİBBERİSH",
173
  "Anlamsız veya tekrarlı içerik.",
@@ -181,6 +193,8 @@ def run_moderation(text: str, platform_dil: str = "tr"):
181
 
182
  # Fast path: if blacklist catches profanity/insult, skip all ML inference.
183
  if profanity_hits or insult_hits:
 
 
184
  return _blacklist_early_result(profanity_hits, insult_hits, dil, temiz)
185
 
186
  if dil == "en":
@@ -191,6 +205,8 @@ def run_moderation(text: str, platform_dil: str = "tr"):
191
  "score": float(gb_raw.get("score", 0.0)),
192
  }
193
  if gb.get("label", "").lower() == "noise" and gb.get("score", 0.0) > 0.98:
 
 
194
  return (
195
  "🗑️ GIBBERISH/SPAM",
196
  "Metin anlamsız karakter dizileri içeriyor.",
@@ -201,6 +217,7 @@ def run_moderation(text: str, platform_dil: str = "tr"):
201
  )
202
 
203
  raw_res = state["D_EN"].predict(temiz)
 
204
  res = {k: float(v) for k, v in raw_res.items()}
205
  tox_score = float(res.get("toxicity", 0.0))
206
  ins_score = float(res.get("insult", 0.0))
@@ -223,15 +240,22 @@ def run_moderation(text: str, platform_dil: str = "tr"):
223
  },
224
  )
225
  detail.update({"action": ACTION_MAP.get(verdict["risk_level"], "MONITOR")})
 
226
  return verdict["decision"], verdict["reason"], verdict["risk_level"], dil, temiz, detail
227
 
228
  off_score = _tr_off_scores_batched([temiz], state, batch_size=1)[0]
229
- return _tr_result_with_off_score(temiz, profanity_hits, insult_hits, off_score, state, dil)
 
 
 
 
230
 
231
 
232
  def run_moderation_batch(texts, platform_dil: str = "tr", batch_size: int = 8):
233
  state = _ensure_runtime_ready()
234
  dil = "en" if platform_dil == "en" else "tr"
 
 
235
 
236
  results = [None] * len(texts)
237
  tr_pending = []
@@ -241,6 +265,7 @@ def run_moderation_batch(texts, platform_dil: str = "tr", batch_size: int = 8):
241
  temiz = clean_text_nfkc(text)
242
 
243
  if is_spam(temiz, dil):
 
244
  results[idx] = (
245
  "🗑️ SPAM/GİBBERİSH",
246
  "Anlamsız veya tekrarlı içerik.",
@@ -253,11 +278,55 @@ def run_moderation_batch(texts, platform_dil: str = "tr", batch_size: int = 8):
253
 
254
  profanity_hits, insult_hits = _extract_blacklist_hits(temiz, dil)
255
  if profanity_hits or insult_hits:
 
256
  results[idx] = _blacklist_early_result(profanity_hits, insult_hits, dil, temiz)
257
  continue
258
 
259
  if dil == "en":
260
- results[idx] = run_moderation(text, platform_dil="en")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  continue
262
 
263
  tr_pending.append((idx, temiz, profanity_hits, insult_hits))
@@ -267,6 +336,11 @@ def run_moderation_batch(texts, platform_dil: str = "tr", batch_size: int = 8):
267
  off_scores = _tr_off_scores_batched(tr_pending_texts, state, batch_size=batch_size)
268
  for pending, off_score in zip(tr_pending, off_scores):
269
  idx, temiz, profanity_hits, insult_hits = pending
270
- results[idx] = _tr_result_with_off_score(temiz, profanity_hits, insult_hits, off_score, state, dil)
 
 
 
 
 
271
 
272
  return results
 
64
  }
65
 
66
 
67
+ def _log_pipeline_counts(early_exit_count: int, detoxify_call_count: int):
68
+ print(f"Early exit: {early_exit_count}")
69
+ print(f"Detoxify çağrısı: {detoxify_call_count}")
70
+ print(f"CUDA aktif: {torch.cuda.is_available()}")
71
+
72
+
73
  def _extract_blacklist_hits(cleaned_text: str, dil: str):
74
  pure_text = re.sub(r"[^a-zA-ZçğıöşüÇĞİÖŞÜ0-9\s]", "", cleaned_text).lower()
75
  words_in_pure_text = set(pure_text.split())
 
131
 
132
  def _tr_result_with_off_score(cleaned_text: str, profanity_hits, insult_hits, off_score: float, state, dil: str):
133
  # Only run Detoxify on uncertain content to reduce inference cost.
134
+ detoxify_called = False
135
  if off_score < 0.60:
136
  raw_threat_res = state["D_MULTI"].predict(cleaned_text)
137
+ detoxify_called = True
138
  else:
139
  raw_threat_res = {
140
  "toxicity": off_score,
 
166
  },
167
  )
168
  detail.update({"action": ACTION_MAP.get(verdict["risk_level"], "MONITOR")})
169
+ return (verdict["decision"], verdict["reason"], verdict["risk_level"], dil, cleaned_text, detail), detoxify_called
170
 
171
 
172
  def run_moderation(text: str, platform_dil: str = "tr"):
173
  state = _ensure_runtime_ready()
174
+ early_exit_count = 0
175
+ detoxify_call_count = 0
176
 
177
  temiz = clean_text_nfkc(text)
178
  dil = "en" if platform_dil == "en" else "tr"
179
 
180
  if is_spam(temiz, dil):
181
+ early_exit_count += 1
182
+ _log_pipeline_counts(early_exit_count, detoxify_call_count)
183
  return (
184
  "🗑️ SPAM/GİBBERİSH",
185
  "Anlamsız veya tekrarlı içerik.",
 
193
 
194
  # Fast path: if blacklist catches profanity/insult, skip all ML inference.
195
  if profanity_hits or insult_hits:
196
+ early_exit_count += 1
197
+ _log_pipeline_counts(early_exit_count, detoxify_call_count)
198
  return _blacklist_early_result(profanity_hits, insult_hits, dil, temiz)
199
 
200
  if dil == "en":
 
205
  "score": float(gb_raw.get("score", 0.0)),
206
  }
207
  if gb.get("label", "").lower() == "noise" and gb.get("score", 0.0) > 0.98:
208
+ early_exit_count += 1
209
+ _log_pipeline_counts(early_exit_count, detoxify_call_count)
210
  return (
211
  "🗑️ GIBBERISH/SPAM",
212
  "Metin anlamsız karakter dizileri içeriyor.",
 
217
  )
218
 
219
  raw_res = state["D_EN"].predict(temiz)
220
+ detoxify_call_count += 1
221
  res = {k: float(v) for k, v in raw_res.items()}
222
  tox_score = float(res.get("toxicity", 0.0))
223
  ins_score = float(res.get("insult", 0.0))
 
240
  },
241
  )
242
  detail.update({"action": ACTION_MAP.get(verdict["risk_level"], "MONITOR")})
243
+ _log_pipeline_counts(early_exit_count, detoxify_call_count)
244
  return verdict["decision"], verdict["reason"], verdict["risk_level"], dil, temiz, detail
245
 
246
  off_score = _tr_off_scores_batched([temiz], state, batch_size=1)[0]
247
+ result, detoxify_called = _tr_result_with_off_score(temiz, profanity_hits, insult_hits, off_score, state, dil)
248
+ if detoxify_called:
249
+ detoxify_call_count += 1
250
+ _log_pipeline_counts(early_exit_count, detoxify_call_count)
251
+ return result
252
 
253
 
254
  def run_moderation_batch(texts, platform_dil: str = "tr", batch_size: int = 8):
255
  state = _ensure_runtime_ready()
256
  dil = "en" if platform_dil == "en" else "tr"
257
+ early_exit_count = 0
258
+ detoxify_call_count = 0
259
 
260
  results = [None] * len(texts)
261
  tr_pending = []
 
265
  temiz = clean_text_nfkc(text)
266
 
267
  if is_spam(temiz, dil):
268
+ early_exit_count += 1
269
  results[idx] = (
270
  "🗑️ SPAM/GİBBERİSH",
271
  "Anlamsız veya tekrarlı içerik.",
 
278
 
279
  profanity_hits, insult_hits = _extract_blacklist_hits(temiz, dil)
280
  if profanity_hits or insult_hits:
281
+ early_exit_count += 1
282
  results[idx] = _blacklist_early_result(profanity_hits, insult_hits, dil, temiz)
283
  continue
284
 
285
  if dil == "en":
286
+ gb = None
287
+ if state["GB_PIPE"] is not None:
288
+ gb_raw = state["GB_PIPE"](temiz)[0]
289
+ gb = {
290
+ "label": str(gb_raw.get("label", "")),
291
+ "score": float(gb_raw.get("score", 0.0)),
292
+ }
293
+ if gb.get("label", "").lower() == "noise" and gb.get("score", 0.0) > 0.98:
294
+ early_exit_count += 1
295
+ results[idx] = (
296
+ "🗑️ GIBBERISH/SPAM",
297
+ "Metin anlamsız karakter dizileri içeriyor.",
298
+ "LOW",
299
+ "en",
300
+ temiz,
301
+ {"gibberish": gb, "action": "MONITOR", "detox": {}},
302
+ )
303
+ continue
304
+
305
+ raw_res = state["D_EN"].predict(temiz)
306
+ detoxify_call_count += 1
307
+ res = {k: float(v) for k, v in raw_res.items()}
308
+ tox_score = float(res.get("toxicity", 0.0))
309
+ ins_score = float(res.get("insult", 0.0))
310
+ identity_attack = float(res.get("identity_attack", 0.0))
311
+ detail = {
312
+ "detox": res,
313
+ "insult": ins_score,
314
+ "toxicity": tox_score,
315
+ "identity_attack": identity_attack,
316
+ "hits": profanity_hits,
317
+ "insult_hits": insult_hits,
318
+ "gibberish": gb if state["GB_PIPE"] is not None else None,
319
+ }
320
+ verdict = calculate_verdict(
321
+ profanity_hits,
322
+ insult_hits,
323
+ {
324
+ "off_score": 0.0,
325
+ "detox_toxicity": tox_score,
326
+ },
327
+ )
328
+ detail.update({"action": ACTION_MAP.get(verdict["risk_level"], "MONITOR")})
329
+ results[idx] = (verdict["decision"], verdict["reason"], verdict["risk_level"], dil, temiz, detail)
330
  continue
331
 
332
  tr_pending.append((idx, temiz, profanity_hits, insult_hits))
 
336
  off_scores = _tr_off_scores_batched(tr_pending_texts, state, batch_size=batch_size)
337
  for pending, off_score in zip(tr_pending, off_scores):
338
  idx, temiz, profanity_hits, insult_hits = pending
339
+ result, detoxify_called = _tr_result_with_off_score(temiz, profanity_hits, insult_hits, off_score, state, dil)
340
+ if detoxify_called:
341
+ detoxify_call_count += 1
342
+ results[idx] = result
343
+
344
+ _log_pipeline_counts(early_exit_count, detoxify_call_count)
345
 
346
  return results