abdull4h commited on
Commit
bc85188
·
verified ·
1 Parent(s): 64f3706

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -44
app.py CHANGED
@@ -34,6 +34,9 @@ class Vision2030Assistant:
34
  def __init__(self):
35
  """Initialize the Vision 2030 Assistant with basic knowledge"""
36
  logger.info("Initializing Vision 2030 Assistant...")
 
 
 
37
 
38
  # Initialize embedding models
39
  self.load_embedding_models()
@@ -57,7 +60,38 @@ class Vision2030Assistant:
57
  self.has_pdf_content = False
58
 
59
  logger.info("Vision 2030 Assistant initialized successfully")
60
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  @spaces.GPU
62
  def load_embedding_models(self):
63
  """Load embedding models for retrieval"""
@@ -369,71 +403,72 @@ class Vision2030Assistant:
369
  return ""
370
 
371
  def generate_response(self, user_input):
372
- """Generate response based on user input"""
373
  if not user_input or user_input.strip() == "":
374
  return ""
375
 
376
  start_time = time.time()
377
 
378
- # Default response in case of failure
379
  default_response = {
380
  "en": "I apologize, but I couldn't process your request properly. Please try again.",
381
  "ar": "أعتذر، لم أتمكن من معالجة طلبك بشكل صحيح. الرجاء المحاولة مرة أخرى."
382
  }
383
 
384
  try:
385
- # Detect language
386
  try:
387
- lang = detect(user_input)
388
- if lang != "ar": # Simplify to just Arabic vs non-Arabic
389
- lang = "en"
390
  except:
391
- lang = "en" # Default fallback
392
 
393
  logger.info(f"Detected language: {lang}")
394
 
395
- # Check for specific question patterns
396
- if lang == "ar":
397
- # National identity
398
- if "الهوية الوطنية" in user_input or "تعزيز الهوية" in user_input:
399
- reply = "تتضمن رؤية 2030 مبادرات متعددة لتعزيز الهوية الوطنية السعودية بما في ذلك البرامج الثقافية والحفاظ على التراث وتعزيز القيم السعودية."
400
- # Hajj and Umrah
401
- elif "المعتمرين" in user_input or "الحجاج" in user_input or "العمرة" in user_input or "الحج" in user_input:
402
- reply = "تهدف رؤية 2030 إلى زيادة القدرة على استقبال المعتمرين من 8 ملايين إلى 30 مليون معتمر سنويًا."
403
- # Economic diversification
404
- elif "تنويع مصادر الدخل" in user_input or "الاقتصاد المزدهر" in user_input or "تنمية الاقتصاد" in user_input:
405
- reply = "تهدف رؤية 2030 إلى زيادة الإيرادات الحكومية غير النفطية من 163 مليار ريال سعودي إلى 1 تريليون ريال سعودي من خلال تطوير قطاعات متنوعة مثل السياحة والتصنيع والطاقة المتجددة."
406
- # UNESCO sites
407
- elif "المواقع الأثرية" in user_input or "اليونسكو" in user_input or "التراث العالمي" in user_input:
408
- reply = "تضع رؤية 2030 هدفًا بتسجيل ما لا يقل عن 10 مواقع سعودية في قائمة التراث العالمي لليونسكو."
409
- # Real wealth
410
- elif "الثروة الحقيقية" in user_input or "أثمن" in user_input or "ثروة" in user_input:
411
- reply = "الثروة الحقيقية للمملكة العربية السعودية، كما أكدت رؤية 2030، هي شعبها، وخاصة الشباب."
412
- # Global gateway
413
- elif "بوابة للعالم" in user_input or "مكانتها" in user_input or "موقعها الاستراتيجي" in user_input:
414
- reply = "تهدف المملكة العربية السعودية إلى تعزيز مكانتها كبوابة عالمية من خلال الاستفادة من موقعها الاستراتيجي بين آسيا وأوروبا وأفريقيا."
415
- # Key pillars
416
- elif "ركائز" in user_input or "اركان" in user_input:
417
- reply = "الركائز الرئيسية لرؤية 2030 هي مجتمع حيوي، واقتصاد مزدهر، ووطن طموح."
418
- # General Vision 2030
419
- elif "ما هي" in user_input or "ماهي" in user_input:
420
- reply = "رؤية 2030 هي الإطار الاستراتيجي للمملكة العربية السعودية للحد من الاعتماد على النفط وتنويع الاقتصاد وتطوير القطاعات العامة. الركائز الرئيسية لرؤية 2030 هي مجتمع حيوي، واقتصاد مزدهر، ووطن طموح."
421
- else:
422
- # Use retrieved context
423
- context = self.retrieve_context(user_input, lang)
 
 
 
 
 
 
424
  reply = context if context else "لم أتمكن من العثور على معلومات كافية حول هذا السؤال."
425
- else: # English
426
- # Use retrieved context
427
- context = self.retrieve_context(user_input, lang)
428
- reply = context if context else "I couldn't find enough information about this question."
429
 
430
- # Record response time
431
  response_time = time.time() - start_time
432
  self.metrics["response_times"].append(response_time)
433
-
434
  logger.info(f"Generated response in {response_time:.2f}s")
435
 
436
- # Store the interaction for later evaluation
437
  interaction = {
438
  "timestamp": datetime.now().isoformat(),
439
  "user_input": user_input,
@@ -447,8 +482,10 @@ class Vision2030Assistant:
447
 
448
  except Exception as e:
449
  logger.error(f"Error generating response: {str(e)}")
 
450
  return default_response.get(lang, default_response["en"])
451
 
 
452
  def evaluate_factual_accuracy(self, response, reference):
453
  """Simple evaluation of factual accuracy by keyword matching"""
454
  # This is a simplified approach - in production, use more sophisticated methods
 
34
  def __init__(self):
35
  """Initialize the Vision 2030 Assistant with basic knowledge"""
36
  logger.info("Initializing Vision 2030 Assistant...")
37
+
38
+ # Load QA pipelines for English & Arabic
39
+ self._load_qa_pipelines()
40
 
41
  # Initialize embedding models
42
  self.load_embedding_models()
 
60
  self.has_pdf_content = False
61
 
62
  logger.info("Vision 2030 Assistant initialized successfully")
63
+
64
+ @spaces.GPU
65
+ def _load_qa_pipelines(self):
66
+ """
67
+ Load or initialize QA models for English and Arabic.
68
+ You can choose any Hugging Face QA model; below are just examples.
69
+ """
70
+ logger.info("Loading QA pipelines...")
71
+ try:
72
+ # English QA pipeline
73
+ self.qa_pipeline_en = pipeline(
74
+ "question-answering",
75
+ model="distilbert-base-cased-distilled-squad",
76
+ tokenizer="distilbert-base-cased-distilled-squad",
77
+ device=0 if has_gpu else -1 # Use GPU if available
78
+ )
79
+
80
+ # Arabic QA pipeline
81
+ # For Arabic, you can use a model like `aubmindlab/bert-base-arabertv02-qa`:
82
+ self.qa_pipeline_ar = pipeline(
83
+ "question-answering",
84
+ model="aubmindlab/bert-base-arabertv02-qa",
85
+ tokenizer="aubmindlab/bert-base-arabertv02-qa",
86
+ device=0 if has_gpu else -1
87
+ )
88
+
89
+ logger.info("QA pipelines loaded successfully.")
90
+ except Exception as e:
91
+ logger.error(f"Error loading QA pipelines: {str(e)}")
92
+ self.qa_pipeline_en = None
93
+ self.qa_pipeline_ar = None
94
+
95
  @spaces.GPU
96
  def load_embedding_models(self):
97
  """Load embedding models for retrieval"""
 
403
  return ""
404
 
405
  def generate_response(self, user_input):
406
+ """Generate a more detailed answer using a QA pipeline if available."""
407
  if not user_input or user_input.strip() == "":
408
  return ""
409
 
410
  start_time = time.time()
411
 
 
412
  default_response = {
413
  "en": "I apologize, but I couldn't process your request properly. Please try again.",
414
  "ar": "أعتذر، لم أتمكن من معالجة طلبك بشكل صحيح. الرجاء المحاولة مرة أخرى."
415
  }
416
 
417
  try:
418
+ # 1) Detect language
419
  try:
420
+ lang_detected = detect(user_input)
421
+ lang = "ar" if lang_detected == "ar" else "en"
 
422
  except:
423
+ lang = "en" # fallback
424
 
425
  logger.info(f"Detected language: {lang}")
426
 
427
+ # 2) Retrieve relevant context (could be from PDF or base knowledge)
428
+ context = self.retrieve_context(user_input, lang)
429
+
430
+ # 3) Decide whether to use QA pipeline or fallback
431
+ if lang == "ar" and self.qa_pipeline_ar is not None and context:
432
+ # Use Arabic QA pipeline
433
+ try:
434
+ answer = self.qa_pipeline_ar(question=user_input, context=context)
435
+ reply = answer["answer"].strip()
436
+
437
+ # If the QA model returns something too short or obviously unhelpful,
438
+ # you can fallback to the original context-based approach:
439
+ if len(reply) < 2:
440
+ reply = context # fallback to returning the raw context
441
+ except Exception as e:
442
+ logger.error(f"Error in Arabic QA pipeline: {str(e)}")
443
+ # fallback
444
+ reply = context if context else "لم أتمكن من العثور على معلومات كافية حول هذا السؤال."
445
+
446
+ elif lang == "en" and self.qa_pipeline_en is not None and context:
447
+ # Use English QA pipeline
448
+ try:
449
+ answer = self.qa_pipeline_en(question=user_input, context=context)
450
+ reply = answer["answer"].strip()
451
+ if len(reply) < 2:
452
+ reply = context
453
+ except Exception as e:
454
+ logger.error(f"Error in English QA pipeline: {str(e)}")
455
+ reply = context if context else "I couldn't find enough information about this question."
456
+
457
+ else:
458
+ # 4) If no QA pipeline or no context, fallback to your existing approach
459
+ # e.g., returning context or a short fallback message.
460
+
461
+ if lang == "ar":
462
  reply = context if context else "لم أتمكن من العثور على معلومات كافية حول هذا السؤال."
463
+ else:
464
+ reply = context if context else "I couldn't find enough information about this question."
 
 
465
 
466
+ # 5) Record metrics and return
467
  response_time = time.time() - start_time
468
  self.metrics["response_times"].append(response_time)
 
469
  logger.info(f"Generated response in {response_time:.2f}s")
470
 
471
+ # Store the interaction
472
  interaction = {
473
  "timestamp": datetime.now().isoformat(),
474
  "user_input": user_input,
 
482
 
483
  except Exception as e:
484
  logger.error(f"Error generating response: {str(e)}")
485
+ # fallback to default
486
  return default_response.get(lang, default_response["en"])
487
 
488
+
489
  def evaluate_factual_accuracy(self, response, reference):
490
  """Simple evaluation of factual accuracy by keyword matching"""
491
  # This is a simplified approach - in production, use more sophisticated methods