File size: 23,004 Bytes
a854c1b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
"""
وحدة المساعد الذكي لنظام إدارة المناقصات - Hybrid Face
"""

import os
import logging
import threading
import datetime
import json
import re
from pathlib import Path

# تهيئة السجل
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger('ai_assistant')

class AIAssistant:
    """المساعد الذكي"""
    
    def __init__(self, config=None, db=None):
        """تهيئة المساعد الذكي"""
        self.config = config
        self.db = db
        self.processing_in_progress = False
        self.current_query = None
        self.processing_results = {}
        self.conversation_history = []
        
        # إعدادات المساعد الذكي
        self.ai_model = config.AI_MODEL if config and hasattr(config, 'AI_MODEL') else "gpt-4"
        self.ai_temperature = config.AI_TEMPERATURE if config and hasattr(config, 'AI_TEMPERATURE') else 0.7
        self.ai_max_tokens = config.AI_MAX_TOKENS if config and hasattr(config, 'AI_MAX_TOKENS') else 2000
        
        # إنشاء مجلد المساعد الذكي إذا لم يكن موجوداً
        if config and hasattr(config, 'EXPORTS_PATH'):
            self.exports_path = Path(config.EXPORTS_PATH)
        else:
            self.exports_path = Path('data/exports')
            
        if not self.exports_path.exists():
            self.exports_path.mkdir(parents=True, exist_ok=True)
    
    def process_query(self, query, context=None, callback=None):
        """معالجة استعلام المستخدم"""
        if self.processing_in_progress:
            logger.warning("هناك عملية معالجة جارية بالفعل")
            return False
        
        self.processing_in_progress = True
        self.current_query = query
        self.processing_results = {
            "query": query,
            "context": context,
            "processing_start_time": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            "status": "جاري المعالجة",
            "response": "",
            "suggestions": [],
            "references": []
        }
        
        # إضافة الاستعلام إلى سجل المحادثة
        self.conversation_history.append({
            "role": "user",
            "content": query,
            "timestamp": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        })
        
        # بدء المعالجة في خيط منفصل
        thread = threading.Thread(
            target=self._process_query_thread,
            args=(query, context, callback)
        )
        thread.daemon = True
        thread.start()
        
        return True
    
    def _process_query_thread(self, query, context, callback):
        """خيط معالجة الاستعلام"""
        try:
            # تحليل الاستعلام
            query_type = self._analyze_query(query)
            
            # معالجة الاستعلام بناءً على نوعه
            if query_type == "document_analysis":
                response = self._handle_document_analysis_query(query, context)
            elif query_type == "pricing":
                response = self._handle_pricing_query(query, context)
            elif query_type == "risk_analysis":
                response = self._handle_risk_analysis_query(query, context)
            elif query_type == "project_management":
                response = self._handle_project_management_query(query, context)
            elif query_type == "reporting":
                response = self._handle_reporting_query(query, context)
            else:
                response = self._handle_general_query(query, context)
            
            # توليد اقتراحات
            suggestions = self._generate_suggestions(query_type, query, response)
            
            # تحديث نتائج المعالجة
            self.processing_results["response"] = response
            self.processing_results["query_type"] = query_type
            self.processing_results["suggestions"] = suggestions
            self.processing_results["status"] = "اكتملت المعالجة"
            self.processing_results["processing_end_time"] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            
            # إضافة الاستجابة إلى سجل المحادثة
            self.conversation_history.append({
                "role": "assistant",
                "content": response,
                "timestamp": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            })
            
            logger.info(f"اكتملت معالجة الاستعلام: {query[:50]}...")
            
        except Exception as e:
            logger.error(f"خطأ في معالجة الاستعلام: {str(e)}")
            self.processing_results["status"] = "فشلت المعالجة"
            self.processing_results["error"] = str(e)
            
            # إضافة رسالة الخطأ إلى سجل المحادثة
            self.conversation_history.append({
                "role": "system",
                "content": f"حدث خطأ أثناء معالجة الاستعلام: {str(e)}",
                "timestamp": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            })
        
        finally:
            self.processing_in_progress = False
            
            # استدعاء دالة الاستجابة إذا تم توفيرها
            if callback and callable(callback):
                callback(self.processing_results)
    
    def _analyze_query(self, query):
        """تحليل نوع الاستعلام"""
        query = query.lower()
        
        # تحديد نوع الاستعلام بناءً على الكلمات المفتاحية
        if any(keyword in query for keyword in ["تحليل المستند", "تحليل وثيقة", "استخراج بيانات", "قراءة مستند"]):
            return "document_analysis"
        elif any(keyword in query for keyword in ["تسعير", "سعر", "تكلفة", "ميزانية", "تقدير"]):
            return "pricing"
        elif any(keyword in query for keyword in ["مخاطر", "تحليل المخاطر", "تقييم المخاطر"]):
            return "risk_analysis"
        elif any(keyword in query for keyword in ["مشروع", "إدارة المشروع", "جدول زمني", "خطة"]):
            return "project_management"
        elif any(keyword in query for keyword in ["تقرير", "إحصائيات", "تحليل البيانات", "رسم بياني"]):
            return "reporting"
        else:
            return "general"
    
    def _handle_document_analysis_query(self, query, context):
        """معالجة استعلام تحليل المستندات"""
        # محاكاة استجابة المساعد الذكي لاستعلام تحليل المستندات
        response = """
يمكنني مساعدتك في تحليل المستندات واستخراج المعلومات المهمة منها. لتحليل مستند، يرجى اتباع الخطوات التالية:

1. انتقل إلى وحدة "تحليل المستندات" من القائمة الجانبية.
2. انقر على زر "تحميل مستند" واختر المستند المراد تحليله.
3. حدد نوع المستند (مناقصة، عقد، مواصفات فنية، إلخ).
4. انقر على زر "تحليل" لبدء عملية التحليل.

سيقوم النظام باستخراج المعلومات التالية من المستند:
- البنود والكميات
- الكيانات (العميل، الموقع، المقاول، إلخ)
- التواريخ المهمة
- المبالغ والتكاليف
- المخاطر المحتملة

بعد اكتمال التحليل، يمكنك مراجعة النتائج وتعديلها إذا لزم الأمر، ثم استخدامها في وحدات النظام الأخرى مثل التسعير وتحليل المخاطر.
"""
        
        # إضافة مراجع ذات صلة
        self.processing_results["references"] = [
            {"title": "دليل استخدام وحدة تحليل المستندات", "type": "manual"},
            {"title": "أنواع المستندات المدعومة", "type": "documentation"},
            {"title": "تقنيات استخراج البيانات من المستندات", "type": "article"}
        ]
        
        return response
    
    def _handle_pricing_query(self, query, context):
        """معالجة استعلام التسعير"""
        # محاكاة استجابة المساعد الذكي لاستعلام التسعير
        response = """
يمكنني مساعدتك في تسعير المشاريع وتقدير التكاليف. لإنشاء تسعير لمشروع، يرجى اتباع الخطوات التالية:

1. انتقل إلى وحدة "التسعير المتكامل" من القائمة الجانبية.
2. اختر المشروع المراد تسعيره أو أنشئ مشروعاً جديداً.
3. أدخل بنود المشروع والكميات التقديرية (يمكن استيرادها من نتائج تحليل المستندات).
4. حدد الموارد المطلوبة (مواد، معدات، عمالة).
5. اختر استراتيجية التسعير المناسبة:
   - شاملة: تغطية كاملة للتكاليف والمخاطر مع هامش ربح مناسب.
   - تنافسية: تخفيض الهوامش لتقديم سعر تنافسي.
   - متوازنة: توازن بين الربحية والتنافسية.
6. انقر على زر "حساب التسعير" لإنشاء التسعير.

سيقوم النظام بحساب:
- التكاليف المباشرة (بنود المشروع)
- التكاليف غير المباشرة (نفقات عامة، إدارية، ربح)
- تكاليف المخاطر
- ضريبة القيمة المضافة
- السعر النهائي

يمكنك تعديل المعلمات وإعادة حساب التسعير، ثم تصدير النتائج إلى تقرير مفصل.
"""
        
        # إضافة مراجع ذات صلة
        self.processing_results["references"] = [
            {"title": "دليل استخدام وحدة التسعير المتكامل", "type": "manual"},
            {"title": "استراتيجيات التسعير", "type": "documentation"},
            {"title": "حساب التكاليف غير المباشرة", "type": "article"}
        ]
        
        return response
    
    def _handle_risk_analysis_query(self, query, context):
        """معالجة استعلام تحليل المخاطر"""
        # محاكاة استجابة المساعد الذكي لاستعلام تحليل المخاطر
        response = """
يمكنني مساعدتك في تحليل وإدارة مخاطر المشروع. لإجراء تحليل للمخاطر، يرجى اتباع الخطوات التالية:

1. انتقل إلى وحدة "تحليل المخاطر" من القائمة الجانبية.
2. اختر المشروع المراد تحليل مخاطره.
3. اختر طريقة التحليل:
   - شاملة: تحليل مفصل يغطي جميع جوانب المشروع.
   - أساسية: تحليل سريع للمخاطر الرئيسية.
4. انقر على زر "تحليل المخاطر" لبدء التحليل.

سيقوم النظام بما يلي:
- تحديد المخاطر المحتملة بناءً على بيانات المشروع
- تصنيف المخاطر إلى فئات (فني، مالي، إداري، إلخ)
- إنشاء مصفوفة المخاطر (الاحتمالية × التأثير)
- تطوير استراتيجيات التخفيف لكل مخاطرة
- إنشاء ملخص للمخاطر وتوصيات

يمكنك مراجعة نتائج التحليل وتعديلها، ثم تصدير التقرير النهائي واستخدامه في خطة إدارة المشروع.
"""
        
        # إضافة مراجع ذات صلة
        self.processing_results["references"] = [
            {"title": "دليل استخدام وحدة تحليل المخاطر", "type": "manual"},
            {"title": "منهجيات تحليل المخاطر", "type": "documentation"},
            {"title": "استراتيجيات التخفيف من المخاطر", "type": "article"}
        ]
        
        return response
    
    def _handle_project_management_query(self, query, context):
        """معالجة استعلام إدارة المشاريع"""
        # محاكاة استجابة المساعد الذكي لاستعلام إدارة المشاريع
        response = """
يمكنني مساعدتك في إدارة المشاريع وتتبع تقدمها. لإدارة مشروع، يرجى اتباع الخطوات التالية:

1. انتقل إلى وحدة "إدارة المشاريع" من القائمة الجانبية.
2. أنشئ مشروعاً جديداً أو اختر مشروعاً موجوداً.
3. أدخل معلومات المشروع الأساسية (الاسم، العميل، الوصف، التواريخ).
4. أضف بنود المشروع (يمكن استيرادها من نتائج تحليل المستندات).
5. أنشئ الجدول الزمني للمشروع وحدد المراحل والمهام.
6. عين الموارد للمهام وحدد التبعيات بينها.

يمكنك استخدام وحدة إدارة المشاريع لـ:
- تتبع تقدم المشروع ومقارنته بالخطة
- إدارة الموارد وتوزيعها
- متابعة المشكلات والمخاطر
- إدارة التغييرات في نطاق العمل
- إنشاء تقارير حالة المشروع

كما يمكنك دمج نتائج التسعير وتحليل المخاطر في خطة المشروع لإدارة شاملة.
"""
        
        # إضافة مراجع ذات صلة
        self.processing_results["references"] = [
            {"title": "دليل استخدام وحدة إدارة المشاريع", "type": "manual"},
            {"title": "أفضل ممارسات إدارة المشاريع", "type": "documentation"},
            {"title": "إنشاء جداول زمنية فعالة", "type": "article"}
        ]
        
        return response
    
    def _handle_reporting_query(self, query, context):
        """معالجة استعلام التقارير"""
        # محاكاة استجابة المساعد الذكي لاستعلام التقارير
        response = """
يمكنني مساعدتك في إنشاء تقارير وتحليلات للمشاريع والمناقصات. لإنشاء تقرير، يرجى اتباع الخطوات التالية:

1. انتقل إلى وحدة "التقارير والتحليلات" من القائمة الجانبية.
2. اختر نوع التقرير:
   - تقرير المشروع: معلومات شاملة عن مشروع محدد
   - تقرير التسعير: تفاصيل تسعير مشروع أو مناقصة
   - تقرير المخاطر: تحليل مخاطر المشروع واستراتيجيات التخفيف
   - تقرير الأداء: مقارنة الأداء الفعلي بالمخطط
   - تقرير مالي: تحليل مالي للمشاريع والمناقصات
3. حدد معلمات التقرير (المشروع، الفترة الزمنية، إلخ).
4. انقر على زر "إنشاء التقرير".

يمكنك تخصيص التقارير بإضافة أو إزالة أقسام، وتغيير طريقة عرض البيانات (جداول، رسوم بيانية، إلخ).

التقارير المنشأة يمكن:
- تصديرها بتنسيقات مختلفة (PDF، Excel، Word)
- مشاركتها مع أعضاء الفريق أو العملاء
- جدولتها للإنشاء التلقائي بشكل دوري
- حفظها كقوالب لاستخدامها في المستقبل
"""
        
        # إضافة مراجع ذات صلة
        self.processing_results["references"] = [
            {"title": "دليل استخدام وحدة التقارير والتحليلات", "type": "manual"},
            {"title": "أنواع التقارير المتاحة", "type": "documentation"},
            {"title": "إنشاء رسوم بيانية فعالة", "type": "article"}
        ]
        
        return response
    
    def _handle_general_query(self, query, context):
        """معالجة استعلام عام"""
        # محاكاة استجابة المساعد الذكي لاستعلام عام
        response = """
مرحباً بك في المساعد الذكي لنظام إدارة المناقصات Hybrid Face. يمكنني مساعدتك في مجموعة متنوعة من المهام المتعلقة بإدارة المناقصات والمشاريع.

يمكنني مساعدتك في:
- تحليل مستندات المناقصات واستخراج المعلومات المهمة منها
- تسعير المشاريع وتقدير التكاليف
- تحليل وإدارة مخاطر المشاريع
- إدارة المشاريع وتتبع تقدمها
- إنشاء تقارير وتحليلات

للحصول على مساعدة محددة، يرجى طرح سؤال يتعلق بإحدى هذه المجالات. على سبيل المثال:
- "كيف يمكنني تحليل مستند مناقصة؟"
- "ساعدني في تسعير مشروع جديد"
- "كيف أقوم بتحليل مخاطر المشروع؟"
- "أريد إنشاء تقرير عن حالة المشروع"

يمكنك أيضاً استخدام الوحدات المختلفة في النظام مباشرة من القائمة الجانبية.
"""
        
        # إضافة مراجع ذات صلة
        self.processing_results["references"] = [
            {"title": "دليل المستخدم الشامل", "type": "manual"},
            {"title": "نظرة عامة على النظام", "type": "documentation"},
            {"title": "الأسئلة الشائعة", "type": "faq"}
        ]
        
        return response
    
    def _generate_suggestions(self, query_type, query, response):
        """توليد اقتراحات للمستخدم بناءً على الاستعلام والاستجابة"""
        suggestions = []
        
        if query_type == "document_analysis":
            suggestions = [
                "كيف يمكنني استيراد نتائج تحليل المستندات إلى وحدة التسعير؟",
                "ما هي أنواع المستندات المدعومة للتحليل؟",
                "كيف يمكنني تحسين دقة تحليل المستندات؟"
            ]
        elif query_type == "pricing":
            suggestions = [
                "ما هي استراتيجية التسعير المناسبة لمشروعي؟",
                "كيف يمكنني حساب التكاليف غير المباشرة؟",
                "كيف أضيف تكاليف المخاطر إلى التسعير؟"
            ]
        elif query_type == "risk_analysis":
            suggestions = [
                "ما هي أفضل استراتيجيات التخفيف من المخاطر؟",
                "كيف يمكنني تحديد المخاطر الحرجة في المشروع؟",
                "كيف أدمج تحليل المخاطر في خطة المشروع؟"
            ]
        elif query_type == "project_management":
            suggestions = [
                "كيف أنشئ جدولاً زمنياً فعالاً للمشروع؟",
                "كيف أتتبع تقدم المشروع مقارنة بالخطة؟",
                "كيف أدير التغييرات في نطاق المشروع؟"
            ]
        elif query_type == "reporting":
            suggestions = [
                "ما هي أنواع التقارير المتاحة في النظام؟",
                "كيف يمكنني تخصيص تقرير المشروع؟",
                "كيف أقوم بجدولة إنشاء تقارير دورية؟"
            ]
        else:
            suggestions = [
                "كيف يمكنني البدء باستخدام النظام؟",
                "ما هي الوحدات المتاحة في النظام؟",
                "كيف يمكنني إنشاء مشروع جديد؟"
            ]
        
        return suggestions
    
    def get_processing_status(self):
        """الحصول على حالة المعالجة الحالية"""
        if not self.processing_in_progress:
            if not self.processing_results:
                return {"status": "لا توجد معالجة جارية"}
            else:
                return {"status": self.processing_results.get("status", "غير معروف")}
        
        return {
            "status": "جاري المعالجة",
            "query": self.current_query,
            "start_time": self.processing_results.get("processing_start_time")
        }
    
    def get_processing_results(self):
        """الحصول على نتائج المعالجة"""
        return self.processing_results
    
    def get_conversation_history(self, limit=10):
        """الحصول على سجل المحادثة"""
        if limit and limit > 0:
            return self.conversation_history[-limit:]
        return self.conversation_history
    
    def clear_conversation_history(self):
        """مسح سجل المحادثة"""
        self.conversation_history = []
        return True
    
    def export_conversation_history(self, output_path=None):
        """تصدير سجل المحادثة إلى ملف JSON"""
        if not self.conversation_history:
            logger.warning("لا يوجد سجل محادثة للتصدير")
            return None
        
        if not output_path:
            # إنشاء اسم ملف افتراضي
            timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f"conversation_history_{timestamp}.json"
            output_path = os.path.join(self.exports_path, filename)
        
        try:
            with open(output_path, 'w', encoding='utf-8') as f:
                json.dump(self.conversation_history, f, ensure_ascii=False, indent=4)
            
            logger.info(f"تم تصدير سجل المحادثة إلى: {output_path}")
            return output_path
        
        except Exception as e:
            logger.error(f"خطأ في تصدير سجل المحادثة: {str(e)}")
            return None