mo-456 commited on
Commit
9717c6f
·
verified ·
1 Parent(s): a9c2d55

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -265
app.py CHANGED
@@ -3,255 +3,142 @@ from sentence_transformers import SentenceTransformer, util
3
  import torch
4
  import logging
5
  from typing import List
6
-
7
- # Set up logging
8
- logging.basicConfig(level=logging.INFO)
 
 
 
 
 
9
  logger = logging.getLogger(__name__)
10
 
11
- # Load model
12
- logger.info("Loading model...")
13
- try:
14
- model = SentenceTransformer(
15
- "CAMeL-Lab/bert-base-arabic-camelbert-ca",
16
- device="cpu",
17
- cache_folder="./model_cache"
18
- )
19
- except Exception as e:
20
- logger.error(f"Failed to load model: {e}")
21
- raise
22
 
23
- # Load knowledge file
24
- logger.info("Loading knowledge file...")
25
- try:
26
  with open("knowledge.txt", "r", encoding="utf-8") as f:
27
- knowledge_text = f.read()
28
- if not knowledge_text.strip():
29
- raise ValueError("knowledge.txt is empty")
30
- except Exception as e:
31
- logger.error(f"Error reading knowledge.txt: {e}")
32
- raise
33
-
34
- def split_text(text: str, chunk_size: int = 300) -> List[str]:
35
- """Split text into meaningful semantic chunks"""
36
- sections = []
37
- current_section = []
38
- current_length = 0
39
-
40
- for section in text.split("\n\n---\n\n"):
41
- section = section.strip()
42
- if not section:
43
- continue
44
-
45
- for para in section.split("\n\n"):
46
- para = para.strip()
47
- if not para:
48
- continue
49
 
50
- if current_length + len(para) > chunk_size and current_section:
51
- sections.append("\n\n".join(current_section))
52
- current_section = []
53
- current_length = 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
- current_section.append(para)
56
- current_length += len(para)
57
-
58
- if current_section:
59
- sections.append("\n\n".join(current_section))
60
-
61
- return sections
62
 
63
- logger.info("Generating embeddings...")
64
- try:
65
- chunks = split_text(knowledge_text)
66
- corpus_embeddings = model.encode(chunks, convert_to_tensor=True, batch_size=8)
67
- except Exception as e:
68
- logger.error(f"Error generating embeddings: {e}")
69
- raise
70
 
71
- def generate_comprehensive_answer(question: str, top_chunks: List[tuple]) -> str:
72
- """Generate a well-structured, comprehensive answer"""
73
- # Header with unit name
74
- answer = "## المساعد الآلي لوحدة الشفافية\n\n"
 
 
 
75
 
76
- # Add introduction based on question type
77
- if "؟" in question:
78
- answer += "بناءً على سؤالك، إليك الإجابة التفصيلية:\n\n"
 
 
 
 
 
 
 
 
 
79
  else:
80
- answer += "فيما يلي المعلومات المطلوبة:\n\n"
81
 
82
- # Add content from relevant chunks
 
83
  for chunk, score in top_chunks:
84
- if score > 0.4: # Only include good matches
85
- answer += f"{chunk}\n\n"
86
-
87
- # Add confidence indication
88
- best_score = top_chunks[0][1] if top_chunks else 0
89
- confidence = "عالية جدًا" if best_score > 0.8 else "عالية" if best_score > 0.6 else "متوسطة"
90
- answer += f"\n**مستوى الدقة:** {confidence} ({best_score:.2f})"
91
 
92
- # Add footer with suggestions
93
- answer += "\n\nلمزيد من المعلومات، يمكنك:\n"
94
- answer += "- طرح سؤال أكثر تحديدًا\n"
95
- answer += "- الرجوع إلى الوثائق الرسمية\n"
96
- answer += "- التواصل مع وحدة الشفافية مباشرة"
97
 
98
- return answer
99
 
100
- def answer_question(question: str) -> str:
101
  try:
102
  if not question.strip():
103
- return "## المساعد الآلي لوحدة الشفافية\n\nالرجاء إدخال سؤال واضح ومحدد."
104
-
105
- # Preprocess question
106
- question = question.strip().replace("؟", "").strip()
107
 
108
- # Get embeddings
 
109
  question_embedding = model.encode(question, convert_to_tensor=True)
110
- scores = util.cos_sim(question_embedding, corpus_embeddings)[0]
111
 
112
- # Get top relevant chunks
113
- top_k = min(5, len(chunks))
114
- top_results = torch.topk(scores, k=top_k)
115
 
116
- # Prepare chunks with scores
117
- relevant_chunks = [
118
- (chunks[idx], score.item())
119
- for score, idx in zip(top_results[0], top_results[1])
120
- if score > 0.3 # Minimum relevance threshold
121
- ]
 
 
 
122
 
123
- if relevant_chunks:
124
- return generate_comprehensive_answer(question, relevant_chunks)
125
- else:
126
- return "## المساعد الآلي لوحدة الشفافية\n\nعذرًا، لم أتمكن من العثور على إجابة دقيقة. يرجى:\n- صياغة السؤال بطريقة أخرى\n- استخدام مصطلحات مختلفة\n- تقديم مزيد من التفاصيل في سؤالك"
127
-
128
  except Exception as e:
129
- logger.error(f"Error answering question: {e}")
130
- return "## المساعد الآلي لوحدة الشفافية\n\nحدث خطأ غير متوقع. يرجى المحاولة مرة أخرى أو التواصل مع الدعم الفني."
131
 
132
- # Sleek Black and White UI
133
  css = """
134
- body {
135
- background-color: #000000 !important;
136
- color: #ffffff !important;
137
- }
138
-
139
  .arabic-ui {
140
  direction: rtl;
141
  text-align: right;
142
- font-family: 'Tahoma', 'Arial', sans-serif;
143
- background-color: #000000;
144
- color: #ffffff;
145
  }
146
-
147
  .header {
148
- background-color: #000000;
149
- color: #ffffff;
150
  padding: 20px;
151
  border-radius: 8px;
152
- margin-bottom: 20px;
153
- border-bottom: 2px solid #ffffff;
154
- }
155
-
156
- .answer-container {
157
- background-color: #121212;
158
- color: #ffffff;
159
- padding: 25px;
160
- border-radius: 10px;
161
- border-right: 3px solid #ffffff;
162
- margin-bottom: 20px;
163
- }
164
-
165
- .question-input {
166
- background-color: #121212;
167
- color: #ffffff;
168
- border: 2px solid #333333;
169
- border-radius: 8px;
170
- padding: 15px;
171
- font-size: 16px;
172
- min-height: 120px;
173
- }
174
-
175
- .question-input:focus {
176
- border-color: #ffffff;
177
- box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.2);
178
- }
179
-
180
- .submit-btn {
181
- background-color: #333333;
182
- color: #ffffff !important;
183
- border: 1px solid #ffffff;
184
- padding: 12px 30px;
185
- font-size: 16px;
186
- border-radius: 8px;
187
- transition: all 0.3s;
188
- }
189
-
190
- .submit-btn:hover {
191
- background-color: #555555;
192
- transform: translateY(-2px);
193
- }
194
-
195
- .clear-btn {
196
- background-color: #333333;
197
- color: #ffffff !important;
198
- border: 1px solid #ffffff;
199
- padding: 12px 30px;
200
- font-size: 16px;
201
- border-radius: 8px;
202
- transition: all 0.3s;
203
- }
204
-
205
- .clear-btn:hover {
206
- background-color: #555555;
207
- transform: translateY(-2px);
208
- }
209
-
210
- .examples-container {
211
- background-color: #121212;
212
- padding: 15px;
213
- border-radius: 8px;
214
- margin-bottom: 20px;
215
- border: 1px solid #333333;
216
- }
217
-
218
- .examples-label {
219
- color: #ffffff;
220
- font-weight: bold;
221
- margin-bottom: 10px;
222
- }
223
-
224
- .example-btn {
225
- background-color: #333333;
226
- color: #ffffff;
227
- border: 1px solid #555555;
228
- margin: 5px;
229
- border-radius: 6px;
230
- transition: all 0.2s;
231
- }
232
-
233
- .example-btn:hover {
234
- background-color: #555555;
235
- }
236
-
237
- .markdown-text {
238
- color: #ffffff;
239
- line-height: 1.8;
240
- font-size: 16px;
241
- }
242
-
243
- .markdown-text h1, .markdown-text h2, .markdown-text h3 {
244
- color: #ffffff;
245
- margin-top: 20px;
246
- margin-bottom: 15px;
247
- }
248
-
249
- .markdown-text strong {
250
- color: #dddddd;
251
- }
252
-
253
- label {
254
- color: #ffffff !important;
255
  }
256
  """
257
 
@@ -259,58 +146,24 @@ with gr.Blocks(css=css) as demo:
259
  with gr.Column(elem_classes="arabic-ui"):
260
  gr.Markdown("""
261
  <div class="header">
262
- <h1 style="text-align: center; margin-bottom: 10px;">المساعد الآلي لوحدة الشفافية</h1>
263
- <h3 style="text-align: center; font-weight: normal;">نظام الإجابة الآلي للاستفسارات المتعلقة بالشفافية والموازنة التشاركية</h3>
264
  </div>
265
  """)
266
 
267
- with gr.Row():
268
- question_input = gr.Textbox(
269
- label="نص السؤال",
270
- placeholder="مثال: ما هي آليات المشاركة المجتمعية في الموازنة التشاركية؟",
271
- lines=3,
272
- max_lines=5,
273
- elem_classes="question-input"
274
- )
275
 
276
- answer_output = gr.Markdown(
277
- label="الإجابة",
278
- elem_classes=["answer-container", "markdown-text"]
 
 
 
 
279
  )
280
 
281
- with gr.Column(elem_classes="examples-container"):
282
- gr.Markdown("أسئلة نموذجية", elem_classes="examples-label")
283
- examples = gr.Examples(
284
- examples=[
285
- ["ما هي الركائز الأساسية للنموذج المصري للموازنة التشاركية؟"],
286
- ["كيف تقيس وحدة الشفافية مستوى رضا المواطنين؟"],
287
- ["ما هي أحدث إحصائيات مؤشر شفافية الموازنة المفتوحة؟"]
288
- ],
289
- inputs=question_input,
290
- elem_id="example-buttons",
291
- examples_per_page=3
292
- )
293
-
294
- with gr.Row():
295
- submit_btn = gr.Button("الحصول على الإجابة",
296
- elem_classes="submit-btn")
297
- clear_btn = gr.Button("مسح النموذج",
298
- elem_classes="clear-btn")
299
-
300
- submit_btn.click(
301
- fn=answer_question,
302
- inputs=question_input,
303
- outputs=answer_output
304
- )
305
-
306
- clear_btn.click(
307
- lambda: ("", ""),
308
- inputs=None,
309
- outputs=[question_input, answer_output]
310
- )
311
 
312
- demo.launch(
313
- server_name="0.0.0.0",
314
- server_port=7860,
315
- show_error=True
316
- )
 
3
  import torch
4
  import logging
5
  from typing import List
6
+ import re
7
+ import numpy as np
8
+
9
+ # Configure advanced logging
10
+ logging.basicConfig(
11
+ level=logging.INFO,
12
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
13
+ )
14
  logger = logging.getLogger(__name__)
15
 
16
+ # Load model with enhanced settings
17
+ model = SentenceTransformer(
18
+ "CAMeL-Lab/bert-base-arabic-camelbert-ca",
19
+ device="cuda" if torch.cuda.is_available() else "cpu"
20
+ )
 
 
 
 
 
 
21
 
22
+ # Advanced knowledge loader with semantic organization
23
+ def load_knowledge():
 
24
  with open("knowledge.txt", "r", encoding="utf-8") as f:
25
+ sections = {}
26
+ current_section = ""
27
+
28
+ for line in f:
29
+ line = line.strip()
30
+ if line.startswith("## "):
31
+ current_section = line[3:]
32
+ sections[current_section] = []
33
+ elif line and current_section:
34
+ sections[current_section].append(line)
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ # Create semantic chunks
37
+ chunks = []
38
+ chunk_ids = []
39
+ for section, content in sections.items():
40
+ section_text = " ".join(content)
41
+ sentences = re.split(r'[\.\n]', section_text)
42
+
43
+ current_chunk = ""
44
+ for sent in sentences:
45
+ sent = sent.strip()
46
+ if not sent:
47
+ continue
48
+
49
+ if len(current_chunk) + len(sent) < 200:
50
+ current_chunk += sent + ". "
51
+ else:
52
+ chunks.append(f"{section}: {current_chunk.strip()}")
53
+ chunk_ids.append(section)
54
+ current_chunk = sent + ". "
55
+
56
+ if current_chunk:
57
+ chunks.append(f"{section}: {current_chunk.strip()}")
58
+ chunk_ids.append(section)
59
 
60
+ return chunks, chunk_ids
 
 
 
 
 
 
61
 
62
+ knowledge_chunks, chunk_categories = load_knowledge()
63
+ knowledge_embeddings = model.encode(knowledge_chunks, convert_to_tensor=True)
 
 
 
 
 
64
 
65
+ # Advanced Arabic response generator
66
+ def generate_arabic_response(question, top_chunks):
67
+ response = "المساعد الآلي لوحدة الشفافية\n\n"
68
+
69
+ # Analyze question type
70
+ question_type = "عام" # default
71
+ q_words = question.split()
72
 
73
+ if any(w in ["كيف", "طريقة", "خطوات"] for w in q_words):
74
+ question_type = "إجرائي"
75
+ elif any(w in ["ما هي", ا هو", "تعريف"] for w in q_words):
76
+ question_type = "تعريفي"
77
+ elif any(w in ["لماذا", "سبب", "أسباب"] for w in q_words):
78
+ question_type = "تفسيري"
79
+
80
+ # Generate context-aware response
81
+ if question_type == "تعريفي":
82
+ response += "بناءً على سؤالك عن المفاهيم الأساسية:\n\n"
83
+ elif question_type == "إجرائي":
84
+ response += "لتنفيذ ما تبحث عنه، إليك الخطوات العملية:\n\n"
85
  else:
86
+ response += "إليك الإجابة الشاملة على سؤالك:\n\n"
87
 
88
+ # Build comprehensive answer
89
+ used_sections = set()
90
  for chunk, score in top_chunks:
91
+ section = chunk.split(":")[0]
92
+ if section not in used_sections and score > 0.35:
93
+ response += f"• {chunk}\n\n"
94
+ used_sections.add(section)
 
 
 
95
 
96
+ # Add intelligent follow-up
97
+ if len(used_sections) > 1:
98
+ response += "\nهذه المعلومات مترابطة حيث أن "
99
+ response += " و".join(list(used_sections)[:3]) + " جوانب متكاملة."
 
100
 
101
+ return response
102
 
103
+ def answer_question(question):
104
  try:
105
  if not question.strip():
106
+ return "الرجاء إدخال سؤال واضح ومحدد"
 
 
 
107
 
108
+ # Arabic question preprocessing
109
+ question = re.sub(r'[؟\?]', '', question).strip()
110
  question_embedding = model.encode(question, convert_to_tensor=True)
 
111
 
112
+ # Semantic search with diversity
113
+ cos_scores = util.cos_sim(question_embedding, knowledge_embeddings)[0]
114
+ top_k = min(5, len(knowledge_chunks))
115
 
116
+ # Get diverse results from different sections
117
+ top_indices = torch.topk(cos_scores, k=top_k).indices.tolist()
118
+ top_chunks = [(knowledge_chunks[idx], cos_scores[idx].item())
119
+ for idx in top_indices if cos_scores[idx] > 0.3]
120
+
121
+ if not top_chunks:
122
+ return "لم أجد إجابة دقيقة، لكن يمكنك:\n- صياغة السؤال بطريقة أخرى\n- الرجوع للوثائق الرسمية"
123
+
124
+ return generate_arabic_response(question, top_chunks)
125
 
 
 
 
 
 
126
  except Exception as e:
127
+ logger.error(f"Error: {str(e)}")
128
+ return "حدث خطأ تقني، يرجى المحاولة لاحقاً"
129
 
130
+ # Modern Arabic UI
131
  css = """
 
 
 
 
 
132
  .arabic-ui {
133
  direction: rtl;
134
  text-align: right;
135
+ font-family: 'Tahoma', sans-serif;
 
 
136
  }
 
137
  .header {
138
+ background: #2c3e50;
139
+ color: white;
140
  padding: 20px;
141
  border-radius: 8px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  }
143
  """
144
 
 
146
  with gr.Column(elem_classes="arabic-ui"):
147
  gr.Markdown("""
148
  <div class="header">
149
+ <h2>المساعد الآلي لوحدة الشفافية</h2>
150
+ <p>نظام ذكي لفهم واستجابة استفساراتك باللغة العربية</p>
151
  </div>
152
  """)
153
 
154
+ question = gr.Textbox(label="اكتب سؤالك هنا", placeholder="مثال: ما هي مراحل الموازنة التشاركية؟")
155
+ answer = gr.Textbox(label="الإجابة", interactive=False)
 
 
 
 
 
 
156
 
157
+ gr.Examples(
158
+ examples=[
159
+ ["ما هي أهداف التنمية المستدامة الرئيسية؟"],
160
+ ["كيف يمكن المشاركة في الموازنة التشاركية؟"],
161
+ ["ما دور ديوان المحاسبة في تحقيق الشفافية؟"]
162
+ ],
163
+ inputs=question
164
  )
165
 
166
+ submit = gr.Button("الحصول على إجابة ذكية")
167
+ submit.click(answer_question, inputs=question, outputs=answer)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
+ demo.launch(server_name="0.0.0.0", server_port=7860)