walker11 commited on
Commit
d8baaa6
·
verified ·
1 Parent(s): ee989b2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +193 -725
app.py CHANGED
@@ -13,8 +13,8 @@ logger = logging.getLogger(__name__)
13
 
14
  class ArabicContentModerator:
15
  """
16
- Enhanced Arabic Story Content Moderation Model using Deepseek API
17
- Checks for cultural violations, religious content, and inappropriate content with strict enforcement
18
  """
19
 
20
  def __init__(self, deepseek_api_key: str = None):
@@ -34,329 +34,66 @@ class ArabicContentModerator:
34
  "Content-Type": "application/json"
35
  }
36
 
37
- # Comprehensive Arabic profanity and offensive terms
38
- self.profanity_terms = {
39
- # Sexual terms (explicit)
40
- 'explicit_sexual': [
41
- 'زب', 'زبر', 'زبي', 'كس', 'كسك', 'كسها', 'كسي', 'طيز', 'طيزك', 'طيزها',
42
- 'نيك', 'نيكه', 'نيكها', 'ناك', 'منيوك', 'منيوكة', 'مناك', 'متناك',
43
- 'لحس', 'لحسه', 'لحسها', 'لاحس', 'ملحوس', 'ملحوسة', 'عرص', 'عرصه',
44
- 'شرموط', 'شرموطه', 'قحبه', 'قحبة', 'عاهر', 'عاهرة', 'بغي', 'بغيه',
45
- 'ديوث', 'ديوثه', 'قواد', 'قوادة', 'فاجر', 'فاجرة', 'فاسق', 'فاسقة'
46
- ],
47
-
48
- # Bathroom/excretory terms
49
- 'excretory': [
50
- 'خرا', 'خراء', 'خرة', 'زفت', 'زفته', 'بول', 'بوله', 'غائط', 'براز',
51
- 'تبول', 'تبرز', 'حقير', 'نجس', 'قذر', 'قذره', 'وسخ', 'وسخه'
52
- ],
53
-
54
- # Family honor insults
55
- 'family_honor': [
56
- 'ابن الكلب', 'ابن الكلبه', 'ابن الحرام', 'ابن الزنا', 'ابن القحبه',
57
- 'بنت الكلب', 'بنت الكلبه', 'بنت الحرام', 'بنت الزنا', 'بنت القحبه',
58
- 'يلعن ابوك', 'يلعن امك', 'يلعن اختك', 'يلعن اهلك', 'يلعن عرضك',
59
- 'كلب', 'كلبه', 'حيوان', 'حيوانه', 'وضيع', 'وضيعه', 'حقير', 'حقيره'
60
- ],
61
-
62
- # Religious blasphemy
63
- 'religious_blasphemy': [
64
- 'يلعن الله', 'لعنة الله', 'يلعن الدين', 'لعنة الدين', 'يلعن الرسول',
65
- 'كسم الله', 'كسم الدين', 'كسم الرسول', 'كسم المسيح', 'كسم النبي',
66
- 'تف على الله', 'تف على الدين', 'تف على الرسول', 'خرا على الله',
67
- 'زب الله', 'زب الدين', 'زب الرسول', 'طيز الله', 'طيز الدين'
68
- ],
69
-
70
- # Ethnic/racial slurs
71
- 'ethnic_slurs': [
72
- 'عبد', 'عبده', 'زنجي', 'زنجيه', 'اسود', 'سوده', 'خواجه', 'خواجة',
73
- 'يهودي نجس', 'يهوديه نجسه', 'مسيحي كافر', 'مسيحيه كافره',
74
- 'بدوي', 'بدويه', 'فلاح', 'فلاحه', 'صعيدي', 'صعيديه'
75
- ]
76
- }
77
-
78
- # Religious terms that require careful handling
79
- self.religious_sensitive_terms = [
80
- 'الله', 'محمد', 'الرسول', 'النبي', 'القرآن', 'الإسلام', 'المسيح', 'عيسى',
81
- 'موسى', 'إبراهيم', 'الأنبياء', 'الصحابة', 'الخلفاء', 'الإمام', 'الشيخ',
82
- 'المسجد', 'الكعبة', 'مكة', 'المدينة', 'الحج', 'الصلاة', 'الصوم', 'الزكاة'
83
- ]
84
-
85
- # Cultural taboos in Arabic society
86
- self.cultural_taboos = [
87
- 'عري', 'عريان', 'عريانه', 'عاري', 'عاريه', 'مثلي', 'مثليه', 'شاذ', 'شاذه',
88
- 'خمر', 'خمرة', 'مخمور', 'مخمورة', 'سكران', 'سكرانه', 'مسكر', 'مسكرة',
89
- 'قمار', 'مقامر', 'مقامرة', 'ميسر', 'رهان', 'مراهنة', 'خنزير', 'خنزيرة'
90
- ]
91
-
92
- # Enhanced Arabic Content Moderation with Comprehensive Checking
93
  self.moderation_prompt = """
94
- أنت مراجع محتوى عربي محترف متخصص في التمييز بين القصص الأدبية والمحتوى الإخباري مع التطبيق الصارم للمعايير الثقافية والدينية العربية.
95
-
96
- ## معايير الرفض الصارمة:
97
-
98
- ### 1. المحتوى الإخباري والصحفي - رفض فوري:
99
- **يجب رفض النصوص التي تحتوي على:**
100
-
101
- **أ) التقارير الرياضية:**
102
- - "بعد المباراة خرج وقال"
103
- - "اللاعب تألق ومنع أهداف"
104
- - "فاز بجائزة رجل المباراة"
105
- - "المباراة انتهت بنتيجة"
106
- - "في الشوط الأول"
107
- - "المدرب صرح"
108
-
109
- **ب) المؤتمرات الصحفية:**
110
- - "في مؤتمر صحفي"
111
- - "صرح الوزير"
112
- - "أعلن المسؤول"
113
- - "في تصريحات خاصة"
114
- - "قال النائب"
115
- - "أكد الخبير"
116
-
117
- **ج) الاجتماعات والفعاليات:**
118
- - "في اجتماع اليوم"
119
- - "خلال الجلسة"
120
- - "في المنتدى"
121
- - "أثناء المؤتمر"
122
- - "في الورشة"
123
- - "خلال اللقاء"
124
-
125
- ### 2. الانتهاكات الدينية - رفض صارم ومطلق:
126
- **رفض فوري ونهائي للمحتوى الذي يحتوي على:**
127
-
128
- **أ) التجديف والكفر:**
129
- - أي استهزاء أو تهكم على الله سبحانه وتعالى
130
- - السخرية من الأنبياء أو الرسل (محمد، عيسى، موسى، إبراهيم)
131
- - انتقاد أو تشكيك في القرآن الكريم أو الأحاديث النبوية
132
- - التطاول على الصحابة أو أمهات المؤمنين
133
- - السب أو اللعن بالدين أو الله أو الرسول
134
-
135
- **ب) الاستهزاء بالشعائر:**
136
- - السخرية من الصلاة، الصوم، الحج، الزكاة
137
- - التهكم على المساجد أو الأماكن المقدسة
138
- - الاستهزاء بالحجاب أو اللباس الإسلامي
139
- - انتقاد الأحكام الشرعية بطريقة مسيئة
140
-
141
- **ج) التشكيك في العقيدة:**
142
- - إنكار وجود الله أو صفاته
143
- - التشكيك في الآخرة أو يوم القيامة
144
- - إنكار النبوة أو الوحي
145
- - الترويج للإلحاد أو الكفر
146
-
147
- ### 3. الانتهاكات الثقافية العربية - رفض صارم:
148
 
149
- **أ) انتهاك الحياء والعفة:**
150
- - الوصف الجنسي الصريح أو المبطن
151
- - المشاهد الإباحية أو الإيحاءات الجنسية
152
- - الحديث عن العلاقات غير الشرعية بتفصيل
153
- - وصف الأجساد بطريقة مثيرة أو فاضحة
154
- - الترويج للعري أو السفور
155
 
156
- **ب) انتهاك قيم الأسرة:**
157
- - تمجيد العلاقات خارج إطار الزواج
158
- - السخرية من الزواج أو الأسرة
159
- - الترويج للشذوذ الجنسي أو المثلية
160
- - انتهاك احترام الوالدين أو كبار السن
161
- - تشجيع العقوق أو قطيعة الرحم
162
 
163
- **ج) انتهاك الأخلاق الاجتماعية:**
164
- - الترويج للخمر أو المخدرات
165
- - تمجيد القمار أو الميسر
166
- - الترويج للجريمة أو العنف
167
- - انتهاك كرامة المرأة أو الرجل
168
- - الطعن في الشرف أو العرض
169
 
170
- ### 4. السب والشتم والألفاظ النابية - رفض مطلق:
 
171
 
172
- **أ) السب الجنسي الصريح:**
173
- - الألفاظ المتعلقة بالأعضاء التناسلية
174
- - الكلمات الجنسية الفاحشة
175
- - السب بالعرض أو الشرف
176
 
177
- **ب) السب الإخراجي:**
178
- - الألفاظ المتعلقة بالفضلات أو النجاسة
179
- - السب بالقذارة أو الوسخ
180
 
181
- **ج) السب العائلي:**
182
- - إهانة الأم أو الأب
183
- - السب بالأخت أو الزوجة
184
- - انتهاك كرامة الأسرة
 
185
 
186
- **د) السب العرقي والطائفي:**
187
- - الألفاظ العنصرية ضد الأعراق
188
- - السب الطائفي أو المذهبي
189
- - التحقير القبلي أو الجهوي
190
 
191
- ### 5. المحتوى المقبول - القصص الأدبية الراقية:
 
 
 
192
 
193
- **أ) القصص التربوية:**
194
- - تعزيز القيم الإسلامية والأخلاق
195
- - التركيز على الفضائل والأخلاق الحميدة
196
- - قصص الأنبياء والصالحين (بأدب واحترام)
197
- - الحكايات التراثية الراقية
198
 
199
- **ب) القصص الاجتماعية الهادفة:**
200
- - معالجة المشاكل الاجتماعية بحكمة
201
- - تقوية الروابط الأسرية
202
- - احترام الثقافة والتقاليد العربية
203
- - التأكيد على أهمية العلم والتعلم
204
 
205
- **ج) القصص الخيالية المناسبة:**
206
- - الحكايات الشعبية النظيفة
207
- - قصص الأطفال التربوية
208
- - الخيال العلمي المناسب ثقافياً
209
- - قصص المغامرات النظيفة
210
 
211
- ### 6. معايير الأسلوب والأدب:
212
 
213
- **أ) اللغة الراقية:**
214
- - استخدام اللغة العربية الفصحى أو العامية المهذبة
215
- - تجنب الألفاظ الركيكة أو المبتذلة
216
- - الحفاظ ��لى جمال اللغة وبلاغتها
217
 
218
- **ب) الأسلوب المحترم:**
219
- - تجنب الإثارة أو الإسفاف
220
- - الحفاظ على كرامة الشخصيات
221
- - احترام المشاعر والأحاسيس
222
 
223
- ## أمثلة للرفض الفوري:
224
-
225
- **انتهاكات دينية (يجب رفضها):**
226
- - أي نص يحتوي على سب أو استهزاء بالله أو الرسول
227
- - أي نص يشكك في العقيدة الإسلامية
228
- - أي نص يسخر من الشعائر الدينية
229
-
230
- **انتهاكات ثقافية (يجب رفضها):**
231
- - أي نص يروج للعلاقات غير الشرعية
232
- - أي نص يحتوي على وصف جنسي صريح
233
- - أي نص يروج للخمر أو المخدرات
234
-
235
- **سب وشتم (يجب رفضه):**
236
- - أي نص يحتوي على ألفاظ نابية أو فاحشة
237
- - أي نص يسب الأسرة أو العرض
238
- - أي نص يحتوي على تحقير عرقي أو طائفي
239
-
240
- ## أمثلة للقبول:
241
-
242
- **قصة أدبية راقية (يجب قبولها):**
243
- "كان رجل صالح يعيش في قرية صغيرة، يساعد الفقراء ويعطف على اليتامى. في يوم من الأيام، مرض ابنه الوحيد، فصبر واحتسب، ولم يفقد إيمانه بالله..."
244
-
245
- **حكاية تراثية (يجب قبولها):**
246
- "يحكى أن ملكاً عادلاً كان يتنكر في زي فقير ليتفقد أحوال رعيته. في إحدى جولاته، رأى رجلاً يطعم الطيور من قوت يومه..."
247
-
248
- ## الاستجابة المطلوبة:
249
- بعد المراجعة الدقيقة والشاملة، أجب بكلمة واحدة فقط:
250
- - "true" - إذا كان النص قصة أدبية إبداعية راقية خالية من جميع الانتهاكات الدينية والثقافية والأخلاقية
251
- - "no" - إذا كان النص إخبارياً أو يحتوي على أي انتهاك ديني أو ثقافي أو أخلاقي مهما كان بسيطاً
252
-
253
- **تذكر: المعايير صارمة جداً، وأي شك في المحتوى يستوجب الرفض الفوري**
254
-
255
- النص المطلوب مراجعته:
256
  """
257
 
258
- def _check_profanity_and_violations(self, content: str) -> Dict[str, Any]:
259
- """
260
- Enhanced pre-check for profanity and cultural violations
261
-
262
- Args:
263
- content: Content to check
264
-
265
- Returns:
266
- Dictionary with violation details
267
- """
268
- violations = {
269
- 'has_violations': False,
270
- 'violation_types': [],
271
- 'severity': 'none',
272
- 'details': []
273
- }
274
-
275
- content_lower = content.lower()
276
-
277
- # Check for explicit profanity
278
- for category, terms in self.profanity_terms.items():
279
- for term in terms:
280
- if term in content_lower:
281
- violations['has_violations'] = True
282
- violations['violation_types'].append(category)
283
- violations['severity'] = 'critical'
284
- violations['details'].append(f"Found {category} term: {term}")
285
-
286
- # Check for inappropriate religious content
287
- religious_violations = [
288
- 'يلعن الله', 'لعنة الله', 'يلعن الدين', 'تف على الله', 'كسم الله',
289
- 'خرا على الله', 'زب الله', 'طيز الله', 'كسم الدين', 'يلعن الرسول'
290
- ]
291
-
292
- for violation in religious_violations:
293
- if violation in content_lower:
294
- violations['has_violations'] = True
295
- violations['violation_types'].append('religious_blasphemy')
296
- violations['severity'] = 'critical'
297
- violations['details'].append(f"Religious violation detected: {violation}")
298
-
299
- # Check for cultural taboos
300
- for taboo in self.cultural_taboos:
301
- if taboo in content_lower:
302
- violations['has_violations'] = True
303
- violations['violation_types'].append('cultural_taboo')
304
- violations['severity'] = 'high' if violations['severity'] != 'critical' else 'critical'
305
- violations['details'].append(f"Cultural taboo detected: {taboo}")
306
-
307
- # Check for inappropriate sexual content patterns
308
- sexual_patterns = [
309
- r'نيك', r'ناك', r'منيوك', r'لحس', r'ملحوس', r'عرص', r'شرموط',
310
- r'قحبة', r'عاهر', r'بغي', r'ديوث', r'قواد'
311
- ]
312
-
313
- for pattern in sexual_patterns:
314
- if re.search(pattern, content_lower):
315
- violations['has_violations'] = True
316
- violations['violation_types'].append('sexual_content')
317
- violations['severity'] = 'critical'
318
- violations['details'].append(f"Sexual content pattern detected: {pattern}")
319
-
320
- return violations
321
-
322
- def _check_religious_sensitivity(self, content: str) -> Dict[str, Any]:
323
- """
324
- Check for inappropriate use of religious terms
325
-
326
- Args:
327
- content: Content to check
328
-
329
- Returns:
330
- Dictionary with religious sensitivity analysis
331
- """
332
- sensitivity = {
333
- 'has_issues': False,
334
- 'religious_terms_found': [],
335
- 'context_issues': [],
336
- 'severity': 'none'
337
- }
338
-
339
- content_lower = content.lower()
340
-
341
- # Find religious terms
342
- for term in self.religious_sensitive_terms:
343
- if term.lower() in content_lower:
344
- sensitivity['religious_terms_found'].append(term)
345
-
346
- # Check for inappropriate contexts with religious terms
347
- if sensitivity['religious_terms_found']:
348
- inappropriate_contexts = [
349
- 'يلعن', 'تف على', 'خرا على', 'كسم', 'زب', 'طيز', 'نيك', 'لعنة'
350
- ]
351
-
352
- for context in inappropriate_contexts:
353
- if context in content_lower:
354
- sensitivity['has_issues'] = True
355
- sensitivity['context_issues'].append(context)
356
- sensitivity['severity'] = 'critical'
357
-
358
- return sensitivity
359
-
360
  def _call_deepseek_api(self, story_content: str) -> Dict[str, Any]:
361
  """
362
  Call Deepseek API for content moderation
@@ -373,21 +110,21 @@ class ArabicContentModerator:
373
  "messages": [
374
  {
375
  "role": "system",
376
- "content": "أنت مراجع محتوى عربي محترف متخصص في التطبيق الصارم للمعايير الثقافية والدينية العربية. يجب عليك رفض أي محتوى إخباري أو يحتوي على انتهاكات دينية أو ثقافية أو أخلاقية بصرامة تامة."
377
  },
378
  {
379
- "role": "user",
380
  "content": f"{self.moderation_prompt}\n\n{story_content}"
381
  }
382
  ],
383
  "max_tokens": 10,
384
- "temperature": 0.0,
385
  "stream": False
386
  }
387
 
388
  response = requests.post(
389
- self.api_url,
390
- headers=self.headers,
391
  json=payload,
392
  timeout=30
393
  )
@@ -398,13 +135,132 @@ class ArabicContentModerator:
398
  logger.error(f"API Error: {response.status_code} - {response.text}")
399
  return {"error": f"API Error: {response.status_code}"}
400
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
  except Exception as e:
402
  logger.error(f"Error processing API response: {str(e)}")
403
  return {
404
  "approved": False,
405
  "response": "no",
406
  "reason": "خطأ في معالجة نتيجة المراجعة",
407
- "violation_type": "processing_error",
408
  "error": str(e),
409
  "timestamp": datetime.now().isoformat()
410
  }
@@ -416,7 +272,7 @@ app = Flask(__name__)
416
  # Initialize the moderator (API key will be set via environment variable)
417
  try:
418
  moderator = ArabicContentModerator()
419
- logger.info("Enhanced Arabic Content Moderator initialized successfully")
420
  except ValueError as e:
421
  logger.error(f"Failed to initialize moderator: {e}")
422
  moderator = None
@@ -425,71 +281,34 @@ except ValueError as e:
425
  def home():
426
  """Home endpoint with API documentation"""
427
  return jsonify({
428
- "service": "مراجع المحتوى الأدبي العربي المحسن مع التطبيق الصارم للمعايير الثقافية والدينية",
429
- "service_en": "Enhanced Arabic Literary Content Moderator with Strict Cultural and Religious Standards",
430
- "version": "4.0.0",
431
- "description": "AI-powered professional literary critic for Arabic short stories with comprehensive cultural, religious, and profanity filtering",
432
- "description_ar": "ناقد أدبي محترف مدعوم بالذكاء الاصطناعي للقصص العربية القصيرة مع فلترة شاملة للمحتوى الثقافي والديني والألفاظ النابية",
433
  "endpoints": {
434
  "/health": "Health check",
435
  "/moderate": "POST - Moderate single story",
436
- "/moderate/batch": "POST - Moderate multiple stories",
437
- "/violations/check": "POST - Check for specific violations without full moderation"
438
  },
439
  "features": [
440
- "Comprehensive profanity detection with Arabic terms database",
441
- "Strict religious content filtering and blasphemy detection",
442
- "Cultural taboo identification and rejection",
443
- "Enhanced news content detection and rejection",
444
- "Family honor and respect enforcement",
445
- "Ethnic and racial slur detection",
446
- "Sexual content and inappropriate material filtering",
447
- "Religious sensitivity analysis",
448
  "Professional literary criticism standards",
449
- "Multi-level violation severity assessment"
450
- ],
451
- "violation_categories": [
452
- "explicit_sexual - Explicit sexual terms and content",
453
- "excretory - Bathroom and excretory terms",
454
- "family_honor - Family honor insults and disrespect",
455
- "religious_blasphemy - Religious blasphemy and disrespect",
456
- "ethnic_slurs - Ethnic and racial discrimination",
457
- "cultural_taboo - Cultural taboos and inappropriate content",
458
- "sexual_content - Sexual content patterns",
459
- "religious_violation - Inappropriate religious content usage"
460
- ],
461
- "rejected_content_types": [
462
- "Sports reports and match analysis",
463
- "Press conferences and official statements",
464
- "Meeting minutes and proceedings",
465
- "Political news and announcements",
466
- "Economic reports and market updates",
467
- "Technical reviews and product launches",
468
- "Local news and municipal updates",
469
- "Content with profanity or offensive language",
470
- "Religious blasphemy or disrespectful content",
471
- "Culturally inappropriate material",
472
- "Sexual or adult content",
473
- "Family honor violations"
474
  ],
475
- "cultural_standards": {
476
- "religious_respect": "Strict enforcement of Islamic values and respect for all religions",
477
- "family_values": "Protection of family honor and traditional values",
478
- "language_purity": "Rejection of profanity and offensive language",
479
- "cultural_sensitivity": "Adherence to Arab cultural norms and traditions",
480
- "moral_guidelines": "Enforcement of high moral and ethical standards"
481
- },
482
  "usage": {
483
  "moderate": {
484
  "method": "POST",
485
  "payload": {"story_content": "Arabic story text"},
486
- "response": {
487
- "approved": "boolean",
488
- "response": "true/no",
489
- "reason": "detailed reason in Arabic",
490
- "violation_type": "type of violation if any",
491
- "violation_details": "detailed violation analysis"
492
- }
493
  }
494
  },
495
  "status": "healthy" if moderator else "service unavailable"
@@ -500,77 +319,15 @@ def health_check():
500
  """Health check endpoint"""
501
  return jsonify({
502
  "status": "healthy" if moderator else "unhealthy",
503
- "service": "Enhanced Arabic Content Moderator with Strict Standards",
504
  "timestamp": datetime.now().isoformat(),
505
- "api_available": moderator is not None,
506
- "features_active": [
507
- "profanity_detection",
508
- "religious_filtering",
509
- "cultural_compliance",
510
- "news_detection",
511
- "ai_moderation"
512
- ] if moderator else []
513
  })
514
 
515
- @app.route('/violations/check', methods=['POST'])
516
- def check_violations():
517
- """
518
- Check for specific violations without full moderation
519
-
520
- Expected JSON payload:
521
- {
522
- "content": "Text to check for violations"
523
- }
524
-
525
- Returns detailed violation analysis
526
- """
527
- if not moderator:
528
- return jsonify({
529
- "error": "خدمة المراجعة غير متوفرة - لم يتم تكوين مفتاح API",
530
- "error_en": "Moderation service not available - API key not configured"
531
- }), 500
532
-
533
- try:
534
- data = request.get_json()
535
-
536
- if not data or 'content' not in data:
537
- return jsonify({
538
- "error": "المحتوى مفقود في الطلب",
539
- "error_en": "Missing content in request"
540
- }), 400
541
-
542
- content = data['content']
543
-
544
- # Check for violations
545
- profanity_check = moderator._check_profanity_and_violations(content)
546
- religious_check = moderator._check_religious_sensitivity(content)
547
- news_check = moderator._pre_check_news_content(content)
548
-
549
- return jsonify({
550
- "content_analysis": {
551
- "profanity_violations": profanity_check,
552
- "religious_sensitivity": religious_check,
553
- "news_content_detected": news_check,
554
- "overall_safe": not (profanity_check['has_violations'] or
555
- religious_check['has_issues'] or
556
- news_check),
557
- "content_length": len(content),
558
- "timestamp": datetime.now().isoformat()
559
- }
560
- })
561
-
562
- except Exception as e:
563
- logger.error(f"Error in check_violations: {str(e)}")
564
- return jsonify({
565
- "error": "خطأ داخلي في الخادم",
566
- "error_en": "Internal server error",
567
- "details": str(e)
568
- }), 500
569
-
570
  @app.route('/moderate', methods=['POST'])
571
  def moderate_content():
572
  """
573
- Enhanced moderation endpoint with strict cultural and religious standards
574
 
575
  Expected JSON payload:
576
  {
@@ -581,9 +338,7 @@ def moderate_content():
581
  {
582
  "approved": true/false,
583
  "response": "true"/"no",
584
- "reason": "detailed reason in Arabic",
585
- "violation_type": "type of violation",
586
- "violation_details": "detailed analysis",
587
  "timestamp": "ISO timestamp"
588
  }
589
  """
@@ -609,11 +364,6 @@ def moderate_content():
609
  story_content = data['story_content']
610
  result = moderator.moderate_story(story_content)
611
 
612
- # Add additional metadata
613
- result["moderation_version"] = "4.0.0"
614
- result["strict_mode"] = True
615
- result["cultural_compliance"] = "enforced"
616
-
617
  return jsonify(result)
618
 
619
  except Exception as e:
@@ -623,14 +373,13 @@ def moderate_content():
623
  "error_en": "Internal server error",
624
  "approved": False,
625
  "response": "no",
626
- "violation_type": "system_error",
627
  "details": str(e)
628
  }), 500
629
 
630
  @app.route('/moderate/batch', methods=['POST'])
631
  def moderate_batch():
632
  """
633
- Enhanced batch moderation endpoint with detailed violation tracking
634
 
635
  Expected JSON payload:
636
  {
@@ -661,21 +410,14 @@ def moderate_batch():
661
 
662
  results = []
663
  approved_count = 0
664
- violation_stats = {}
665
 
666
  for i, story in enumerate(stories):
667
  logger.info(f"Moderating story {i+1}/{len(stories)}")
668
  result = moderator.moderate_story(story)
669
-
670
- # Track violation statistics
671
- violation_type = result.get("violation_type", "none")
672
- violation_stats[violation_type] = violation_stats.get(violation_type, 0) + 1
673
-
674
  results.append({
675
  "story_index": i,
676
  "result": result
677
  })
678
-
679
  if result.get("approved", False):
680
  approved_count += 1
681
 
@@ -685,14 +427,7 @@ def moderate_batch():
685
  "total_processed": len(results),
686
  "approved_count": approved_count,
687
  "rejected_count": len(results) - approved_count,
688
- "approval_rate": f"{(approved_count/len(results)*100):.1f}%" if results else "0%",
689
- "violation_statistics": violation_stats
690
- },
691
- "moderation_info": {
692
- "version": "4.0.0",
693
- "strict_mode": True,
694
- "cultural_compliance": "enforced",
695
- "religious_filtering": "active"
696
  },
697
  "timestamp": datetime.now().isoformat()
698
  })
@@ -705,274 +440,7 @@ def moderate_batch():
705
  "details": str(e)
706
  }), 500
707
 
708
- @app.route('/standards', methods=['GET'])
709
- def get_standards():
710
- """
711
- Get detailed information about moderation standards and criteria
712
- """
713
- return jsonify({
714
- "moderation_standards": {
715
- "version": "4.0.0",
716
- "enforcement_level": "strict",
717
- "cultural_compliance": {
718
- "religious_respect": {
719
- "description": "Strict enforcement of respect for Islamic values and all religions",
720
- "violations_include": [
721
- "Blasphemy against Allah, prophets, or religious figures",
722
- "Mockery of religious practices or symbols",
723
- "Inappropriate use of religious terms",
724
- "Disrespect towards religious texts or teachings"
725
- ]
726
- },
727
- "family_values": {
728
- "description": "Protection of family honor and traditional values",
729
- "violations_include": [
730
- "Insults targeting family members",
731
- "Disrespect towards parents or elders",
732
- "Inappropriate sexual content",
733
- "Promotion of immoral relationships"
734
- ]
735
- },
736
- "language_purity": {
737
- "description": "Rejection of profanity and offensive language",
738
- "categories": [
739
- "Sexual explicit terms",
740
- "Excretory language",
741
- "Family honor insults",
742
- "Ethnic and racial slurs"
743
- ]
744
- }
745
- },
746
- "content_requirements": {
747
- "acceptable_genres": [
748
- "Educational moral stories",
749
- "Traditional folk tales",
750
- "Religious stories (respectful)",
751
- "Social stories with positive messages",
752
- "Children's educational content",
753
- "Historical narratives (appropriate)",
754
- "Fantasy and adventure (culturally appropriate)"
755
- ],
756
- "rejected_content": [
757
- "News reports and journalism",
758
- "Sports commentary and analysis",
759
- "Political statements and speeches",
760
- "Commercial product reviews",
761
- "Technical documentation",
762
- "Adult or sexual content",
763
- "Content with profanity",
764
- "Religious blasphemy",
765
- "Cultural violations"
766
- ]
767
- }
768
- },
769
- "violation_categories": {
770
- "critical": [
771
- "religious_blasphemy",
772
- "explicit_sexual",
773
- "family_honor_severe"
774
- ],
775
- "high": [
776
- "cultural_taboo",
777
- "ethnic_slurs",
778
- "sexual_content"
779
- ],
780
- "medium": [
781
- "excretory",
782
- "inappropriate_language"
783
- ]
784
- },
785
- "enforcement_policy": {
786
- "zero_tolerance": [
787
- "Religious blasphemy or disrespect",
788
- "Explicit sexual content",
789
- "Severe family honor violations",
790
- "Ethnic or racial discrimination"
791
- ],
792
- "strict_filtering": [
793
- "All forms of profanity",
794
- "Cultural taboos",
795
- "Inappropriate religious content usage",
796
- "News and journalistic content"
797
- ]
798
- }
799
- })
800
-
801
  if __name__ == '__main__':
802
  # For local testing
803
  port = int(os.environ.get('PORT', 7860))
804
- app.run(host='0.0.0.0', port=port, debug=False)f"Exception calling Deepseek API: {str(e)}")
805
- return {"error": str(e)}
806
-
807
- def _pre_check_news_content(self, story_content: str) -> bool:
808
- """
809
- Pre-check for obvious news content patterns
810
-
811
- Args:
812
- story_content: Content to check
813
-
814
- Returns:
815
- True if appears to be news content, False otherwise
816
- """
817
- # News indicators in Arabic
818
- news_patterns = [
819
- r'بعد المباراة.*قال',
820
- r'في مؤتمر صحفي',
821
- r'صرح.*الوزير',
822
- r'أعلن.*المسؤول',
823
- r'فاز.*بجائزة.*رجل المباراة',
824
- r'تألق.*ومنع.*أهداف',
825
- r'خلال.*الاجتماع',
826
- r'في.*الجلسة',
827
- r'الرئيس.*التقى',
828
- r'البرلمان.*ناقش',
829
- r'الحكومة.*قررت',
830
- r'البورصة.*ارتفعت',
831
- r'أسعار.*النفط',
832
- r'الشركة.*حققت',
833
- r'المحافظ.*افتتح',
834
- r'بلدية.*المدينة',
835
- r'التطبيق.*الجديد',
836
- r'الهاتف.*يتميز',
837
- r'في.*محافظة'
838
- ]
839
-
840
- # Check for news patterns
841
- for pattern in news_patterns:
842
- if re.search(pattern, story_content, re.IGNORECASE):
843
- return True
844
-
845
- # Check for sports-specific terms
846
- sports_terms = ['المباراة', 'اللاعب', 'المدرب', 'الفريق', 'الهدف', 'الشوط']
847
- news_verbs = ['صرح', 'أعلن', 'أكد', 'قال', 'فاز', 'تألق']
848
-
849
- has_sports = any(term in story_content for term in sports_terms)
850
- has_news_verbs = any(verb in story_content for verb in news_verbs)
851
-
852
- if has_sports and has_news_verbs:
853
- return True
854
-
855
- return False
856
-
857
- def _validate_story_format(self, story_content: str) -> bool:
858
- """
859
- Enhanced validation of story format and content
860
-
861
- Args:
862
- story_content: Story content to validate
863
-
864
- Returns:
865
- Boolean indicating if format is valid
866
- """
867
- if not story_content or not isinstance(story_content, str):
868
- return False
869
-
870
- # Check minimum length (at least 50 characters for a meaningful story)
871
- if len(story_content.strip()) < 50:
872
- return False
873
-
874
- # Check for Arabic characters (must have substantial Arabic content)
875
- arabic_pattern = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]')
876
- arabic_chars = len(arabic_pattern.findall(story_content))
877
-
878
- # Arabic characters should be at least 30% of total characters
879
- if arabic_chars < len(story_content.strip()) * 0.3:
880
- return False
881
-
882
- # Pre-check for obvious news content
883
- if self._pre_check_news_content(story_content):
884
- return False
885
-
886
- return True
887
-
888
- def moderate_story(self, story_content: str) -> Dict[str, Any]:
889
- """
890
- Main method to moderate Arabic story content with enhanced validation and strict enforcement
891
-
892
- Args:
893
- story_content: The Arabic story to moderate
894
-
895
- Returns:
896
- Dictionary with moderation result
897
- """
898
- # Enhanced validation
899
- if not self._validate_story_format(story_content):
900
- return {
901
- "approved": False,
902
- "response": "no",
903
- "reason": "المحتوى يبدو أنه تقرير إخباري أو صحفي وليس قصة أدبية، أو فشل في التحقق من صحة التنسيق",
904
- "violation_type": "format_violation",
905
- "timestamp": datetime.now().isoformat()
906
- }
907
-
908
- # Clean and prepare content
909
- cleaned_content = story_content.strip()
910
-
911
- # Check for profanity and violations first
912
- violation_check = self._check_profanity_and_violations(cleaned_content)
913
- if violation_check['has_violations']:
914
- return {
915
- "approved": False,
916
- "response": "no",
917
- "reason": "المحتوى يحتوي على انتهاكات صريحة للقيم الدينية أو الثقافية أو ألفاظ نابية",
918
- "violation_type": "content_violation",
919
- "violation_details": violation_check,
920
- "timestamp": datetime.now().isoformat()
921
- }
922
-
923
- # Check for religious sensitivity issues
924
- religious_check = self._check_religious_sensitivity(cleaned_content)
925
- if religious_check['has_issues']:
926
- return {
927
- "approved": False,
928
- "response": "no",
929
- "reason": "المحتوى يحتوي على استخدام غير مناسب للمصطلحات الدينية أو انتهاكات دينية",
930
- "violation_type": "religious_violation",
931
- "religious_details": religious_check,
932
- "timestamp": datetime.now().isoformat()
933
- }
934
-
935
- # Call Deepseek API for final check
936
- api_response = self._call_deepseek_api(cleaned_content)
937
-
938
- if "error" in api_response:
939
- logger.error(f"Moderation failed: {api_response['error']}")
940
- return {
941
- "approved": False,
942
- "response": "no",
943
- "reason": "خطأ في خدمة المراجعة",
944
- "violation_type": "service_error",
945
- "error": api_response["error"],
946
- "timestamp": datetime.now().isoformat()
947
- }
948
-
949
- try:
950
- # Extract the moderation decision
951
- ai_response = api_response.get("choices", [{}])[0].get("message", {}).get("content", "").strip().lower()
952
-
953
- # Clean the response (remove any extra whitespace or characters)
954
- ai_response = re.sub(r'[^\w]', '', ai_response)
955
-
956
- # Determine if content is approved (be very strict)
957
- approved = ai_response == "true"
958
- response_value = "true" if approved else "no"
959
-
960
- result = {
961
- "approved": approved,
962
- "response": response_value,
963
- "ai_decision": ai_response,
964
- "timestamp": datetime.now().isoformat(),
965
- "content_length": len(cleaned_content),
966
- "violation_type": "none" if approved else "ai_detected"
967
- }
968
-
969
- if not approved:
970
- result["reason"] = "المحتوى ينتهك المعايير الصارمة للثقافة العربية والإسلامية، أو أنه ليس قصة أدبية حقيقية بل محتوى إخباري أو غير مناسب"
971
- else:
972
- result["reason"] = "المحتوى مقبول ويلتزم بالمعايير الصارمة المطلوبة للثقافة العربية والإسلامية"
973
-
974
- logger.info(f"Moderation completed: {response_value} for content of length {len(cleaned_content)}")
975
- return result
976
-
977
- except Exception as e:
978
- logger.error(
 
13
 
14
  class ArabicContentModerator:
15
  """
16
+ Arabic Story Content Moderation Model using Deepseek API
17
+ Checks for cultural violations and inappropriate content
18
  """
19
 
20
  def __init__(self, deepseek_api_key: str = None):
 
34
  "Content-Type": "application/json"
35
  }
36
 
37
+ # The Definitive Prompt for Word-Level Contextual Analysis
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  self.moderation_prompt = """
39
+ أنت ناقد أدبي فائق الدقة، خبير في الأدب العربي والثقافة الإسلامية. مهمتك ليست مجرد المراجعة، بل التشريح الأدبي للنص. يجب أن تركز في كل كلمة، وتفهم موقعها ودلالتها داخل السياق السردي العام قبل إصدار أي حكم. قرارك هو نتاج تحليل عميق، وليس رد فعل سطحي تجاه مفردات معينة.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
+ **المنهجية التحليلية: من الكلمة إلى النص**
 
 
 
 
 
42
 
43
+ اتبع هذه المنهجية الصارمة، حيث كل كلمة هي وحدة تحليل أساسية:
 
 
 
 
 
44
 
45
+ **أولاً: التحليل الدقيق للسياق والغرض**
46
+ قبل أن تبدأ، اقرأ النص بالكامل لتفهم عالمه. ثم أعد القراءة مع التركيز على بناء الجمل واختيار الكلمات. اسأل نفسك باستمرار:
47
+ * **ما وظيفة هذه الكلمة هنا؟** هل هي جزء من حوار يكشف عن شخصية منحرفة؟ هل هي استعارة أدبية تغير المعنى الظاهري؟ أم هي صوت مباشر من السرد يروج لانتهاك؟
48
+ * **ما هي نبرة القصة؟** هل هي ساخرة، مأساوية، نقدية؟ النبرة تغير دلالة الكلمات بشكل جذري.
49
+ * تذكر، قصة تصور شخصية تنطق بالكفر للكشف عن ضلالها تختلف جذرياً عن نص يدعو إلى الكفر. الفهم الدقيق لهذه النية هو جوهر عملك.
 
50
 
51
+ **ثانياً: التحقق من الهوية الأدبية (هل البنية هي بنية قصة؟)**
52
+ بعد فهم السياق، تأكد من أن النص عمل سردي حقيقي يمتلك العناصر الأساسية: حبكة، شخصيات، حوار، وصف. ارفض بشكل قاطع أي محتوى غير قصصي (مقالات، تعليقات، مواد دراسية، إلخ).
53
 
54
+ **ثالثاً: تطبيق معايير المراجعة بناءً على التحليل السياقي (مدونة السلوك للناقد)**
55
+ استخدم هذه المدونة كمرجع لتحديد الانتهاكات. لا تقم بتطبيقها بشكل آلي. يجب أن يمر كل انتهاك محتمل عبر فلتر "التحليل السياقي للكلمة" الذي قمت به في الخطوة الأولى.
 
 
56
 
57
+ ---
58
+ **(((مدونة السلوك والمحتوى المرفوض)))**
 
59
 
60
+ **1. الإساءة الدينية والثقافية:**
61
+ * **أ) سب الذات الإلهية أو الأديان:** أي ازدراء أو سب مباشر لله تعالى، القرآن، النبي محمد ﷺ، الصحابة، أو الرسل والأنبياء في الديانات السماوية الأخرى.
62
+ * **ب) الاستهزاء بالشعائر والرموز الدينية:** السخرية من الصلاة، الصيام، الحج، الزكاة، المساجد، الكعبة، إلخ.
63
+ * **ج) الكفر والتجديف الصريح:** إنكار وجود الله، إنكار البعث والحساب، أو إنكار النبوة.
64
+ * **د) التحريض الطائفي والمذهبي:** إثارة الفتنة بين المذاهب أو الأديان.
65
 
66
+ **2. الألفاظ النابية والبذاءة:**
67
+ * **أ) الشتائم الجنسية الصريحة:** استخدام أي لفظ يصف الأعضاء التناسلية أو الأفعال الجنسية بشكل مبتذل.
68
+ * **ب) سب الأهل والأعراض:** الشتائم التي تتضمن الأب أو الأم أو الأخت.
69
+ * **ج) الشتائم العامة المهينة:** الألفاظ التي تحط من الكرامة الإنسانية.
70
 
71
+ **3. المحتوى الجنسي والأخلاقي:**
72
+ * **أ) الوصف الجنسي الفاضح:** وصف تفصيلي للأعضاء التناسلية أو الأفعال الجنسية بهدف الإثارة.
73
+ * **ب) تمجيد العلاقات المحرمة والشذوذ الجنسي:** الترويج للزنا، الخيانة، أو العلاقات المثلية وتقديمها على أنها أمر إيجابي.
74
+ * **ج) الإيحاءات والتلميحات المبتذلة:** العبارات التي تحمل معانٍ جنسية مبطنة ورخيصة.
75
 
76
+ **4. العنف والكراهية:**
77
+ * **أ) العنف المفرط والمقزز:** الوصف التصويري المفصل لأعمال القتل والتعذيب والتشويه.
78
+ * **ب) تمجيد الجريمة والكراهية:** الدعوة الصريحة للقتل، الانتقام، إيذاء النفس، أو التحريض العرقي.
 
 
79
 
80
+ **5. المحتوى المخالف للقانون والأخلاق العامة:**
81
+ * **أ) الترويج للمخدرات والمسكرات:** التشجيع على تعاطي المخدرات أو شرب الخمر.
82
+ * **ب) الإساءة للمرأة وتحقيرها:** العبارات التي تصور المرأة ككائن ناقص أو مجرد أداة.
 
 
83
 
84
+ ---
85
+ **رابعاً: القرار النهائي المبني على التحليل الدقيق**
 
 
 
86
 
87
+ بعد تشريح النص كلمة بكلمة وفهم سياقه الأدبي العميق، أصدر حكمك النهائي:
88
 
89
+ - **إذا كان النص قصة أدبية حقيقية، وبعد فحص كل كلمة حساسة في سياقها، تأكدت من أنها لا تمثل انتهاكاً مباشراً من قبل صوت السرد نفسه، أجب بـ `true` فقط.**
90
+ - **إذا كان النص غير قصصي، أو إذا كانت كلماته أو عباراته، حتى بعد تحليل السياق، تشكل انتهاكاً واضحاً ومباشراً للمعايير، أجب بـ `no` فقط.**
 
 
91
 
92
+ إجابتك يجب أن تكون `true` أو `no` فقط. لا مجال للتردد. حكمك يعتمد على تحليل دقيق وليس على انطباع عام.
 
 
 
93
 
94
+ **النص المطلوب مراجعته:**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  """
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  def _call_deepseek_api(self, story_content: str) -> Dict[str, Any]:
98
  """
99
  Call Deepseek API for content moderation
 
110
  "messages": [
111
  {
112
  "role": "system",
113
+ "content": "أنت ناقد أدبي محترف متخصص في الأدب العربي والثقافة الإسلامية. مهمتك مراجعة النصوص بدقة شديدة للتأكد من التزامها بالقيم الدينية والثقافية العربية الإسلامية ومن كونها قصصاً أدبية حقيقية."
114
  },
115
  {
116
+ "role": "user",
117
  "content": f"{self.moderation_prompt}\n\n{story_content}"
118
  }
119
  ],
120
  "max_tokens": 10,
121
+ "temperature": 0.0, # Changed to 0.0 for more consistent results
122
  "stream": False
123
  }
124
 
125
  response = requests.post(
126
+ self.api_url,
127
+ headers=self.headers,
128
  json=payload,
129
  timeout=30
130
  )
 
135
  logger.error(f"API Error: {response.status_code} - {response.text}")
136
  return {"error": f"API Error: {response.status_code}"}
137
 
138
+ except Exception as e:
139
+ logger.error(f"Exception calling Deepseek API: {str(e)}")
140
+ return {"error": str(e)}
141
+
142
+ def _validate_story_format(self, story_content: str) -> bool:
143
+ """
144
+ Enhanced validation of story format and content
145
+
146
+ Args:
147
+ story_content: Story content to validate
148
+
149
+ Returns:
150
+ Boolean indicating if format is valid
151
+ """
152
+ if not story_content or not isinstance(story_content, str):
153
+ return False
154
+
155
+ # Check minimum length (at least 50 characters for a meaningful story)
156
+ if len(story_content.strip()) < 50:
157
+ return False
158
+
159
+ # Check for Arabic characters (must have substantial Arabic content)
160
+ arabic_pattern = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]')
161
+ arabic_chars = len(arabic_pattern.findall(story_content))
162
+
163
+ # Arabic characters should be at least 30% of total characters
164
+ if arabic_chars < len(story_content.strip()) * 0.3:
165
+ return False
166
+
167
+ # Quick pre-screening for obvious violations (before API call)
168
+ content_lower = story_content.lower()
169
+
170
+ # Check for common profanity patterns across dialects AND religious violations
171
+ profanity_patterns = [
172
+ # Sexual profanity
173
+ r'\bكس\b', r'\bزب\b', r'\bنيك\b', r'\bمنيوك\b', r'\bشرموط\b',
174
+ r'\bقحب\b', r'\bلحس\b', r'\bمص\b', r'\bطيز\b', r'\bبزاز\b',
175
+ r'\bتبن\b', r'\bنعل\b', r'\bكوس\b', r'\bأير\b', r'\bمنايك\b',
176
+ r'\bخرا\b', r'\bكداب\b', r'\bعرص\b', r'\bخول\b', r'\bحيوان\b',
177
+
178
+ # Religious violations and blasphemy
179
+ r'الله كذاب', r'لعن الله', r'تبا لله', r'يلعن رب', r'الله غبي',
180
+ r'القرآن كذب', r'كتاب مزور', r'خرافات القرآن', r'قرآن مؤلف',
181
+ r'محمد كذاب', r'الرسول دجال', r'نبي كاذب', r'لعنة على محمد',
182
+ r'أبو بكر منافق', r'عمر ظالم', r'علي مخادع', r'الصحابة كذابون',
183
+ r'الصلاة مضيعة', r'رمضان تخلف', r'الحج طقوس', r'الكعبة صنم',
184
+ r'المسيح كذاب', r'الإنجيل محرف', r'موسى دجال', r'التوراة مزورة',
185
+ r'لا إله', r'الله وهم', r'الجنة وهم', r'النار خيال', r'القيامة كذبة',
186
+ r'لعنة الله', r'الله يلعنك', r'ملعون من رب', r'بيوت خرافة',
187
+ r'السنة نواصب', r'الشيعة رافضة', r'الصوفية مشركون', r'الوهابيون كفار'
188
+ ]
189
+
190
+ for pattern in profanity_patterns:
191
+ if re.search(pattern, content_lower):
192
+ return False
193
+
194
+ return True
195
+
196
+ def moderate_story(self, story_content: str) -> Dict[str, Any]:
197
+ """
198
+ Main method to moderate Arabic story content with enhanced validation
199
+
200
+ Args:
201
+ story_content: The Arabic story to moderate
202
+
203
+ Returns:
204
+ Dictionary with moderation result
205
+ """
206
+ # Enhanced validation
207
+ if not self._validate_story_format(story_content):
208
+ return {
209
+ "approved": False,
210
+ "response": "no",
211
+ "reason": "فشل في التحقق من صحة تنسيق القصة أو عدم وجود محتوى عربي كافٍ",
212
+ "timestamp": datetime.now().isoformat()
213
+ }
214
+
215
+ # Clean and prepare content
216
+ cleaned_content = story_content.strip()
217
+
218
+ # Call Deepseek API
219
+ api_response = self._call_deepseek_api(cleaned_content)
220
+
221
+ if "error" in api_response:
222
+ logger.error(f"Moderation failed: {api_response['error']}")
223
+ return {
224
+ "approved": False,
225
+ "response": "no",
226
+ "reason": "خطأ في خدمة المراجعة",
227
+ "error": api_response["error"],
228
+ "timestamp": datetime.now().isoformat()
229
+ }
230
+
231
+ try:
232
+ # Extract the moderation decision
233
+ ai_response = api_response.get("choices", [{}])[0].get("message", {}).get("content", "").strip().lower()
234
+
235
+ # Clean the response (remove any extra whitespace or characters)
236
+ ai_response = re.sub(r'[^\w]', '', ai_response)
237
+
238
+ # Determine if content is approved (be more strict)
239
+ approved = ai_response == "true"
240
+ response_value = "true" if approved else "no"
241
+
242
+ result = {
243
+ "approved": approved,
244
+ "response": response_value,
245
+ "ai_decision": ai_response,
246
+ "timestamp": datetime.now().isoformat(),
247
+ "content_length": len(cleaned_content)
248
+ }
249
+
250
+ if not approved:
251
+ result["reason"] = "المحتوى ينتهك القواعد المجتمعية أو الثقافية أو الدينية، أو أنه ليس قصة أدبية حقيقية"
252
+ else:
253
+ result["reason"] = "المحتوى مقبول ويلتزم بالمعايير المطلوبة"
254
+
255
+ logger.info(f"Moderation completed: {response_value} for content of length {len(cleaned_content)}")
256
+ return result
257
+
258
  except Exception as e:
259
  logger.error(f"Error processing API response: {str(e)}")
260
  return {
261
  "approved": False,
262
  "response": "no",
263
  "reason": "خطأ في معالجة نتيجة المراجعة",
 
264
  "error": str(e),
265
  "timestamp": datetime.now().isoformat()
266
  }
 
272
  # Initialize the moderator (API key will be set via environment variable)
273
  try:
274
  moderator = ArabicContentModerator()
275
+ logger.info("Arabic Content Moderator initialized successfully")
276
  except ValueError as e:
277
  logger.error(f"Failed to initialize moderator: {e}")
278
  moderator = None
 
281
  def home():
282
  """Home endpoint with API documentation"""
283
  return jsonify({
284
+ "service": "مراجع المحتوى الأدبي العربي المحسن",
285
+ "service_en": "Enhanced Arabic Literary Content Moderator",
286
+ "version": "2.0.0",
287
+ "description": "AI-powered professional literary critic for Arabic short stories with comprehensive dialect-aware moderation",
288
+ "description_ar": "ناقد أدبي محترف مدعوم بالذكاء الاصطناعي للقصص العربية القصيرة مع مراجعة شاملة لجميع اللهجات العربية",
289
  "endpoints": {
290
  "/health": "Health check",
291
  "/moderate": "POST - Moderate single story",
292
+ "/moderate/batch": "POST - Moderate multiple stories"
 
293
  },
294
  "features": [
295
+ "Comprehensive profanity detection across all Arabic dialects",
296
+ "Enhanced religious and cultural compliance checking with specific examples",
 
 
 
 
 
 
297
  "Professional literary criticism standards",
298
+ "Strict content type validation (stories only)",
299
+ "Multi-dialect offensive content detection (Gulf, Levantine, Egyptian, Maghrebi, Iraqi, Sudanese, Yemeni)",
300
+ "Comprehensive religious blasphemy detection (Islam, Christianity, Judaism, other faiths)",
301
+ "Advanced sectarian and inter-religious conflict prevention",
302
+ "Takfir and religious defamation blocking",
303
+ "Advanced pre-screening before API calls",
304
+ "Arabic language purity validation",
305
+ "Context-aware violation detection"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
306
  ],
 
 
 
 
 
 
 
307
  "usage": {
308
  "moderate": {
309
  "method": "POST",
310
  "payload": {"story_content": "Arabic story text"},
311
+ "response": {"approved": "boolean", "response": "true/no"}
 
 
 
 
 
 
312
  }
313
  },
314
  "status": "healthy" if moderator else "service unavailable"
 
319
  """Health check endpoint"""
320
  return jsonify({
321
  "status": "healthy" if moderator else "unhealthy",
322
+ "service": "Enhanced Arabic Content Moderator",
323
  "timestamp": datetime.now().isoformat(),
324
+ "api_available": moderator is not None
 
 
 
 
 
 
 
325
  })
326
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
  @app.route('/moderate', methods=['POST'])
328
  def moderate_content():
329
  """
330
+ Enhanced moderation endpoint
331
 
332
  Expected JSON payload:
333
  {
 
338
  {
339
  "approved": true/false,
340
  "response": "true"/"no",
341
+ "reason": "reason in Arabic",
 
 
342
  "timestamp": "ISO timestamp"
343
  }
344
  """
 
364
  story_content = data['story_content']
365
  result = moderator.moderate_story(story_content)
366
 
 
 
 
 
 
367
  return jsonify(result)
368
 
369
  except Exception as e:
 
373
  "error_en": "Internal server error",
374
  "approved": False,
375
  "response": "no",
 
376
  "details": str(e)
377
  }), 500
378
 
379
  @app.route('/moderate/batch', methods=['POST'])
380
  def moderate_batch():
381
  """
382
+ Enhanced batch moderation endpoint
383
 
384
  Expected JSON payload:
385
  {
 
410
 
411
  results = []
412
  approved_count = 0
 
413
 
414
  for i, story in enumerate(stories):
415
  logger.info(f"Moderating story {i+1}/{len(stories)}")
416
  result = moderator.moderate_story(story)
 
 
 
 
 
417
  results.append({
418
  "story_index": i,
419
  "result": result
420
  })
 
421
  if result.get("approved", False):
422
  approved_count += 1
423
 
 
427
  "total_processed": len(results),
428
  "approved_count": approved_count,
429
  "rejected_count": len(results) - approved_count,
430
+ "approval_rate": f"{(approved_count/len(results)*100):.1f}%" if results else "0%"
 
 
 
 
 
 
 
431
  },
432
  "timestamp": datetime.now().isoformat()
433
  })
 
440
  "details": str(e)
441
  }), 500
442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
  if __name__ == '__main__':
444
  # For local testing
445
  port = int(os.environ.get('PORT', 7860))
446
+ app.run(host='0.0.0.0', port=port, debug=False)