amira01 commited on
Commit
3b1892c
·
verified ·
1 Parent(s): 340c256

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -202
app.py CHANGED
@@ -1,153 +1,79 @@
1
- import faiss
2
- import json
3
- import gradio as gr
4
  import os
5
- from typing import List, Dict, Any
 
6
  from langchain_huggingface import HuggingFaceEmbeddings
7
  from langchain_openai import ChatOpenAI
8
  from langchain_core.runnables import RunnablePassthrough
9
  from langchain_community.vectorstores import FAISS
10
- from langchain_core.documents import Document
11
  from langchain.chains import RetrievalQA, LLMChain
12
  from langchain.prompts import PromptTemplate
13
- from langchain_core.messages import AIMessage ,HumanMessage
14
- from langchain_openai import ChatOpenAI
15
 
 
16
 
17
- # 1. Document loading and processing functions (updated)
18
- def load_and_process_files(file_paths: List[str]) -> List[Document]:
19
- """Load and process a list of JSON files"""
20
- all_documents = []
21
-
22
- for file_path in file_paths:
23
- try:
24
- if not os.path.exists(file_path):
25
- print(f"Warning: File {file_path} not found. Skipping.")
26
- continue
27
-
28
- with open(file_path, "r", encoding="utf-8") as f:
29
- data = json.load(f)
30
-
31
- file_name = os.path.basename(file_path)
32
- section = "Section1" if "Section1" in file_name else "Section2"
33
-
34
- # Automatic content type detection
35
- if isinstance(data, dict):
36
- if "الموضوعات" in data:
37
- documents = process_policy_content(data, file_name, section)
38
- elif "الحالات" in data:
39
- documents = process_cases_content(data, file_name, section)
40
- else:
41
- documents = [create_document(str(data), file_name, section, "general_content")]
42
- else:
43
- documents = [create_document(str(data), file_name, section, "general_content")]
44
-
45
- all_documents.extend(documents)
46
- print(f"Loaded {len(documents)} documents from {file_name}")
47
-
48
- except json.JSONDecodeError:
49
- print(f"Error: Invalid JSON format in file {file_path}")
50
- except Exception as e:
51
- print(f"Unexpected error processing {file_path}: {str(e)}")
52
-
53
- return all_documents
54
 
55
- def process_policy_content(data: Dict[str, Any], file_name: str, section: str) -> List[Document]:
56
- """Process policy content"""
57
- documents = []
58
- for topic in data.get("الموضوعات", []):
59
- content = f"# {topic.get('العنوان', '')}\n\n"
60
- content += f"{topic.get('النص', '')}\n\n"
61
-
62
- if "الأنشطة" in topic:
63
- content += "## الأنشطة:\n"
64
- for idx, activity in enumerate(topic["الأنشطة"], 1):
65
- content += f"### {idx}. {activity.get('وصف النشاط', '')}\n"
66
- content += f"- المسؤول: {activity.get('المسئول', '')}\n"
67
- content += f"- الشروط: {activity.get('الشروط المسبقة', '')}\n"
68
- if 'كود النشاط' in activity:
69
- content += f"- الكود: {activity['كود النشاط']}\n"
70
- content += "\n"
71
-
72
- documents.append(create_document(content, file_name, section, "policy"))
73
-
74
- return documents
75
 
76
- def process_cases_content(data: Dict[str, Any], file_name: str, section: str) -> List[Document]:
77
- """Process special cases content"""
78
- content = f"# {data.get('العنوان', 'Special Cases')}\n\n"
79
 
80
- for case in data.get("الحالات", []):
81
- content += "## Case\n"
82
- content += f"- المسؤول: {case.get('المسئول', '')}\n"
83
- content += f"- المستند: {case.get('المستند', '')}\n"
84
- content += f"- التغطية: {case.get('التغطية', '')}\n"
85
- content += f"### Description:\n{case.get('الوصف', '')}\n\n"
86
 
87
- return [create_document(content, file_name, section, "special_case")]
88
-
89
- def create_document(content: str, file_name: str, section: str, doc_type: str) -> Document:
90
- """Create document with metadata"""
91
- return Document(
92
- page_content=content,
93
- metadata={
94
- "source": file_name,
95
- "section": section,
96
- "type": doc_type,
97
- "length": len(content)
98
- }
99
- )
100
-
101
- # 2. Embeddings creation and save/load functions
102
- def get_or_create_embeddings(
103
- documents: List[Document],
104
- save_path: str = "embeddings",
105
- model_name: str = "intfloat/multilingual-e5-large"
106
-
107
- ) -> FAISS:
108
- """
109
- Create new embeddings every time (skip loading saved ones)
110
 
111
- Args:
112
- documents: List of documents to create embeddings from
113
- save_path: Path to save embeddings (not used for loading)
114
- model_name: HuggingFace embeddings model name
115
-
116
- Returns:
117
- FAISS: New vector store
118
- """
119
- # Always create new embeddings
120
- print("🛠️ Creating fresh embeddings...")
121
- embedding_model = HuggingFaceEmbeddings(model_name=model_name)
122
- vectorstore = FAISS.from_documents(documents, embedding_model)
123
-
124
- # Optional: Save for other purposes (but won't be loaded next time)
125
- os.makedirs(save_path, exist_ok=True)
126
- vectorstore.save_local(save_path)
127
- print(f"💾 Embeddings saved to: {save_path} (not used for loading)")
 
128
 
129
- return vectorstore
 
 
 
130
 
131
- # 3. Chain setup functions
132
  def setup_chains(vectorstore: FAISS):
133
- """Setup processing chains"""
134
  llm = ChatOpenAI(
135
  model="meta-llama/llama-3-70b-instruct",
136
  base_url="https://openrouter.ai/api/v1",
137
  api_key="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",
138
- temperature=0.3
139
  )
140
 
141
- # Question rephrasing chain
142
  rephrase_prompt = PromptTemplate.from_template("""
143
-
144
-
145
  قم بتحويل العبارة التالية من العامية المصرية إلى اللغة العربية الفصحى مع الالتزام بالتالي:
146
  1. إذا كانت العبارة بالفصحى بالفعل، اتركها كما هي دون تغيير
147
  2. لا تقم بإضافة أي كلمات أو تعليقات إضافية
148
  3. حافظ على نفس المعنى بدقة
149
  4. غير فقط الكلمات العامية إلى فصحى مع الحفاظ على الكلمات الفصيحة كما هي
150
-
151
  السؤال: "{question}"
152
  السؤال بالفصحى:
153
  """)
@@ -157,92 +83,126 @@ def setup_chains(vectorstore: FAISS):
157
  | llm
158
  )
159
 
160
- # QA chain
161
  qa_prompt = PromptTemplate.from_template(
162
-
163
  """
164
- أجب على السؤال التالي بناءً فقط على المعلومات الموجودة في النصوص المقدمة لك.
165
 
166
  اشتراطات الإجابة:
167
- 1. الإجابة يجب أن تكون دقيقة وكاملة دون نقص
168
- 2. لا تذكر أي أوراق أو مستندات مطلوبة
169
- 3. لا تذكر أرقام خطوات أو إجراءات
170
- 4. لا تشير إلى مصدر المعلومة
171
- 5. التزم باللغة العربية فقط
172
- 6. لا تضيف أي معلومات خارج النص المقدم
173
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  أمثلة توضيحية:
175
- 1. ما هي المستندات المطلوبة لتسجيل الأسرة في التأمين الصحي الشامل؟
 
176
  الإجابة:
177
-
178
- صورة بطاقة الرقم القومي للعائل (سارية - وجهين).
179
-
180
- صور بطاقات الأرقام القومية للزوجة والأبناء (سارية - وجهين).
181
-
182
- صور شهادات ميلاد مميكنة للأبناء تحت سن 15 سنة.
183
-
184
- وثيقة زواج مميكنة.
185
-
186
- قيد عائلي مميكن (إن تطلب الأمر).
187
-
188
- 2. كيف يتم تسجيل الأطفال المكفولين بنظام الأسر البديلة؟
189
  الإجابة:
190
- يتم تقديم المستندات التالية:
191
-
192
- عقد كفالة الطفل مدعوم بشعار الجمهورية من وزارة التضامن الاجتماعي.
193
-
194
- صورة بطاقة الرقم القومي للعائل والطفل.
195
-
196
- صورة كارنيه الأسرة البديلة.
197
-
198
- إقرار من كافل الطفل بدفع اشتراكات التأمين الصحي الشامل عن الطفل المكفول.
 
 
 
 
199
 
200
 
201
-
202
  السؤال: {question}
203
  النصوص: {context}
204
  الإجابة:
205
  """)
206
  qa_chain = RetrievalQA.from_chain_type(
207
  llm=llm,
208
- retriever=vectorstore.as_retriever(),
 
 
 
 
 
 
209
  return_source_documents=True,
210
  chain_type_kwargs={"prompt": qa_prompt}
211
  )
212
 
213
  return rephrase_chain, qa_chain
214
 
215
-
216
- # 4. Question processing function
217
  def process_question(question: str, rephrase_chain, qa_chain, chat_history: list) -> tuple:
218
- """معالجة السؤال وإرجاع الإجابة بالتنسيق الجديد"""
 
 
219
 
220
  rewritten = rephrase_chain.invoke({"question": question})
221
  fusha_question = rewritten.content.strip()
 
222
 
223
  result = qa_chain.invoke(fusha_question)
224
  answer = result["result"]
225
 
226
- chat_history.append((question, answer))
 
 
 
 
227
 
 
 
 
 
228
  return "", chat_history
229
- # 5. Gradio interface
230
- def create_gradio_interface(rephrase_chain: LLMChain, qa_chain: RetrievalQA) -> gr.Blocks:
231
- """Create Gradio interface"""
232
-
233
 
234
- with gr.Blocks(title="المساعد الذكي للتامين الصحي ") as demo:
 
 
235
  gr.Markdown("## المساعد الذكي للتامين الصحي")
236
  gr.Markdown("اسأل عن أي معلومات في وثائق وسياسه التأمين")
237
 
238
- chatbot = gr.Chatbot(label="المحادثة", height=500, type="tuples" )
239
  question_box = gr.Textbox(label="اكتب سؤالك هنا", placeholder="مثال: ما هي شروط تغيير وحدة الرعاية؟")
240
 
241
  with gr.Row():
242
  submit_btn = gr.Button("إرسال")
243
  clear_btn = gr.Button("مسح المحادثة")
244
 
245
-
246
  chat_history = gr.State([])
247
 
248
  submit_btn.click(
@@ -259,44 +219,12 @@ def create_gradio_interface(rephrase_chain: LLMChain, qa_chain: RetrievalQA) ->
259
 
260
  return demo
261
 
262
- # 6. Main function (updated)
263
- def main():
264
- # Required files list
265
- data_files = [
266
- "Section1p1.json",
267
- "Section1p2.json",
268
- "Section1p3.json",
269
- "Section2.json",
270
- "Section3.json",
271
- "Section4.json"
272
- ]
273
-
274
- # Load and process files
275
- print("Loading documents...")
276
- documents = load_and_process_files(data_files)
277
-
278
- if not documents:
279
- raise ValueError("No documents loaded. Please check the files.")
280
-
281
- print(f"Successfully loaded {len(documents)} documents")
282
 
283
- # Create/load embeddings
284
- print("Setting up search models...")
285
- vectorstore = get_or_create_embeddings(documents)
286
 
287
- # Setup processing chains
288
  rephrase_chain, qa_chain = setup_chains(vectorstore)
289
 
290
- # Create Gradio interface
291
- print("Launching interface...")
292
  demo = create_gradio_interface(rephrase_chain, qa_chain)
293
-
294
- # Launch interface
295
-
296
- demo.launch(
297
- show_api=True,
298
- share=False
299
- )
300
-
301
- if __name__ == "__main__":
302
- main()
 
1
+
 
 
2
  import os
3
+ from datetime import datetime
4
+ import gradio as gr
5
  from langchain_huggingface import HuggingFaceEmbeddings
6
  from langchain_openai import ChatOpenAI
7
  from langchain_core.runnables import RunnablePassthrough
8
  from langchain_community.vectorstores import FAISS
 
9
  from langchain.chains import RetrievalQA, LLMChain
10
  from langchain.prompts import PromptTemplate
 
 
11
 
12
+ LOG_FILE = "chat_log.txt"
13
 
14
+ def init_log_file():
15
+ """تهيئة ملف السجل"""
16
+ if not os.path.exists(LOG_FILE):
17
+ with open(LOG_FILE, 'w', encoding='utf-8') as f:
18
+ f.write("سجل محادثات التأمين الصحي\n")
19
+ f.write("="*50 + "\n\n")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
+ def write_to_log(message):
22
+ """كتابة رسالة إلى ملف السجل"""
23
+ with open(LOG_FILE, 'a', encoding='utf-8') as f:
24
+ f.write(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} - {message}\n")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
+ def load_embeddings() -> FAISS:
27
+ """تحميل ملفات FAISS مباشرة من المسار الحالي"""
28
+ required_files = ["index.faiss", "index.pkl", "source_files.txt"]
29
 
30
+ missing_files = [file for file in required_files if not os.path.exists(file)]
31
+ if missing_files:
32
+ error_msg = f"الملفات التالية غير موجودة في المسار الحالي: {', '.join(missing_files)}"
33
+ write_to_log(error_msg)
34
+ raise ValueError(error_msg)
 
35
 
36
+ write_to_log("جاري تحميل ملفات FAISS من المسار الحالي")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
+ try:
39
+ embedding_model = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-large")
40
+
41
+ vectorstore = FAISS.load_local(
42
+ folder_path=".",
43
+ embeddings=embedding_model,
44
+ allow_dangerous_deserialization=True
45
+ )
46
+ write_to_log("تم تحميل ملفات FAISS بنجاح")
47
+
48
+ try:
49
+ with open("source_files.txt", "r", encoding="utf-8") as f:
50
+ sources = f.read().splitlines()
51
+ write_to_log(f"الملفات المصدر المستخدمة: {', '.join(sources)}")
52
+ except Exception as e:
53
+ write_to_log(f"تحذير: لا يمكن قراءة ملف المصادر - {str(e)}")
54
+
55
+ return vectorstore
56
 
57
+ except Exception as e:
58
+ error_msg = f"فشل في تحميل ملفات FAISS: {str(e)}"
59
+ write_to_log(error_msg)
60
+ raise RuntimeError(error_msg)
61
 
 
62
  def setup_chains(vectorstore: FAISS):
63
+ """إعداد سلاسل المعالجة"""
64
  llm = ChatOpenAI(
65
  model="meta-llama/llama-3-70b-instruct",
66
  base_url="https://openrouter.ai/api/v1",
67
  api_key="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",
68
+ temperature=0.4
69
  )
70
 
 
71
  rephrase_prompt = PromptTemplate.from_template("""
 
 
72
  قم بتحويل العبارة التالية من العامية المصرية إلى اللغة العربية الفصحى مع الالتزام بالتالي:
73
  1. إذا كانت العبارة بالفصحى بالفعل، اتركها كما هي دون تغيير
74
  2. لا تقم بإضافة أي كلمات أو تعليقات إضافية
75
  3. حافظ على نفس المعنى بدقة
76
  4. غير فقط الكلمات العامية إلى فصحى مع الحفاظ على الكلمات الفصيحة كما هي
 
77
  السؤال: "{question}"
78
  السؤال بالفصحى:
79
  """)
 
83
  | llm
84
  )
85
 
 
86
  qa_prompt = PromptTemplate.from_template(
 
87
  """
88
+ أجب على السؤال التالي بناءً على المعلومات الموجودة في النصوص المقدمة لك.
89
 
90
  اشتراطات الإجابة:
91
+ 1. اذا كان السوال به اكتر من جزء فتجيب عن كل جزء فالسوال ولا تترك شي
92
+ 2. الإجابة يجب أن تكون كاملة دون حذف شي من النص
93
+ 3. ذكر جميع الاوراق أو المستندات المطلوبة
94
+ 4. التزم باللغة العربية فقط
95
+ 5. اذا كان المطلوب اوراق طفل مولود فلا تذكر بطاقه الرقم القومي للمولود بدلا منها اذكر شهاده الميلاد
96
+ 6. التامين الصحي شامل هذه المناطق فقط (بورسعيد، الإسماعيلية، السويس، جنوب سيناء، ال��قصر، وأسوان)
97
+ 7. لا تذكر أرقام خطوات أو إجراءات
98
+ 8. لا تشير إلى مصدر المعلومة
99
+ 9. لا تضيف أي معلومات خارجية
100
+
101
+ تعليمات الإجابة:
102
+ 1. إذا كان السؤال عن المستندات:
103
+ - حافظ على التقسيمات الأصلية (مستندات تسجيل، مستندات مالية، ...)
104
+ - اذكر جميع البنود دون حذف
105
+ - حافظ على التنسيق النقطي
106
+
107
+ 2. إذا كان السؤال عن خطوات أو إجراءات:
108
+ - اذكر جميع الخطوات مرتبة
109
+ - اذكر المسؤول عن كل خطوة إن ورد
110
+ - أضف الشروط المسبقة إن وجدت
111
+
112
+ 3. إذا جمع السؤال بين المستندات والإجراءات:
113
+ - أجب بكل الأقسام المطلوبة
114
+ - افصل بينها بعناوين واضحة
115
+
116
+ 4. التزم حرفياً بالنصوص الأصلية دون إضافة أو حذف
117
+
118
  أمثلة توضيحية:
119
+ --------------------------------------------------------------------------------
120
+ السؤال: ما هي مستندات تسجيل طفل مولود؟
121
  الإجابة:
122
+ مستندات التسجيل (يتم استلام صور مع ضرورة الاطلاع على الأصل):
123
+ - صورة بطاقة الرقم القومي (سارية - وجهين)
124
+ - صورة شهادة ميلاد مميكنة للطفل
125
+ - أصل بطاقة التأمين الصحي الشامل للأسرة
126
+ - أصل قيد عائلي مميكن إن تطلب الأمر
127
+ -
128
+ مستندات الدخل:
129
+ - طبعة التأمينات الاجتماعية
130
+ - طبعة مدد تأمينية
131
+ -
132
+ --------------------------------------------------------------------------------
133
+ السؤال: ما هي خطوات تسجيل طفل مولود؟
134
  الإجابة:
135
+ 1. تقديم المستندات المطلوبة إلى مكتب التأمين الصحي
136
+ - المسؤول: رب الأسرة
137
+ - الشروط: اكتمال المستندات
138
+ -
139
+
140
+ --------------------------------------------------------------------------------
141
+ السؤال: ما هي إجراءات ومستندات تسجيل مولود جديد؟
142
+ الإجابة:
143
+ أولاً: المستندات المطلوبة
144
+ -
145
+
146
+ ثانياً: خطوات التسجيل
147
+ -
148
 
149
 
 
150
  السؤال: {question}
151
  النصوص: {context}
152
  الإجابة:
153
  """)
154
  qa_chain = RetrievalQA.from_chain_type(
155
  llm=llm,
156
+ retriever = vectorstore.as_retriever(
157
+ search_type="mmr",
158
+ search_kwargs={
159
+ 'k': 6,
160
+ 'fetch_k': 20,
161
+ 'lambda_mult': 0.7 }),
162
+ #retriever=vectorstore.as_retriever(),
163
  return_source_documents=True,
164
  chain_type_kwargs={"prompt": qa_prompt}
165
  )
166
 
167
  return rephrase_chain, qa_chain
168
 
 
 
169
  def process_question(question: str, rephrase_chain, qa_chain, chat_history: list) -> tuple:
170
+ """معالجة السؤال وتسجيل التفاصيل"""
171
+ # تسجيل السؤال الأصلي
172
+ write_to_log(f"السؤال الأصلي: {question}")
173
 
174
  rewritten = rephrase_chain.invoke({"question": question})
175
  fusha_question = rewritten.content.strip()
176
+ write_to_log(f"السؤال المحول: {fusha_question}")
177
 
178
  result = qa_chain.invoke(fusha_question)
179
  answer = result["result"]
180
 
181
+ sources = set()
182
+ for doc in result["source_documents"]:
183
+ source_info = f"{doc.metadata['source']} - {doc.metadata['section']}"
184
+ sources.add(source_info)
185
+ write_to_log(f"مستند مسترجع: {source_info}")
186
 
187
+ write_to_log(f"الإجابة النهائية: {answer}")
188
+ write_to_log("="*50) # خط فاصل بين المحادثات
189
+
190
+ chat_history.append((question, answer))
191
  return "", chat_history
 
 
 
 
192
 
193
+ def create_gradio_interface(rephrase_chain: LLMChain, qa_chain: RetrievalQA) -> gr.Blocks:
194
+ """إنشاء واجهة Gradio"""
195
+ with gr.Blocks(title="المساعد الذكي للتامين الصحي") as demo:
196
  gr.Markdown("## المساعد الذكي للتامين الصحي")
197
  gr.Markdown("اسأل عن أي معلومات في وثائق وسياسه التأمين")
198
 
199
+ chatbot = gr.Chatbot(label="المحادثة", height=500, type="tuples")
200
  question_box = gr.Textbox(label="اكتب سؤالك هنا", placeholder="مثال: ما هي شروط تغيير وحدة الرعاية؟")
201
 
202
  with gr.Row():
203
  submit_btn = gr.Button("إرسال")
204
  clear_btn = gr.Button("مسح المحادثة")
205
 
 
206
  chat_history = gr.State([])
207
 
208
  submit_btn.click(
 
219
 
220
  return demo
221
 
222
+ if __name__ == "__main__":
223
+ init_log_file()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
 
225
+ vectorstore = load_embeddings()
 
 
226
 
 
227
  rephrase_chain, qa_chain = setup_chains(vectorstore)
228
 
 
 
229
  demo = create_gradio_interface(rephrase_chain, qa_chain)
230
+ demo.launch(show_api=True , share=True)