Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
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
|
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 |
-
|
388 |
-
|
389 |
-
lang = "en"
|
390 |
except:
|
391 |
-
lang = "en" #
|
392 |
|
393 |
logger.info(f"Detected language: {lang}")
|
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 |
reply = context if context else "لم أتمكن من العثور على معلومات كافية حول هذا السؤال."
|
425 |
-
|
426 |
-
|
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
|
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
|
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
|