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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +737 -183
app.py CHANGED
@@ -13,8 +13,8 @@ logger = logging.getLogger(__name__)
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,77 +34,329 @@ class ArabicContentModerator:
34
  "Content-Type": "application/json"
35
  }
36
 
37
- # Flexible Arabic Content Moderation - Strict only on Religion & Profanity
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  self.moderation_prompt = """
39
- أنت مراجع محتوى عربي محترف. مهمتك مراجعة النصوص العربية مع التركيز الشديد على الانتهاكات الدينية والسب والشتم فقط، مع المرونة في باقي الجوانب.
40
-
41
- ## معايير المراجعة
42
-
43
- ### 1. التحقق من طبيعة النص (مرن):
44
- - قبول أي نص سردي يحتوي على عناصر القصة الأساسية
45
- - قبول النصوص الإبداعية حتى لو كانت قصيرة أو بسيطة
46
- - قبول الحوارات والمونولوجات والنصوص التجريبية
47
- - قب��ل الأساليب الأدبية المختلفة (حديثة، تقليدية، تجريبية)
48
- - **لا رفض** للنصوص الإبداعية إلا إذا كانت أخباراً صحفية واضحة أو مقالات أكاديمية بحتة
49
-
50
- ### 2. الانتهاكات الدينية - فحص صارم جداً:
51
- **رفض فوري للمحتوى الذي يحتوي على:**
52
- - أي استهزاء أو تهكم على الله أو الأنبياء أو الأسماء الحسنى
53
- - انتقاد أو تشكيك في الآيات القرآنية أو الأحاديث النبوية
54
- - السخرية من الصلاة أو الصوم أو الحج أو أي شعيرة دينية
55
- - التطاول على الصحابة أو العلماء المعتبرين
56
- - التجديف أو الكفر أو الردة الصريحة
57
- - نسبة أقوال كاذبة للرسول أو تحريف النصوص الدينية
58
- - السب بالدين أو اللعن بالآيات
59
-
60
- ### 3. السب والشتم - فحص صارم جداً:
61
- **رفض فوري للمحتوى الذي يحتوي على:**
62
- - الألفاظ الجنسية الصريحة أو الوصف الجنسي المبتذل
63
- - السب بالأعضاء التناسلية أو الوظائف الجنسية
64
- - الألفاظ الإخراجية والمصطلحات القذرة
65
- - إهانة الأم أو العرض أو الشرف بألفاظ نابية
66
- - السب العرقي أو الطائفي بألفاظ قبيحة
67
- - الكلمات المبتذلة الخادشة للحياء العام
68
-
69
- ### 4. الجوانب الأخرى - مرونة عالية:
70
- **قبول المحتوى حتى لو احتوى على:**
71
- - نقد اجتماعي أو سياسي معتدل
72
- - مواضيع حساسة إذا تم تناولها بأدب
73
- - عنف درامي غير مفرط ومبرر قصصياً
74
- - صراعات عاطفية أو اجتماعية
75
- - تناول قضايا معاصرة أو تاريخية
76
- - اختلافات ثقافية أو اجتماعية
77
- - انتقاد سلوكيات أو ممارسات اجتماعية (بدون سب)
78
-
79
- ### 5. اللغة والأسلوب - مرونة عالية:
80
- **قبول:**
81
- - اللهجات المحلية والعامية المفهومة
82
- - الأساليب الأدبية المختلفة
83
- - التجديد في الشكل الأدبي
84
- - المزج بين الفصحى والعامية
85
- - استخدام كلمات أجنبية إذا كانت مناسبة للسياق
86
-
87
- ## إرشادات التقييم المرن:
88
-
89
- 1. **أعط الأولوية للإبداع**: اقبل النصوص الإبداعية حتى لو كانت غير تقليدية
90
- 2. **السياق مهم**: اعتبر السياق القصصي والغرض الأدبي
91
- 3. **التساهل في النقد**: لا ترفض النصوص للنقد الاجتماعي المهذب
92
- 4. **المرونة الثقافية**: اقبل تنوع الأساليب والمواضيع العربية
93
- 5. **التركيز على الجوهر**: ركز فقط على الانتهاكات الدينية والسب الصريح
94
-
95
- ## الانتهاكات الوحيدة المرفوضة:
96
- 1. **الانتهاكات الدينية الصريحة** (كما هو محدد أعلاه)
97
- 2. **السب والشتم الفاحش** (كما هو محدد أعلاه)
98
- 3. **النصوص غير السردية تماماً** (الأخبار الصحفية البحتة أو المقالات الأكاديمية)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
  ## الاستجابة المطلوبة:
101
- بعد المراجعة، أجب بكلمة واحدة فقط:
102
- - "true" - إذا كان النص مقبولاً (خال من الانتهاكات الدينية والسب الفاحش)
103
- - "no" - إذا احتوى على انتهاكات دينية صريحة أو سب فاحش فقط
 
 
104
 
105
  النص المطلوب مراجعته:
106
  """
107
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  def _call_deepseek_api(self, story_content: str) -> Dict[str, Any]:
109
  """
110
  Call Deepseek API for content moderation
@@ -121,21 +373,21 @@ class ArabicContentModerator:
121
  "messages": [
122
  {
123
  "role": "system",
124
- "content": "أنت مراجع محتوى عربي محترف. مهمتك مراجعة النصوص العربية مع التركيز الشديد على الانتهاكات الدينية والسب والشتم فقط، مع المرونة في باقي الجوانب."
125
  },
126
  {
127
- "role": "user",
128
  "content": f"{self.moderation_prompt}\n\n{story_content}"
129
  }
130
  ],
131
  "max_tokens": 10,
132
- "temperature": 0.0, # Changed to 0.0 for more consistent results
133
  "stream": False
134
  }
135
 
136
  response = requests.post(
137
- self.api_url,
138
- headers=self.headers,
139
  json=payload,
140
  timeout=30
141
  )
@@ -146,105 +398,13 @@ class ArabicContentModerator:
146
  logger.error(f"API Error: {response.status_code} - {response.text}")
147
  return {"error": f"API Error: {response.status_code}"}
148
 
149
- except Exception as e:
150
- logger.error(f"Exception calling Deepseek API: {str(e)}")
151
- return {"error": str(e)}
152
-
153
- def _validate_story_format(self, story_content: str) -> bool:
154
- """
155
- Enhanced validation of story format and content
156
-
157
- Args:
158
- story_content: Story content to validate
159
-
160
- Returns:
161
- Boolean indicating if format is valid
162
- """
163
- if not story_content or not isinstance(story_content, str):
164
- return False
165
-
166
- # Check minimum length (at least 50 characters for a meaningful story)
167
- if len(story_content.strip()) < 50:
168
- return False
169
-
170
- # Check for Arabic characters (must have substantial Arabic content)
171
- arabic_pattern = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]')
172
- arabic_chars = len(arabic_pattern.findall(story_content))
173
-
174
- # Arabic characters should be at least 30% of total characters
175
- if arabic_chars < len(story_content.strip()) * 0.3:
176
- return False
177
-
178
- return True
179
-
180
- def moderate_story(self, story_content: str) -> Dict[str, Any]:
181
- """
182
- Main method to moderate Arabic story content with enhanced validation
183
-
184
- Args:
185
- story_content: The Arabic story to moderate
186
-
187
- Returns:
188
- Dictionary with moderation result
189
- """
190
- # Enhanced validation
191
- if not self._validate_story_format(story_content):
192
- return {
193
- "approved": False,
194
- "response": "no",
195
- "reason": "فشل في التحقق من صحة تنسيق القصة أو عدم وجود محتوى عربي كافٍ",
196
- "timestamp": datetime.now().isoformat()
197
- }
198
-
199
- # Clean and prepare content
200
- cleaned_content = story_content.strip()
201
-
202
- # Call Deepseek API
203
- api_response = self._call_deepseek_api(cleaned_content)
204
-
205
- if "error" in api_response:
206
- logger.error(f"Moderation failed: {api_response['error']}")
207
- return {
208
- "approved": False,
209
- "response": "no",
210
- "reason": "خطأ في خدمة المراجعة",
211
- "error": api_response["error"],
212
- "timestamp": datetime.now().isoformat()
213
- }
214
-
215
- try:
216
- # Extract the moderation decision
217
- ai_response = api_response.get("choices", [{}])[0].get("message", {}).get("content", "").strip().lower()
218
-
219
- # Clean the response (remove any extra whitespace or characters)
220
- ai_response = re.sub(r'[^\w]', '', ai_response)
221
-
222
- # Determine if content is approved (be more strict)
223
- approved = ai_response == "true"
224
- response_value = "true" if approved else "no"
225
-
226
- result = {
227
- "approved": approved,
228
- "response": response_value,
229
- "ai_decision": ai_response,
230
- "timestamp": datetime.now().isoformat(),
231
- "content_length": len(cleaned_content)
232
- }
233
-
234
- if not approved:
235
- result["reason"] = "المحتوى ينتهك القواعد المجتمعية أو الثقافية أو الدينية، أو أنه ليس قصة أدبية حقيقية"
236
- else:
237
- result["reason"] = "المحتوى مقبول ويلتزم بالمعايير المطلوبة"
238
-
239
- logger.info(f"Moderation completed: {response_value} for content of length {len(cleaned_content)}")
240
- return result
241
-
242
  except Exception as e:
243
  logger.error(f"Error processing API response: {str(e)}")
244
  return {
245
  "approved": False,
246
  "response": "no",
247
  "reason": "خطأ في معالجة نتيجة المراجعة",
 
248
  "error": str(e),
249
  "timestamp": datetime.now().isoformat()
250
  }
@@ -256,7 +416,7 @@ app = Flask(__name__)
256
  # Initialize the moderator (API key will be set via environment variable)
257
  try:
258
  moderator = ArabicContentModerator()
259
- logger.info("Arabic Content Moderator initialized successfully")
260
  except ValueError as e:
261
  logger.error(f"Failed to initialize moderator: {e}")
262
  moderator = None
@@ -265,28 +425,71 @@ except ValueError as e:
265
  def home():
266
  """Home endpoint with API documentation"""
267
  return jsonify({
268
- "service": "مراجع المحتوى الأدبي العربي المحسن",
269
- "service_en": "Enhanced Arabic Literary Content Moderator",
270
- "version": "2.0.0",
271
- "description": "AI-powered professional literary critic for Arabic short stories with enhanced cultural and religious compliance",
272
- "description_ar": "ناقد أدبي محترف مدعوم بالذكاء الاصطناعي للقصص العربية القصيرة مع التزام معزز بالقيم الثقافية والدينية",
273
  "endpoints": {
274
  "/health": "Health check",
275
  "/moderate": "POST - Moderate single story",
276
- "/moderate/batch": "POST - Moderate multiple stories"
 
277
  },
278
  "features": [
279
- "Enhanced religious and cultural compliance checking",
 
 
 
 
 
 
 
280
  "Professional literary criticism standards",
281
- "Strict content type validation (stories only)",
282
- "Comprehensive profanity and inappropriate content detection",
283
- "Arabic language purity validation"
284
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  "usage": {
286
  "moderate": {
287
  "method": "POST",
288
  "payload": {"story_content": "Arabic story text"},
289
- "response": {"approved": "boolean", "response": "true/no"}
 
 
 
 
 
 
290
  }
291
  },
292
  "status": "healthy" if moderator else "service unavailable"
@@ -297,15 +500,77 @@ def health_check():
297
  """Health check endpoint"""
298
  return jsonify({
299
  "status": "healthy" if moderator else "unhealthy",
300
- "service": "Enhanced Arabic Content Moderator",
301
  "timestamp": datetime.now().isoformat(),
302
- "api_available": moderator is not None
 
 
 
 
 
 
 
303
  })
304
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  @app.route('/moderate', methods=['POST'])
306
  def moderate_content():
307
  """
308
- Enhanced moderation endpoint
309
 
310
  Expected JSON payload:
311
  {
@@ -316,7 +581,9 @@ def moderate_content():
316
  {
317
  "approved": true/false,
318
  "response": "true"/"no",
319
- "reason": "reason in Arabic",
 
 
320
  "timestamp": "ISO timestamp"
321
  }
322
  """
@@ -342,6 +609,11 @@ def moderate_content():
342
  story_content = data['story_content']
343
  result = moderator.moderate_story(story_content)
344
 
 
 
 
 
 
345
  return jsonify(result)
346
 
347
  except Exception as e:
@@ -351,13 +623,14 @@ def moderate_content():
351
  "error_en": "Internal server error",
352
  "approved": False,
353
  "response": "no",
 
354
  "details": str(e)
355
  }), 500
356
 
357
  @app.route('/moderate/batch', methods=['POST'])
358
  def moderate_batch():
359
  """
360
- Enhanced batch moderation endpoint
361
 
362
  Expected JSON payload:
363
  {
@@ -388,14 +661,21 @@ def moderate_batch():
388
 
389
  results = []
390
  approved_count = 0
 
391
 
392
  for i, story in enumerate(stories):
393
  logger.info(f"Moderating story {i+1}/{len(stories)}")
394
  result = moderator.moderate_story(story)
 
 
 
 
 
395
  results.append({
396
  "story_index": i,
397
  "result": result
398
  })
 
399
  if result.get("approved", False):
400
  approved_count += 1
401
 
@@ -405,7 +685,14 @@ def moderate_batch():
405
  "total_processed": len(results),
406
  "approved_count": approved_count,
407
  "rejected_count": len(results) - approved_count,
408
- "approval_rate": f"{(approved_count/len(results)*100):.1f}%" if results else "0%"
 
 
 
 
 
 
 
409
  },
410
  "timestamp": datetime.now().isoformat()
411
  })
@@ -418,7 +705,274 @@ def moderate_batch():
418
  "details": str(e)
419
  }), 500
420
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  if __name__ == '__main__':
422
  # For local testing
423
  port = int(os.environ.get('PORT', 7860))
424
- app.run(host='0.0.0.0', port=port, debug=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
  "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
  "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
  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
  # 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
  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
  """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
  {
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
  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
  "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
 
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
  "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
  "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(