mo-456 commited on
Commit
d545b79
·
verified ·
1 Parent(s): b754287

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +59 -89
app.py CHANGED
@@ -1,46 +1,40 @@
1
  import gradio as gr
2
  from sentence_transformers import SentenceTransformer, util
 
 
3
  import torch
4
  import logging
5
  import re
6
  import os
7
  from typing import List, Tuple
8
 
9
- # إعداد التسجيل
10
  logging.basicConfig(level=logging.INFO)
11
  logger = logging.getLogger(__name__)
12
 
13
- # تحميل نموذج MARBERT
14
- try:
15
- model = SentenceTransformer("UBC-NLP/MARBERT", device="cuda" if torch.cuda.is_available() else "cpu")
16
- logger.info("تم تحميل النموذج بنجاح")
17
- except Exception as e:
18
- logger.error(f"فشل تحميل النموذج: {e}")
19
- raise
20
 
21
- # تحميل المعرفة
22
- def load_knowledge() -> List[str]:
23
- if not os.path.exists("knowledge.txt"):
24
- logger.warning("ملف المعرفة غير موجود.")
25
- return ["عام: لا يوجد محتوى معرفي متاح."]
26
-
27
- chunks = []
28
- current_section = "عام"
29
  with open("knowledge.txt", encoding="utf-8") as f:
30
  for line in f:
31
  line = line.strip()
32
  if line.startswith("##"):
33
- current_section = line.replace("##", "").strip()
34
- elif line:
35
- chunks.append(f"{current_section}: {line}")
36
-
37
- logger.info(f"تم تحميل {len(chunks)} قطعة معرفة.")
38
- return chunks
39
-
40
- knowledge_chunks = load_knowledge()
41
- knowledge_embeddings = model.encode(knowledge_chunks, convert_to_tensor=True)
42
-
43
- # معالجة السؤال
 
44
  def preprocess_question(question: str) -> str:
45
  question = re.sub(r'[؟\?،,\.]', '', question).strip()
46
  replacements = {
@@ -56,18 +50,23 @@ def preprocess_question(question: str) -> str:
56
  question = re.sub(pattern, repl, question)
57
  return question
58
 
 
 
 
 
 
 
 
 
 
 
59
  # توليد الرد
60
- def generate_response(question: str, top_chunks: List[Tuple[str, float]]) -> str:
61
- if not top_chunks:
62
- suggestions = [
63
- "أعد صياغة سؤالك.",
64
- "جرّب استخدام كلمات أخرى.",
65
- "ابحث في قسم مختلف من المعرفة."
66
- ]
67
- return "لم يتم العثور على إجابة دقيقة.\n\nاقتراحات:\n" + "\n".join(f"- {s}" for s in suggestions)
68
 
69
  sections = {}
70
- for chunk, score in top_chunks:
71
  if ":" in chunk:
72
  section, content = chunk.split(":", 1)
73
  else:
@@ -77,68 +76,39 @@ def generate_response(question: str, top_chunks: List[Tuple[str, float]]) -> str
77
  sections[section].append((content.strip(), score))
78
 
79
  main_section = max(sections, key=lambda s: sum(x[1] for x in sections[s]) / len(sections[s]))
80
-
81
  response = f"سؤالك: {question}\n\n"
82
- response += f"{main_section}:\n"
 
83
  for content, _ in sorted(sections[main_section], key=lambda x: x[1], reverse=True):
84
- response += f"- {content}\n"
85
-
86
- other_sections = [s for s in sections if s != main_section]
87
- if other_sections:
88
- response += "\nمعلومات إضافية:\n"
89
- for section in other_sections[:2]:
90
- response += f"\nمن {section}:\n"
91
- for content, _ in sorted(sections[section], key=lambda x: x[1], reverse=True)[:2]:
92
- response += f"- {content}\n"
93
 
94
  return response
95
 
96
- # الرد النهائي
97
- def answer_question(question: str) -> str:
98
- if not question or len(question.strip()) < 3:
99
- return "يرجى إدخال سؤال واضح لا يقل عن ثلاث كلمات."
100
-
101
- question = preprocess_question(question)
102
- logger.info(f"معالجة السؤال: {question}")
103
-
104
- try:
105
- q_embedding = model.encode(question, convert_to_tensor=True)
106
- cos_scores = util.cos_sim(q_embedding, knowledge_embeddings)[0]
107
- top_k = min(5, len(knowledge_chunks))
108
- top_results = torch.topk(cos_scores, k=top_k)
109
-
110
- top_chunks = [
111
- (knowledge_chunks[idx], score.item())
112
- for idx, score in zip(top_results.indices, top_results.values)
113
- if score.item() > 0.6
114
- ]
115
-
116
- if not top_chunks:
117
- with open("unanswered.txt", "a", encoding="utf-8") as f:
118
- f.write(f"{question}\n")
119
-
120
- return generate_response(question, top_chunks)
121
-
122
- except Exception as e:
123
- logger.error(f"خطأ أثناء توليد الإجابة: {e}")
124
- return "حدث خطأ غير متوقع أثناء توليد الإجابة."
125
 
126
  # واجهة Gradio
127
  with gr.Blocks(css=".arabic-ui {direction: rtl; text-align: right; font-family: Tahoma;}") as demo:
128
  with gr.Column(elem_classes="arabic-ui"):
129
- gr.Markdown("### المساعد الذكي لوحدة الشفافية\nاسأل عن الموازنة، المشاركة المجتمعية، أو الشفافية المالية.")
130
- question = gr.Textbox(label="سؤالك", placeholder="مثال: ما هي أهداف الموازنة التشاركية؟", lines=3)
131
- submit_btn = gr.Button("إرسال السؤال", variant="primary")
132
- answer = gr.Textbox(label="الإجابة", lines=12, interactive=False)
133
- gr.Examples(
134
- examples=[
135
- ["ما هي أهداف الموازنة التشاركية؟"],
136
- ["من هي رئيسة وحدة الشفافية؟"],
137
- ["ما هو دور المواطن في إعداد الموازنة؟"]
138
- ],
139
- inputs=question
140
- )
141
- submit_btn.click(answer_question, inputs=question, outputs=answer)
142
 
143
  if __name__ == "__main__":
144
  demo.launch(server_name="0.0.0.0", server_port=7860, share=False)
 
1
  import gradio as gr
2
  from sentence_transformers import SentenceTransformer, util
3
+ import faiss
4
+ import numpy as np
5
  import torch
6
  import logging
7
  import re
8
  import os
9
  from typing import List, Tuple
10
 
 
11
  logging.basicConfig(level=logging.INFO)
12
  logger = logging.getLogger(__name__)
13
 
14
+ # تحميل النموذج
15
+ model = SentenceTransformer("UBC-NLP/MARBERT", device="cuda" if torch.cuda.is_available() else "cpu")
16
+ logger.info(" النموذج محمّل")
 
 
 
 
17
 
18
+ # تحميل وتنظيف المعرفة
19
+ knowledge_chunks = []
20
+ section = "عام"
21
+ if os.path.exists("knowledge.txt"):
 
 
 
 
22
  with open("knowledge.txt", encoding="utf-8") as f:
23
  for line in f:
24
  line = line.strip()
25
  if line.startswith("##"):
26
+ section = line.replace("##", "").strip()
27
+ elif line and len(line) > 10:
28
+ knowledge_chunks.append(f"{section}: {line}")
29
+ else:
30
+ knowledge_chunks = ["عام: لا يوجد محتوى معرفي."]
31
+
32
+ # التضمينات + FAISS
33
+ knowledge_embeddings = model.encode(knowledge_chunks, convert_to_numpy=True, normalize_embeddings=True)
34
+ index = faiss.IndexFlatIP(knowledge_embeddings.shape[1])
35
+ index.add(knowledge_embeddings)
36
+
37
+ # تنظيف السؤال
38
  def preprocess_question(question: str) -> str:
39
  question = re.sub(r'[؟\?،,\.]', '', question).strip()
40
  replacements = {
 
50
  question = re.sub(pattern, repl, question)
51
  return question
52
 
53
+ # البحث الدلالي
54
+ def semantic_search(question: str, top_k=5) -> List[Tuple[str, float]]:
55
+ embedding = model.encode(question, convert_to_numpy=True, normalize_embeddings=True)
56
+ scores, indices = index.search(np.array([embedding]), top_k)
57
+ results = []
58
+ for i, score in zip(indices[0], scores[0]):
59
+ if score > 0.6:
60
+ results.append((knowledge_chunks[i], float(score)))
61
+ return results
62
+
63
  # توليد الرد
64
+ def generate_response(question: str, results: List[Tuple[str, float]]) -> str:
65
+ if not results:
66
+ return "لم أتمكن من العثور على إجابة مباشرة. حاول إعادة صياغة سؤالك."
 
 
 
 
 
67
 
68
  sections = {}
69
+ for chunk, score in results:
70
  if ":" in chunk:
71
  section, content = chunk.split(":", 1)
72
  else:
 
76
  sections[section].append((content.strip(), score))
77
 
78
  main_section = max(sections, key=lambda s: sum(x[1] for x in sections[s]) / len(sections[s]))
 
79
  response = f"سؤالك: {question}\n\n"
80
+ response += f"{main_section}:
81
+ "
82
  for content, _ in sorted(sections[main_section], key=lambda x: x[1], reverse=True):
83
+ if len(content) > 15:
84
+ response += f"- {content}\n"
 
 
 
 
 
 
 
85
 
86
  return response
87
 
88
+ # دالة الاستجابة
89
+ def answer_question(q: str) -> str:
90
+ if not q or len(q.strip()) < 3:
91
+ return "يرجى إدخال سؤال واضح مكون من 3 كلمات أو أكثر."
92
+ q_clean = preprocess_question(q)
93
+ results = semantic_search(q_clean)
94
+ return generate_response(q_clean, results)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
  # واجهة Gradio
97
  with gr.Blocks(css=".arabic-ui {direction: rtl; text-align: right; font-family: Tahoma;}") as demo:
98
  with gr.Column(elem_classes="arabic-ui"):
99
+ gr.Markdown("""
100
+ ### المساعد الذكي للموازنة التشاركية
101
+ اطرح سؤالك حول وحدة الشفافية أو المشاريع أو المؤشرات الدولية.
102
+ """)
103
+ question = gr.Textbox(label="سؤالك", placeholder="مثال: من هي رئيسة وحدة الشفافية؟", lines=3)
104
+ submit = gr.Button("إرسال")
105
+ answer = gr.Textbox(label="الإجابة", lines=10, interactive=False)
106
+ gr.Examples([
107
+ ["من هي رئيسة وحدة الشفافية؟"],
108
+ ["ما هي أهداف الموازنة التشاركية؟"],
109
+ ["كم حصلت مصر في مؤشر الشفافية؟"]
110
+ ], inputs=question)
111
+ submit.click(fn=answer_question, inputs=question, outputs=answer)
112
 
113
  if __name__ == "__main__":
114
  demo.launch(server_name="0.0.0.0", server_port=7860, share=False)