abdull4h commited on
Commit
72544b8
·
verified ·
1 Parent(s): 37ea574

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +122 -804
app.py CHANGED
@@ -1,820 +1,138 @@
1
  import os
2
- import re
3
- import json
4
- import torch
5
- import numpy as np
6
- import pandas as pd
7
- from tqdm import tqdm
8
- from pathlib import Path
9
- import spaces
10
-
11
- # PDF processing
12
- import PyPDF2
13
-
14
- # LLM and embeddings
15
- from transformers import AutoTokenizer, AutoModelForCausalLM
16
- from sentence_transformers import SentenceTransformer
17
-
18
- # RAG components
19
- from langchain.text_splitter import RecursiveCharacterTextSplitter
20
- from langchain_community.vectorstores import FAISS
21
- from langchain.schema import Document
22
- from langchain.embeddings import HuggingFaceEmbeddings
23
-
24
- # Arabic text processing
25
- import arabic_reshaper
26
- from bidi.algorithm import get_display
27
-
28
- # Evaluation
29
- from rouge_score import rouge_scorer
30
- import sacrebleu
31
- from sklearn.metrics import accuracy_score, precision_recall_fscore_support
32
- import matplotlib.pyplot as plt
33
- import seaborn as sns
34
- from collections import defaultdict
35
-
36
- # Gradio for the interface
37
  import gradio as gr
 
38
 
39
- # Helper functions
40
- def safe_tokenize(text):
41
- """Pure regex tokenizer with no NLTK dependency"""
42
- if not text:
43
- return []
44
- # Replace punctuation with spaces around them
45
- text = re.sub(r'([.,!?;:()\[\]{}"\'/\\])', r' \1 ', text)
46
- # Split on whitespace and filter empty strings
47
- return [token for token in re.split(r'\s+', text.lower()) if token]
48
-
49
- def detect_language(text):
50
- """Detect if text is primarily Arabic or English"""
51
- # Simple heuristic: count Arabic characters
52
- arabic_chars = re.findall(r'[\u0600-\u06FF]', text)
53
- is_arabic = len(arabic_chars) > len(text) * 0.5
54
- return "arabic" if is_arabic else "english"
55
-
56
- # Evaluation metrics
57
- def calculate_bleu(prediction, reference):
58
- """Calculate BLEU score without any NLTK dependency"""
59
- # Tokenize texts using our own tokenizer
60
- pred_tokens = safe_tokenize(prediction.lower())
61
- ref_tokens = [safe_tokenize(reference.lower())]
62
-
63
- # If either is empty, return 0
64
- if not pred_tokens or not ref_tokens[0]:
65
- return {"bleu_1": 0, "bleu_2": 0, "bleu_4": 0}
66
-
67
- # Get n-grams function
68
- def get_ngrams(tokens, n):
69
- return [tuple(tokens[i:i+n]) for i in range(len(tokens) - n + 1)]
70
-
71
- # Calculate precision for each n-gram level
72
- precisions = []
73
- for n in range(1, 5): # 1-gram to 4-gram
74
- if len(pred_tokens) < n:
75
- precisions.append(0)
76
- continue
77
-
78
- pred_ngrams = get_ngrams(pred_tokens, n)
79
- ref_ngrams = get_ngrams(ref_tokens[0], n)
80
-
81
- # Count matches
82
- matches = sum(1 for ng in pred_ngrams if ng in ref_ngrams)
83
-
84
- # Calculate precision
85
- if pred_ngrams:
86
- precisions.append(matches / len(pred_ngrams))
87
- else:
88
- precisions.append(0)
89
-
90
- # Return BLEU scores
91
- return {
92
- "bleu_1": precisions[0],
93
- "bleu_2": (precisions[0] * precisions[1]) ** 0.5 if len(precisions) > 1 else 0,
94
- "bleu_4": (precisions[0] * precisions[1] * precisions[2] * precisions[3]) ** 0.25 if len(precisions) > 3 else 0
95
- }
96
-
97
- def calculate_meteor(prediction, reference):
98
- """Simple word overlap metric as METEOR alternative"""
99
- # Tokenize with our custom tokenizer
100
- pred_tokens = set(safe_tokenize(prediction.lower()))
101
- ref_tokens = set(safe_tokenize(reference.lower()))
102
-
103
- # Calculate Jaccard similarity as METEOR alternative
104
- if not pred_tokens or not ref_tokens:
105
- return 0
106
-
107
- intersection = len(pred_tokens.intersection(ref_tokens))
108
- union = len(pred_tokens.union(ref_tokens))
109
-
110
- return intersection / union if union > 0 else 0
111
-
112
- def calculate_f1_precision_recall(prediction, reference):
113
- """Calculate word-level F1, precision, and recall with custom tokenizer"""
114
- # Tokenize with our custom tokenizer
115
- pred_tokens = set(safe_tokenize(prediction.lower()))
116
- ref_tokens = set(safe_tokenize(reference.lower()))
117
-
118
- # Calculate overlap
119
- common = pred_tokens.intersection(ref_tokens)
120
-
121
- # Calculate precision, recall, F1
122
- precision = len(common) / len(pred_tokens) if pred_tokens else 0
123
- recall = len(common) / len(ref_tokens) if ref_tokens else 0
124
- f1 = 2 * precision * recall / (precision + recall) if (precision + recall) else 0
125
-
126
- return {'precision': precision, 'recall': recall, 'f1': f1}
127
-
128
- def evaluate_retrieval_quality(contexts, query, language):
129
- """Evaluate the quality of retrieved contexts"""
130
- # This is a placeholder function
131
- return {
132
- 'language_match_ratio': 1.0,
133
- 'source_diversity': len(set([ctx.get('source', '') for ctx in contexts])) / max(1, len(contexts)),
134
- 'mrr': 1.0
135
- }
136
-
137
- # PDF Processing and Vector Store
138
- def simple_process_pdfs(pdf_paths):
139
- """Process PDF documents and return document objects"""
140
- documents = []
141
-
142
- print(f"Processing PDFs: {pdf_paths}")
143
-
144
- for pdf_path in pdf_paths:
145
- try:
146
- if not os.path.exists(pdf_path):
147
- print(f"Warning: {pdf_path} does not exist")
148
- continue
149
 
150
- print(f"Processing {pdf_path}...")
151
- text = ""
152
- with open(pdf_path, 'rb') as file:
153
- reader = PyPDF2.PdfReader(file)
154
- for page in reader.pages:
155
- page_text = page.extract_text()
156
- if page_text: # If we got text from this page
157
- text += page_text + "\n\n"
158
-
159
- if text.strip(): # If we got some text
160
- doc = Document(
161
- page_content=text,
162
- metadata={"source": pdf_path, "filename": os.path.basename(pdf_path)}
163
- )
164
- documents.append(doc)
165
- print(f"Successfully processed: {pdf_path}")
166
- else:
167
- print(f"Warning: No text extracted from {pdf_path}")
168
- except Exception as e:
169
- print(f"Error processing {pdf_path}: {e}")
170
- import traceback
171
- traceback.print_exc()
172
-
173
- print(f"Processed {len(documents)} PDF documents")
174
- return documents
175
-
176
- def create_vector_store(documents):
177
- """Split documents into chunks and create a FAISS vector store"""
178
- # Text splitter for breaking documents into chunks
179
- text_splitter = RecursiveCharacterTextSplitter(
180
- chunk_size=500,
181
- chunk_overlap=50,
182
- separators=["\n\n", "\n", ".", "!", "?", ",", " ", ""]
183
- )
184
-
185
- # Split documents into chunks
186
- chunks = []
187
- for doc in documents:
188
- doc_chunks = text_splitter.split_text(doc.page_content)
189
- # Preserve metadata for each chunk
190
- chunks.extend([
191
- Document(page_content=chunk, metadata=doc.metadata)
192
- for chunk in doc_chunks
193
- ])
194
-
195
- print(f"Created {len(chunks)} chunks from {len(documents)} documents")
196
-
197
- # Create a proper embedding function for LangChain
198
- embedding_function = HuggingFaceEmbeddings(
199
- model_name="sentence-transformers/paraphrase-multilingual-mpnet-base-v2"
200
- )
201
-
202
- # Create FAISS index
203
- vector_store = FAISS.from_documents(
204
- chunks,
205
- embedding_function
206
- )
207
-
208
- return vector_store
209
-
210
- # Model Loading and RAG System - Improved to handle SentencePiece issues
211
- @spaces.GPU
212
- def load_model_and_tokenizer():
213
- """Load the ALLaM-7B model and tokenizer with error handling"""
214
- model_name = "ALLaM-AI/ALLaM-7B-Instruct-preview"
215
- print(f"Loading model: {model_name}")
216
-
217
- try:
218
- # Check if sentencepiece is installed
219
- try:
220
- import sentencepiece
221
- print("SentencePiece is installed")
222
- except ImportError:
223
- print("Warning: SentencePiece is not installed. Attempting to proceed with AutoTokenizer only.")
224
-
225
- # First attempt with AutoTokenizer
226
- tokenizer = AutoTokenizer.from_pretrained(
227
- model_name,
228
- trust_remote_code=True,
229
- use_fast=False
230
- )
231
-
232
- # Load model with appropriate settings for ALLaM
233
- model = AutoModelForCausalLM.from_pretrained(
234
- model_name,
235
- torch_dtype=torch.bfloat16,
236
- trust_remote_code=True,
237
- device_map="auto",
238
- )
239
-
240
- print("Model loaded successfully with AutoTokenizer!")
241
- return model, tokenizer
242
-
243
- except Exception as e:
244
- print(f"First loading attempt failed: {e}")
245
-
246
- # If SentencePiece error, provide helpful message
247
- if "SentencePiece" in str(e):
248
- raise ImportError(
249
- "The model requires SentencePiece library which is missing. "
250
- "Add 'sentencepiece>=0.1.95' to your requirements.txt file."
251
- )
252
-
253
- # Other general error
254
- raise Exception(f"Failed to load model: {e}")
255
-
256
- def retrieve_context(query, vector_store, top_k=5):
257
- """Retrieve most relevant document chunks for a given query"""
258
- # Search the vector store using similarity search
259
- results = vector_store.similarity_search_with_score(query, k=top_k)
260
-
261
- # Format the retrieved contexts
262
- contexts = []
263
- for doc, score in results:
264
- contexts.append({
265
- "content": doc.page_content,
266
- "source": doc.metadata.get("source", "Unknown"),
267
- "relevance_score": score
268
- })
269
-
270
- return contexts
271
-
272
- @spaces.GPU
273
- def generate_response(query, contexts, model, tokenizer, language="auto"):
274
- """Generate a response using retrieved contexts with ALLaM-specific formatting"""
275
- # Auto-detect language if not specified
276
- if language == "auto":
277
- language = detect_language(query)
278
-
279
- # Format the prompt based on language
280
- if language == "arabic":
281
- instruction = (
282
- "أنت مساعد افتراضي يهتم برؤية السعودية 2030. استخدم المعلومات التالية للإجابة على السؤال. "
283
- "إذا لم تعرف الإجابة، فقل بأمانة إنك لا تعرف."
284
- )
285
- else: # english
286
- instruction = (
287
- "You are a virtual assistant for Saudi Vision 2030. Use the following information to answer the question. "
288
- "If you don't know the answer, honestly say you don't know."
289
- )
290
-
291
- # Combine retrieved contexts
292
- context_text = "\n\n".join([f"Document: {ctx['content']}" for ctx in contexts])
293
-
294
- # Format the prompt for ALLaM instruction format
295
- prompt = f"""<s>[INST] {instruction}
296
-
297
- Context:
298
- {context_text}
299
-
300
- Question: {query} [/INST]</s>"""
301
-
302
- try:
303
- # Generate response with appropriate parameters for ALLaM
304
- inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
305
-
306
- # Generate with appropriate parameters
307
- outputs = model.generate(
308
- inputs.input_ids,
309
- attention_mask=inputs.attention_mask,
310
- max_new_tokens=512,
311
- temperature=0.7,
312
- top_p=0.9,
313
- do_sample=True,
314
- repetition_penalty=1.1
315
- )
316
-
317
- # Decode the response
318
- full_output = tokenizer.decode(outputs[0], skip_special_tokens=True)
319
-
320
- # Extract just the answer part (after the instruction)
321
- response = full_output.split("[/INST]")[-1].strip()
322
-
323
- # If response is empty for some reason, return the full output
324
- if not response:
325
- response = full_output
326
-
327
- return response
328
-
329
- except Exception as e:
330
- print(f"Error during generation: {e}")
331
- # Fallback response
332
- return "I apologize, but I encountered an error while generating a response."
333
-
334
- # Assistant Class
335
- class Vision2030Assistant:
336
- def __init__(self, model, tokenizer, vector_store):
337
- self.model = model
338
- self.tokenizer = tokenizer
339
- self.vector_store = vector_store
340
- self.conversation_history = []
341
-
342
- def answer(self, user_query):
343
- """Process a user query and return a response with sources"""
344
- # Detect language
345
- language = detect_language(user_query)
346
-
347
- # Add user query to conversation history
348
- self.conversation_history.append({"role": "user", "content": user_query})
349
-
350
- # Get the full conversation context
351
- conversation_context = "\n".join([
352
- f"{'User' if msg['role'] == 'user' else 'Assistant'}: {msg['content']}"
353
- for msg in self.conversation_history[-6:] # Keep last 3 turns (6 messages)
354
- ])
355
-
356
- # Enhance query with conversation context for better retrieval
357
- enhanced_query = f"{conversation_context}\n{user_query}"
358
-
359
- # Retrieve relevant contexts
360
- contexts = retrieve_context(enhanced_query, self.vector_store, top_k=5)
361
-
362
- # Generate response
363
- response = generate_response(user_query, contexts, self.model, self.tokenizer, language)
364
-
365
- # Add response to conversation history
366
- self.conversation_history.append({"role": "assistant", "content": response})
367
-
368
- # Also return sources for transparency
369
- sources = [ctx.get("source", "Unknown") for ctx in contexts]
370
- unique_sources = list(set(sources))
371
-
372
- return response, unique_sources, contexts
373
-
374
- def reset_conversation(self):
375
- """Reset the conversation history"""
376
- self.conversation_history = []
377
- return "Conversation has been reset."
378
-
379
- # Comprehensive evaluation dataset
380
- comprehensive_evaluation_data = [
381
- # === Overview ===
382
- {
383
- "query": "ما هي رؤية السعودية 2030؟",
384
- "reference": "رؤية السعودية 2030 هي خطة استراتيجية تهدف إلى تنويع الاقتصاد السعودي وتقليل الاعتماد على النفط مع تطوير قطاعات مختلفة مثل الصحة والتعليم والسياحة.",
385
- "category": "overview",
386
- "language": "arabic"
387
- },
388
- {
389
- "query": "What is Saudi Vision 2030?",
390
- "reference": "Saudi Vision 2030 is a strategic framework aiming to diversify Saudi Arabia's economy and reduce dependence on oil, while developing sectors like health, education, and tourism.",
391
- "category": "overview",
392
- "language": "english"
393
- },
394
-
395
- # === Economic Goals ===
396
- {
397
- "query": "ما هي الأهداف الاقتصادية لرؤية 2030؟",
398
- "reference": "تشمل الأهداف الاقتصادية زيادة مساهمة القطاع الخاص إلى 65%، وزيادة الصادرات غير النفطية إلى 50% من الناتج المحلي غير النفطي، وخفض البطالة إلى 7%.",
399
- "category": "economic",
400
- "language": "arabic"
401
- },
402
- {
403
- "query": "What are the economic goals of Vision 2030?",
404
- "reference": "The economic goals of Vision 2030 include increasing private sector contribution from 40% to 65% of GDP, raising non-oil exports from 16% to 50%, reducing unemployment from 11.6% to 7%.",
405
- "category": "economic",
406
- "language": "english"
407
- },
408
-
409
- # === Social Goals ===
410
- {
411
- "query": "كيف تعزز رؤية 2030 الإرث الثقافي السعودي؟",
412
- "reference": "تتضمن رؤية 2030 الحفاظ على الهوية الوطنية، تسجيل مواقع أثرية في اليونسكو، وتعزيز الفعاليات الثقافية.",
413
- "category": "social",
414
- "language": "arabic"
415
- },
416
- {
417
- "query": "How does Vision 2030 aim to improve quality of life?",
418
- "reference": "Vision 2030 plans to enhance quality of life by expanding sports facilities, promoting cultural activities, and boosting tourism and entertainment sectors.",
419
- "category": "social",
420
- "language": "english"
421
- }
422
- ]
423
-
424
- # Gradio Interface
425
- def initialize_system():
426
- """Initialize the Vision 2030 Assistant system"""
427
- # Define paths for PDF files in the root directory
428
- pdf_files = ["saudi_vision203.pdf", "saudi_vision2030_ar.pdf"]
429
-
430
- # Print available files for debugging
431
- print("Files in current directory:", os.listdir("."))
432
-
433
- # Process PDFs and create vector store
434
- vector_store_dir = "vector_stores"
435
- os.makedirs(vector_store_dir, exist_ok=True)
436
-
437
- if os.path.exists(os.path.join(vector_store_dir, "index.faiss")):
438
- print("Loading existing vector store...")
439
- embedding_function = HuggingFaceEmbeddings(
440
- model_name="sentence-transformers/paraphrase-multilingual-mpnet-base-v2"
441
- )
442
- vector_store = FAISS.load_local(vector_store_dir, embedding_function)
443
- else:
444
- print("Creating new vector store...")
445
- documents = simple_process_pdfs(pdf_files)
446
- if not documents:
447
- raise ValueError("No documents were processed successfully. Cannot continue.")
448
- vector_store = create_vector_store(documents)
449
- vector_store.save_local(vector_store_dir)
450
-
451
- # Load model and tokenizer
452
- model, tokenizer = load_model_and_tokenizer()
453
-
454
- # Initialize assistant
455
- assistant = Vision2030Assistant(model, tokenizer, vector_store)
456
-
457
- return assistant
458
-
459
- def evaluate_response(query, response, reference):
460
- """Evaluate a single response against a reference"""
461
- # Calculate metrics
462
- rouge = rouge_scorer.RougeScorer(['rouge1', 'rouge2', 'rougeL'], use_stemmer=True)
463
- rouge_scores = rouge.score(response, reference)
464
-
465
- bleu_scores = calculate_bleu(response, reference)
466
- meteor = calculate_meteor(response, reference)
467
- word_metrics = calculate_f1_precision_recall(response, reference)
468
-
469
- # Format results
470
- evaluation_results = {
471
- "ROUGE-1": f"{rouge_scores['rouge1'].fmeasure:.4f}",
472
- "ROUGE-2": f"{rouge_scores['rouge2'].fmeasure:.4f}",
473
- "ROUGE-L": f"{rouge_scores['rougeL'].fmeasure:.4f}",
474
- "BLEU-1": f"{bleu_scores['bleu_1']:.4f}",
475
- "BLEU-4": f"{bleu_scores['bleu_4']:.4f}",
476
- "METEOR": f"{meteor:.4f}",
477
- "Word Precision": f"{word_metrics['precision']:.4f}",
478
- "Word Recall": f"{word_metrics['recall']:.4f}",
479
- "Word F1": f"{word_metrics['f1']:.4f}"
480
- }
481
-
482
- return evaluation_results
483
-
484
- @spaces.GPU
485
- def run_conversation(assistant, query):
486
- """Run a query through the assistant and return the response"""
487
- response, sources, contexts = assistant.answer(query)
488
- return response, sources, contexts
489
-
490
- @spaces.GPU
491
- def run_evaluation_on_sample(assistant, sample_index=0):
492
- """Run evaluation on a selected sample from the evaluation dataset"""
493
- if sample_index < 0 or sample_index >= len(comprehensive_evaluation_data):
494
- return "Invalid sample index", "", "", {}
495
-
496
- # Get the sample
497
- sample = comprehensive_evaluation_data[sample_index]
498
- query = sample["query"]
499
- reference = sample["reference"]
500
- category = sample["category"]
501
- language = sample["language"]
502
-
503
- # Reset conversation and get response
504
- assistant.reset_conversation()
505
- response, sources, contexts = assistant.answer(query)
506
-
507
- # Evaluate response
508
- evaluation_results = evaluate_response(query, response, reference)
509
-
510
- return query, response, reference, evaluation_results, sources, category, language
511
-
512
- def qualitative_evaluation_interface(assistant=None):
513
- """Create a Gradio interface for qualitative evaluation"""
514
-
515
- # If assistant is None, create a simplified interface
516
- if assistant is None:
517
- with gr.Blocks(title="Vision 2030 Assistant - Initialization Error") as interface:
518
- gr.Markdown("# Vision 2030 Assistant - Initialization Error")
519
- gr.Markdown("There was an error initializing the assistant. Please check the logs for details.")
520
- gr.Textbox(label="Status", value="System initialization failed")
521
- return interface
522
-
523
- sample_options = [f"{i+1}. {item['query'][:50]}..." for i, item in enumerate(comprehensive_evaluation_data)]
524
-
525
- with gr.Blocks(title="Vision 2030 Assistant - Qualitative Evaluation") as interface:
526
- gr.Markdown("# Vision 2030 Assistant - Qualitative Evaluation")
527
- gr.Markdown("This interface allows you to evaluate the Vision 2030 Assistant on predefined samples or your own queries.")
528
-
529
- with gr.Tab("Sample Evaluation"):
530
- gr.Markdown("### Evaluate the assistant on predefined samples")
531
-
532
- sample_dropdown = gr.Dropdown(
533
- choices=sample_options,
534
- label="Select a sample query",
535
- value=sample_options[0] if sample_options else None
536
- )
537
-
538
- eval_button = gr.Button("Evaluate Sample")
539
-
540
- with gr.Row():
541
- with gr.Column():
542
- sample_query = gr.Textbox(label="Query")
543
- sample_category = gr.Textbox(label="Category")
544
- sample_language = gr.Textbox(label="Language")
545
-
546
- with gr.Column():
547
- sample_response = gr.Textbox(label="Assistant Response")
548
- sample_reference = gr.Textbox(label="Reference Answer")
549
- sample_sources = gr.Textbox(label="Sources Used")
550
-
551
- with gr.Row():
552
- metrics_display = gr.JSON(label="Evaluation Metrics")
553
-
554
- with gr.Tab("Custom Evaluation"):
555
- gr.Markdown("### Evaluate the assistant on your own query")
556
-
557
- custom_query = gr.Textbox(
558
- lines=3,
559
- placeholder="Enter your question about Saudi Vision 2030...",
560
- label="Your Query"
561
- )
562
-
563
- custom_reference = gr.Textbox(
564
- lines=3,
565
- placeholder="Enter a reference answer (optional)...",
566
- label="Reference Answer (Optional)"
567
- )
568
-
569
- custom_eval_button = gr.Button("Get Response and Evaluate")
570
-
571
- custom_response = gr.Textbox(label="Assistant Response")
572
- custom_sources = gr.Textbox(label="Sources Used")
573
-
574
- custom_metrics = gr.JSON(
575
- label="Evaluation Metrics (if reference provided)",
576
- visible=True
577
- )
578
-
579
- with gr.Tab("Conversation Mode"):
580
- gr.Markdown("### Have a conversation with the Vision 2030 Assistant")
581
-
582
- chatbot = gr.Chatbot(label="Conversation")
583
-
584
- conv_input = gr.Textbox(
585
- placeholder="Ask about Saudi Vision 2030...",
586
- label="Your message"
587
- )
588
-
589
- with gr.Row():
590
- conv_button = gr.Button("Send")
591
- reset_button = gr.Button("Reset Conversation")
592
-
593
- conv_sources = gr.Textbox(label="Sources Used")
594
-
595
- # Sample evaluation event handlers
596
- def handle_sample_selection(selection):
597
- if not selection:
598
- return "", "", "", "", "", "", ""
599
-
600
- # Extract index from the selection string
601
- try:
602
- index = int(selection.split(".")[0]) - 1
603
- query, response, reference, metrics, sources, category, language = run_evaluation_on_sample(assistant, index)
604
- sources_str = ", ".join(sources)
605
- return query, response, reference, metrics, sources_str, category, language
606
- except Exception as e:
607
- print(f"Error in handle_sample_selection: {e}")
608
- import traceback
609
- traceback.print_exc()
610
- return f"Error processing selection: {e}", "", "", {}, "", "", ""
611
-
612
- eval_button.click(
613
- handle_sample_selection,
614
- inputs=[sample_dropdown],
615
- outputs=[sample_query, sample_response, sample_reference, metrics_display,
616
- sample_sources, sample_category, sample_language]
617
- )
618
-
619
- sample_dropdown.change(
620
- handle_sample_selection,
621
- inputs=[sample_dropdown],
622
- outputs=[sample_query, sample_response, sample_reference, metrics_display,
623
- sample_sources, sample_category, sample_language]
624
- )
625
-
626
- # Custom evaluation event handlers
627
- @spaces.GPU
628
- def handle_custom_evaluation(query, reference):
629
- if not query:
630
- return "Please enter a query", "", {}
631
-
632
- # Reset conversation to ensure clean state
633
- assistant.reset_conversation()
634
-
635
- # Get response
636
- response, sources, _ = assistant.answer(query)
637
- sources_str = ", ".join(sources)
638
-
639
- # Evaluate if reference is provided
640
- metrics = {}
641
- if reference:
642
- metrics = evaluate_response(query, response, reference)
643
-
644
- return response, sources_str, metrics
645
-
646
- custom_eval_button.click(
647
- handle_custom_evaluation,
648
- inputs=[custom_query, custom_reference],
649
- outputs=[custom_response, custom_sources, custom_metrics]
650
- )
651
-
652
- # Conversation mode event handlers
653
- @spaces.GPU
654
- def handle_conversation(message, history):
655
- if not message:
656
- return history, "", ""
657
-
658
- # Get response
659
- response, sources, _ = assistant.answer(message)
660
- sources_str = ", ".join(sources)
661
-
662
- # Update history
663
- history = history + [[message, response]]
664
 
665
- return history, "", sources_str
666
-
667
- def reset_conv():
668
- result = assistant.reset_conversation()
669
- return [], result, ""
670
-
671
- conv_button.click(
672
- handle_conversation,
673
- inputs=[conv_input, chatbot],
674
- outputs=[chatbot, conv_input, conv_sources]
675
- )
676
 
677
- reset_button.click(
678
- reset_conv,
679
- inputs=[],
680
- outputs=[chatbot, conv_input, conv_sources]
681
- )
682
-
683
- return interface
684
-
685
- # Main function to run in Hugging Face Space
686
- def main():
687
- # Start with a debugging report
688
- print("=" * 50)
689
- print("SYSTEM INITIALIZATION")
690
- print("=" * 50)
691
- print("Current directory:", os.getcwd())
692
- print("Files in directory:", os.listdir("."))
693
- print("=" * 50)
694
-
695
- # Check for SentencePiece
696
- try:
697
- import sentencepiece
698
- print("SentencePiece is installed: ✓")
699
- except ImportError:
700
- print("WARNING: SentencePiece is NOT installed! This will cause errors with the tokenizer.")
701
-
702
- # Initialize the system with simplified error handling
703
- try:
704
- # First create a very simple Gradio interface to show we're starting
705
- with gr.Blocks(title="Vision 2030 Assistant - Starting") as loading_interface:
706
- gr.Markdown("# Vision 2030 Assistant")
707
- gr.Markdown("System is initializing. This may take a few minutes...")
708
- status = gr.Textbox(value="Loading resources...", label="Status")
709
-
710
- with gr.Blocks(title="Vision 2030 Assistant - Model Loading") as model_interface:
711
- gr.Markdown("# Vision 2030 Assistant - Loading Model")
712
- gr.Markdown("The system is now loading the ALLaM-7B model. This may take several minutes.")
713
- status = gr.Textbox(value="Loading model...", label="Status")
714
-
715
- # Now try the actual initialization
716
- try:
717
- print("Starting system initialization...")
718
- assistant = initialize_system()
719
-
720
- print("Creating interface...")
721
- interface = qualitative_evaluation_interface(assistant)
722
 
723
- print("Launching interface...")
724
- return interface
725
- except ImportError as e:
726
- print(f"Import error during initialization: {e}")
727
-
728
- # Create a simple error interface specifically for SentencePiece errors
729
- if "SentencePiece" in str(e):
730
- with gr.Blocks(title="Vision 2030 Assistant - SentencePiece Error") as sp_error:
731
- gr.Markdown("# Vision 2030 Assistant - SentencePiece Error")
732
- gr.Markdown("The model requires the SentencePiece library which is missing.")
733
-
734
- gr.Markdown("""
735
- ## How to Fix:
736
-
737
- Add these lines to your `requirements.txt` file:
738
- ```
739
- sentencepiece>=0.1.95
740
- protobuf>=3.20.0
741
- ```
742
 
743
- Then rebuild your Hugging Face Space.
744
- """)
 
 
 
 
745
 
746
- return sp_error
747
- else:
748
- # For other import errors
749
- with gr.Blocks(title="Vision 2030 Assistant - Import Error") as import_error:
750
- gr.Markdown("# Vision 2030 Assistant - Import Error")
751
- gr.Markdown(f"An import error occurred: {str(e)}")
752
 
753
- # Display possible solutions
754
- gr.Markdown("""
755
- ## Possible solutions:
 
 
 
 
 
756
 
757
- Check your `requirements.txt` file for missing dependencies.
758
- """)
 
 
759
 
760
- return import_error
761
- except Exception as e:
762
- print(f"Error during initialization: {e}")
763
- import traceback
764
- traceback.print_exc()
765
-
766
- # Create a general error interface
767
- with gr.Blocks(title="Vision 2030 Assistant - Error") as debug_interface:
768
- gr.Markdown("# Vision 2030 Assistant - Initialization Error")
769
- gr.Markdown("There was an error initializing the assistant.")
770
-
771
- # Display error details
772
- gr.Textbox(
773
- value=f"Error: {str(e)}",
774
- label="Error Details",
775
- lines=5
776
- )
777
-
778
- # Show file system status
779
- files_list = "\n".join(os.listdir("."))
780
- gr.Textbox(
781
- value=files_list,
782
- label="Files in Directory",
783
- lines=10
784
- )
785
 
786
- # Add a button to check PDFs
787
- def check_pdfs():
788
- result = []
789
- for pdf_file in ["saudi_vision203.pdf", "saudi_vision2030_ar.pdf"]:
790
- if os.path.exists(pdf_file):
791
- size = os.path.getsize(pdf_file) / (1024 * 1024) # Size in MB
792
- result.append(f"{pdf_file}: Found ({size:.2f} MB)")
793
- else:
794
- result.append(f"{pdf_file}: Not found")
795
- return "\n".join(result)
796
-
797
- check_btn = gr.Button("Check PDF Files")
798
- pdf_status = gr.Textbox(label="PDF Status", lines=3)
799
- check_btn.click(check_pdfs, inputs=[], outputs=[pdf_status])
800
 
801
- return debug_interface
802
- except Exception as e:
803
- print(f"Critical error: {e}")
804
- with gr.Blocks(title="Vision 2030 Assistant - Critical Error") as critical_error:
805
- gr.Markdown("# Vision 2030 Assistant - Critical Error")
806
- gr.Markdown(f"A critical error occurred: {str(e)}")
807
-
808
- # Display stacktrace
809
- import traceback
810
- trace = traceback.format_exc()
811
- gr.Textbox(
812
- value=trace,
813
- label="Error Traceback",
814
- lines=15
815
- )
816
- return critical_error
817
 
818
  if __name__ == "__main__":
819
- demo = main()
820
- demo.launch()
 
1
  import os
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import gradio as gr
3
+ import spaces
4
 
5
+ # Create a simple version for quick testing
6
+ def main():
7
+ with gr.Blocks(title="Vision 2030 Assistant - Debugging") as interface:
8
+ gr.Markdown("# Vision 2030 Assistant - System Check")
9
+ gr.Markdown("This interface tests your system configuration to ensure all components are working.")
10
+
11
+ # Check files tab
12
+ with gr.Tab("File Check"):
13
+ gr.Markdown("### Check PDF Files and Directory Structure")
14
+ check_btn = gr.Button("Check Files")
15
+ files_output = gr.Textbox(label="Files Status", lines=10)
16
+
17
+ def check_files():
18
+ results = []
19
+ # List files
20
+ results.append("Files in directory:")
21
+ files = os.listdir(".")
22
+ results.append("\n".join(files))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
+ # Check PDFs
25
+ results.append("\nPDF Status:")
26
+ for pdf_file in ["saudi_vision203.pdf", "saudi_vision2030_ar.pdf"]:
27
+ if os.path.exists(pdf_file):
28
+ size = os.path.getsize(pdf_file) / (1024 * 1024) # Size in MB
29
+ results.append(f"{pdf_file}: Found ({size:.2f} MB)")
30
+ else:
31
+ results.append(f"{pdf_file}: Not found")
32
+
33
+ return "\n".join(results)
34
+
35
+ check_btn.click(check_files, inputs=[], outputs=[files_output])
36
+
37
+ # Check dependencies tab
38
+ with gr.Tab("Dependency Check"):
39
+ gr.Markdown("### Check Required Dependencies")
40
+ dep_btn = gr.Button("Check Dependencies")
41
+ dep_output = gr.Textbox(label="Dependency Status", lines=20)
42
+
43
+ @spaces.GPU
44
+ def check_dependencies():
45
+ results = []
46
+
47
+ # Basic dependencies
48
+ for lib_name in [
49
+ "torch",
50
+ "transformers",
51
+ "sentencepiece",
52
+ "accelerate",
53
+ "langchain",
54
+ "langchain_community",
55
+ "PyPDF2"
56
+ ]:
57
+ try:
58
+ module = __import__(lib_name)
59
+ if hasattr(module, "__version__"):
60
+ results.append(f"✓ {lib_name}: {module.__version__}")
61
+ else:
62
+ results.append(f"✓ {lib_name}: Installed (no version info)")
63
+ except ImportError:
64
+ results.append(f"✗ {lib_name}: Not installed")
65
+ except Exception as e:
66
+ results.append(f"? {lib_name}: Error - {str(e)}")
67
+
68
+ # Test GPU access
69
+ try:
70
+ import torch
71
+ results.append(f"\nGPU status:")
72
+ results.append(f"CUDA available: {torch.cuda.is_available()}")
73
+ if torch.cuda.is_available():
74
+ results.append(f"CUDA device count: {torch.cuda.device_count()}")
75
+ results.append(f"CUDA current device: {torch.cuda.current_device()}")
76
+ results.append(f"CUDA device name: {torch.cuda.get_device_name(0)}")
77
+ except Exception as e:
78
+ results.append(f"GPU status check error: {str(e)}")
79
+
80
+ return "\n".join(results)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
+ dep_btn.click(check_dependencies, inputs=[], outputs=[dep_output])
 
 
 
 
 
 
 
 
 
 
83
 
84
+ # Test tokenizer tab
85
+ with gr.Tab("Model Check"):
86
+ gr.Markdown("### Test Model Loading")
87
+ model_btn = gr.Button("Test Tokenizer Only")
88
+ model_output = gr.Textbox(label="Model Status", lines=15)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
+ @spaces.GPU
91
+ def test_tokenizer():
92
+ results = []
93
+
94
+ try:
95
+ results.append("Testing AutoTokenizer...")
96
+ from transformers import AutoTokenizer
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
+ # Check if accelerate is available
99
+ try:
100
+ import accelerate
101
+ results.append(f"Accelerate version: {accelerate.__version__}")
102
+ except ImportError:
103
+ results.append("Accelerate is not installed")
104
 
105
+ # Check if sentencepiece is available
106
+ try:
107
+ import sentencepiece
108
+ results.append("SentencePiece is installed")
109
+ except ImportError:
110
+ results.append("SentencePiece is not installed")
111
 
112
+ # Try loading just the tokenizer
113
+ model_name = "ALLaM-AI/ALLaM-7B-Instruct-preview"
114
+ tokenizer = AutoTokenizer.from_pretrained(
115
+ model_name,
116
+ trust_remote_code=True,
117
+ use_fast=False
118
+ )
119
+ results.append(f"✓ Successfully loaded tokenizer for {model_name}")
120
 
121
+ # Test tokenization
122
+ tokens = tokenizer("Hello, this is a test", return_tensors="pt")
123
+ results.append(f"✓ Tokenizer works properly")
124
+ results.append(f"Input IDs: {tokens.input_ids.shape}")
125
 
126
+ except Exception as e:
127
+ results.append(f"✗ Error: {str(e)}")
128
+ import traceback
129
+ results.append(traceback.format_exc())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
+ return "\n".join(results)
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
+ model_btn.click(test_tokenizer, inputs=[], outputs=[model_output])
134
+
135
+ interface.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
  if __name__ == "__main__":
138
+ main()