moazx commited on
Commit
c5e1945
·
1 Parent(s): c7ec461

Project setup

Browse files
.env.example ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # OpenAI Configuration
2
+ OPENAI_API_KEY = ""
3
+ OPENAI_BASE_URL= "https://models.inference.ai.azure.com"
4
+
5
+ # HuggingFace Configuration
6
+ HUGGINGFACE_HUB_TOKEN = ""
7
+
8
+ # Tavily Search Configuration
9
+ TAVILY_API_KEY = ""
10
+
11
+ # Application Configuration
12
+ LOG_LEVEL=INFO
13
+ MAX_RETRIES=3
14
+ REQUEST_TIMEOUT=30
.gitignore ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+ #poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ #pdm.lock
116
+ #pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ #pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # SageMath parsed files
135
+ *.sage.py
136
+
137
+ # Environments
138
+ .env
139
+ .envrc
140
+ .venv
141
+ env/
142
+ venv/
143
+ ENV/
144
+ env.bak/
145
+ venv.bak/
146
+
147
+ # Spyder project settings
148
+ .spyderproject
149
+ .spyproject
150
+
151
+ # Rope project settings
152
+ .ropeproject
153
+
154
+ # mkdocs documentation
155
+ /site
156
+
157
+ # mypy
158
+ .mypy_cache/
159
+ .dmypy.json
160
+ dmypy.json
161
+
162
+ # Pyre type checker
163
+ .pyre/
164
+
165
+ # pytype static type analyzer
166
+ .pytype/
167
+
168
+ # Cython debug symbols
169
+ cython_debug/
170
+
171
+ # PyCharm
172
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
173
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
174
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
175
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
176
+ #.idea/
177
+
178
+ # Abstra
179
+ # Abstra is an AI-powered process automation framework.
180
+ # Ignore directories containing user credentials, local state, and settings.
181
+ # Learn more at https://abstra.io/docs
182
+ .abstra/
183
+
184
+ # Visual Studio Code
185
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
188
+ # you could uncomment the following to ignore the entire vscode folder
189
+ # .vscode/
190
+
191
+ # Ruff stuff:
192
+ .ruff_cache/
193
+
194
+ # PyPI configuration file
195
+ .pypirc
196
+
197
+ # Cursor
198
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
199
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
200
+ # refer to https://docs.cursor.com/context/ignore-files
201
+ .cursorignore
202
+ .cursorindexingignore
203
+
204
+ # Marimo
205
+ marimo/_static/
206
+ marimo/_lsp/
207
+ __marimo__/
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Moaz Eldsouky
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
app.py ADDED
@@ -0,0 +1,408 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import asyncio
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ import sys
7
+ import os
8
+ sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
9
+
10
+ # Configure logging
11
+ logging.basicConfig(
12
+ level=logging.INFO,
13
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
14
+ )
15
+ logger = logging.getLogger(__name__)
16
+
17
+ try:
18
+ from src.agent import safe_run_agent_streaming, safe_run_agent, clear_memory
19
+ from src.data_loaders import process_uploaded_file
20
+ from src.utils import initialize_knowledge_base
21
+ except ImportError as e:
22
+ logger.error(f"Failed to import required modules: {e}")
23
+ raise
24
+
25
+ # Initialize knowledge base on startup
26
+ logger.info("Initializing knowledge base...")
27
+ try:
28
+ knowledge_base = initialize_knowledge_base()
29
+ if knowledge_base:
30
+ logger.info("Knowledge base initialized successfully")
31
+ else:
32
+ logger.warning("Knowledge base initialization failed - some features may be limited")
33
+ except Exception as e:
34
+ logger.error(f"Knowledge base initialization error: {e}")
35
+ knowledge_base = None
36
+
37
+ # Global variable to store processed document context
38
+ processed_docs = []
39
+
40
+ async def chat_function_streaming(message: str, history: list):
41
+ """Process user message through the agent with streaming and better error handling"""
42
+ if not message or not message.strip():
43
+ history.append([message, "عذراً، لم أتلقَ أي سؤال. يرجى إدخال سؤالك أو طلبك."])
44
+ yield history, ""
45
+ return
46
+
47
+ # Add user message to history with empty response
48
+ history.append([message, ""])
49
+
50
+ try:
51
+ # Prepare message with document context if available
52
+ message_to_agent = message
53
+ if processed_docs:
54
+ str_processed_docs = "\n".join([
55
+ f"{doc.page_content}\n{doc.metadata}"
56
+ for doc in processed_docs
57
+ ])
58
+ message_to_agent = f"{message}\n\nThis is Information you can use:\n\n{str_processed_docs}"
59
+
60
+ # Stream the response
61
+ accumulated_response = ""
62
+ async for chunk in safe_run_agent_streaming(message_to_agent):
63
+ accumulated_response += chunk
64
+ history[-1][1] = accumulated_response
65
+ yield history, ""
66
+
67
+ except Exception as e:
68
+ logger.error(f"Error in chat_function_streaming: {e}")
69
+ history[-1][1] = f"عذراً، حدث خطأ: {str(e)}"
70
+ yield history, ""
71
+
72
+ def upload_and_process_file(file) -> str:
73
+ """Process uploaded file and add to knowledge base"""
74
+ global processed_docs
75
+
76
+ if file is None:
77
+ return "لم يتم رفع أي ملف"
78
+
79
+ try:
80
+ # Gradio's file object has a .name attribute which is the path to the temporary file
81
+ file_path = Path(file) # file is already a path string in newer versions
82
+
83
+ # Validate file type
84
+ allowed_extensions = {'.pdf', '.txt', '.docx', '.doc'}
85
+ if file_path.suffix.lower() not in allowed_extensions:
86
+ return f"نوع الملف غير مدعوم: {file_path.suffix}. الأنواع المدعومة: {', '.join(allowed_extensions)}"
87
+
88
+ # Check file size (limit to 10MB)
89
+ file_size = file_path.stat().st_size
90
+ if file_size > 10 * 1024 * 1024: # 10MB
91
+ return "الملف كبير جداً. الحد الأقصى 10 ميجابايت."
92
+
93
+ # Process the uploaded file
94
+ new_documents = process_uploaded_file(file_path)
95
+
96
+ if new_documents:
97
+ # Extend the global processed_docs list with the new documents
98
+ processed_docs.extend(new_documents)
99
+ return f"تم معالجة الملف '{file_path.name}' بنجاح. تمت إضافة {len(new_documents)} وثيقة."
100
+ else:
101
+ return f"لم يتم العثور على محتوى قابل للمعالجة في الملف '{file_path.name}'"
102
+
103
+ except Exception as e:
104
+ logger.error(f"Error processing file {file}: {e}")
105
+ return f"خطأ في معالجة الملف '{file}': {str(e)}"
106
+
107
+ def clear_chat_memory_and_history():
108
+ """Clear the conversation memory, processed documents, chat history, and upload status"""
109
+ global processed_docs
110
+
111
+ try:
112
+ clear_memory()
113
+ processed_docs = []
114
+ logger.info("Successfully cleared chat memory and history")
115
+ # Return empty chat history, clear status, and empty upload status
116
+ return [], "تم مسح الذاكرة بنجاح. بدأت محادثة جديدة!", ""
117
+ except Exception as e:
118
+ logger.error(f"Error clearing memory: {e}")
119
+ return [], f"خطأ في مسح الذاكرة: {str(e)}", ""
120
+
121
+ def validate_startup():
122
+ """Validate system before launching"""
123
+ required_env_vars = ["OPENAI_API_KEY"]
124
+ missing_vars = [var for var in required_env_vars if not os.getenv(var)]
125
+
126
+ if missing_vars:
127
+ error_msg = f"Missing required environment variables: {', '.join(missing_vars)}"
128
+ logger.error(error_msg)
129
+ raise ValueError(error_msg)
130
+
131
+ logger.info("Startup validation passed")
132
+
133
+ # Wrapper function to handle async streaming for Gradio
134
+ def chat_function_wrapper(message, history):
135
+ """Wrapper to run the async streaming function"""
136
+ try:
137
+ # Create new event loop for this thread
138
+ loop = asyncio.new_event_loop()
139
+ asyncio.set_event_loop(loop)
140
+
141
+ try:
142
+ # Run the async generator
143
+ async_gen = chat_function_streaming(message, history)
144
+
145
+ # Iterate through the async generator
146
+ while True:
147
+ try:
148
+ result = loop.run_until_complete(async_gen.__anext__())
149
+ yield result
150
+ except StopAsyncIteration:
151
+ break
152
+
153
+ finally:
154
+ loop.close()
155
+
156
+ except Exception as e:
157
+ # Fallback to non-streaming if streaming fails
158
+ try:
159
+ # Check if we have processed documents
160
+ if processed_docs:
161
+ # Create string representation of processed documents
162
+ str_processed_docs = "\n".join([
163
+ f"{doc.page_content}\n{doc.metadata}"
164
+ for doc in processed_docs
165
+ ])
166
+ message_to_agent = f"{message}\n\nThis is Information you can use:\n\n{str_processed_docs}"
167
+ # Pass message with document context to the agent
168
+ response = asyncio.run(safe_run_agent(message_to_agent))
169
+ else:
170
+ # Process normally without document context
171
+ response = asyncio.run(safe_run_agent(message))
172
+
173
+ # Add the new conversation to history
174
+ history.append([message, response])
175
+ yield history, ""
176
+ except Exception as fallback_error:
177
+ history.append([message, f"Error: {str(fallback_error)}"])
178
+ yield history, ""
179
+
180
+ def create_interface():
181
+ """Create and configure the Gradio interface"""
182
+
183
+ # Custom CSS for full-screen responsive layout
184
+ custom_css = """
185
+ @import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
186
+
187
+ /* Global font */
188
+ * {
189
+ font-family: 'Roboto', sans-serif;
190
+ }
191
+
192
+ /* Better RTL support for Arabic */
193
+ .rtl {
194
+ direction: rtl;
195
+ text-align: right;
196
+ }
197
+
198
+ /* Apply Roboto font only to English content explicitly if needed */
199
+ :lang(en) {
200
+ font-family: 'Roboto', sans-serif;
201
+ }
202
+
203
+ /* Responsive design for small screens */
204
+ @media (max-width: 768px) {
205
+ .gradio-row {
206
+ flex-direction: column !important;
207
+ }
208
+ }
209
+
210
+ /* 👇 Control font size in the input Textbox */
211
+ textarea {
212
+ font-size: 18px !important;
213
+ }
214
+
215
+ /* 👇 Control font size in the Chatbot messages */
216
+ .message, .message-user, .message-ai {
217
+ font-size: 18px !important;
218
+ line-height: 1.6;
219
+ }
220
+
221
+ /* 👇 Optional: Adjust file upload input and other text areas */
222
+ input[type="file"], .gr-textbox, .gr-textbox textarea {
223
+ font-size: 16px !important;
224
+ }
225
+ """
226
+
227
+
228
+ # Create the Gradio interface with full-screen layout
229
+ with gr.Blocks(
230
+ title="الشفاء الرقمية للرعاية الصحية - المساعد الطبي",
231
+ css=custom_css,
232
+ theme=gr.themes.Soft()
233
+ ) as interface:
234
+
235
+ # Arabic Header with RTL support
236
+ gr.Markdown(
237
+ """
238
+ <div style="text-align: center; direction: rtl;">
239
+
240
+ # 🏥 الشفاء الرقمية للرعاية الصحية - المساعد الطبي
241
+
242
+ ### اطرح أسئلة طبية أو ارفع وثائق للحصول على مساعدة
243
+
244
+ </div>
245
+ """,
246
+ elem_classes="rtl"
247
+ )
248
+
249
+ # Full-width responsive layout
250
+ with gr.Row():
251
+ with gr.Column(scale=3, min_width=400): # Increased scale for chat area
252
+ chatbot = gr.Chatbot(
253
+ label="💬 محادثة المساعد الطبي",
254
+ height=600, # Increased height
255
+ show_label=True,
256
+ container=True,
257
+ bubble_full_width=False,
258
+ rtl=True # Enable RTL for Arabic support
259
+ )
260
+
261
+ with gr.Row():
262
+ msg = gr.Textbox(
263
+ label="رسالتك",
264
+ placeholder="اطرح سؤالاً طبياً باللغة العربية أو الإنجليزية...",
265
+ scale=4,
266
+ container=False,
267
+ rtl=True
268
+ )
269
+ submit_btn = gr.Button("إرسال", variant="primary", scale=1)
270
+
271
+ gr.Markdown(
272
+ """
273
+ <div style="text-align: center; direction: rtl; color: #666; margin-top: 10px;">
274
+ <em>
275
+ ملاحظة: هذا مشروع تجريبي شخصي لاغراض تعليمية فقط.
276
+ <br>
277
+ لإنشاء مشروع مماثل، يمكنكم التواصل مع المطور:
278
+ <br>
279
+ <a href="mailto:moazeldsoky8@gmail.com">Email</a> | <a href="https://github.com/MoazEldsouky">GitHub</a> | <a href="https://www.linkedin.com/in/moaz-eldesouky-762288251/">LinkedIn</a>
280
+ <br>
281
+ WhatsApp: +201096448317
282
+ <br>
283
+ في حالات الطوارئ، اتصل بـ 997 فوراً.
284
+ </em>
285
+ </div>
286
+ """,
287
+ elem_classes="rtl"
288
+ )
289
+
290
+ with gr.Column(scale=2, min_width=300): # Side panel
291
+ # Document Upload Section
292
+ gr.Markdown("### 📁 رفع الوثائق", elem_classes="rtl")
293
+ file_upload = gr.File(
294
+ label="ارفع وثيقة طبية",
295
+ file_types=[".pdf", ".txt", ".docx", ".doc"],
296
+ type="filepath"
297
+ )
298
+ upload_status = gr.Textbox(
299
+ label="حالة الرفع",
300
+ interactive=False,
301
+ max_lines=3,
302
+ rtl=True
303
+ )
304
+
305
+ # Memory Management Section
306
+ gr.Markdown("### 🧠 إدارة الذاكرة", elem_classes="rtl")
307
+ clear_btn = gr.Button(
308
+ "🗑️ مسح الذاكرة وبدء محادثة جديدة",
309
+ variant="secondary",
310
+ size="lg"
311
+ )
312
+ clear_status = gr.Textbox(
313
+ label="حالة المسح",
314
+ interactive=False,
315
+ rtl=True
316
+ )
317
+
318
+ # About section in Arabic
319
+ with gr.Accordion("ℹ️ حول مساعد الشفاء الرقمي", open=False):
320
+ gr.Markdown(
321
+ """
322
+ <div style="direction: rtl; text-align: right;">
323
+
324
+ **الميزات:**
325
+ - معلومات وإرشادات طبية
326
+ - مساعدة في حجز المواعيد
327
+ - دعم تحليل الوثائق
328
+ - دعم ثنائي اللغة (العربية/الإنجليزية)
329
+ - متاح 24/7 لخدمتكم
330
+
331
+ **مهم:**
332
+ - هذا ليس بديلاً عن المشورة الطبية المهنية
333
+ - في حالات الطوارئ، اتصل دائماً بـ 997
334
+ - الاستجابات مولدة بالذكاء الاصطناعي ويجب التحقق منها مع المختصين الطبيين
335
+
336
+ **معلومات الاتصال:**
337
+ - الطوارئ: 997
338
+ - خدمة العملاء: متوفرة على مدار الساعة
339
+ - الموقع الإلكتروني: www.alshifadigital.com
340
+ - الهاتف: 9200-000-000 (متوفر خلال ساعات العمل الرسمية)
341
+
342
+ </div>
343
+ """,
344
+ elem_classes="rtl"
345
+ )
346
+
347
+ # Event handlers with streaming support
348
+ def submit_message(message, history):
349
+ """Handle message submission"""
350
+ if message.strip():
351
+ yield from chat_function_wrapper(message, history)
352
+
353
+ # Connect the submit events
354
+ msg.submit(
355
+ submit_message,
356
+ inputs=[msg, chatbot],
357
+ outputs=[chatbot, msg]
358
+ )
359
+
360
+ submit_btn.click(
361
+ submit_message,
362
+ inputs=[msg, chatbot],
363
+ outputs=[chatbot, msg]
364
+ )
365
+
366
+ # File upload handler
367
+ file_upload.upload(
368
+ upload_and_process_file,
369
+ inputs=file_upload,
370
+ outputs=upload_status
371
+ )
372
+
373
+ # Clear memory handler - now clears memory, chat history, and upload status
374
+ clear_btn.click(
375
+ clear_chat_memory_and_history,
376
+ inputs=[],
377
+ outputs=[chatbot, clear_status, upload_status]
378
+ )
379
+
380
+ return interface
381
+
382
+ def launch_gradio():
383
+ """Launch Gradio with startup validation"""
384
+ try:
385
+ validate_startup()
386
+ logger.info("Starting Gradio interface...")
387
+
388
+ interface = create_interface()
389
+
390
+ interface.launch(
391
+ server_name="0.0.0.0",
392
+ server_port=int(os.getenv("PORT", 7860)),
393
+ share=bool(os.getenv("GRADIO_SHARE", False)),
394
+ debug=bool(os.getenv("DEBUG", False)),
395
+ show_error=True,
396
+ quiet=False,
397
+ inbrowser=True,
398
+ favicon_path=None,
399
+ ssl_verify=False,
400
+ app_kwargs={}
401
+ )
402
+
403
+ except Exception as e:
404
+ logger.error(f"Failed to launch Gradio: {e}")
405
+ raise
406
+
407
+ if __name__ == "__main__":
408
+ launch_gradio()
data/processed/company_chunks.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f20d3f4e3b7988cf855309ee7689acdee4b5bfa1ed98f07162d660be39d8df3e
3
+ size 112648
data/processed/vector_store/index.faiss ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b031bcd9822372b42f9693b991ff081f3dbdadc762abb5acae174b38c7357191
3
+ size 420909
data/processed/vector_store/index.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2ca52b169948f44e3546b84a7c8f008b731f501547df6604a6d5017dd0f47af6
3
+ size 125794
data/raw_company_info/FAQ.csv ADDED
@@ -0,0 +1,263 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Question,Answer
2
+ ما هي شركة الشفاء الرقمية؟,هي شركة رائدة ومتطورة في مجال الرعاية الصحية عن بُعد (Telehealth)، تأسست لتوفير رعاية طبية شاملة وعالية الجودة عبر الإنترنت.
3
+ ما هي رؤية الشركة؟,أن تكون الخيار الأول والموثوق به عالميًا في مجال الرعاية الصحية الرقمية، وأن تُحدِث فرقًا حقيقيًا وملموسًا في جودة حياة الأفراد والمجتمعات.
4
+ ما هي رسالة الشركة؟,تقديم خدمات طبية موثوقة، آمنة، وسهلة الوصول لجميع أفراد المجتمع، مع التركيز على الكفاءة المهنية والشفافية التامة.
5
+ ما هي القيم الأساسية التي تلتزم بها الشركة؟,السرية والخصوصية، الجودة والاحترافية، التيسير والسرعة، الموثوقية والشفافية، التعاطف والرعاية، والابتكار والتطوير المستمر.
6
+ هل بياناتي محفوظة وآمنة؟,نعم، تلتزم الشركة بأعلى معايير الأمان والخصوصية العالمية لحماية البيانات الشخصية والطبية، وتستخدم تقنيات التشفير المتقدمة (SSL/TLS).
7
+ ما هي المؤهلات التي يتمتع بها الأطباء في الشركة؟,جميع أطبائنا حاصلون على شهادات معتمدة ولديهم سنوات من الخبرة في تخصصاتهم، ويخضعون لعملية تدقيق صارمة لضمان أعلى مستويات الكفاءة والاحترافية.
8
+ ما هي الخدمات التي تقدمها الشركة؟,تشمل الخدمات الاستشارات الطبية عبر الفيديو، الكشف الجسدي في العيادة، مراجعة التقارير الطبية والتحاليل، خدمات الصيدلة والتوصيل المنزلي، حجز مواعيد مع أطباء متخصصين، وخدمات الرعاية النفسية والدعم الصحي. كما تقدم الشركة تحليل نتائج المختبر، نظام السجلات الطبية الإلكترونية الموحدة (EHR)، برامج الصحة الوقائية، وخدمات الطب عن بُعد للمؤسسات والشركات.
9
+ هل يمكن الحصول على استشارة طبية في حالات الطوارئ؟,لا، خدمات شركة الشفاء الرقمية مخصصة للحالات غير الطارئة والاستشارات الروتينية والمتابعة فقط. يجب التوجه فوراً إلى أقرب مستشفى أو الاتصال برقم الطوارئ في حالة وجود أي حالة طارئة.
10
+ ما هي اللغات التي يقدم بها الأطباء الاستشارات؟,يقدم أطباؤنا الاستشارات باللغة العربية بشكل أساسي، بالإضافة إلى إمكانية توفير استشارات بلغات أخرى مثل الإنجليزية حسب توفر الأطباء المتحدثين بهذه اللغات.
11
+ هل يمكنني اختيار الطبيب الذي أرغب في الاستشارة معه؟,نعم، يمكنك تصفح ملفات الأطباء المتوفرين، والاطلاع على تخصصاتهم، خبراتهم، وتقييمات المرضى الآخرين لاختيار الأنسب.
12
+ هل يمكنني حجز استشارة لأحد أفراد عائلتي؟,نعم، يمكنك حجز استشارة نيابة عن أحد أفراد عائلتك (مثل الأطفال أو كبار السن) مع مراعاة الحصول على موافقتهم الصريحة وتقديم معلوماتهم الطبية بدقة.
13
+ هل يمكنني استرداد المبلغ إذا لم أكن راضيًا عن الخدمة؟,نعم، يمكن طلب استرداد المبلغ خلال 24 ساعة من تقديم الخدمة أو عدم إتمامها، وذلك وفقًا لسياسة الاسترداد الخاصة بالشركة.
14
+ هل تشمل الاستشارات وصف الأدوية؟,نعم، إذا رأى الطبيب ضرورة طبية لذلك، يمكنه وصف الأدوية اللازمة خلال الاستشارة. يتم إرسال الوصفة إلكترونيًا ويمكن توصيلها إليك مباشرة عبر خدمة الصيدلية الإلكترونية.
15
+ هل توفرون فحصاً طبياً شاملاً عن بعد؟,لا يمكن إجراء فحص جسدي شامل عن بعد. ولكن، توفر الشركة خدمة الكشف الجسدي في عيادتها الخاصة في جميع التخصصات.
16
+ ما هو عنوان العيادة الخاصة بكم؟,عنوان العيادة هو: الرياض، حي الربيع، طريق الثمامة، المملكة العربية السعودية.
17
+ ما هي طرق الدفع المتاحة؟,نقبل الدفع عبر البطاقات البنكية (فيزا / ماستركارد / مدى) والمحافظ الرقمية (Apple Pay و STC Pay). كما يمكن الدفع عن طريق التحويل البنكي لبعض الخدمات أو الباقات الكبيرة.
18
+ هل تقدمون باقات اشتراك؟,نعم، نوفر خيارات اشتراك شهرية أو سنوية توفر خصومات إضافية ووصولاً غير محدود لبعض الخدمات.
19
+ ما هي خدمات الدعم الفني المتاحة؟,يتوفر الدعم الفني عبر الدردشة المباشرة (24/7) على الموقع الإلكتروني، والهاتف خلال ساعات العمل، والبريد الإلكتروني. كما يوجد قسم للمساعدة والأسئلة الشائعة.
20
+ هل يمكنكم توصيل الأدوية للمنزل؟,نعم، نوفر خدمة توصيل الأدوية والمستلزمات الطبية إلى باب المنزل بسرعة وأمان.
21
+ هل يمكنني مراجعة تقاريري الطبية ونتائج تحاليلي مع طبيب؟,نعم، تقدم الشركة خدمة مراجعة وتقييم للتقارير الطبية السابقة ونتائج التحاليل المخبرية من قبل أطباء متخصصين.
22
+ ما هي برامج الصحة الوقائية التي تقدمونها؟,تقدم الشركة استشارات حول الوقاية من الأمراض وتغيير نمط الحياة، بالإضافة إلى حملات توعية صحية دورية وبرامج مخصصة لمتابعة المؤشرات الحيوية.
23
+ هل تقدمون خدمات للشركات؟,نعم، نوفر حزم رعاية صحية رقمية للشركات والمؤسسات لرعاية موظفيهم، وبرامج صحية مخصصة لتعزيز رفاهية الموظفين.
24
+ كيف يمكنني الاشتراك في خدماتكم؟,يمكنك الاشتراك بزيارة الموقع الإلكتروني وإنشاء حساب، ثم اختيار الباقة المناسبة، وإدخال معلومات الدفع.
25
+ كيف يمكنني إلغاء الاشتراك؟,يمكن إلغاء الاشتراك عبر تسجيل الدخول إلى حسابك على الموقع ثم التوجه إلى "إدارة الاشتراكات". أو يمكنك التواصل مع فريق الدعم الفني للمساعدة في إتمام عملية الإلغاء.
26
+ هل توفرون خدمة السجلات الطبية الإلكترونية؟,نعم، لدينا نظام آمن لتخزين السجل الطبي الموحد للمريض، بما في ذلك التشخيصات، الأدوية الموصوفة، ونتائج الفحوصات.
27
+ ما هي أوقات عمل الشركة؟,أيام العمل من الأحد إلى الخميس، من 9 صباحًا حتى 9 مساءً بتوقيت المملكة العربية السعودية (EEST).
28
+ هل الشركة تعمل في العطلات الأسبوعية؟,لا، العطلات الأسبوعية هي الجمعة والسبت.
29
+ ما هي سياسة الخصوصية المتعلقة بجمع البيانات؟,يتم جمع البيانات الشخصية والمعلومات الصحية فقط لغرض تقديم الخدمات الطبية وتحسينها، وبموافقة صريحة من المستخدم.
30
+ هل تتم مشاركة بياناتي مع أطراف ثالثة؟,لا يتم مشاركة البيانات الشخصية أو الصحية مع أي طرف ثالث دون إذن مسبق وصريح من المستخدم، إلا في الحالات التي يتطلبها القانون أو بأمر قضائي.
31
+ هل يمكنني تعديل أو حذف بياناتي؟,نعم، يحق للمستخدم الوصول إلى بياناته الشخصية وتعديلها أو طلب حذفها في أي وقت.
32
+ ما هي الشروط التي تحكم استخدام خدمات الشركة؟,من الشروط الأساسية عدم استخدام الخدمة في حالات الطوارئ، وتقديم معلومات صحيحة وكاملة ودقيقة، وأن الشركة غير مسؤولة عن أي سوء استخدام للخدمة.
33
+ هل يمكن الحصول على استشارة بخصوص مشاكل الجهاز الهضمي؟,نعم، الشركة تقدم استشارات مع أطباء عامين ومتخصصين في مختلف التخصصات مثل الباطنية، والتي تشمل مشاكل الجهاز الهضمي.
34
+ هل يمكنني الحصول على استشارة بخصوص مشاكل العيون؟,نعم، من بين التخصصات التي يقدمها أطباؤنا هو تخصص العيون.
35
+ هل يمكنني الحصول على استشارة بخصوص مشاكل الأنف والأذن والحنجرة؟,نعم، توفر الشركة استشارات مع أطباء متخصصين في الأنف والأذن والحنجرة.
36
+ هل يمكنني الحصول على استشارة بخصوص الأمراض الجلدية؟,نعم�� لدينا أطباء متخصصون في الأمراض الجلدية.
37
+ هل يمكنني الحصول على استشارة بخصوص صحة المرأة والولادة؟,نعم، نوفر استشارات مع أطباء نساء وولادة.
38
+ هل يمكنني طلب الأدوية التي لا تتطلب وصفة طبية؟,نعم، يمكنك طلب الأدوية التي لا تتطلب وصفة طبية مباشرة من الصيدلية الرقمية.
39
+ هل يوجد دعم للصحة النفسية؟,نعم، نوفر جلسات استشارية مع أخصائيين نفسيين ومعالجين سلوكيين لدعم الصحة النفسية.
40
+ هل يمكنني الحصول على دعم بخصوص التغذية واللياقة البدنية؟,نعم، تقدم الشركة استشارات في مجالات الصحة العامة، التغذية، واللياقة البدنية.
41
+ ما هو مبدأ تأسيس شركة الشفاء الرقمية؟,تأسست الشركة على مبدأ توفير رعاية طبية شاملة وعالية الجودة عبر الإنترنت.
42
+ ما هو هدف الشركة الأساسي؟,تهدف إلى سد الفجوة بين المرضى والأطباء المتخصصين، وتمكين الأفراد من الحصول على استشارات طبية موثوقة ومتابعة مستمرة.
43
+ كيف تضمنون جودة الرعاية الصحية؟,نضمن أن جميع خدماتنا الطبية تُقدم من قبل أطباء ومتخصصين مؤهلين تأهيلاً عاليًا ويتمتعون بخبرة واسعة في مجالاتهم.
44
+ ما هو الالتزام بالسرية والخصوصية؟,نلتزم بأقصى درجات السرية في التعامل مع بيانات المرضى ومعلوماتهم الصحية، ونطبق بروتوكولات أمان صارمة لضمان حمايتها.
45
+ ماذا يعني "التيسير والسرعة" كقيمة أساسية؟,يعني أن الشركة تهدف إلى جعل الرعاية الصحية سهلة ومتاحة للجميع، بغض النظر عن موقعهم الجغرافي، وتوفر حلولاً سريعة وفعالة للحصول على الاستشارات والمواعيد.
46
+ كيف تبني الشركة الثقة مع المرضى؟,تبني الشركة الثقة من خلال تقديم معلومات واضحة وصادقة حول خدماتها وتكاليفها، وتحرص على بناء علاقات طويلة الأمد قائمة على المصداقية والنزاهة.
47
+ ما هو دور الابتكار في الشركة؟,نتبنى أحدث التقنيات ونبحث دائمًا عن طرق جديدة ومبتكرة لتحسين خدماتنا وتوسيع نطاقها لمواكبة التطورات في مجال الرعاية الصحية الرقمية.
48
+ ماذا تشمل خدمة الاستشارات الطبية عبر الفيديو؟,تشمل استشارات فورية ومجدولة مع أطباء عامين ومتخصصين، وإمكانية التواصل الصوتي والمرئي الآمن والمشفر، وخاصية تبادل الملفات والصور.
49
+ هل يمكنني إجراء فحص جسدي في عيادتكم لجميع التخصصات؟,نعم، تقدم الشركة خدمات الكشف الجسدي في عيادتها الخاصة في جميع التخصصات.
50
+ هل هناك خدمة لمراجعة نتائج التحاليل المخبرية؟,نعم، نقدم خدمة مراجعة وتقييم لنتائج التحاليل المخبرية من قبل أطباء متخصصين لتقديم تفسير واضح وشامل.
51
+ ما هي وظيفة خدمة الصيدلة والتوصيل المنزلي؟,تشمل صرف الوصفات الطبية الإلكترونية وتوصيل الأدوية والمستلزمات الطبية إلى باب المنزل بسرعة وأمان.
52
+ كيف يمكنني حجز موعد مع طبيب متخصص؟,يمكنك استخدام منصة سهلة الاستخدام لحجز مواعيد مع مجموعة واسعة من الأطباء الاستشاريين.
53
+ ماذا تتضمن خدمة الرعاية النفسية؟,تتضمن جلسات استشارية مع أخصائيين نفسيين ومعالجين سلوكيين، وتقديم استشارات في مجالات الصحة العامة وإدارة الإجهاد.
54
+ ما هي فوائد نظام السجلات الطبية الإلكترونية الموحدة (EHR)؟,يخزن السجل الطبي للمريض بشكل آمن، ويمكّن الأطباء من الوصول إليه لتوفير رعاية أكثر دقة، ويقلل من الحاجة لتكرار الفحوصات.
55
+ ما هي برامج الطب عن بُعد التي تقدمونها للمؤسسات؟,نقدم حزم رعاية صحية رقمية للشركات لرعاية موظفيهم، وبرامج صحية مخصصة لتعزيز رفاهيتهم.
56
+ ما هو رقم هاتف الشركة؟,رقم هاتف الشركة هو 9200-000-000.
57
+ ما هو البريد الإلكتروني للدعم؟,البريد الإلكتروني للدعم هو support@alshifa-care.com.
58
+ هل يمكنني استخدام الدردشة المباشرة للدعم الفني؟,نعم، الدردشة المباشرة متاحة على مدار الساعة (24/7) على الموقع الإلكتروني لتقديم المساعدة الفورية.
59
+ ما هي المحافظ الرقمية التي تقبلونها للدفع؟,نقبل الدفع السريع والآمن عبر Apple Pay و STC Pay.
60
+ ماذا يحدث إذا قدمت معلومات طبية غير دقيقة؟,أي معلومات غير دقيقة قد تؤثر سلبًا على جودة الرعاية المقدمة، والشركة غير مسؤولة عن أي نتائج سلبية تنجم عن ذلك.
61
+ هل يمكنني استخدام محتوى الموقع لأغراض شخصية؟,جميع المحتويات والمواد على المنصة هي ملك للشركة، ويُمنع نسخها أو تعديلها أو إعادة نشرها دون إذن كتابي مسبق.
62
+ هل تحتفظ الشركة بالحق في تعديل شروط الاستخدام؟,نعم، تحتفظ الشركة بالحق في تعديل شروط الاستخدام في أي وقت دون إشعار مسبق.
63
+ بموجب أي قانون يتم تفسير شروط الاستخدام؟,تخضع شروط الاستخدام وتُفسر وفقًا لقوانين المملكة العربية السعودية.
64
+ كيف يتم إخطار المستخدمين بالتحديثات على سياسة الخصوصية؟,سيتم إخطار المستخدمين بأي تغييرات جوهرية في سياسة الخصوصية من خلال الموقع الإلكتروني أو البريد الإلكتروني.
65
+ هل يمكنني التحكم في إعدادات ملفات تعريف الارتباط؟,نعم، يمكن للمستخدمين التحكم في إعدادات ملفات تعريف الارتباط (Cookies) من خلال متصفحاتهم.
66
+ هل يمكنني حجز موعد مع أطباء في تخصصات نادرة؟,نعم، المنصة تمكّنك من حجز مواعيد مع مجموعة واسعة من الأطباء الاستشاريين في تخصصات نادرة أو دقيقة.
67
+ ما هو الغرض من استخدام البيانات المجمعة (التي لا تحدد هوية فردية)؟,قد تُستخدم البيانات المجمعة لأغراض البحث والإحصاءات لتحسين الخدمات الصحية بشكل عام.
68
+ هل يمكنني حجز موعد للحصول على استشارة مع طبيب عام؟,نعم، يمكنك حجز استشارات فورية ومجدولة مع أطباء عامين.
69
+ كيف يمكنني العثور على الأطباء المناسبين لي؟,يمكنك الاطلاع على الملفات الشخصية للأطباء، خبراتهم، وتقييمات المرضى الآخرين لاختيار الأنسب.
70
+ ما هي أنواع الخدمات التي يمكن أن أحصل عليها عبر الفيديو؟,يمكنك الحصول على استشارات فورية أو مجدولة مع أطباء عامين ومتخصصين، بالإضافة إلى جلسات متابعة مستمرة للحالات المزمنة.
71
+ هل يتم تشفير الاتصالات عبر الفيديو؟,نعم، يتم تشفير التواصل الصوتي والمرئي بشكل آمن ومشفر.
72
+ هل يمكن تبادل الملفات والصور خلال الاستشارة؟,نعم، تتوفر خاصية تبادل الملفات والصور لتحسين جودة التشخيص.
73
+ هل يمكنني حجز مواعيد للكشف الجسدي في العيادة؟,نعم، يمكنك حجز المواعيد المسبقة لضمان حصولك على الرعاية اللازمة في الوقت المناسب.
74
+ هل يمكنني الحصول على شرح مفصل لنتائج تحاليلي المخبرية؟,نعم، تقدم الشركة شرحًا مفصلاً لنتائج التحاليل المخبرية وربطها بالحالة الصحية العامة للمريض.
75
+ هل يمكنني الحصول على توصيات بناءً على نتائج تحاليلي؟,نعم، يتم تقديم توصيات بناءً على النتائج لمساعدة المرضى على فهم حالتهم الصحية بشكل أفضل.
76
+ ما هو هدف الشركة من برامج الصحة الوقائية؟,الهدف هو توعية صحية دورية حول الأمراض الشائعة وطرق الوقاية منها.
77
+ ماذا يحدث في حالة عدم اتباع إرشادات الطبيب؟,الشركة غير مسؤولة عن أي نتائج سلبية تنجم عن عدم اتباع إرشادات الطبيب.
78
+ هل يمكنني استخدام المنصة باللغة الإنجليزية؟,نعم، يمكن توفير استشارات باللغة الإنجليزية حسب توفر الأطباء المتحدثين بهذه اللغات.
79
+ ما هو هدف الشركة من بناء مجتمع صحي واعي؟,تطمح الشركة إلى بناء مجتمع صحي واعي، حيث تكون الوقاية والعلاج السريع جزءًا لا يتجزأ من الثقافة العامة.
80
+ ما هو الغرض من السجلات الطبية الإلكترونية الموحدة؟,يقلل النظام من الحاجة لتكرار الفحوصات ويسهل عملية المتابعة.
81
+ ما هي الالتزامات القانونية التي تتبعها الشركة في حماية البيانات؟,تلتزم الشركة بجميع اللوائح والقوانين المتعلقة بحماية البيانات الصحية، مثل قانون حماية البيانات العامة (GDPR) ومعايير HIPAA حيثما ينطبق ذلك.
82
+ ما هو التشفير المستخدم لحماية البيانات؟,يتم تشفير جميع الاتصالات والبيانات باستخدام أحدث بروتوكولات الأمان مثل AES-256 و TLS 1.2.
83
+ ما هي حقوق المستخدم بخصوص بياناته؟,يحق للمستخدم الوصول إلى بياناته الشخصية، وتعديلها، أو طلب حذفها في أي وقت.
84
+ هل يمكن للمستخدم سحب موافقته على معالجة البيانات؟,نعم، يحق للمستخدم سحب موافقته على معالجة البيانات، شريطة ألا يتعارض ذلك مع الالتزامات القانونية.
85
+ هل يمكنني استخدام خدمات الشركة في عطلة رسمية؟,قد تكون الشركة مغلقة خلال الأعياد الرسمية في المملكة العربية السعودية، ولكن قد تتوفر بعض خدمات الدعم الفني أو الدردشة المباشرة.
86
+ كيف يمكنني معرفة التغييرات في أوقات العمل خلال العطلات؟,سيتم الإعلان عن أي تغييرات في أوقات العمل خلال العطلات مسبقًا عبر الموقع ووسائل التواصل الاجتماعي.
87
+ ماذا يحدث بعد إتمام عملية الاشتراك؟,ستتلقى تأكيدًا عبر البريد الإلكتروني، ويمكنك البدء في حجز المواعيد والاستفادة من الخدمات.
88
+ هل هناك سياسات مختلفة للإلغاء حسب نوع الاشتراك؟,نعم، يرجى مراجعة شروط الاشتراك في كل باقة، حيث قد تختلف سياسات الإلغاء والاسترداد بناءً على نوع الخدمة أو مدة الاشتراك.
89
+ ما هو الغرض من استخدام ملفات تعريف الارتباط (Cookies)؟,نستخدم ملفات تعريف الارتباط لتحسين تجربة التصفح، تحليل أداء الموقع، وتخصيص المحتوى.
90
+ هل يمكنني الحصول على توصيات بخصوص نمط الحياة لتعزيز الصحة العامة؟,نعم، تقدم الشركة استشارات حول الوقاية من الأمراض وتغيير نمط الحياة لتعزيز الصحة العامة.
91
+ هل يمكنني الحصول على دعم لبرامج إدارة الإجهاد؟,نعم، نوفر استشارات في مجالات الصحة العامة وإدارة الإجهاد.
92
+ ما هو عنوان الموقع الإلكتروني للشركة؟,الموقع الإلكتروني هو [www.alshifa-care.com](https://www.google.com/search?q=https://www.alshifa-care.com).
93
+ ما هي وسائل التواصل الاجتماعي الخاصة بالشركة؟,يمكن التواصل مع الشركة عبر تويتر (X)، لينكد إن، فيسبوك، وإنستغرام.
94
+ هل يمكنني تقديم ملاحظاتي أو مشاكل عبر البريد الإلكتروني؟,نعم، يمكنك إرسال استفساراتكم أو مشاكلكم عبر البريد الإلكتروني، وسيقوم فريق الدعم بالرد في أقرب وقت.
95
+ ما هي أنواع الباقات والعضويات التي تقدمونها؟,تقدم الشركة خيارات اشتراك شهرية أو سنوية توفر خصومات إضافية ووصولاً غير محدود لبعض الخدمات.
96
+ هل يمكنني الحصول على مساعدة فورية للدعم الفني؟,نعم، الدردشة المباشرة متوفرة على مدار الساعة (24/7) لتقديم المساعدة الفورية.
97
+ ما هي الميزات المتاحة عند حجز موعد مع طبيب متخصص؟,يمكنك الاطلاع على الملفات الشخصية للأطباء، خبراتهم، وتقييمات المرضى الآخرين.
98
+ ما هو الهدف من السجلات الطبية الإلكترونية الموحدة؟,يُمكّن السجل الأطباء من الوصول إلى السجل الطبي للمريض (بموافقته) لتوفير رعاية أكثر دقة وشمولية.
99
+ هل يمكن للمستخدمين الحصول على دليل شامل للأسئلة الشائعة؟,نعم، يتوفر على الموقع قسم للمساعدة والأسئلة الشائعة يحتوي على إجابات لمعظم الاستفسارات.
100
+ ما هو الغرض من تأسيس شركة الشفاء الرقمية؟,الغرض هو سد الفجوة بين المرضى والأطباء المتخصصين، وتمكين الأفراد من الحصول على استشارات طبية موثوقة ومتابعة مستمرة.
101
+ ماذا تعني كلمة "التعاطف والرعاية" كقيمة أساسية للشركة؟,تعني أن الشركة تتعامل مع كل مريض كفرد فريد وتقدم الرعاية بتعاطف وتفهم، مع الحرص على توفير بيئة داعمة ومريحة.
102
+ هل يمكنني الحصول على استشارة طبية بخصوص الأطفال؟,نعم، لدينا أطباء متخصصون في تخصص الأطفال.
103
+ ما هي المدة التي يمكنني خلالها طلب استرداد المبلغ؟,يمكن طلب استرداد المبلغ خلال 24 ساعة من تقديم الخدمة أو عدم إتمامها.
104
+ هل هناك خصومات عند الاشتراك في باقات طويلة الأمد؟,نعم، خيارات الاشتراك الشهرية أو السنوية توفر خصومات إضافية.
105
+ هل يمكنني الحصول على وصفة طبية إلكترونية؟,نعم، يمكن إرسال الوصفة إلكترونيًا إذا رأى الطبيب ضرورة لذلك.
106
+ ما هي المسؤولية الملقاة على عاتق المستخدم؟,يجب على المستخدم تقديم معلومات طبية وشخصية صحيحة وكاملة ودقيقة أثناء التسجيل وخلال الاستشارات.
107
+ ما هي الخدمات التي تقدمونها للمتابعة بعد العمليات الجراحية؟,نوفر جلسات متابعة مستمرة للحالات بعد العمليات الجراحية.
108
+ هل يتم تقييم أداء الأطباء؟,نعم، يتم تقييم أداء الأطباء بانتظام بناءً على معايير الجودة ورضا المرضى.
109
+ ما هو التزام الشركة تجاه التكنولوجيا؟,تلتزم الشركة بتسخير أحدث التكنولوجيا الرقمية لبناء جسر فعال بين المرضى والخبراء الطبيين.
110
+ ما هي الفائدة من نظام السجلات الطبية الإلكترونية للمرضى؟,يمكّن النظام المريض من الوصول إلى سجله الطبي.
111
+ كيف يمكنني التواصل مع الدعم الفني عبر الهاتف؟,يتوفر فريق دعم مخصص جاهز للإجابة على الاستفسارات التقنية والخدمية خلال ساعات العمل الرسمية.
112
+ هل يمكنني حجز موعد مع أخصائي نفسي؟,نعم، نوفر جلسات استشارية مع أخصائيين نفسيين ومعالجين سلوكيين.
113
+ ما هو الهدف من خدمة تحليل نتائج المختبر؟,الهدف هو توجيه المريض إلى التحاليل اللازمة بناءً على الأعراض أو التاريخ المرضي.
114
+ هل يمكنني طلب الأدوية بدون وصفة من الصيدلية الرقمية؟,نعم، يمكنك طلب الأدوية التي لا تتطلب وصفة طبية مباشرة من الصيدلية الرقمية.
115
+ هل يمكنني حجز استشارة لأحد كبار السن من عائلتي؟,نعم، يمكنك حجز استشارة نيابة عن أحد كبار السن مع مراعاة الحصول على موافقته.
116
+ ما هي فوائد برامج الصحة الوقائية للموظفين؟,البرامج الصحية المخصصة للشركات تهدف إلى تعزيز رفاهية الموظفين وتقليل التغيب عن العمل.
117
+ هل هناك أي محتوى على المنصة محمي بحقوق الملكية الفكرية؟,نعم، جميع المحتويات والمواد المتوفرة على المنصة هي ملك لشركة الشفاء الرقمية ومحمية بموجب قوانين الملكية الفكرية.
118
+ ما هو الدور الأساسي لشركة الشفاء الرقمية؟,دورها هو أن تكون شركة رائدة ومتطورة في مجال الرعاية الصحية عن بُعد.
119
+ هل يمكنني الحصول على استشارات بخصوص الأمراض المزمنة؟,نعم، نوفر جلسات متابعة مستمرة للحالات المزمنة.
120
+ كيف يمكنني العثور على معلومات حول خبرات الأطباء؟,يمكنك الاطلاع على الملفات الشخصية للأطباء، والتي تتضمن خبراتهم.
121
+ هل يتم تحديث سياسة الخصوصية؟,نعم، قد يتم تحديث سياسة الخصوصية من وقت لآخر، وسيتم إخطار المستخ��مين بأي تغييرات جوهرية.
122
+ ما هي الإجراءات الأمنية المطبقة على خوادم وقواعد بيانات الشركة؟,يتم تطبيق إجراءات أمنية صارمة على الخوادم وقواعد البيانات لمنع الوصول غير المصرح به.
123
+ هل يمكنني الحصول على دعم فني خارج ساعات العمل الرسمية؟,قد تتوفر بعض خدمات الدعم الفني أو الدردشة المباشرة خارج ساعات العمل المحددة.
124
+ ما هو دور "الشفافية" كقيمة أساسية؟,تعني بناء الثقة مع المرضى من خلال تقديم معلومات واضحة وصادقة حول الخدمات وتكاليفها، وضمان الحصول على رأي طبي دقيق وموثوق به.
125
+ ما هي التخصصات المتاحة للاستشارات الطبية عبر الفيديو؟,تشمل التخصصات الباطنية، الأطفال، الجلدية، النساء والولادة، العيون، والأنف والأذن والحنجرة.
126
+ كيف يمكنني حجز موعد للكشف الجسدي في عيادتكم؟,يمكنك حجز المواعيد المسبقة لضمان حصولك على الرعاية اللازمة في الوقت المناسب.
127
+ هل يمكنني الحصول على تقييم لنتائج صور الأشعة؟,نعم، تقدم الشركة خدمة مراجعة وتقييم لصور الأشعة من قبل أطباء متخصصين.
128
+ هل يمكنني طلب توصيل أدوية لا تتطلب وصفة طبية؟,نعم، يمكنك طلب الأدوية التي لا تتطلب وصفة طبية مباشرة من الصيدلية الرقمية.
129
+ ما هو الغرض من نظام السجلات الطبية الإلكترونية الموحدة؟,يهدف إلى توفير رعاية أكثر دقة وشمولية عن طريق تمكين الأطباء من الوصول إلى السجل الطبي للمريض.
130
+ هل يمكن أن تساعدوني في فهم حالتي الصحية بشكل أفضل بناءً على نتائج التحاليل؟,نعم، يتم تقديم توصيات بناءً على النتائج ومساعدة المرضى على فهم حالتهم الصحية بشكل أفضل.
131
+ هل يمكنني الحصول على دعم بخصوص مؤشراتي الحيوية؟,نعم، نوفر برامج مخصصة لمتابعة المؤشرات الحيوية (مثل ضغط الدم، السكري) للأشخاص المعرضين للخطر.
132
+ ما هي الفائدة من حجز مواعيد مع متخصصين عبر المنصة؟,تمكنك المنصة من الاطلاع على الملفات الشخصية للأطباء، خبراتهم، وتقييمات المرضى الآخرين لاختيار الأنسب.
133
+ ماذا يحدث إذا كان هناك نزاع قضائي؟,في حالة وجود أي نزاعات، يكون الاختصاص القضائي للمحاكم المختصة في المملكة العربية السعودية.
134
+ هل يمكنني استخدام الدردشة المباشرة لطرح أسئلة حول خدمات الشركة؟,نعم، الدردشة المباشرة متاحة لتقديم المساعدة الفورية والإجابة على الاستفسارات.
135
+ هل يمكنني الحصول على دعم لبرامج التغذية؟,نعم، نقدم استشارات في مجالات الصحة العامة والتغذية.
136
+ ما هو التزام الشركة تجاه جودة الحياة؟,تهدف الشركة إلى إحداث فرق حقيقي وملموس في جودة حياة الأفراد والمجتمعات.
137
+ ما هي أنواع البطاقات البنكية التي تقبلونها للدفع؟,نقبل جميع البطاقات الائتمانية والخصم المباشر الرئيسية (فيزا / ماستركارد / مدى).
138
+ هل يمكنني الحصول على استشارة بخصوص الحالات المزمنة؟,نعم، نوفر جلسات متابعة مستمرة للحالات المزمنة.
139
+ ما هي طرق التواصل الأخرى المتاحة غير الهاتف والبريد الإلكتروني؟,يمكن التواصل عبر الموقع الإلكتروني ووسائل التواصل الاجتماعي مثل تويتر، لينكد إن، وفيسبوك.
140
+ ما هو هدف الشركة في مجال الرعاية الصحية؟,الهدف هو جعل الرعاية الصحية في متناول الجميع، وتقديم حلول مبتكرة تسهل وصول المرضى للخدمات التي يحتاجونها دون عناء.
141
+ هل يمكنني حجز استشارة لأطفالي؟,نعم، يمكنك حجز استشارة نيابة عن أطفالك.
142
+ ما هو نطاق عمل الشركة؟,نطاق العمل يشمل الرعاية الصحية عن بُعد.
143
+ كيف يمكنني التأكد من أن الأطباء مؤهلون؟,جميع الأطباء يخضعون لعملية تد��يق صارمة لضمان أعلى مستويات الكفاءة والاحترافية.
144
+ هل يمكنني الحصول على استشارة بخصوص مشاكل الباطنية؟,نعم، لدينا أطباء باطنية متخصصون.
145
+ ما هي الخيارات المتاحة لطلب الأدوية؟,يمكنك الحصول على الوصفات الطبية الإلكترونية وتوصيل الأدوية للمنزل.
146
+ هل يمكنني الحصول على دعم بخصوص الصحة العامة؟,نعم، نقدم استشارات في مجالات الصحة العامة.
147
+ كيف يتم حماية معلوماتي الشخصية والطبية؟,تستخدم الشركة تقنيات التشفير المتقدمة لحماية جميع الاتصالات والبيانات المخزنة.
148
+ هل يمكنني معرفة تقييمات المرضى الآخرين للأطباء؟,نعم، يمكنك الاطلاع على تقييمات المرضى الآخرين عند اختيار الطبيب.
149
+ هل يمكنني طلب الدعم الفني عن طريق الهاتف؟,نعم، يتوفر فريق دعم مخصص عبر الهاتف خلال ساعات العمل الرسمية.
150
+ هل يمكنني حجز موعد مع أخصائي في اللياقة البدنية؟,نعم، نقدم استشارات في مجالات اللياقة البدنية.
151
+ ما هو هدف الشركة في بناء جسر فعال بين المرضى والخبراء؟,الهدف هو تقديم خدمات طبية موثوقة وآمنة وسهلة الوصول لجميع أفراد المجتمع.
152
+ هل يمكنني الحصول على توصيات بناءً على التحاليل المخبرية؟,نعم، يتم تقديم توصيات بناءً على النتائج ومساعدة المرضى على فهم حالتهم الصحية.
153
+ هل يمكنني الحصول على استشارة بخصوص برامج دعم شاملة للحالات المزمنة؟,نعم، نوفر برامج دعم شاملة للمرضى الذين يعانون من حالات صحية مزمنة.
154
+ هل يمكنني الوصول إلى سجلاتي الطبية من أي مكان؟,نعم، يوفر النظام السجل الطبي الإلكتروني الموحد الذي يمكن الوصول إليه (بموافقتك).
155
+ هل هناك أي برامج توعية صحية تقدمونها؟,نعم، نوفر حملات توعية صحية دورية عبر المنصة حول الأمراض الشائعة وطرق الوقاية منها.
156
+ ما هي أنواع الاستشارات التي تقدمونها للأطباء العامين؟,نقدم استشارات فورية ومجدولة مع أطباء عامين.
157
+ هل يمكنني حجز موعد مع طبيب باطنية؟,نعم، يمكنك حجز موعد مع طبيب متخصص في تخصص الباطنية.
158
+ هل يمكنني الحصول على استشارة عن طريق الهاتف؟,نعم، من بين الخدمات المتاحة التواصل الصوتي والمرئي.
159
+ هل يمكنني حجز موعد عبر الموقع الإلكتروني؟,نعم، يمكن حجز المواعيد المسبقة لضمان حصولك على الرعاية اللازمة.
160
+ هل تقدمون خدمات للعائلات؟,نعم، نقدم خيارات اشتراك متعددة تناسب احتياجات الأفراد والعائلات.
161
+ ما هي المدة المتوقعة للرد على استفسارات البريد الإلكتروني؟,يتم الرد على استفسارات البريد الإلكتروني خلال 24 ساعة عمل.
162
+ ما هي فوائد العضويات السنوية؟,توفر العضويات السنوية خصومات إضافية ووصولاً غير محدود لبعض الخدمات.
163
+ ما هي أهمية "الاحترافية" كقيمة أساسية؟,تعني أن الشركة تضمن أن جميع خدماتها الطبية تُقدم من قبل متخصصين مؤهلين، وتلتزم بأعلى معايير الرعاية الصحية العالمية.
164
+ هل يمكنني طلب الأدوية التي وصفت لي إلكترونياً؟,نعم، يمكنك صرف الوصفات الطبية الإلكترونية التي يكتبها أطباؤنا.
165
+ هل يمكنني حجز استشارة في أي وقت؟,نعم، يمكنك الحصول على استشارات فورية أو مجدولة.
166
+ ما هو التزام الشركة تجاه الشفافية؟,نلتزم بتقديم معلومات واضحة وصادقة حول خدماتنا وتكاليفها.
167
+ هل يمكنني استخدام تطبيق Apple Pay للدفع؟,نعم، يمكنك الدفع السريع والآمن عبر تطبيق Apple Pay.
168
+ ما هي أنواع الاستشارات النفسية التي تقدمونها؟,نقدم جلسات استشارية مع أخصائيين نفسيين ومعالجين سلوكيين.
169
+ هل يمكنني الحصول على استشارة بخصوص مشاكل النساء والولادة؟,نعم، ��وفر استشارات مع أطباء نساء وولادة.
170
+ ما هي شروط الاشتراك في الخدمات؟,باستخدامك لخدمات الشركة، فإنك توافق على الالتزام بالشروط والأحكام.
171
+ هل يمكنني الحصول على استشارة من أخصائي تغذية؟,نعم، نقدم استشارات في مجالات التغذية.
172
+ هل يمكنني الحصول على معلومات حول كيفية الوقاية من الأمراض؟,نعم، تقدم الشركة استشارات حول الوقاية من الأمراض وتغيير نمط الحياة لتعزيز الصحة العامة.
173
+ ما هو الغرض من تقديم استشارات طبية عبر الفيديو؟,الغرض هو توفير رعاية طبية شاملة وعالية الجودة في أي وقت ومن أي مكان.
174
+ هل يمكنني حجز موعد مع أخصائي نفسي عبر الفيديو؟,نعم، يمكنك حجز جلسات استشارية مع أخصائيين نفسيين.
175
+ ما هو هدف الشركة من تقديم خدمات الطب عن بُعد للمؤسسات؟,الهدف هو تقديم حزم رعاية صحية رقمية للشركات لرعاية موظفيهم وتعزيز رفاهيتهم.
176
+ ما هي إجراءات الأمان المتبعة لحماية البيانات؟,يتم تشفير جميع الاتصالات والبيانات باستخدام أحدث بروتوكولات الأمان.
177
+ هل يمكنني الاطلاع على ملفات الأطباء المتوفرين؟,نعم، يمكنك تصفح ملفات الأطباء المتوفرين والاطلاع على تخصصاتهم وخبراتهم.
178
+ هل يمكنني إلغاء الاشتراك بنفسي؟,نعم، يمكنك تسجيل الدخول إلى حسابك وإلغاء الاشتراك من "إدارة الاشتراكات".
179
+ ما هي المعلومات التي يتم جمعها؟,يتم جمع البيانات الشخصية (مثل الاسم والعمر) والمعلومات الصحية (التاريخ المرضي والتشخيصات).
180
+ ما هو الغرض من "التعاطف والرعاية" في تعاملكم مع المرضى؟,التعامل مع كل مريض كفرد فريد وتقديم الرعاية بتعاطف وتفهم، مع توفير بيئة داعمة ومريحة.
181
+ ما هي أنواع الملفات التي يمكن تبادلها خلال الاستشارة؟,يمكن تبادل الملفات والصور لتحسين جودة التشخيص.
182
+ هل يمكنني طلب مساعدة من الدعم الفني عبر الهاتف في أي وقت؟,فريق الدعم المخصص متوفر للإجابة على الاستفسارات التقنية والخدمية خلال ساعات العمل الرسمية.
183
+ ما هي وسائل التواصل الاجتماعي المتاحة لشركة الشفاء الرقمية؟,تويتر (X)، لينكد إن، فيسبوك، وإنستغرام.
184
+ ماذا يحدث إذا واجهت صعوبة في إلغاء الاشتراك؟,يمكنك التواصل مع فريق الدعم الفني لمساعدتك في إتمام عملية الإلغاء.
185
+ ما هو الغرض من "التيسير والسرعة"؟,الهدف هو جعل الرعاية الصحية سهلة ومتاحة للجميع، وتوفير حلولاً سريعة وفعالة للحصول على الاستشارات.
186
+ هل يمكنني الحصول على استشارة بخصوص مشاكل الأذن؟,نعم، لدينا أطباء متخصصون في الأنف والأذن والحنجرة.
187
+ ما هو الالتزام الأساسي لسياسة الخصوصية؟,تتعهد سياسة الخصوصية بجمع البيانات فقط لغرض تقديم الخدمات الطبية وتحسينها، وبموافقة صريحة من المستخدم.
188
+ هل يمكنني طلب الأدوية التي تتطلب وصفة طبية؟,نعم، يمكن صرف الوصفات الطبية الإلكترونية التي يكتبها أطباؤنا.
189
+ هل يتم حفظ السجل الطبي الإلكتروني للمريض؟,نعم، يتم تخزين السجل الطبي للمريض بشكل آمن.
190
+ ما هي القيمة المضافة من استخدام التكنولوجيا في الشركة؟,تسخير أحدث التكنولوجيا الرقمية لبناء جسر فعال بين المرضى والخبراء الطبيين.
191
+ هل يمكنني حجز استشارة للأطفال؟,نعم، يمكنك حجز استشارة نيابة عن الأطفال.
192
+ ما هي فوائد الاستشارات الطبية عبر الفيديو؟,تمكنك من الحصول على استشارات طبية موثوقة ومتابعة مستمرة في أي وقت ومن أي مكان.
193
+ هل يمكنني الدفع عبر المحافظ الرقمية؟,نعم، يمكنك الدفع عبر تطبيق Apple Pay و STC Pay.
194
+ ما هو عنوان البريد الإلكتروني للدعم الفني؟,البريد ا��إلكتروني للدعم هو support@alshifa-care.com.
195
+ ما هي شروط الاستخدام المتعلقة بالملكية الفكرية؟,يُمنع نسخ، تعديل، توزيع، أو إعادة نشر أي من المواد الموجودة على المنصة دون إذن كتابي مسبق.
196
+ هل يمكنني حجز موعد مع أخصائي سلوكي؟,نعم، نقدم جلسات استشارية مع أخصائيين نفسيين ومعالجين سلوكيين.
197
+ ما هي فوائد نظام السجلات الطبية الإلكترونية؟,يقلل من الحاجة لتكرار الفحوصات ويسهل عملية المتابعة.
198
+ هل يمكنني الحصول على دعم بخصوص إدارة الإجهاد؟,نعم، نقدم استشارات في مجالات إدارة الإجهاد.
199
+ ما هي أوقات العمل الرسمية للشركة؟,من الأحد إلى الخميس، من 9 صباحًا حتى 9 مساءً بتوقيت المملكة العربية السعودية (EEST).
200
+ هل يمكنني طلب استشارة بخصوص الأمراض الشائعة؟,نعم، نوفر حملات توعية صحية دورية حول الأمراض الشائعة وطرق الوقاية منها.
201
+ ما هي طريقة تصفح الأطباء المتاحة؟,يمكنك تصفح ملفات الأطباء المتوفرين، والاطلاع على تخصصاتهم، خبراتهم، وتقييمات المرضى الآخرين.
202
+ هل يمكنني الحصول على شرح لتاريخي المرضي؟,نعم، يتم تخزين السجل الطبي للمريض بما في ذلك التشخيصات والأدوية الموصوفة وتاريخ الاستشارات.
203
+ هل يمكنني حجز موعد للكشف الجسدي في عيادتكم في أي وقت؟,يمكنك حجز المواعيد المسبقة لضمان حصولك على الرعاية اللازمة في الوقت المناسب.
204
+ ما هي سياسة الدفع عند استخدام الباقات الكبيرة؟,يمكن الترتيب للدفع عن طريق التحويل البنكي لبعض الخدمات أو الباقات الكبيرة.
205
+ هل يمكنني الحصول على دعم لبرامج متابعة السكري؟,نعم، نوفر برامج مخصصة لمتابعة المؤشرات الحيوية مثل السكري للأشخاص المعرضين للخطر.
206
+ ما هي شروط الاستخدام المتعلقة بالقانون الحاكم؟,تخضع شروط الاستخدام وتُفسر وفقًا لقوانين المملكة العربية السعودية.
207
+ ما هو الغرض من استخدام ملفات تعريف الارتباط؟,الهدف هو تحسين تجربة التصفح، تحليل أداء الموقع، وتخصيص المحتوى.
208
+ هل يمكنني طلب الأدوية التي تتطلب وصفة طبية إلكترونياً؟,نعم، يمكن صرف الوصفات الطبية الإلكترونية التي يكتبها أطباؤنا.
209
+ هل يتم تخزين بياناتي بشكل آمن؟,نعم، يتم تطبيق إجراءات أمنية صارمة على خوادمنا وقواعد بياناتنا لمنع الوصول غير المصرح به.
210
+ ما هو التزام الشركة تجاه خصوصية المريض؟,خصوصية المريض هي على رأس أولوياتنا، ونلتزم بأقصى درجات السرية.
211
+ ما هي أنواع الخدمات التي يمكن أن أحصل عليها للرعاية النفسية؟,يمكنك الحصول على جلسات استشارية مع أخصائيين نفسيين ومعالجين سلوكيين.
212
+ ما هو نطاق التخصصات المتاحة للاستشارات؟,لدينا أطباء متخصصون في مختلف التخصصات مثل الباطنية، الأطفال، الجلدية، النساء والولادة، العيون، والأنف والأذن والحنجرة.
213
+ هل يمكنني الحصول على مساعدة فورية للدعم الفني؟,نعم، الدردشة المباشرة متوفرة على مدار الساعة (24/7) على موقعنا الإلكتروني.
214
+ ما هي أنواع الاستشارات التي تقدمونها للأطفال؟,نقدم استشارات مع أطباء متخصصين في تخصص الأطفال.
215
+ ما هو التزام الشركة تجاه جودة الرعاية؟,نلتزم بتقديم أعلى معايير الرعاية الصحية وفقًا لأفضل الممارسات العالمية.
216
+ ما هي فوائد برامج الصحة الوقائية؟,تساعد على الوقاية من الأمراض وتغيير نمط الحياة لتعزيز الصحة العامة.
217
+ ما هي شروط الاستخدام المتعلقة بالطوارئ الطبية؟,تُخصص خدماتنا للحالات غير الطارئة فقط، ويجب البحث عن رعاية طبية فورية في حالة الطوارئ.
218
+ هل يمكنني استخدام خدمة الصيدلة لتوصيل الأدوية الموصوفة لي؟,نعم، يمكنك صرف الوصفات الطبية الإلكترونية وتوصيل الأدوية إليك
219
+ هل الصيدلية الإلكترونية توفر جميع أنواع الأدوية؟,تسعى صيدليتنا لتوفير مجموعة واسعة من الأدوية والمستلزمات الطبية، بما في ذلك الأدوية الموصوفة وغير الموصوفة.
220
+ ما هي المدة الزمنية لتوصيل الأدوية؟,تختلف مدة التوصيل حسب الموقع الجغرافي، ولكننا نسعى لتوصيل الأدوية في أقرب وقت ممكن.
221
+ هل تتوفر خدمة توصيل الأدوية في جميع مناطق المملكة؟,نعمل على توسيع نطاق تغطية خدمة التوصيل لتشمل معظم مناطق المملكة العربية السعودية.
222
+ هل يمكنني استلام الأدوية من الصيدلية بدلاً من التوصيل؟,حالياً، الخدمة الأساسية هي التوصيل المنزلي، ولكن يمكنك الاستفسار من فريق الدعم عن خيارات أخرى إن وجدت.
223
+ هل يمكنني الحصول على استشارة لمتابعة حالة مزمنة؟,نعم، نقدم خدمات متابعة للحالات المزمنة لضمان استمرارية الرعاية الصحية.
224
+ هل يمكنني حجز استشارة لأحد أفراد أسرتي؟,نعم، يمكنك حجز استشارة لأفراد عائلتك، مع ضرورة تقديم معلوماتهم الطبية الصحيحة.
225
+ هل تقدمون استشارات للأطفال؟,نعم، لدينا أطباء متخصصون في طب الأطفال لتقديم الاستشارات اللازمة.
226
+ هل تتوفر استشارات الرعاية النفسية لجميع الأعمار؟,نعم، نقدم استشارات نفسية لمختلف الفئات العمرية بما في ذلك الأطفال، المراهقين، والبالغين.
227
+ ما هي سياسة الخصوصية الخاصة بالبيانات الطبية؟,يتم جمع البيانات الشخصية فقط لتقديم الخدمة، ولا يتم مشاركتها مع أي طرف ثالث دون إذن مسبق، ويتم تشفير جميع الاتصالات والبيانات.
228
+ هل يمكنني طلب نسخة من سجلي الطبي عبر المنصة؟,نعم، يمكنك طلب الوصول إلى سجلك الطبي المحفوظ لدينا وفقًا لسياسة الخصوصية وشروط الاستخدام.
229
+ هل الخدمات متوفرة خارج المملكة العربية السعودية؟,حالياً، نركز على خدمة العملاء داخل المملكة العربية السعودية، ولكننا ندرس التوسع المستقبلي.
230
+ هل يمكنني تغيير موعد الاستشارة المحجوز؟,نعم، يمكنك تغيير موعد الاستشارة من خلال حسابك أو بالتواصل مع الدعم الفني، مع مراعاة سياسة الإلغاء والتعديل.
231
+ هل يمكن إلغاء الاستشارة واسترداد المبلغ؟,يمكن إلغاء الاستشارة وطلب استرداد المبلغ إذا تم الإلغاء خلال الفترة المحددة في شروط الخدمة.
232
+ هل أحتاج إلى دفع رسوم إضافية على الاستشارة؟,الرسوم موضحة ضمن تفاصيل الباقة أو الخدمة المختارة. قد تفرض رسوم إضافية لخدمات معينة يتم توضيحها مسبقاً.
233
+ هل توفرون خدمة عملاء باللغة الإنجليزية؟,نعم، يتوفر لدينا دعم عملاء يتحدث اللغة الإنجليزية بالإضافة إلى اللغة العربية.
234
+ ما هي الخطوات المتبعة عند الشعور بتحسن بعد الاستشارة؟,ننصح بمتابعة خطة العلاج الموصوفة، وفي حال الحاجة، يمكنك حجز استشارة متابعة مع نفس الطبيب.
235
+ هل يمكنني تقييم الطبيب بعد الاستشارة؟,نعم، نشجع المستخدمين على تقييم الأطباء بعد كل استشارة للمساهمة في تحسين جودة الخدمة.
236
+ هل يمكنني تقديم شكوى في حال عدم رضائي عن الخدمة؟,نعم، يمكنك تقديم شكوى عبر قنوات الدعم المتاحة، وسنتعامل معها بجدية واهتمام.
237
+ هل تتوفر باقات اشتراك شهرية أو سنوية؟,نعم، نوفر باقات اشتراك شهرية وسنوية لتلبية الاحتياجات المختلفة، مع مزايا وخصومات خاصة.
238
+ هل هناك فترة تجريبية مجانية للخدمات؟,حالياً لا توجد فترة تجريبية مجانية، ولكن قد نقدم عروضًا خاصة من وقت لآخر.
239
+ هل توفرون خدمة ترجمة فورية أثناء الاستشارة؟,لا نقدم خدمة ترجمة فورية حاليًا، ولكن يمكن اختيار أطباء يتحدثون لغات متعددة.
240
+ هل يتم تسجيل الاستشارات لأغراض المراجعة؟,يتم تسجيل بعض الاستشارات لأغراض ضمان الجودة والتدريب، مع الحفاظ على السرية التامة وبعد موافقتك الصريحة.
241
+ هل يمكن للطبيب طلب فحوصات مخبرية؟,نعم، يمكن للطبيب طلب فحوصات مخبرية وإرسال طلب التحويل إلكترونياً.
242
+ هل يمكنني تحميل نتائج الفحوصات الطبية لمراجعتها؟,نعم، يمكنك تحميل نتائج الفحوصات المخبرية والأشعة ليقوم الطبيب بمراجعتها وتقديم رأيه.
243
+ ما هي الإجراءات المتبعة في حال انقطاع الاتصال أثناء الاستشارة؟,في حال انقطاع الاتصال، سيحاول الطبيب أو فريق الدعم إعادة الاتصال بك لإكمال الاستشارة.
244
+ هل يمكنني تغيير كلمة المرور لحسابي؟,نعم، يمكنك تغيير كلمة المرور الخاصة بحسابك من خلال إعدادات الملف الشخصي.
245
+ ماذا أفعل إذا نسيت كلمة المرور الخاصة بي؟,"يمكنك استخدام خيار ""نسيت كلمة المرور"" على صفحة تسجيل الدخول لإعادة تعيينها."
246
+ هل أحتاج إلى تقديم هوية للتحقق من شخصيتي؟,قد يُطلب منك تقديم إثبات هوية عند التسجيل أو في حالات معينة لضمان سلامة بياناتك وتوافقها مع اللوائح.
247
+ هل يمكن للأطباء تقديم شهادات مرضية إلكترونية؟,نعم، في بعض الحالات التي تستدعي ذلك، يمكن للطبيب إصدار شهادة مرضية إلكترونية معتمدة.
248
+ هل خدمة الرعاية النفسية تشمل جلسات علاج سلوكي معرفي (CBT)؟,نعم، يقدم أخصائيونا النفسيون جلسات علاج سلوكي معرفي وتقنيات أخرى للعلاج النفسي.
249
+ هل يمكنني الحصول على وصفة طبية قابلة للتجديد؟,يعتمد ذلك على تقييم الطبيب ونوع الدواء، حيث يمكن إصدار وصفات قابلة للتجديد لبعض الحالات.
250
+ هل توفرون تقارير طبية شاملة بعد الاستشارة؟,نعم، يمكنك الحصول على ملخص للاستشارة يتضمن التشخيص، خطة العلاج، والأدوية الموصوفة.
251
+ هل هناك حدود لعدد الاستشارات التي يمكنني الحصول عليها؟,يعتمد ذلك على الباقة التي اشتركت بها. بعض الباقات توفر عددًا محدودًا، بينما تتيح أخرى استشارات غير محدودة.
252
+ هل يمكنني الحصول على رأي طبي ثانٍ؟,نعم، يمكنك حجز استشارة مع طبيب آخر للحصول على رأي طبي ثانٍ، وذلك ضمن الخدمات المتاحة.
253
+ هل تتوفر خدمات طب الأسنان عن بعد؟,حاليًا لا نقدم خدمات طب الأسنان عن بعد، ولكننا نسعى لتوسيع نطاق التخصصات مستقبلاً.
254
+ هل يمكنني استشارة طبيب أخصائي دون تحويل من طبيب عام؟,نعم، يمكنك حجز موعد مباشر مع الطبيب الأخصائي الذي تختاره.
255
+ هل يتم تتبع الأدوية بعد شحنها؟,نعم، نوفر خدمة تتبع الشحنات للأدوية لضمان وصولها بأمان وفي الوقت المحدد.
256
+ هل تتوفر خدمة الاستشارات الصوتية فقط بدون فيديو؟,نعم، بعض الأطباء قد يقدمون خيار الاستشارة الصوتية فقط، وذلك يعتمد على تفضيل الطبيب ونوع الحالة.
257
+ كيف يمكنني التأكد من كفاءة الأطباء؟,يتم اختيار الأطباء بعناية فائقة بناءً على مؤهلاتهم، خبرتهم، وتراخيصهم المهنية، ويتم تقييم أدائهم باستمرار.
258
+ هل يمكن للأطباء وصف أدوية نفسية؟,يمكن للأطباء النفسيين المرخصين وصف الأدوية النفسية إذا رأوا ضرورة لذلك، وفقًا للوائح المحلية.
259
+ ما هي ساعات استجابة الدعم الفني عبر البريد الإلكتروني؟,نهدف إلى الرد على جميع الاستفسارات عبر البريد الإلكتروني خلال 24 ساعة عمل.
260
+ هل يمكنني إلغاء موعد الصيدلية والتوصيل؟,نعم، يمكن إلغاء الطلب قبل عملية الشحن، يرجى التواصل مع الدعم الفني في أقرب وقت مم��ن.
261
+ هل هناك رسوم خفية على الخدمات؟,لا، جميع الرسوم والتكاليف موضحة بشفافية تامة قبل إتمام عملية الدفع.
262
+ هل يمكنني الاحتفاظ بسجلي الطبي على جهازي الخاص؟,يمكنك تنزيل نسخة من ملخص الاستشارات والتقارير المتاحة لك على المنصة.
263
+ هل تتوافق المنصة مع متصفحات الإنترنت المختلفة؟,نعم، تم تصميم المنصة لتكون متوافقة مع معظم متصفحات الإنترنت الشائعة (كروم، فايرفوكس، سفاري، إيدج).
data/raw_company_info/info.md ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # شركة الشفاء الرقمية للرعاية الصحية
2
+
3
+ ## 🌟 نبذة عن الشركة
4
+
5
+ شركة الشفاء الرقمية هي شركة رائدة ومتطورة في مجال **الرعاية الصحية عن بُعد (Telehealth)**، تأسست على مبدأ توفير رعاية طبية شاملة وعالية الجودة عبر الإنترنت. نهدف إلى سد الفجوة بين المرضى والأطباء المتخصصين، وتمكين الأفراد من الحصول على استشارات طبية موثوقة، متابعة مستمرة، وخدمات صحية متكاملة في أي وقت ومن أي مكان، وذلك بفضل أحدث التقنيات الرقمية والكوادر الطبية المتميزة. نحن نؤمن بأن الرعاية الصحية يجب أن تكون في متناول الجميع، ولذلك نعمل بلا كلل لتقديم حلول مبتكرة تسهل وصول المرضى للخدمات التي يحتاجونها دون عناء التنقل أو الانتظار.
6
+
7
+ ---
8
+
9
+ ## 🎯 الرؤية
10
+
11
+ أن نكون **الخيار الأول والموثوق به عالميًا** في مجال الرعاية الصحية الرقمية، وأن نُحدِث فرقًا حقيقيًا وملموسًا في جودة حياة الأفراد والمجتمعات من خلال تقديم حلول صحية مبتكرة ومستدامة، تُلبي احتياجات الحاضر وتتطلع لمستقبل صحي أفضل للجميع. نطمح إلى بناء مجتمع صحي واعي، حيث تكون الوقاية والعلاج السريع جزءًا لا يتجزأ من الثقافة العامة.
12
+
13
+ ---
14
+
15
+ ## 📌 الرسالة
16
+
17
+ تقديم خدمات طبية **موثوقة، آمنة، وسهلة الوصول** لجميع أفراد المجتمع، مع التركيز على الكفاءة المهنية والشفافية التامة، وذلك من خلال تسخير **أحدث التكنولوجيا الرقمية** لبناء جسر فعال بين المرضى والخبراء الطبيين. نلتزم بتقديم تجربة رعاية صحية سلسة وشاملة، تراعي احتياجات كل فرد وتضمن خصوصيته وأمن معلوماته.
18
+
19
+ ---
20
+
21
+ ## 💡 القيم الأساسية
22
+
23
+ في شركة الشفاء الرقمية، تتجسد قيمنا في كل جانب من جوانب عملنا، وهي تشكل حجر الزاوية الذي نبني عليه علاقاتنا مع مرضانا وشركائنا:
24
+
25
+ * **السرية والخصوصية (Confidentiality & Privacy):** نلتزم بأقصى درجات السرية في التعامل مع بيانات المرضى ومعلوماتهم الصحية، ونطبق بروتوكولات أمان صارمة لضمان حماية معلوماتهم الشخصية والطبية من أي وصول غير مصرح به. خصوصية المريض هي على رأس أولوياتنا.
26
+ * **الجودة والاحترافية (Quality & Professionalism):** نضمن أن جميع خدماتنا الطبية تُقدم من قبل أطباء ومتخصصين مؤهلين تأهيلاً عاليًا، ويتمتعون بخبرة واسعة في مجالاتهم. نسعى دائمًا للتميز وتقديم أعلى معايير الرعاية الصحية وفقًا لأفضل الممارسات العالمية.
27
+ * **التيسير والسرعة (Accessibility & Speed):** نهدف إلى جعل الرعاية الصحية سهلة ومتاحة للجميع، بغض النظر عن موقعهم الجغرافي. نوفر حلولاً سريعة وفعالة للحصول على الاستشارات والمواعيد، مما يوفر الوقت والجهد على المرضى.
28
+ * **الموثوقية والشفافية (Reliability & Transparency):** نبني الثقة مع مرضانا من خلال تقديم معلومات واضحة وصادقة حول خدماتنا وتكاليفها، ونحرص على بناء علاقات طويلة الأمد قائمة على المصداقية والنزاهة. نضمن الحصول على رأي طبي دقيق وموثوق به.
29
+ * **التعاطف والرعاية (Empathy & Care):** نتعامل مع كل مريض كفرد فريد له احتياجاته الخاصة، ونقدم الرعاية بتعاطف وتفهم، مع الحرص على توفير بيئة داعمة ومريحة تساهم في شفائهم وراحتهم النفسية.
30
+ * **الابتكار والتطوير المستمر (Innovation & Continuous Improvement):** نتبنى أحدث التقنيات ونبحث دائمًا عن طرق جديدة ومبتكرة لتحسين خدماتنا وتوسيع نطاقها، لضمان مواكبة التطورات في مجال الرعاية الصحية الرقمية وتلبية الاحتياجات المتغيرة لمرضانا.
31
+
32
+ ---
33
+
34
+ ## 🩺 الخدمات التي نقدمها
35
+
36
+ نقدم في شركة الشفاء الرقمية مجموعة واسعة ومتكاملة من الخدمات الصحية الرقمية التي تلبي مختلف احتياجات الرعاية:
37
+
38
+ * **الاستشارات الطبية عبر الفيديو (Video Consultations):**
39
+ * استشارات فورية ومجدولة مع أطباء عامين ومتخصصين في مختلف التخصصات (الباطنية، الأطفال، الجلدية، النساء والولادة، العيون، الأنف والأذن والحنجرة، وغيرها).
40
+ * إمكانية التواصل الصوتي والمرئي الآمن والمشفر، مع خاصية تبادل الملفات والصور لتحسين جودة التشخيص.
41
+ * جلسات متابعة مستمرة للحالات المزمنة أو بعد العمليات الجراحية.
42
+ * **الكشف الجسدي في العيادة (In-clinic Physical Examination):**
43
+ * تقديم خدمات الكشف الجسدي في عيادتنا الخاصة في جميع التخصصات.
44
+ * إمكانية حجز المواعيد المسبقة لضمان حصولك على الرعاية اللازمة في الوقت المناسب.
45
+ * **مراجعة التقارير الطبية والتحاليل (Medical Report & Lab Results Review):**
46
+ * تقديم خدمة مراجعة وتقييم للتقارير الطبية السابقة، صور الأشعة، ونتائج التحاليل المخبرية من قبل أطباء متخصصين لتقديم تفسير واضح وشامل.
47
+ * تقديم توصيات بناءً على النتائج ومساعدة المرضى على فهم حالتهم الصحية بشكل أفضل.
48
+ * **خدمات الصيدلة والتوصيل المنزلي (Pharmacy & Home Delivery Services):**
49
+ * صرف الوصفات الطبية الإلكترونية التي يكتبها أطباؤنا.
50
+ * توصيل الأدوية والمستلزمات الطبية إلى باب المنزل بسرعة وأمان، مع ضمان سلامة المنتجات وجودتها.
51
+ * إمكانية طلب الأدوية التي لا تتطلب وصفة طبية مباشرة من الصيدلية الرقمية.
52
+ * **حجز مواعيد مع أطباء متخصصين (Specialist Doctor Appointments):**
53
+ * منصة سهلة الاستخدام لحجز مواعيد مع مجموعة واسعة من الأطباء الاستشاريين في تخصصات نادرة أو دقيقة.
54
+ * إمكانية الاطلاع على الملفات الشخصية للأطباء، خبراتهم، وتقييمات المرضى الآخرين لاختيار الأنسب.
55
+ * **خدمات الرعاية النفسية والدعم الصحي (Mental Health & Wellness Support):**
56
+ * جلسات استشارية مع أخصائيين نفسيين ومعالجين سلوكيين لدعم الصحة النفسية.
57
+ * تقديم استشارات في مجالات الصحة العامة، التغذية، اللياقة البدنية، وإدارة الإجهاد.
58
+ * برامج دعم شاملة للمرضى الذين يعانون من حالات صحية مزمنة.
59
+ * **تحليل نتائج المختبر (Laboratory Results Analysis):**
60
+ * شرح مفصل لنتائج التحاليل المخبرية وربطها بالحالة الصحية العامة للمريض.
61
+ * توجيه المريض إلى التحاليل اللازمة بناءً على الأعراض أو التاريخ المرضي.
62
+ * **السجلات الطبية الإلكترونية الموحدة (Unified Electronic Health Records - EHR):**
63
+ * نظام آمن لتخزين السجل الطبي للمريض، بما في ذلك التشخيصات، الأدوية الموصوفة، نتائج الفحوصات، وتاريخ الاستشارات.
64
+ * يمكّن الأطباء من الوصول إلى السجل الطبي للمريض (بموافقة المريض) لتوفير رعاية أكثر دقة وشمولية.
65
+ * يقلل من الحاجة لتكرار الفحوصات ويسهل عملية المتابعة.
66
+ * **برامج الصحة الوقائية (Preventive Health Programs):**
67
+ * تقديم استشارات حول الوقاية من الأمراض وتغيير نمط الحياة لتعزيز الصحة العامة.
68
+ * حملات توعية صحية دورية عبر المنصة حول الأمراض الشائعة وطرق الوقاية منها.
69
+ * برامج مخصصة لمتابعة المؤشرات الحيوية (مثل ضغط الدم، السكري) للأشخاص المعرضين للخطر.
70
+ * **خدمات الطب عن بُعد للمؤسسات والشركات (Corporate Telehealth Solutions):**
71
+ * تقديم حزم رعاية صحية رقمية للشركات والمؤسسات لرعاية موظفيهم.
72
+ * برامج صحية مخصصة للشركات لتعزيز رفاهية الموظفين وتقليل التغيب عن العمل.
73
+
74
+ ---
75
+
76
+ ## 📞 معلومات الاتصال
77
+
78
+ نحن هنا لخدمتكم والإجابة على استفساراتكم. يمكنكم التواصل معنا عبر القنوات التالية:
79
+
80
+ * **الهاتف:** 9200-000-000 (متوفر خلال ساعات العمل الرسمية)
81
+ * **البريد الإلكتروني:** support@alshifa-care.com (نعد بالرد على استفساراتكم خلال 24 ساعة عمل)
82
+ * **الموقع الإلكتروني:** [www.alshifa-care.com](https://www.google.com/search?q=https://www.alshifa-care.com) (منصتكم المتكاملة للرعاية الصحية الرقمية)
83
+ * **العنوان:** الرياض، حي الربيع، طريق الثمامة، المملكة العربية السعودية.
84
+ * **وسائل التواصل الاجتماعي:**
85
+ * **تويتر (X):** @AlShifaDigital
86
+ * **لينكد إن (LinkedIn):** AlShifa Digital Healthcare
87
+ * **فيسبوك (Facebook):** AlShifaDigitalCare
88
+ * **إنستغرام (Instagram):** @alshifadigital
89
+
90
+ ---
91
+
92
+ ## 💳 طرق الدفع والدعم الفني
93
+
94
+ نسعى لتوفير أقصى درجات الراحة لعملائنا، لذا نوفر خيارات دفع متعددة ودعمًا فنيًا متميزًا:
95
+
96
+ * **طرق الدفع:**
97
+ * **البطاقات البنكية:** نقبل جميع البطاقات الائتمانية والخصم المباشر الرئيسية (فيزا / ماستركارد / مدى).
98
+ * **المحافظ الرقمية:** الدفع السريع والآمن عبر تطبيق Apple Pay و STC Pay.
99
+ * **تحويل بنكي:** (خاص لبعض الخدمات أو الباقات الكبيرة، يمكن الترتيب مسبقاً).
100
+ * **الباقات والعضويات:** خيارات اشتراك شهرية أو سنوية توفر خصومات إضافية ووصولاً غير محدود لبعض الخدمات.
101
+ * **الدعم الفني:**
102
+ * **الدردشة المباشرة (Live Chat):** متوفرة على مدار الساعة (24/7) على موقعنا الإلكتروني لتقديم المساعدة الفورية.
103
+ * **الهاتف:** فريق دعم مخصص جاهز للإجابة على استفساراتكم التقنية والخدمية خلال ساعات العمل.
104
+ * **البريد الإلكتروني:** يمكنكم إرسال استفساراتكم أو مشاكلكم وسيقوم فريق الدعم بالرد عليكم في أقرب وقت ممكن.
105
+ * **قسم المساعدة والأسئلة الشائعة:** دليل شامل ومتجدد على موقعنا يحتوي على إجابات لمعظم الاستفسارات الشائعة حول استخدام المنصة والخدمات.
106
+
107
+ ---
108
+
109
+ ## ❓ الأسئلة الشائعة (FAQ)
110
+
111
+ نقدم لكم إجابات لأكثر الأسئلة شيوعًا لضمان وضوح كامل حول خدماتنا:
112
+
113
+ **س: ما هي المؤهلات التي يتمتع بها الأطباء في شركة الشفاء الرقمية؟**
114
+ ج: جميع أطبائنا حاصلون على شهادات معتمدة ولديهم سنوات من الخبرة في تخصصاتهم. يخضعون لعملية تدقيق صارمة لضمان أعلى مستويات الكفاءة والاحترافية، ويتم تقييم أدائهم بانتظام بناءً على معايير الجودة ورضا المرضى.
115
+
116
+ **س: هل يمكنني استرداد المبلغ إذا لم أكن راضيًا عن الخدمة؟**
117
+ ج: نعم، نسعى دائمًا لرضاكم التام. يمكن طلب استرداد المبلغ خلال **24 ساعة** من تقديم الخدمة أو عدم إتمامها، وذلك وفقًا لسياسة الاسترداد الخاصة بنا، والتي تحدد الشروط والأحكام لكل خدمة. يرجى مراجعة صفحة "شروط الاستخدام" للحصول على تفاصيل كاملة.
118
+
119
+ **س: هل الاستشارات تشمل وصف الأدوية؟**
120
+ ج: نعم، إذا رأى الطبيب ضرورة طبية لذلك، يمكنه وصف الأدوية اللازمة خلال الاستشارة. يتم إرسال الوصفة إلكترونيًا ويمكن توصيلها إليك مباشرة عبر خدمة الصيدلية الإلكترونية لدينا، أو يمكنك الحصول عليها من أي صيدلية أخرى.
121
+
122
+ **س: هل بياناتي محفوظة وآمنة؟**
123
+ ج: بالتأكيد. نحن نلتزم بأعلى معايير الأمان والخصوصية العالمية لحماية بياناتك الشخصية والطبية. نستخدم تقنيات التشفير المتقدمة (SSL/TLS) لحماية جميع الاتصالات والبيانات المخزنة، ونلتزم بجميع اللوائح والقوانين المتعلقة بحماية البيانات الصحية، مثل قانون حماية البيانات العامة (GDPR) ومعايير HIPAA حيثما ينطبق ذلك. يتم الوصول إلى بياناتك من قبل الأطباء المعنيين فقط وبموافقتك الصريحة.
124
+
125
+ **س: هل يمكنني اختيار الطبيب ��لذي أرغب في الاستشارة معه؟**
126
+ ج: نعم، يمكنك تصفح ملفات الأطباء المتوفرين، والاطلاع على تخصصاتهم، خبراتهم، اللغات التي يتحدثونها، وتقييمات المرضى الآخرين، ومن ثم اختيار الطبيب الأنسب لاحتياجاتك.
127
+
128
+ **س: هل يمكنني الحصول على استشارة طبية في حالات الطوارئ؟**
129
+ ج: لا. خدمات شركة الشفاء الرقمية مخصصة للحالات غير الطارئة والاستشارات الروتينية والمتابعة. **يُمنع منعًا باتًا استخدام الخدمة في حالات الطوارئ الطبية.** في حالة وجود أي حالة طارئة، يرجى التوجه فوراً إلى أقرب مستشفى أو الاتصال بالرقم المخصص للطوارئ في بلدك.
130
+
131
+ **س: ما هي اللغات التي يقدم بها الأطباء الاستشارات؟**
132
+ ج: يقدم أطباؤنا الاستشارات باللغة العربية بشكل أساسي، بالإضافة إلى إمكانية توفير استشارات بلغات أخرى مثل الإنجليزية حسب توفر الأطباء المتحدثين بهذه اللغات. يمكنك التحقق من اللغات التي يتحدثها الطبيب في ملفه الشخصي.
133
+
134
+ **س: هل يمكنني حجز استشارة لأحد أفراد عائلتي؟**
135
+ ج: نعم، يمكنك حجز استشارة نيابة عن أحد أفراد عائلتك (مثل الأطفال أو كبار السن) مع مراعاة الحصول على موافقتهم الصريحة (إذا كانوا بالغين وقادرين على اتخاذ القرار)، وتقديم معلوماتهم الطبية بدقة.
136
+
137
+ **س: هل توفرون فحصاً طبياً شاملاً عن بعد؟**
138
+ ج: لا يمكن إجراء فحص جسدي شامل عن بعد. ولكن في عيادتنا الخاصة نوفر **خدمة الكشف الجسدي في كل التخصصات**.
139
+ ---
140
+
141
+ ## 📜 شروط الاستخدام
142
+
143
+ باستخدامك لخدمات شركة الشفاء الرقمية، فإنك توافق على الالتزام بالشروط والأحكام التالية:
144
+
145
+ * **عدم استخدام الخدمة في حالات الطوارئ:** تُخصص خدماتنا للحالات غير الطارئة فقط. في أي حالة طارئة، يجب البحث عن رعاية طبية فورية من خلال المستشفيات أو خدمات الطوارئ المحلية.
146
+ * **دقة المعلومات المقدمة:** يجب على المستخدم تقديم معلومات طبية وشخصية صحيحة وكاملة ودقيقة أثناء التسجيل وخلال الاستشارات. أي معلومات غير دقيقة قد تؤثر سلبًا على جودة الرعاية المقدمة.
147
+ * **مسؤولية المستخدم:** الشركة غير مسؤولة عن أي سوء استخدام للخدمة، أو عن أي نتائج سلبية تنجم عن عدم اتباع إرشادات الطبيب أو تقديم معلومات خاطئة.
148
+ * **الملكية الفكرية:** جميع المحتويات والمواد المتوفرة على المنصة (بما في ذلك النصوص، الرسومات، الشعارات، الأيقونات، الصور، ومقاطع الفيديو) هي ملك لشركة الشفاء الرقمية ومحمية بموجب قوانين الملكية الفكرية. يُمنع منعًا باتًا نسخ، تعديل، توزيع، أو إعادة نشر أي من هذه المواد دون إذن كتابي مسبق.
149
+ * **التعديلات على الشروط:** تحتفظ الشركة بالحق في تعديل شروط الاستخدام هذه في أي وقت دون إشعار مسبق. يُعد استمرارك في استخدام الخدمة بعد نشر التعديلات موافقة منك على الشروط المعدلة.
150
+ * **القانون الحاكم:** تخضع شروط الاستخدام هذه وتفسر وفقًا لقوانين المملكة العربية السعودية. في حالة وجود أي نزاعات، يكون الاختصاص القضائي للمحاكم المختصة في المملكة العربية السعودية.
151
+
152
+ ---
153
+
154
+ ## 🔒 سياسة الخصوصية
155
+
156
+ نحن في شركة الشفاء الرقمية نولي أهمية قصوى لخصوصية بياناتك وحمايتها. تتعهد سياستنا للخصوصية بما يلي:
157
+
158
+ * **جمع البيانات:** يتم جمع البيانات الشخصية (مثل الاسم، العمر، الجنس، معلومات الاتصال) والمعلومات الصحية (التاريخ المرضي، التشخيصات، الأدوية، نتائج الفحوصات) فقط لغرض تقديم الخدمات الطبية وتحسينها، وبموافقة صريحة من المستخدم.
159
+ * **استخدام البيانات:** تُستخدم البيانات لتقديم الاستشارات الطبية، إدارة المواعيد، معالجة الدفعات، وتحسين تجربة المستخدم على المنصة. قد تُستخدم البيانات المجمعة (التي لا تحدد هوية فردية) لأغراض البحث والإحصاءات لتحسين الخدمات الصحية بشكل عام.
160
+ * **مشاركة البيانات:** لا يتم مشاركة البيانات الشخصية أو الصحية مع أي طرف ثالث (بما في ذلك الشركاء التجاريين أو المعلنين) دون إذن مسبق وصريح من المستخدم، إلا في الحالات التي يتطلبها القانون أو بأمر قضائي.
161
+ * **أمن البيانات:** يتم تشفير جميع الاتصالات والبيانات باستخدام أحدث بروتوكولات الأمان (مثل AES-256 و TLS 1.2) لحماية المعلومات أثناء النقل والتخزين. يتم تطبيق إجراءات أمنية صارمة على خوادمنا وقواعد بياناتنا لمنع الوصول غير المصرح به.
162
+ * **حقوق المستخدم:** يحق للمستخدم الوصول إلى بياناته الشخصية، وتعديلها، أو طلب حذفها (مع مراعاة المتطلبات القانونية للاحتفاظ بالسجلات الطبية) في أي وقت. كما يحق للمستخدم سحب موافقته على معالجة البيانات، شريطة ألا يتعارض ذلك مع الالتزامات القانونية.
163
+ * **ملفات تعريف الارتباط (Cookies):** نستخدم ملفات تعريف الارتباط لتحسين تجربة التصفح، تحليل أداء الموقع، وتخصيص المحتوى. يمكن للمستخدمين التحكم في إعدادات ملفات تعريف الارتباط من خلال متصفحاتهم.
164
+ * **التحديثات على سياسة الخصوصية:** قد نقوم بتحديث سياسة الخصوصية هذه من وقت لآخر. سيتم إخطار المستخدمين بأي تغييرات جوهرية من خلال الموقع الإلكتروني أو البريد الإلكتروني.
165
+
166
+ ---
167
+
168
+ ## ⏰ أوقات العمل والعطل الرسمية
169
+
170
+ نحن ملتزمون بتوفير خدماتنا لكم بأقصى درجات المرونة، مع مراعاة أوقات الراحة اللازمة لفريقنا:
171
+
172
+ * **أيام العمل:** من الأحد إلى الخميس.
173
+ * **الساعات:** 9 صباحًا حتى 9 مساءً بتوقيت المملكة العربية السعودية (EEST).
174
+ * **العطلات الأسبوعية:** الجمعة والسبت.
175
+ * **العطل الرسمية:** بالإضافة إلى العطلات الأسبوعية، تكون الشركة مغلقة خلال الأعياد الرسمية في المملكة العربية السعودية (مثل عيدي الفطر والأضحى واليوم الوطني). سيتم الإعلان عن أي تغييرات في أوقات العمل خلال العطلات مسبقًا عبر الموقع ووسائل التواصل الاجتماعي.
176
+
177
+ **ملاحظة:** قد تتوفر بعض خدمات الدعم الفني أو الدردشة المباشرة خارج ساعات العمل المحددة، يرجى مراجعة قسم الدعم الفني للحصول على التفاصيل.
178
+
179
+ ---
180
+
181
+ ## 📝 كيفية الاشتراك أو إلغاء الخدمة
182
+
183
+ نسعى لجعل عملية الاشتراك وإلغاء الخدمة بسيطة وواضحة:
184
+
185
+ ### للاشتراك في خدماتنا:
186
+
187
+ 1. **إنشاء حساب:** قم بزيارة موقعنا الإلكتروني [www.alshifa-care.com](https://www.google.com/search?q=https://www.alshifa-care.com) وانقر على "تسجيل" أو "إنشاء حساب". اتبع الخطوات لإدخال معلوماتك الأساسية وإنشاء ملفك الشخصي.
188
+ 2. **اختيار الباقة:** تصفح باقات الخدمات المتاحة لدينا. نقدم خيارات متعددة تناسب احتياجات الأفراد والعائلات، بما في ذلك الاستشارات الفردية، الباقات الشهرية، والعضويات السنوية التي توفر خصومات ومزايا إضافية.
189
+ 3. **إدخال معلومات الدفع:** بعد اختيار الباقة، سيتم توجيهك إلى صفحة الدفع الآمنة. أدخل معلومات بطاقتك البنكية أو اختر طريقة الدفع المفضلة لديك لإتمام عملية الاشتراك. ستتلقى تأكيدًا عبر البريد الإلكتروني بمجرد اكتمال الاشتراك.
190
+ 4. **بدء الاستفادة:** بمجرد الاشتراك، يمكنك البدء في حجز المواعيد، طلب الاستشارات، والوصول إلى جميع خدماتنا بكل سهولة.
191
+
192
+ ### لإلغاء الاشتراك أو الخدمة:
193
+
194
+ * **عبر حسابك:** قم بتسجيل الدخول إلى حسابك على موقعنا الإلكتروني. ثم توجه إلى "إعدادات الحساب" أو "إدارة الاشتراكات" (قد تختلف التسمية قليلاً حسب التحديثات). اختر "إلغاء الاشتراك" واتبع التعليمات. سيتم تفعيل الإلغاء فورًا أو في نهاية فترة الاشتراك الحالية حسب نوع الباقة.
195
+ * **عبر التواصل مع الدعم الفني:** إذا واجهت أي صعوبة في إلغاء الاشتراك بنفسك، يمكنك التواصل مع فريق الدعم الفني لدينا عبر الهاتف، البريد الإلكتروني، أو الدردشة المباشرة. سيقوم فريقنا بمساعدتك في إتمام عملية الإلغاء وتأكيدها لك.
196
+
197
+ **ملاحظة:** يرجى مراجعة شروط الاشتراك في كل باقة، حيث قد تختلف سياسات الإلغاء والاسترداد بناءً على نوع الخدمة أو مدة الاشتراك.
requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio==5.41.1
2
+ huggingface_hub==0.34.3
3
+ langchain==0.3.27
4
+ langchain_community==0.3.27
5
+ langchain_huggingface==0.3.1
6
+ langchain_openai==0.3.28
7
+ openai==1.99.2
8
+ pandas==2.3.1
9
+ pydantic==2.11.7
10
+ python-dotenv==1.1.1
11
+ pytz==2025.2
12
+ Requests==2.32.4
src/__init__.py ADDED
File without changes
src/agent.py ADDED
@@ -0,0 +1,657 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Al Shifa Digital Healthcare - Medical Chatbot Agent
3
+
4
+ This module implements the core agent functionality for the Al Shifa Digital Healthcare
5
+ medical chatbot system. It provides comprehensive medical assistance, appointment booking,
6
+ and company information services with robust error handling and bilingual support.
7
+
8
+ Author: Al Shifa Digital Healthcare Team
9
+ Version: 1.0.0
10
+ License: Proprietary
11
+ """
12
+
13
+ import logging
14
+ import traceback
15
+ from typing import Any, AsyncGenerator
16
+ import asyncio
17
+ import requests
18
+ from langchain.agents import create_openai_tools_agent, AgentExecutor
19
+ from langchain.memory import ConversationBufferWindowMemory
20
+ from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
21
+ from langchain.schema import OutputParserException
22
+ from langchain.callbacks.base import BaseCallbackHandler
23
+ from openai import RateLimitError, APIError
24
+
25
+ from config import LLM
26
+ from tools import (
27
+ retriever_tool,
28
+ websearch_tool,
29
+ get_current_datetime_tool,
30
+ book_consultation_tool
31
+ )
32
+
33
+ # Configure logging
34
+ logging.basicConfig(
35
+ level=logging.INFO,
36
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
37
+ handlers=[
38
+ logging.FileHandler('agent.log'),
39
+ logging.StreamHandler()
40
+ ]
41
+ )
42
+ logger = logging.getLogger(__name__)
43
+
44
+
45
+ # ============================================================================
46
+ # STREAMING CALLBACK HANDLER
47
+ # ============================================================================
48
+
49
+ class StreamingCallbackHandler(BaseCallbackHandler):
50
+ """Custom callback handler for streaming responses."""
51
+
52
+ def __init__(self):
53
+ self.tokens = []
54
+ self.current_response = ""
55
+
56
+ def on_llm_new_token(self, token: str, **kwargs: Any) -> Any:
57
+ """Called when a new token is generated."""
58
+ self.tokens.append(token)
59
+ self.current_response += token
60
+
61
+ def get_response(self) -> str:
62
+ """Get the current response."""
63
+ return self.current_response
64
+
65
+ def reset(self):
66
+ """Reset the handler for a new response."""
67
+ self.tokens = []
68
+ self.current_response = ""
69
+
70
+
71
+ # ============================================================================
72
+ # CUSTOM EXCEPTION CLASSES
73
+ # ============================================================================
74
+
75
+ class AgentError(Exception):
76
+ """Base exception for agent-related errors."""
77
+ pass
78
+
79
+
80
+ class ToolExecutionError(AgentError):
81
+ """Exception raised when a tool fails to execute."""
82
+ pass
83
+
84
+
85
+ class APIConnectionError(AgentError):
86
+ """Exception raised when API connections fail."""
87
+ pass
88
+
89
+
90
+ class ValidationError(AgentError):
91
+ """Exception raised when input validation fails."""
92
+ pass
93
+
94
+
95
+ # ============================================================================
96
+ # AGENT CONFIGURATION
97
+ # ============================================================================
98
+
99
+ # Available tools for the agent
100
+ AVAILABLE_TOOLS = [
101
+ retriever_tool,
102
+ websearch_tool,
103
+ get_current_datetime_tool,
104
+ book_consultation_tool
105
+ ]
106
+
107
+ # System message template for the agent
108
+ SYSTEM_MESSAGE = """
109
+ You are an advanced medical chatbot for "Al Shifa Digital Healthcare" (شركة الشفاء الرقمية للرعاية الصحية).
110
+ Your name is "Al Shifa Digital Assistant" (روبوت الشفاء الرقمي).
111
+
112
+ **LANGUAGE RULE: Always respond in the SAME language as the user's question (Arabic/English).**
113
+
114
+ **CORE MISSION:**
115
+ Provide accurate, evidence-based medical information and assist with appointment booking while prioritizing patient safety.
116
+
117
+ **WORKING HOURS:**
118
+ أيام العمل من الأحد إلى الخميس، من 9 صباحًا حتى 9 مساءً.
119
+ Working days: Sunday to Thursday, 9 AM to 9 PM.
120
+
121
+ **AVAILABLE TOOLS:**
122
+ 1. **book_consultation:** For appointment booking (collect all required info first)
123
+ 2. **company_knowledge_tool:** For Al Shifa services, hours, company info
124
+ 3. **get_current_datetime:** For current date/time (only reliable source)
125
+ 4. **Tavily_Search_Tool:** For medical questions (always use for medical queries)
126
+
127
+ **WORKFLOW:**
128
+
129
+ **Medical Questions:**
130
+ - Start with safety disclaimer
131
+ - Use Tavily_Search_Tool for current, evidence-based information
132
+ - Never diagnose - recommend professional consultation
133
+ - **EMERGENCIES:** Immediately instruct to call 997 (emergency services) and seek immediate medical attention
134
+
135
+ **Appointment Booking:**
136
+ - **MANDATORY VALIDATION:** Before booking any appointment, MUST verify:
137
+ - Date is Sunday through Thursday (not Friday or Saturday)
138
+ - Time is between 9:00 AM and 9:00 PM
139
+ - If user requests invalid day/time, inform them of working hours and ask for alternative
140
+ - Collect: patient_name, age, gender, contact_number, email, reason_for_consultation, preferred_date, preferred_time
141
+ - Use get_current_datetime for "today" requests, then check company hours
142
+ - **Validation Messages:**
143
+ - Arabic: "عذراً، نحن نعمل من الأحد إلى الخميس، من 9 صباحًا حتى 9 مساءً. يرجى اختيار موعد آخر."
144
+ - English: "Sorry, we work Sunday to Thursday, 9 AM to 9 PM. Please choose another time."
145
+
146
+ **Company Questions:**
147
+ Use company_knowledge_tool directly
148
+
149
+ **CRITICAL RULES:**
150
+ - **Safety First:** Medical emergencies → direct to call 997 immediately
151
+ - **No Diagnosis:** Provide information only, not medical diagnoses
152
+ - **Evidence-Based:** Always use Tavily_Search_Tool for medical information
153
+ - **Language Match:** Respond in user's language
154
+ - **Professional Boundaries:** Clearly state limitations when uncertain
155
+ - **Working Hours Enforcement:** Never book appointments outside working days/hours
156
+
157
+ **SAFETY DISCLAIMERS:**
158
+ - Arabic: "تنويه هام: للطوارئ اتصل بـ 997 فوراً. هذه معلومات تعليمية ولا تغني عن استشارة طبيب."
159
+ - English: "Important: For emergencies call 997 immediately. This is educational information, not medical advice."
160
+
161
+ **EMERGENCY PROTOCOL:**
162
+ If user describes emergency symptoms (chest pain, difficulty breathing, severe bleeding, loss of consciousness, etc.),
163
+ immediately respond:
164
+ "هذه حالة طوارئ! اتصل بـ 997 فوراً واطلب المساعدة الطبية العاجلة" /
165
+ "This is an emergency! Call 997 immediately and seek urgent medical help."
166
+
167
+ **Language:**
168
+
169
+ - Respond in the same language as the user's query.
170
+ - الرد بنفس لغة استعلام المستخدم.
171
+
172
+ """
173
+
174
+ # Create the prompt template
175
+ prompt_template = ChatPromptTemplate.from_messages([
176
+ ("system", SYSTEM_MESSAGE),
177
+ MessagesPlaceholder("chat_history"),
178
+ ("human", "{input}"),
179
+ MessagesPlaceholder("agent_scratchpad"),
180
+ ])
181
+
182
+ # Initialize the agent
183
+ agent = create_openai_tools_agent(
184
+ llm=LLM,
185
+ tools=AVAILABLE_TOOLS,
186
+ prompt=prompt_template,
187
+ )
188
+
189
+ # Create agent executor
190
+ agent_executor = AgentExecutor(
191
+ agent=agent,
192
+ tools=AVAILABLE_TOOLS,
193
+ verbose=True,
194
+ handle_parsing_errors=True,
195
+ max_iterations=10,
196
+ max_execution_time=120, # 2 minutes timeout
197
+ )
198
+
199
+ # Initialize memory
200
+ memory = ConversationBufferWindowMemory(
201
+ memory_key="chat_history",
202
+ return_messages=True,
203
+ max_window_size=10
204
+ )
205
+
206
+ # ============================================================================
207
+ # STREAMING AGENT FUNCTIONS
208
+ # ============================================================================
209
+
210
+ async def run_agent_streaming(user_input: str, max_retries: int = 3) -> AsyncGenerator[str, None]:
211
+ """
212
+ Run the agent with streaming support and comprehensive error handling.
213
+
214
+ This function processes user input through the agent executor with streaming
215
+ capabilities, robust error handling, and automatic retries for recoverable errors.
216
+
217
+ Args:
218
+ user_input (str): The user's input message to process
219
+ max_retries (int, optional): Maximum number of retries for recoverable errors.
220
+ Defaults to 3.
221
+
222
+ Yields:
223
+ str: Chunks of the agent's response as they are generated
224
+
225
+ Raises:
226
+ None: All exceptions are caught and handled internally
227
+ """
228
+ # Input validation
229
+ if not user_input or not user_input.strip():
230
+ logger.warning("Empty input received")
231
+ yield "عذراً، لم أتلقَ أي سؤال. يرجى إدخال سؤالك أو طلبك."
232
+ return
233
+
234
+ retry_count = 0
235
+ last_error = None
236
+
237
+ while retry_count <= max_retries:
238
+ try:
239
+ # Load conversation history from memory
240
+ chat_history = memory.load_memory_variables({})["chat_history"]
241
+
242
+ logger.info(f"Processing user input (attempt {retry_count + 1}): {user_input[:50]}...")
243
+
244
+ # Create streaming callback handler
245
+ streaming_handler = StreamingCallbackHandler()
246
+
247
+ # Create a new executor with streaming callback for this request
248
+ streaming_executor = AgentExecutor(
249
+ agent=agent,
250
+ tools=AVAILABLE_TOOLS,
251
+ verbose=True,
252
+ handle_parsing_errors=True,
253
+ max_iterations=10,
254
+ max_execution_time=120,
255
+ callbacks=[streaming_handler]
256
+ )
257
+
258
+ # Run the agent in a separate thread to avoid blocking
259
+ def run_sync():
260
+ return streaming_executor.invoke({
261
+ "input": user_input.strip(),
262
+ "chat_history": chat_history
263
+ })
264
+
265
+ # Execute the agent with streaming
266
+ full_response = ""
267
+ previous_length = 0
268
+
269
+ # Start the agent execution in background
270
+ loop = asyncio.get_event_loop()
271
+ task = loop.run_in_executor(None, run_sync)
272
+
273
+ # Stream the response as it's being generated
274
+ while not task.done():
275
+ current_response = streaming_handler.get_response()
276
+
277
+ # Yield new tokens if available
278
+ if len(current_response) > previous_length:
279
+ new_content = current_response[previous_length:]
280
+ previous_length = len(current_response)
281
+ yield new_content
282
+
283
+ # Small delay to prevent overwhelming the client
284
+ await asyncio.sleep(0.1)
285
+
286
+ # Get the final result
287
+ response = await task
288
+
289
+ # Yield any remaining content
290
+ final_response = streaming_handler.get_response()
291
+ if len(final_response) > previous_length:
292
+ yield final_response[previous_length:]
293
+
294
+ # If no streaming content was captured, yield the full response
295
+ if not final_response and response and "output" in response:
296
+ full_output = response["output"]
297
+ # Simulate streaming by yielding word by word
298
+ words = full_output.split(' ')
299
+ for word in words:
300
+ yield word + ' '
301
+ await asyncio.sleep(0.05)
302
+
303
+ # Validate response structure
304
+ if not response or "output" not in response:
305
+ raise ValidationError("Invalid response format from agent")
306
+
307
+ if not response["output"] or not response["output"].strip():
308
+ raise ValidationError("Empty response from agent")
309
+
310
+ # Save conversation context to memory
311
+ memory.save_context(
312
+ {"input": user_input},
313
+ {"output": response["output"]}
314
+ )
315
+
316
+ logger.info(f"Successfully processed user input: {user_input[:50]}...")
317
+ return
318
+
319
+ except RateLimitError as e:
320
+ retry_count += 1
321
+ last_error = e
322
+ wait_time = min(2 ** retry_count, 60) # Exponential backoff, max 60 seconds
323
+
324
+ logger.warning(
325
+ f"Rate limit exceeded. Retrying in {wait_time} seconds... "
326
+ f"(Attempt {retry_count}/{max_retries})"
327
+ )
328
+
329
+ if retry_count <= max_retries:
330
+ await asyncio.sleep(wait_time)
331
+ continue
332
+ else:
333
+ logger.error("Rate limit exceeded after maximum retries")
334
+ yield "عذراً، النظام مشغول حالياً. يرجى المحاولة مرة أخرى بعد قليل."
335
+ return
336
+
337
+ except APIError as e:
338
+ retry_count += 1
339
+ last_error = e
340
+ logger.error(f"OpenAI API error: {str(e)}")
341
+
342
+ if retry_count <= max_retries:
343
+ await asyncio.sleep(2)
344
+ continue
345
+ else:
346
+ yield "عذراً، حدث خطأ في الاتصال بالخدمة. يرجى المحاولة مرة أخرى لاحقاً."
347
+ return
348
+
349
+ except requests.exceptions.ConnectionError as e:
350
+ retry_count += 1
351
+ last_error = e
352
+ logger.error(f"Network connection error: {str(e)}")
353
+
354
+ if retry_count <= max_retries:
355
+ await asyncio.sleep(3)
356
+ continue
357
+ else:
358
+ yield "عذراً، لا يمكنني الاتصال بالخدمة حالياً. يرجى التحقق من اتصال الإنترنت والمحاولة مرة أخرى."
359
+ return
360
+
361
+ except requests.exceptions.Timeout as e:
362
+ retry_count += 1
363
+ last_error = e
364
+ logger.error(f"Request timeout: {str(e)}")
365
+
366
+ if retry_count <= max_retries:
367
+ await asyncio.sleep(2)
368
+ continue
369
+ else:
370
+ yield "عذراً، استغرق الطلب وقتاً أطول من المتوقع. يرجى المحاولة مرة أخرى."
371
+ return
372
+
373
+ except requests.exceptions.RequestException as e:
374
+ logger.error(f"Request error: {str(e)}")
375
+ yield "عذراً، حدث خطأ في الطلب. يرجى المحاولة مرة أخرى."
376
+ return
377
+
378
+ except OutputParserException as e:
379
+ logger.error(f"Output parsing error: {str(e)}")
380
+ yield "عذراً، حدث خطأ في معالجة الاستجابة. يرجى إعادة صياغة سؤالك والمحاولة مرة أخرى."
381
+ return
382
+
383
+ except ValidationError as e:
384
+ logger.error(f"Validation error: {str(e)}")
385
+ yield "عذراً، حدث خطأ في التحقق من صحة البيانات. يرجى المحاولة مرة أخرى."
386
+ return
387
+
388
+ except ToolExecutionError as e:
389
+ logger.error(f"Tool execution error: {str(e)}")
390
+ yield "عذراً، حدث خطأ أثناء تنفيذ إحدى العمليات. يرجى المحاولة مرة أخرى أو التواصل مع الدعم الفني."
391
+ return
392
+
393
+ except Exception as e:
394
+ logger.error(f"Unexpected error in run_agent_streaming: {str(e)}")
395
+ logger.error(f"Traceback: {traceback.format_exc()}")
396
+
397
+ # For unexpected errors, don't retry
398
+ yield "عذراً، حدث خطأ غير متوقع. يرجى المحاولة مرة أخرى أو التواصل مع الدعم الفني إذا استمرت المشكلة."
399
+ return
400
+
401
+ # This should never be reached, but just in case
402
+ logger.error(f"Maximum retries exceeded. Last error: {str(last_error)}")
403
+ yield "عذراً، لم أتمكن من معالجة طلبك بعد عدة محاولات. يرجى المحاولة مرة أخرى لاحقاً."
404
+
405
+
406
+ async def safe_run_agent_streaming(user_input: str) -> AsyncGenerator[str, None]:
407
+ """
408
+ Streaming wrapper function with additional safety checks and input validation.
409
+
410
+ This function provides an additional layer of safety by validating input parameters,
411
+ checking input length constraints, and handling any critical errors that might
412
+ occur during streaming agent execution.
413
+
414
+ Args:
415
+ user_input (str): The user's input message to process
416
+
417
+ Yields:
418
+ str: Chunks of the agent's response as they are generated
419
+
420
+ Raises:
421
+ None: All exceptions are caught and handled internally
422
+ """
423
+ try:
424
+ # Input type validation
425
+ if not isinstance(user_input, str):
426
+ logger.warning(f"Invalid input type received: {type(user_input)}")
427
+ yield "عذراً، يجب أن يكون الإدخال نصاً صالحاً."
428
+ return
429
+
430
+ # Input length validation
431
+ stripped_input = user_input.strip()
432
+
433
+ if len(stripped_input) > 1000:
434
+ logger.warning(f"Input too long: {len(stripped_input)} characters")
435
+ yield "عذراً، الرسالة طويلة جداً. يرجى اختصار سؤالك."
436
+ return
437
+
438
+ if len(stripped_input) == 0:
439
+ logger.warning("Empty input after stripping")
440
+ yield "عذراً، لم أتلقَ أي سؤال. يرجى إدخال سؤالك أو طلبك."
441
+ return
442
+
443
+ # Stream the response through the main agent function
444
+ async for chunk in run_agent_streaming(user_input):
445
+ yield chunk
446
+
447
+ except Exception as e:
448
+ logger.critical(f"Critical error in safe_run_agent_streaming: {str(e)}")
449
+ logger.critical(f"Traceback: {traceback.format_exc()}")
450
+ yield "عذراً، حدث خطأ خطير في النظام. يرجى التواصل مع الدعم الفني فوراً."
451
+
452
+
453
+ async def run_agent(user_input: str, max_retries: int = 3) -> str:
454
+ """
455
+ Run the agent with comprehensive error handling and retry logic.
456
+
457
+ This function processes user input through the agent executor with robust
458
+ error handling, automatic retries for recoverable errors, and comprehensive
459
+ logging for debugging and monitoring.
460
+
461
+ Args:
462
+ user_input (str): The user's input message to process
463
+ max_retries (int, optional): Maximum number of retries for recoverable errors.
464
+ Defaults to 3.
465
+
466
+ Returns:
467
+ str: The agent's response or an appropriate error message in Arabic
468
+
469
+ Raises:
470
+ None: All exceptions are caught and handled internally
471
+ """
472
+ # Input validation
473
+ if not user_input or not user_input.strip():
474
+ logger.warning("Empty input received")
475
+ return "عذراً، لم أتلقَ أي سؤال. يرجى إدخال سؤالك أو طلبك."
476
+
477
+ retry_count = 0
478
+ last_error = None
479
+
480
+ while retry_count <= max_retries:
481
+ try:
482
+ # Load conversation history from memory
483
+ chat_history = memory.load_memory_variables({})["chat_history"]
484
+
485
+ logger.info(f"Processing user input (attempt {retry_count + 1}): {user_input[:50]}...")
486
+
487
+ # Invoke the agent with input and history (synchronous call)
488
+ response = agent_executor.invoke({
489
+ "input": user_input.strip(),
490
+ "chat_history": chat_history
491
+ })
492
+
493
+ # Validate response structure
494
+ if not response or "output" not in response:
495
+ raise ValidationError("Invalid response format from agent")
496
+
497
+ if not response["output"] or not response["output"].strip():
498
+ raise ValidationError("Empty response from agent")
499
+
500
+ # Save conversation context to memory
501
+ memory.save_context(
502
+ {"input": user_input},
503
+ {"output": response["output"]}
504
+ )
505
+
506
+ logger.info(f"Successfully processed user input: {user_input[:50]}...")
507
+ return response["output"]
508
+
509
+ except RateLimitError as e:
510
+ retry_count += 1
511
+ last_error = e
512
+ wait_time = min(2 ** retry_count, 60) # Exponential backoff, max 60 seconds
513
+
514
+ logger.warning(
515
+ f"Rate limit exceeded. Retrying in {wait_time} seconds... "
516
+ f"(Attempt {retry_count}/{max_retries})"
517
+ )
518
+
519
+ if retry_count <= max_retries:
520
+ await asyncio.sleep(wait_time)
521
+ continue
522
+ else:
523
+ logger.error("Rate limit exceeded after maximum retries")
524
+ return "عذراً، النظام مشغول حالياً. يرجى المحاولة مرة أخرى بعد قليل."
525
+
526
+ except APIError as e:
527
+ retry_count += 1
528
+ last_error = e
529
+ logger.error(f"OpenAI API error: {str(e)}")
530
+
531
+ if retry_count <= max_retries:
532
+ await asyncio.sleep(2)
533
+ continue
534
+ else:
535
+ return "عذراً، حدث خطأ في الاتصال بالخدمة. يرجى المحاولة مرة أخرى لاحقاً."
536
+
537
+ except requests.exceptions.ConnectionError as e:
538
+ retry_count += 1
539
+ last_error = e
540
+ logger.error(f"Network connection error: {str(e)}")
541
+
542
+ if retry_count <= max_retries:
543
+ await asyncio.sleep(3)
544
+ continue
545
+ else:
546
+ return "عذراً، لا يمكنني الاتصال بالخدمة حالياً. يرجى التحقق من اتصال الإنترنت والمحاولة مرة أخرى."
547
+
548
+ except requests.exceptions.Timeout as e:
549
+ retry_count += 1
550
+ last_error = e
551
+ logger.error(f"Request timeout: {str(e)}")
552
+
553
+ if retry_count <= max_retries:
554
+ await asyncio.sleep(2)
555
+ continue
556
+ else:
557
+ return "عذراً، استغرق الطلب وقتاً أطول من المتوقع. يرجى المحاولة مرة أخرى."
558
+
559
+ except requests.exceptions.RequestException as e:
560
+ logger.error(f"Request error: {str(e)}")
561
+ return "عذراً، حدث خطأ في الطلب. يرجى المحاولة مرة أخرى."
562
+
563
+ except OutputParserException as e:
564
+ logger.error(f"Output parsing error: {str(e)}")
565
+ return "عذراً، حدث خطأ في معالجة الاستجابة. يرجى إعادة صياغة سؤالك والمحاولة مرة أخرى."
566
+
567
+ except ValidationError as e:
568
+ logger.error(f"Validation error: {str(e)}")
569
+ return "عذراً، حدث خطأ في التحقق من صحة البيانات. يرجى المحاولة مرة أخرى."
570
+
571
+ except ToolExecutionError as e:
572
+ logger.error(f"Tool execution error: {str(e)}")
573
+ return "عذراً، حدث خطأ أثناء تنفيذ إحدى العمليات. يرجى المحاولة مرة أخرى أو التواصل مع الدعم الفني."
574
+
575
+ except Exception as e:
576
+ logger.error(f"Unexpected error in run_agent: {str(e)}")
577
+ logger.error(f"Traceback: {traceback.format_exc()}")
578
+
579
+ # For unexpected errors, don't retry
580
+ return "عذراً، حدث خطأ غير متوقع. يرجى المحاولة مرة أخرى أو التواصل مع الدعم الفني إذا استمرت المشكلة."
581
+
582
+ # This should never be reached, but just in case
583
+ logger.error(f"Maximum retries exceeded. Last error: {str(last_error)}")
584
+ return "عذراً، لم أتمكن من معالجة طلبك بعد عدة محاولات. يرجى المحاولة مرة أخرى لاحقاً."
585
+
586
+
587
+ async def safe_run_agent(user_input: str) -> str:
588
+ """
589
+ Wrapper function for run_agent with additional safety checks and input validation.
590
+
591
+ This function provides an additional layer of safety by validating input parameters,
592
+ checking input length constraints, and handling any critical errors that might
593
+ occur during agent execution.
594
+
595
+ Args:
596
+ user_input (str): The user's input message to process
597
+
598
+ Returns:
599
+ str: The agent's response or an appropriate error message in Arabic
600
+
601
+ Raises:
602
+ None: All exceptions are caught and handled internally
603
+ """
604
+ try:
605
+ # Input type validation
606
+ if not isinstance(user_input, str):
607
+ logger.warning(f"Invalid input type received: {type(user_input)}")
608
+ return "عذراً، يجب أن يكون الإدخال نصاً صالحاً."
609
+
610
+ # Input length validation
611
+ stripped_input = user_input.strip()
612
+
613
+ if len(stripped_input) > 1000:
614
+ logger.warning(f"Input too long: {len(stripped_input)} characters")
615
+ return "عذراً، الرسالة طويلة جداً. يرجى اختصار سؤالك."
616
+
617
+ if len(stripped_input) == 0:
618
+ logger.warning("Empty input after stripping")
619
+ return "عذراً، لم أتلقَ أي سؤال. يرجى إدخال سؤالك أو طلبك."
620
+
621
+ # Process the input through the main agent function
622
+ return await run_agent(user_input)
623
+
624
+ except Exception as e:
625
+ logger.critical(f"Critical error in safe_run_agent: {str(e)}")
626
+ logger.critical(f"Traceback: {traceback.format_exc()}")
627
+ return "عذراً، حدث خطأ خطير في النظام. يرجى التواصل مع الدعم الفني فوراً."
628
+
629
+
630
+ def clear_memory() -> None:
631
+ """
632
+ Clear the conversation memory.
633
+
634
+ This function clears all stored conversation history from memory,
635
+ effectively starting a fresh conversation session.
636
+ """
637
+ try:
638
+ memory.clear()
639
+ logger.info("Conversation memory cleared successfully")
640
+ except Exception as e:
641
+ logger.error(f"Error clearing memory: {str(e)}")
642
+
643
+
644
+ def get_memory_summary() -> str:
645
+ """
646
+ Get a summary of the current conversation memory.
647
+
648
+ Returns:
649
+ str: A summary of the conversation history stored in memory
650
+ """
651
+ try:
652
+ memory_vars = memory.load_memory_variables({})
653
+ return str(memory_vars.get("chat_history", "No conversation history available"))
654
+ except Exception as e:
655
+ logger.error(f"Error getting memory summary: {str(e)}")
656
+ return "Error retrieving memory summary"
657
+
src/config.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from pathlib import Path
3
+ from langchain_huggingface import HuggingFaceEmbeddings
4
+ from langchain_openai import ChatOpenAI
5
+ from huggingface_hub import login
6
+ from dotenv import load_dotenv
7
+ import logging
8
+
9
+ # Initialize environment
10
+ load_dotenv()
11
+
12
+ # Setup logging
13
+ logging.basicConfig(level=logging.INFO)
14
+ logger = logging.getLogger(__name__)
15
+
16
+ # Secure HuggingFace login with error handling
17
+ try:
18
+ hf_token = os.getenv("HUGGINGFACE_HUB_TOKEN")
19
+ if hf_token:
20
+ login(hf_token)
21
+ logger.info("Successfully logged into HuggingFace")
22
+ else:
23
+ logger.warning("No HuggingFace token found - some features may be limited")
24
+ except Exception as e:
25
+ logger.error(f"HuggingFace login failed: {e}")
26
+
27
+ # --- File Path Configuration (Cross-platform compatible) ---
28
+ PROJECT_ROOT = Path(__file__).parent.parent.absolute()
29
+ DATA_DIR = PROJECT_ROOT / "data"
30
+ COMPANY_INFO_DIR = DATA_DIR / "raw_company_info"
31
+ PROCESSED_DIR = DATA_DIR / "processed"
32
+ CHUNKS_PATH = PROCESSED_DIR / "company_chunks.pkl"
33
+ VECTOR_STORE_DIR = PROCESSED_DIR / "vector_store"
34
+
35
+ # Ensure directories exist
36
+ PROCESSED_DIR.mkdir(parents=True, exist_ok=True)
37
+ COMPANY_INFO_DIR.mkdir(parents=True, exist_ok=True)
38
+
39
+ # --- LLM Configuration with error handling ---
40
+ def create_llm():
41
+ """Create LLM with proper error handling and fallbacks"""
42
+ openai_key = os.getenv("OPENAI_API_KEY")
43
+
44
+ if not openai_key:
45
+ logger.error("OPENAI_API_KEY not found in environment variables")
46
+ raise ValueError("OpenAI API key is required. Please set OPENAI_API_KEY environment variable.")
47
+
48
+ try:
49
+ return ChatOpenAI(
50
+ model="gpt-4o-mini", # More cost-effective for demos
51
+ api_key=openai_key,
52
+ base_url=os.getenv("OPENAI_BASE_URL"), # Optional custom endpoint
53
+ temperature=0.1,
54
+ max_tokens=1024,
55
+ request_timeout=30, # Increased timeout for stability
56
+ max_retries=2,
57
+ streaming=True,
58
+ )
59
+ except Exception as e:
60
+ logger.error(f"Failed to initialize LLM: {e}")
61
+ raise
62
+
63
+ LLM = create_llm()
64
+
65
+ # --- Embedding Model Configuration with error handling ---
66
+ def create_embedding_model():
67
+ """Create embedding model with proper error handling"""
68
+ try:
69
+ return HuggingFaceEmbeddings(
70
+ model_name="intfloat/multilingual-e5-small",
71
+ model_kwargs={'device': 'cpu'},
72
+ encode_kwargs={'normalize_embeddings': True}
73
+ )
74
+ except Exception as e:
75
+ logger.error(f"Failed to load embedding model: {e}")
76
+ # Fallback to a simpler model
77
+ try:
78
+ return HuggingFaceEmbeddings(
79
+ model_name="sentence-transformers/all-MiniLM-L6-v2",
80
+ model_kwargs={'device': 'cpu'},
81
+ encode_kwargs={'normalize_embeddings': True}
82
+ )
83
+ except Exception as e2:
84
+ logger.error(f"Fallback embedding model also failed: {e2}")
85
+ raise
86
+
87
+ EMBEDDING_MODEL = create_embedding_model()
88
+
89
+ # Configuration validation
90
+ def validate_config():
91
+ """Validate all required configurations"""
92
+ required_env_vars = ["OPENAI_API_KEY"]
93
+ missing_vars = [var for var in required_env_vars if not os.getenv(var)]
94
+
95
+ if missing_vars:
96
+ raise ValueError(f"Missing required environment variables: {missing_vars}")
97
+
98
+ # Check if data directories exist
99
+ if not COMPANY_INFO_DIR.exists():
100
+ logger.warning(f"Company info directory not found: {COMPANY_INFO_DIR}")
101
+
102
+ logger.info("Configuration validation completed")
103
+
104
+ # Run validation on import
105
+ try:
106
+ validate_config()
107
+ except Exception as e:
108
+ logger.error(f"Configuration validation failed: {e}")
109
+ raise e
src/data_loaders.py ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Import required libraries
2
+ import pandas as pd
3
+ from pathlib import Path
4
+ from typing import List
5
+ from langchain.schema import Document
6
+ import logging
7
+
8
+ # For PDF processing - now using LangChain's PyPDFLoader
9
+ from langchain_community.document_loaders import PyPDFLoader
10
+
11
+ # Configure logging
12
+ logger = logging.getLogger(__name__)
13
+
14
+ # --- Existing functions (as provided by user) ---
15
+
16
+ # Define a placeholder for COMPANY_INFO_DIR if it's not defined in config.py
17
+ # In a real application, ensure config.py is accessible or pass this path.
18
+ try:
19
+ from config import COMPANY_INFO_DIR
20
+ except ImportError:
21
+ logger.warning("COMPANY_INFO_DIR not found in config.py. Using a default placeholder.")
22
+ COMPANY_INFO_DIR = Path("./company_info") # Placeholder path, adjust as needed
23
+
24
+ def load_faq_documents(faq_path: Path = Path(COMPANY_INFO_DIR) / "FAQ.csv") -> List[Document]:
25
+ """
26
+ Load and process FAQ documents from CSV file.
27
+
28
+ Args:
29
+ faq_path: Path to the FAQ CSV file
30
+
31
+ Returns:
32
+ List of Document objects
33
+ """
34
+ try:
35
+ # Validate file exists
36
+ if not faq_path.exists():
37
+ raise FileNotFoundError(f"FAQ file not found at {faq_path}")
38
+
39
+ df = pd.read_csv(faq_path)
40
+
41
+ # Validate required columns
42
+ required_cols = ['Question', 'Answer']
43
+ if not all(col in df.columns for col in required_cols):
44
+ raise ValueError(f"CSV must contain columns: {required_cols}")
45
+
46
+ documents = []
47
+ for idx, row in df.iterrows():
48
+ content = f"Question: {row.get('Question', '')}\nAnswer: {row.get('Answer', '')}"
49
+
50
+ doc = Document(
51
+ page_content=content,
52
+ metadata={
53
+ "source": "company_faq",
54
+ "type": "faq",
55
+ "doc_id": f"{idx}",
56
+ "filename": faq_path.name
57
+ }
58
+ )
59
+ documents.append(doc)
60
+
61
+ logger.info(f"Loaded {len(documents)} FAQ documents from {faq_path.name}")
62
+ return documents
63
+
64
+ except Exception as e:
65
+ logger.error(f"Error loading FAQ documents from {faq_path.name}: {str(e)}")
66
+ raise
67
+
68
+
69
+ def load_company_info(info_path: Path = Path(COMPANY_INFO_DIR) / "info.md") -> Document:
70
+ """
71
+ Load company information from markdown file.
72
+
73
+ Args:
74
+ info_path: Path to the company info markdown file
75
+
76
+ Returns:
77
+ Document object containing company info
78
+ """
79
+ try:
80
+ # Validate file exists
81
+ if not info_path.exists():
82
+ raise FileNotFoundError(f"Info file not found at {info_path}")
83
+
84
+ with open(info_path, 'r', encoding='utf-8') as f:
85
+ content = f.read()
86
+
87
+ doc = Document(
88
+ page_content=content,
89
+ metadata={
90
+ "source": "company_info",
91
+ "type": "general_info",
92
+ "filename": info_path.name,
93
+ "doc_id": "company_info_main"
94
+ }
95
+ )
96
+ logger.info(f"Loaded company info document from {info_path.name}")
97
+ return doc
98
+
99
+ except Exception as e:
100
+ logger.error(f"Error loading company info from {info_path.name}: {str(e)}")
101
+ raise
102
+
103
+ # --- New functions for PDF, TXT, and Image loading ---
104
+
105
+ def load_pdf_document(file_path: Path) -> List[Document]:
106
+ """
107
+ Load text from a PDF file using LangChain's PyPDFLoader.
108
+ Each page is treated as a separate document.
109
+
110
+ Args:
111
+ file_path: Path to the PDF file.
112
+
113
+ Returns:
114
+ A list of Document objects, one for each page of the PDF.
115
+ """
116
+ documents = []
117
+ try:
118
+ if not file_path.exists():
119
+ raise FileNotFoundError(f"PDF file not found at {file_path}")
120
+
121
+ loader = PyPDFLoader(str(file_path)) # PyPDFLoader expects a string path
122
+ docs = loader.load() # This returns a list of LangChain Document objects
123
+
124
+ # Enhance metadata for consistency and add source/type
125
+ for doc in docs:
126
+ doc.metadata["source"] = "uploaded_file"
127
+ doc.metadata["type"] = "pdf"
128
+ doc.metadata["filename"] = file_path.name
129
+ # PyPDFLoader usually adds 'page' and 'source' (which is the file path)
130
+ # We can use the existing 'page' if it's there or default to 0
131
+ page_num = doc.metadata.get("page", 0)
132
+ doc.metadata["doc_id"] = f"{file_path.stem}_page_{page_num + 1}" # Ensure page number is 1-indexed
133
+
134
+ documents.extend(docs)
135
+
136
+ logger.info(f"Loaded {len(documents)} pages from PDF using PyPDFLoader: {file_path.name}")
137
+ return documents
138
+ except Exception as e:
139
+ logger.error(f"Error loading PDF file {file_path.name} with PyPDFLoader: {str(e)}")
140
+ raise
141
+
142
+ def load_txt_document(file_path: Path) -> Document:
143
+ """
144
+ Load text from a TXT file.
145
+
146
+ Args:
147
+ file_path: Path to the TXT file.
148
+
149
+ Returns:
150
+ A Document object containing the text from the file.
151
+ """
152
+ try:
153
+ if not file_path.exists():
154
+ raise FileNotFoundError(f"TXT file not found at {file_path}")
155
+
156
+ with open(file_path, 'r', encoding='utf-8') as f:
157
+ content = f.read()
158
+
159
+ doc = Document(
160
+ page_content=content,
161
+ metadata={
162
+ "source": "uploaded_file",
163
+ "type": "txt",
164
+ "filename": file_path.name,
165
+ "doc_id": file_path.stem
166
+ }
167
+ )
168
+ logger.info(f"Loaded TXT file: {file_path.name}")
169
+ return doc
170
+ except Exception as e:
171
+ logger.error(f"Error loading TXT file {file_path.name}: {str(e)}")
172
+ raise
173
+
174
+
175
+ def process_uploaded_file(file_path: Path) -> List[Document]:
176
+ """
177
+ Determines the file extension and calls the appropriate function to process it.
178
+
179
+ Args:
180
+ file_path: Path to the uploaded file.
181
+
182
+ Returns:
183
+ A list of Document objects containing the extracted text.
184
+ Returns an empty list if the file type is unsupported or an error occurs.
185
+ """
186
+ documents = []
187
+ try:
188
+ if not file_path.exists():
189
+ raise FileNotFoundError(f"File not found at {file_path}")
190
+
191
+ extension = file_path.suffix.lower()
192
+
193
+ if extension == '.pdf':
194
+ documents = load_pdf_document(file_path)
195
+ elif extension == '.txt':
196
+ documents = [load_txt_document(file_path)] # Wrap in list for consistency
197
+ else:
198
+ logger.warning(f"Unsupported file type for {file_path.name}: {extension}")
199
+ # Optionally, you could raise an error here if unsupported files should halt execution
200
+ # raise ValueError(f"Unsupported file type: {extension}")
201
+ return [] # Return empty list for unsupported types
202
+
203
+ except FileNotFoundError as fnfe:
204
+ logger.error(f"Processing failed: {fnfe}")
205
+ except Exception as e:
206
+ logger.error(f"An unexpected error occurred while processing {file_path.name}: {str(e)}")
207
+
208
+ return documents
src/retriever.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from utils import *
2
+ from langchain_community.retrievers import BM25Retriever
3
+ from langchain.retrievers import EnsembleRetriever
4
+ from config import logger
5
+
6
+ # Try to load existing vector store, create if not found
7
+ try:
8
+ logger.info("Loading vector store...")
9
+ vector_store = load_company_vector_store()
10
+ if vector_store:
11
+ logger.info("Vector store loaded successfully")
12
+ else:
13
+ # If vector_store is None, this means it didn't exist
14
+ logger.info("Vector store not found, creating new...")
15
+ company_documents = create_company_documents()
16
+ company_chunks = split_documents(company_documents)
17
+ vector_store = create_company_vector_store(company_chunks)
18
+ logger.info("Vector store created successfully")
19
+ except Exception as e:
20
+ # This block will handle other potential errors during the loading/creation process
21
+ logger.error(f"Error loading or creating vector store: {str(e)}")
22
+ # It might be good to exit or handle this more gracefully.
23
+ # For now, let's just re-raise the exception to see what's wrong.
24
+ raise
25
+
26
+
27
+ # Try to load existing company chunks, create if not found
28
+ try:
29
+ logger.info("Loading company chunks...")
30
+ company_chunks = load_chunks()
31
+ if company_chunks:
32
+ logger.info("Company chunks loaded successfully")
33
+ else:
34
+ # If company_chunks is None, this means it didn't exist
35
+ logger.info("Company chunks not found, creating new...")
36
+ company_documents = create_company_documents()
37
+ company_chunks = split_documents(company_documents)
38
+ save_chunks(company_chunks)
39
+ logger.info("Company chunks created successfully")
40
+
41
+ except Exception as e:
42
+ # This block will handle other potential errors during the loading/creation process
43
+ logger.error(f"Error loading or creating company chunks: {str(e)}")
44
+ # It might be good to exit or handle this more gracefully.
45
+ # For now, let's just re-raise the exception to see what's wrong.
46
+ raise
47
+
48
+
49
+ # Create vector retriever
50
+ logger.info("🔍 Creating vector retriever...")
51
+ vector_retriever = vector_store.as_retriever(search_kwargs={"k": 5})
52
+
53
+ # Create BM25 retriever
54
+ logger.info("📝 Creating BM25 retriever...")
55
+ bm25_retriever = BM25Retriever.from_documents(company_chunks)
56
+ bm25_retriever.k = 3
57
+
58
+ # Create hybrid retriever
59
+ logger.info("🔄 Creating hybrid retriever...")
60
+ hybrid_retriever = EnsembleRetriever(
61
+ retrievers=[bm25_retriever, vector_retriever],
62
+ weights=[0.2, 0.8]
63
+ )
64
+
65
+
66
+ logger.info("✅ Retrievers created and hybrid retriever is ready.")
src/text_processor.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain.text_splitter import (
2
+ RecursiveCharacterTextSplitter,
3
+ MarkdownHeaderTextSplitter
4
+ )
5
+
6
+ recursive_500 = RecursiveCharacterTextSplitter(
7
+ chunk_size=500,
8
+ chunk_overlap=50,
9
+ length_function=len,
10
+ separators=[
11
+ "\n\n", # Paragraph breaks
12
+ "\n", # Line breaks
13
+ ".", # Sentences
14
+ ",", # Clauses
15
+ " ", # Words
16
+ ]
17
+ )
18
+
19
+
20
+ markdown_splitter = MarkdownHeaderTextSplitter(
21
+ headers_to_split_on=[
22
+ ("#", "company_title"),
23
+ ("##", "section"),
24
+ ]
25
+ )
src/tools.py ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain.tools.retriever import create_retriever_tool
2
+ from langchain_community.tools import TavilySearchResults
3
+ from langchain.tools import tool
4
+ from retriever import hybrid_retriever
5
+ import pytz
6
+ from datetime import datetime
7
+ from pydantic import BaseModel, Field
8
+ from typing import Optional
9
+ import json
10
+ import uuid
11
+
12
+
13
+ # Optimized retriever tool with faster settings
14
+ retriever_tool = create_retriever_tool(
15
+ hybrid_retriever,
16
+ name="company_knowledge_tool",
17
+ description="Fast tool for company info, history, products, and policies. Use only for Al Shifa Digital Healthcare questions."
18
+ )
19
+
20
+ # Optimized web search tool with reduced results for speed
21
+ websearch_tool = TavilySearchResults(
22
+ max_results=3,
23
+ include_answer=True,
24
+ include_raw_content=False,
25
+ include_images=False,
26
+ search_depth="basic",
27
+ name="Tavily_Search_Tool",
28
+ description="Fast search for medical questions and current info. Use for medical advice and up-to-date information."
29
+ )
30
+
31
+
32
+ @tool
33
+ def get_current_datetime_tool() -> str:
34
+ """
35
+ Returns the current date, time, and day of the week for Saudi Arabia (Asia/Riyadh).
36
+ This is the only reliable source for date and time information. Use this tool
37
+ whenever a user asks about 'today', 'now', or any other time-sensitive query.
38
+ The output is in English but shows Saudi Arabia local time.
39
+ """
40
+ try:
41
+ # Define the timezone for Saudi Arabia
42
+ saudi_tz = pytz.timezone('Asia/Riyadh')
43
+
44
+ # Get the current time in that timezone
45
+ now_saudi = datetime.now(saudi_tz)
46
+
47
+ # Manual mapping to ensure English output regardless of system locale
48
+ days_en = {
49
+ 0: "Monday", 1: "Tuesday", 2: "Wednesday", 3: "Thursday",
50
+ 4: "Friday", 5: "Saturday", 6: "Sunday"
51
+ }
52
+ months_en = {
53
+ 1: "January", 2: "February", 3: "March", 4: "April",
54
+ 5: "May", 6: "June", 7: "July", 8: "August",
55
+ 9: "September", 10: "October", 11: "November", 12: "December"
56
+ }
57
+
58
+ # Get English names using manual mapping
59
+ day_name = days_en[now_saudi.weekday()]
60
+ month_name = months_en[now_saudi.month]
61
+ day = now_saudi.day
62
+ year = now_saudi.year
63
+
64
+ # Format time manually to avoid locale issues
65
+ hour = now_saudi.hour
66
+ minute = now_saudi.minute
67
+
68
+ # Convert to 12-hour format
69
+ if hour == 0:
70
+ hour_12 = 12
71
+ period = "AM"
72
+ elif hour < 12:
73
+ hour_12 = hour
74
+ period = "AM"
75
+ elif hour == 12:
76
+ hour_12 = 12
77
+ period = "PM"
78
+ else:
79
+ hour_12 = hour - 12
80
+ period = "PM"
81
+
82
+ time_str = f"{hour_12:02d}:{minute:02d} {period}"
83
+
84
+ # Create the final string
85
+ return f"Current date and time in Saudi Arabia: {day_name}, {month_name} {day}, {year} at {time_str}"
86
+
87
+ except Exception as e:
88
+ return f"Error getting current datetime: {str(e)}"
89
+
90
+
91
+ # --- Pydantic Model for Structured Tool Input ---
92
+ # All fields are now Optional to prevent validation errors at the agent level.
93
+ # The validation logic is moved inside the tool itself.
94
+ class BookingInput(BaseModel):
95
+ """Inputs for the book_consultation tool."""
96
+ patient_name: Optional[str] = Field(None, description="The user's full name.")
97
+ age: Optional[str] = Field(None, description="The user's age.")
98
+ gender: Optional[str] = Field(None, description="The user's gender.")
99
+ contact_number: Optional[str] = Field(None, description="A phone number for confirmation.")
100
+ email: Optional[str] = Field(None, description="An email address for confirmation and reminders.")
101
+ reason_for_consultation: Optional[str] = Field(None, description="A brief description of the user's symptoms or reason for the visit.")
102
+ preferred_date: Optional[str] = Field(None, description="The user's desired date for the appointment.")
103
+ preferred_time: Optional[str] = Field(None, description="The user's desired time for the appointment.")
104
+ specialty: Optional[str] = Field(None, description="The specific medical field needed.")
105
+ doctor_preference: Optional[str] = Field(None, description="The name of a specific doctor, if requested.")
106
+ consultation_type: Optional[str] = Field(None, description="The method of consultation.")
107
+
108
+ @tool(args_schema=BookingInput)
109
+ def book_consultation_tool(patient_name: Optional[str] = None, age: Optional[str] = None, gender: Optional[str] = None, contact_number: Optional[str] = None, email: Optional[str] = None, reason_for_consultation: Optional[str] = None, preferred_date: Optional[str] = None, preferred_time: Optional[str] = None, consultation_type: Optional[str] = None, specialty: Optional[str] = None, doctor_preference: Optional[str] = None) -> str:
110
+ """
111
+ Books a medical consultation. If required information is missing, it returns a message
112
+ asking for the missing details. Otherwise, it returns the booking data as a JSON object.
113
+ Email is optional and will be set to 'unknown@alshifa-care.com' if not provided.
114
+ """
115
+ # --- 1. Internal Validation: Check for missing required information ---
116
+ missing_fields = []
117
+ if not patient_name:
118
+ missing_fields.append("اسم المريض الكامل (patient_name)")
119
+ if not age:
120
+ missing_fields.append("العمر (age)")
121
+ if not gender:
122
+ missing_fields.append("الجنس (gender)")
123
+ if not contact_number:
124
+ missing_fields.append("رقم التواصل (contact_number)")
125
+ if not reason_for_consultation:
126
+ missing_fields.append("سبب الاستشارة (reason_for_consultation)")
127
+ if not preferred_date:
128
+ missing_fields.append("التاريخ المفضل (preferred_date)")
129
+ if not preferred_time:
130
+ missing_fields.append("الوقت المفضل (preferred_time)")
131
+ # Set default email if not provided
132
+ if not email:
133
+ email = "unknown@alshifa-care.com"
134
+ # --- 2. Handle missing required fields ---
135
+ if missing_fields:
136
+ missing_fields_str = "\n- ".join([""] + missing_fields) # Add newline and bullet points
137
+ return f"""
138
+ عذراً، لا يمكن إتمام الحجز بسبب نقص المعلومات المطلوبة. يرجى توفير:
139
+ {missing_fields_str}
140
+
141
+ Sorry, we cannot complete the booking due to missing required information. Please provide:
142
+ {missing_fields_str}
143
+ """
144
+ # --- 2. If all data is present, proceed with booking ---
145
+ booking_id = f"BK-{uuid.uuid4().hex[:8].upper()}"
146
+ timestamp = datetime.now().isoformat()
147
+ booking_data = {
148
+ "booking_id": booking_id,
149
+ "booking_timestamp": timestamp,
150
+ "patient_details": {"name": patient_name, "age": age, "gender": gender, "contact_number": contact_number, "email": email},
151
+ "consultation_details": {
152
+ "reason": reason_for_consultation,
153
+ "preferred_date": preferred_date,
154
+ "preferred_time": preferred_time,
155
+ "specialty": specialty or "Not Specified",
156
+ "doctor_preference": doctor_preference or "Any",
157
+ "type": consultation_type or "Video Call"
158
+ }
159
+ }
160
+ # 3. Return the final data as a formatted JSON string
161
+ return json.dumps(booking_data, indent=4, ensure_ascii=False)
src/utils.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pickle
2
+ import logging
3
+ from pathlib import Path
4
+ from typing import List, Optional
5
+ from langchain.schema import Document
6
+ from langchain_community.vectorstores import FAISS
7
+
8
+ from config import EMBEDDING_MODEL, VECTOR_STORE_DIR, CHUNKS_PATH
9
+ from data_loaders import load_company_info, load_faq_documents
10
+ from text_processor import markdown_splitter, recursive_500
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ def load_company_vector_store() -> Optional[FAISS]:
15
+ """Load existing vector store with proper error handling"""
16
+ try:
17
+ if Path(VECTOR_STORE_DIR).exists():
18
+ vector_store = FAISS.load_local(
19
+ str(VECTOR_STORE_DIR),
20
+ EMBEDDING_MODEL,
21
+ allow_dangerous_deserialization=True
22
+ )
23
+ logger.info("Successfully loaded existing vector store")
24
+ return vector_store
25
+ else:
26
+ logger.info("No existing vector store found")
27
+ return None
28
+ except Exception as e:
29
+ logger.error(f"Failed to load vector store: {e}")
30
+ return None
31
+
32
+ def create_company_vector_store(documents: List[Document]) -> Optional[FAISS]:
33
+ """Create and save vector store with error handling"""
34
+ if not documents:
35
+ logger.error("No documents provided to create vector store")
36
+ return None
37
+
38
+ try:
39
+ # Ensure directory exists
40
+ Path(VECTOR_STORE_DIR).mkdir(parents=True, exist_ok=True)
41
+
42
+ vector_store = FAISS.from_documents(documents, EMBEDDING_MODEL)
43
+ vector_store.save_local(str(VECTOR_STORE_DIR))
44
+ logger.info(f"Successfully created and saved vector store with {len(documents)} documents")
45
+ return vector_store
46
+ except Exception as e:
47
+ logger.error(f"Failed to create vector store: {e}")
48
+ return None
49
+
50
+ def create_company_documents() -> List[Document]:
51
+ """Create company documents with error handling"""
52
+ try:
53
+ company_documents = []
54
+
55
+ # Load FAQ documents
56
+ try:
57
+ faq_docs = load_faq_documents()
58
+ company_documents.extend(faq_docs)
59
+ logger.info(f"Loaded {len(faq_docs)} FAQ documents")
60
+ except Exception as e:
61
+ logger.error(f"Failed to load FAQ documents: {e}")
62
+
63
+ # Load company info
64
+ try:
65
+ company_info = load_company_info()
66
+ if company_info:
67
+ company_documents.append(company_info)
68
+ logger.info("Loaded company info document")
69
+ except Exception as e:
70
+ logger.error(f"Failed to load company info: {e}")
71
+
72
+ logger.info(f"Total documents loaded: {len(company_documents)}")
73
+ return company_documents
74
+
75
+ except Exception as e:
76
+ logger.error(f"Failed to create company documents: {e}")
77
+ return []
78
+
79
+ def split_documents(company_documents: List[Document]) -> List[Document]:
80
+ """Split documents into chunks with error handling"""
81
+ if not company_documents:
82
+ logger.warning("No documents provided for splitting")
83
+ return []
84
+
85
+ company_chunks = []
86
+
87
+ try:
88
+ for i, doc in enumerate(company_documents):
89
+ try:
90
+ if doc.metadata.get("type") == "general_info":
91
+ # Use markdown splitter for info.md
92
+ split_docs = markdown_splitter.split_text(doc.page_content)
93
+ for d in split_docs:
94
+ d.metadata.update(doc.metadata)
95
+ company_chunks.extend(split_docs)
96
+ logger.debug(f"Split document {i} using markdown splitter")
97
+ else:
98
+ # Use recursive splitter for FAQs
99
+ split_docs = recursive_500.split_documents([doc])
100
+ company_chunks.extend(split_docs)
101
+ logger.debug(f"Split document {i} using recursive splitter")
102
+
103
+ except Exception as e:
104
+ logger.error(f"Failed to split document {i}: {e}")
105
+ continue
106
+
107
+ logger.info(f"Successfully split {len(company_documents)} documents into {len(company_chunks)} chunks")
108
+ return company_chunks
109
+
110
+ except Exception as e:
111
+ logger.error(f"Failed to split documents: {e}")
112
+ return []
113
+
114
+ def load_chunks() -> Optional[List[Document]]:
115
+ """Load pre-processed chunks with error handling"""
116
+ try:
117
+ if Path(CHUNKS_PATH).exists():
118
+ with open(CHUNKS_PATH, 'rb') as f:
119
+ company_chunks = pickle.load(f)
120
+ logger.info(f"Successfully loaded {len(company_chunks)} chunks from cache")
121
+ return company_chunks
122
+ else:
123
+ logger.info("No cached chunks found")
124
+ return None
125
+ except Exception as e:
126
+ logger.error(f"Failed to load chunks: {e}")
127
+ return None
128
+
129
+ def save_chunks(chunks: List[Document]) -> bool:
130
+ """Save processed chunks to file"""
131
+ try:
132
+ # Ensure directory exists
133
+ Path(CHUNKS_PATH).parent.mkdir(parents=True, exist_ok=True)
134
+
135
+ with open(CHUNKS_PATH, 'wb') as f:
136
+ pickle.dump(chunks, f)
137
+ logger.info(f"Successfully saved {len(chunks)} chunks to {CHUNKS_PATH}")
138
+ return True
139
+ except Exception as e:
140
+ logger.error(f"Failed to save chunks: {e}")
141
+ return False
142
+
143
+ def initialize_knowledge_base() -> Optional[FAISS]:
144
+ """Initialize the complete knowledge base"""
145
+ try:
146
+ # Try to load existing vector store
147
+ vector_store = load_company_vector_store()
148
+ if vector_store:
149
+ return vector_store
150
+
151
+ # If no existing store, create new one
152
+ logger.info("Creating new knowledge base...")
153
+
154
+ # Load or create chunks
155
+ chunks = load_chunks()
156
+ if not chunks:
157
+ logger.info("No cached chunks found, processing documents...")
158
+ documents = create_company_documents()
159
+ if documents:
160
+ chunks = split_documents(documents)
161
+ if chunks:
162
+ save_chunks(chunks)
163
+
164
+ if chunks:
165
+ vector_store = create_company_vector_store(chunks)
166
+ return vector_store
167
+ else:
168
+ logger.error("No chunks available to create vector store")
169
+ return None
170
+
171
+ except Exception as e:
172
+ logger.error(f"Failed to initialize knowledge base: {e}")
173
+ return None
src/vector_store.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from utils import *
2
+
3
+ # Try to load existing vector store, create if not found
4
+ try:
5
+ print("Loading vector store...")
6
+ vector_store = load_company_vector_store()
7
+ if vector_store:
8
+ print("Vector store loaded successfully")
9
+ else:
10
+ # If vector_store is None, this means it didn't exist
11
+ print("Vector store not found, creating new...")
12
+ company_documents = create_company_documents()
13
+ company_chunks = split_documents(company_documents)
14
+ vector_store = create_company_vector_store(company_chunks)
15
+ print("Vector store created successfully")
16
+ except Exception as e:
17
+ # This block will handle other potential errors during the loading/creation process
18
+ logger.error(f"Error loading or creating vector store: {str(e)}")
19
+ # It might be good to exit or handle this more gracefully.
20
+ # For now, let's just re-raise the exception to see what's wrong.
21
+ raise
22
+
23
+