fansa34 commited on
Commit
d0cd3f5
·
1 Parent(s): 1739591

added docker

Browse files
Files changed (7) hide show
  1. .env +0 -1
  2. .gitignore +5 -1
  3. Dockerfile +32 -0
  4. README.md +1 -0
  5. agent_direct_llm_sections.py +123 -180
  6. app.py +61 -0
  7. requirements.txt +10 -0
.env CHANGED
@@ -1 +0,0 @@
1
- OPENAI_API_KEY =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
 
 
.gitignore CHANGED
@@ -1,2 +1,6 @@
1
  ingestion_storage/
2
- data/supplementary_docs/
 
 
 
 
 
1
  ingestion_storage/
2
+ data/supplementary_docs/
3
+
4
+ __pycache__
5
+
6
+
Dockerfile ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use Python 3.11 slim image
2
+ FROM python:3.11-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Install system dependencies
8
+ RUN apt-get update && apt-get install -y \
9
+ build-essential \
10
+ curl \
11
+ && rm -rf /var/lib/apt/lists/*
12
+
13
+ # Copy requirements first (for better caching)
14
+ COPY requirements.txt .
15
+
16
+ # Install Python dependencies
17
+ RUN pip install --no-cache-dir -r requirements.txt
18
+
19
+ # Copy your application files
20
+ COPY . .
21
+
22
+ # Create necessary directories if they don't exist
23
+ RUN mkdir -p data/section_files storage/supplementary_indices
24
+
25
+ # Set environment variables
26
+ ENV PYTHONPATH=/app
27
+ ENV PYTHONUNBUFFERED=1
28
+
29
+ # Expose the port that FastAPI will run on
30
+ EXPOSE 7860
31
+
32
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -6,6 +6,7 @@ colorTo: yellow
6
  sdk: docker
7
  pinned: false
8
  short_description: agentic RAG
 
9
  ---
10
 
11
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
6
  sdk: docker
7
  pinned: false
8
  short_description: agentic RAG
9
+ app_port: 7860
10
  ---
11
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
agent_direct_llm_sections.py CHANGED
@@ -1,9 +1,8 @@
1
- # agent_direct_llm_sections.py (with .NET API tools added)
2
 
3
  import os
4
  import sys
5
  from pathlib import Path
6
- # import argparse # Not used by this script's main flow currently
7
  from functools import partial
8
 
9
  # LlamaIndex Core Imports
@@ -16,30 +15,19 @@ from llama_index.core.tools import QueryEngineTool
16
 
17
  # LLM Import (Use Gemini)
18
  from llama_index.llms.google_genai import GoogleGenAI
19
- import traceback # For printing full tracebacks
20
 
21
- # Assuming these are no longer needed as per your focus on direct LLM agent for protocols
22
- # from session_functions import save_session, load_session, delete_session
23
- # from global_settings import SESSION_FILE, STORAGE_PATH
24
-
25
- SECTION_FILES_PATH = "./data/section_files" # Make sure this is correct
26
  SUPPLEMENTARY_INDEXES_BASE_PATH_FOR_AGENT = "./storage/supplementary_indices"
27
 
28
- # --- NEW: Imports for API callers ---
29
- # Make sure api_callers.py is in the same directory or your PYTHONPATH
30
- from api_callers import get_vaccination_statistics, get_patient_vaccination_record
31
- from image_callers import find_relevant_image_info
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
 
44
 
45
 
@@ -55,6 +43,7 @@ from image_callers import find_relevant_image_info
55
 
56
 
57
  def configure_settings():
 
58
  print("Configuring LLM (Google GenAI)...")
59
  gemini_api_key = os.getenv("GOOGLE_API_KEY")
60
  Settings.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5")
@@ -69,19 +58,6 @@ def configure_settings():
69
 
70
 
71
 
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
 
86
 
87
 
@@ -94,6 +70,7 @@ def query_section_directly(
94
  section_title_for_prompt: str,
95
  sub_query: str
96
  ) -> str:
 
97
  print(f"--- INSIDE query_section_directly (Tool for Section ID: {section_id_for_log}) ---")
98
  print(f" Attempting to read: {section_file_path}")
99
  print(f" For sub_query: '{sub_query}'")
@@ -147,7 +124,7 @@ def query_section_directly(
147
  try:
148
  response_obj = Settings.llm.complete(prompt)
149
  if hasattr(response_obj, 'text') and response_obj.text is not None:
150
- final_answer = response_obj.text.strip() # Added .strip()
151
  print(f" LLM response received for section {section_id_for_log} (first 100 chars): {final_answer[:100]}...")
152
  return f"According to Section {section_id_for_log} ('{section_title_for_prompt}'):\n{final_answer}"
153
  else:
@@ -177,93 +154,75 @@ def query_section_directly(
177
 
178
 
179
 
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
- # --- Main Agent Setup and Query Loop ---
198
- def run_direct_protocol_agent():
199
- # Your existing section_tool_definitions
200
- # !!! ENSURE "title" and "filename" keys are correct for each section !!!
201
  section_tool_definitions = [
202
  {
203
  "id": "1", "filename": "section_1.txt",
204
- "title": "LE PROGRAMME ELARGI DE VACCINATION EN ALGERIE", # From your ToC
205
  "description": "Fournit des informations générales UNIQUEMENT de la Section 1 sur 'LE PROGRAMME ELARGI DE VACCINATION EN ALGERIE'. Utiliser pour des questions sur les objectifs, l'historique, les points forts/faibles du programme de vaccination algérien (PEV), et la justification des actualisations du calendrier."
206
  },
207
  {
208
  "id": "2", "filename": "section_2.txt",
209
- "title": "REPERES SUR LES MALADIES CIBLES DU CALENDRIER NATIONAL DE VACCINATION", # From your ToC
210
  "description": "Cette section contient LE CALENDRIER NATIONAL DE VACCINATION 2023 , officiel Fournit des descriptions détaillées UNIQUEMENT de la Section 2 sur les MALADIES spécifiques ciblées par le calendrier (Diphtérie, Rougeole, Oreillons, Coqueluche, Poliomyélite, Rubéole, Tétanos, Tuberculose, Hépatite B, Hib, Pneumocoques). Utiliser pour consulter le calendrier par âge , pour des questions sur la définition, transmission, symptômes, complications, et prévention de ces MALADIES."
211
  },
212
  {
213
  "id": "3", "filename": "section_3.txt",
214
- "title": "REPERES SUR LES VACCINS DU CALENDRIER NATIONAL DE VACCINATION 2023", # From your ToC
215
  "description": "Fournit des informations détaillées UNIQUEMENT de la Section 3 sur les VACCINS spécifiques du calendrier national de vaccination 2023., les méthodes d'administration (3.2), et détails sur chaque vaccin (BCG, Hépatite B, DTCaVPI-Hib-HBV, ROR, etc.) (3.3). Utiliser pour des questions sur les types de vaccins et leur administration."
216
  },
217
  {
218
  "id": "4", "filename": "section_4.txt",
219
- "title": "RATTRAPAGE VACCINAL", # From your ToC
220
- "description": (
221
- "Fournit des informations UNIQUEMENT de la Section 4 concernant le RATTRAPAGE VACCINAL. "
222
- "Utiliser pour déterminer les procédures, règles, et schémas de rattrapage pour des vaccins SPÉCIFIQUEMENT IDENTIFIÉS COMME MANQUANTS OU EN RETARD, "
223
- "après avoir consulté le calendrier vaccinal standard (via l'outil de la Section 11) pour l'âge du patient."
224
- )
225
  },
226
  {
227
  "id": "5", "filename": "section_5.txt",
228
- "title": "VACCINATION DES POPULATIONS PARTICULIÈRES", # From your ToC
229
  "description": "Fournit des informations UNIQUEMENT de la Section 5 sur la VACCINATION DES POPULATIONS PARTICULIÈRES. Inclut directives pour enfant allergique (5.1, y compris œufs), prématurés, diabète, immunosuppression (y compris VIH 5.10), etc. Utiliser pour questions sur la vaccination dans ces contextes cliniques."
230
  },
231
  {
232
  "id": "6", "filename": "section_6.txt",
233
- "title": "LES FONDAMENTAUX DE LA CHAINE DU FROID", # From your ToC
234
  "description": "Fournit des informations UNIQUEMENT de la Section 6 sur la CHAINE DU FROID pour les vaccins (principes, transport, gestion stocks, conservation, pannes)."
235
  },
236
  {
237
  "id": "7", "filename": "section_7.txt",
238
- "title": "SÉCURITÉ DES INJECTIONS", # From your ToC
239
  "description": "Fournit des informations UNIQUEMENT de la Section 7 sur la SÉCURITÉ DES INJECTIONS (matériel, techniques, prévention blessures, élimination déchets)."
240
  },
241
  {
242
  "id": "8", "filename": "section_8.txt",
243
- "title": "TENUE DUNE SEANCE DE VACCINATION ET VACCINOVIGILANCE", # From your ToC
244
- "description": "Fournit des informations UNIQUEMENT de la Section 8 sur la TENUE DUNE SEANCE DE VACCINATION ET LA VACCINOVIGILANCE (préparation matériel, administration, enregistrement, surveillance MAPI/MPVI)."
245
  },
246
  {
247
  "id": "9", "filename": "section_9.txt",
248
- "title": "PLANIFICATION DES SÉANCES DE VACCINATION", # From your ToC
249
  "description": "Fournit des informations UNIQUEMENT de la Section 9 sur la PLANIFICATION DES SÉANCES DE VACCINATION (carte opérationnelle, estimation besoins, gestion stocks)."
250
  },
251
  {
252
  "id": "10", "filename": "section_10.txt",
253
- "title": "MOBILISATION SOCIALE EN FAVEUR DE LA VACCINATION", # From your ToC
254
  "description": "Fournit des informations UNIQUEMENT de la Section 10 sur la MOBILISATION SOCIALE (communication, gestion rumeurs, hésitation vaccinale)."
255
  },
256
- {
257
- "id": "11",
258
- "filename": "section_11.txt", # Or section_11_calendrier_vaccinal.txt
259
- "title": "Calendrier National de Vaccination Algérien 2023 (Tableau Détaillé)",
260
- "description": (
261
- "Source faisant autorité contenant UNIQUEMENT LE TABLEAU DÉTAILLÉ du Calendrier National de Vaccination Algérien 2023. "
262
- "Consulter cet outil EXCLUSIVEMENT pour déterminer avec précision : les vaccins spécifiques recommandés à chaque âge (par exemple, à 2 mois, 11 mois, 18 mois, 3 ans, 6 ans), "
263
- "le nombre de doses pour chaque vaccin, l'âge exact d'administration pour chaque dose, et les intervalles requis entre les doses. "
264
- "C'est la référence principale pour toute question sur le schéma vaccinal standard par âge en Algérie et pour calculer les doses dues ou ce qu'un enfant aurait dû recevoir à un certain âge."
265
- )
266
- }
267
  ]
268
 
269
 
@@ -282,8 +241,9 @@ def run_direct_protocol_agent():
282
 
283
 
284
 
285
- print("\n--- Creating Function Tools ---")
286
- tools_list = [] # Using your existing variable name
 
287
  section_files_dir = Path(SECTION_FILES_PATH)
288
 
289
  # Create tools for Algerian Protocol Sections
@@ -291,9 +251,8 @@ def run_direct_protocol_agent():
291
  for section_def in section_tool_definitions:
292
  section_file_path = section_files_dir / section_def["filename"]
293
  section_id_for_tool = section_def["id"]
294
- # Ensure 'title' key exists and is correct in your definitions
295
  section_title_for_tool = section_def.get("title", f"Section {section_id_for_tool} Details")
296
- tool_name = f"algerian_protocol_section_{section_id_for_tool}_tool" # Added prefix
297
 
298
  if not section_file_path.exists():
299
  print(f" ⚠️ Warning: Protocol section file '{section_def['filename']}' not found. Skipping tool '{tool_name}'.")
@@ -314,57 +273,45 @@ def run_direct_protocol_agent():
314
  tools_list.append(protocol_section_tool)
315
  print(f" Tool '{protocol_section_tool.metadata.name}' created.")
316
 
317
-
318
-
319
- # --- NEW: Create and Add Tools for .NET API ---
320
- print(" Creating .NET API Tools...")
321
- stats_api_tool = FunctionTool.from_defaults(
322
- fn=get_vaccination_statistics, # This function comes from api_callers.py
323
- name="get_vaccination_statistics_tool",
324
- description=(
325
- "Fetches current vaccination statistics for a specified Algerian Wilaya (province/state) "
326
- "from an external API, such as coverage rates. "
327
- "The input should be the name of the Wilaya (e.g., 'Algiers', 'Sétif')."
328
  )
329
- )
330
- tools_list.append(stats_api_tool)
331
- print(f" Tool '{stats_api_tool.metadata.name}' created.")
332
-
333
- patient_record_api_tool = FunctionTool.from_defaults(
334
- fn=get_patient_vaccination_record, # This function comes from api_callers.py
335
- name="get_patient_vaccination_record_tool",
336
- description=(
337
- "Retrieves the vaccination record for a specific patient using their unique ID "
338
- "from an external API. The input should be the patient's unique identifier string."
339
  )
340
- )
341
- tools_list.append(patient_record_api_tool)
342
- print(f" Tool '{patient_record_api_tool.metadata.name}' created.")
343
- # --- END NEW API Tools ---
344
-
345
-
346
- # --- NEW: Create and Add Image Retrieval Tool ---
347
- print(" Creating Image Retrieval Tool...")
348
- image_retrieval_tool = FunctionTool.from_defaults(
349
- fn=find_relevant_image_info, # The new Python function
350
- name="image_retrieval_tool",
351
- description=(
352
- "Searches for and provides information about relevant images, figures, diagrams, or flowcharts "
353
- "from the Algerian vaccination protocol document based on a textual description of the desired image. "
354
- "Use this if the user asks for a specific figure (e.g., 'Figure 4.1'), an illustration of a concept "
355
- "(e.g., 'diagram of cold chain levels'), or a visual representation."
356
- "the input for the tool should be a description of the image (e.g., 'Figure 4.1', 'diagram of cold chain levels')."
357
  )
358
- )
359
- tools_list.append(image_retrieval_tool)
360
- print(f" Tool '{image_retrieval_tool.metadata.name}' created.")
361
-
362
-
363
-
364
 
365
-
366
- # --- NEW: Create Tool for the WHO Supplementary Document Index ---
367
- who_doc_index_dir_name = "who_guidelines_index" # Matches output_dir from ingestion script
368
  who_doc_index_path = Path(SUPPLEMENTARY_INDEXES_BASE_PATH_FOR_AGENT) / who_doc_index_dir_name
369
  who_doc_tool_name = "who_general_vaccination_guidelines_tool"
370
  who_doc_description = (
@@ -377,13 +324,8 @@ def run_direct_protocol_agent():
377
  print(f" Creating WHO Document Tool from index: {who_doc_index_path}...")
378
  try:
379
  who_storage_context = StorageContext.from_defaults(persist_dir=str(who_doc_index_path))
380
-
381
  who_vector_index = load_index_from_storage(who_storage_context)
382
-
383
- # Create a query engine for THIS specific WHO document index
384
- who_query_engine = who_vector_index.as_query_engine(
385
- similarity_top_k=3 # Adjust as needed
386
- )
387
 
388
  who_tool = QueryEngineTool.from_defaults(
389
  query_engine=who_query_engine,
@@ -395,14 +337,9 @@ def run_direct_protocol_agent():
395
  except Exception as e:
396
  print(f" ⚠️ Error creating WHO document tool from index {who_doc_index_path}: {e}")
397
  traceback.print_exc()
398
- else:
399
- print(f"⚠️ Warning: WHO document index not found at {who_doc_index_path}. WHO tool will be unavailable.")
400
-
401
 
402
  if not tools_list:
403
- print("No tools were created for the agent. Check file paths and tool definitions.")
404
- return
405
-
406
 
407
 
408
 
@@ -423,10 +360,7 @@ def run_direct_protocol_agent():
423
 
424
 
425
 
426
-
427
- # --- Create Agent with an Updated Custom System Prompt ---
428
- print(f"\n--- Creating ReAct Agent with {len(tools_list)} tools ---")
429
- # --- NEW: Updated custom_system_prompt to include API tools ---
430
  custom_system_prompt = f"""
431
  You are an expert assistant for Algerian vaccination protocols and related health data.
432
  Your primary goal is to answer the user's query accurately and comprehensively by strategically using the available tools.
@@ -450,7 +384,18 @@ def run_direct_protocol_agent():
450
  Always prioritize information from the Algerian national protocol tools for specific local recommendations if available.
451
  Present the final answer clearly in the user's language (likely French).
452
  """
453
- # --- END NEW System Prompt ---
 
 
 
 
 
 
 
 
 
 
 
454
 
455
 
456
 
@@ -470,17 +415,29 @@ def run_direct_protocol_agent():
470
 
471
 
472
 
473
- agent = ReActAgent.from_tools(
474
- tools=tools_list, # Pass the combined list of tools
475
- llm=Settings.llm,
476
- verbose=True,
477
- system_prompt=custom_system_prompt # Use the updated system prompt
478
- )
479
- print("Agent created.")
480
 
481
- # --- Query Loop ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
482
  print("\n*** Enter query for Orchestrator Agent (type 'exit' to quit) ***")
483
- # (Your existing query loop as before)
484
  while True:
485
  user_query = input("\nQuery: ")
486
  if user_query.lower() == 'exit':
@@ -513,27 +470,13 @@ def run_direct_protocol_agent():
513
 
514
 
515
 
516
-
517
-
518
-
 
519
 
520
  if __name__ == "__main__":
521
  try:
522
- if not Path(SECTION_FILES_PATH).is_dir():
523
- print(f"❌ Error: Directory for section files not found: {SECTION_FILES_PATH}")
524
- sys.exit(1)
525
-
526
- # --- NEW: Add check for DOTNET_API_BASE_URL ---
527
- if not os.getenv("DOTNET_API_BASE_URL") or os.getenv("DOTNET_API_BASE_URL") == "http://localhost:5030/api/": # Default placeholder
528
- print("*"*60)
529
- print("⚠️ IMPORTANT WARNING: DOTNET_API_BASE_URL environment variable is not set ")
530
- print(" or is still the default placeholder 'http://YOUR_API_DOMAIN_OR_IP/api'.")
531
- print(" The .NET API tools WILL NOT function correctly. ")
532
- print(" Please set it to your actual .NET API base URL if you intend to use them.")
533
- print("*"*60)
534
- # --- END NEW Check ---
535
-
536
- configure_settings()
537
  run_direct_protocol_agent()
538
  except Exception as e:
539
  print(f"An fatal error occurred: {e}")
 
1
+ # agent_direct_llm_sections.py (Modified for FastAPI integration)
2
 
3
  import os
4
  import sys
5
  from pathlib import Path
 
6
  from functools import partial
7
 
8
  # LlamaIndex Core Imports
 
15
 
16
  # LLM Import (Use Gemini)
17
  from llama_index.llms.google_genai import GoogleGenAI
18
+ import traceback
19
 
20
+ SECTION_FILES_PATH = "./data/section_files"
 
 
 
 
21
  SUPPLEMENTARY_INDEXES_BASE_PATH_FOR_AGENT = "./storage/supplementary_indices"
22
 
23
+ # --- Imports for API callers ---
24
+ try:
25
+ from api_callers import get_vaccination_statistics, get_patient_vaccination_record
26
+ from image_callers import find_relevant_image_info
27
+ API_CALLERS_AVAILABLE = True
28
+ except ImportError:
29
+ print("⚠️ Warning: api_callers.py or image_callers.py not found. API tools will be unavailable.")
30
+ API_CALLERS_AVAILABLE = False
 
 
 
 
 
 
 
31
 
32
 
33
 
 
43
 
44
 
45
  def configure_settings():
46
+ """Configure LLM and embedding settings"""
47
  print("Configuring LLM (Google GenAI)...")
48
  gemini_api_key = os.getenv("GOOGLE_API_KEY")
49
  Settings.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5")
 
58
 
59
 
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
 
63
 
 
70
  section_title_for_prompt: str,
71
  sub_query: str
72
  ) -> str:
73
+ """Query a specific section directly"""
74
  print(f"--- INSIDE query_section_directly (Tool for Section ID: {section_id_for_log}) ---")
75
  print(f" Attempting to read: {section_file_path}")
76
  print(f" For sub_query: '{sub_query}'")
 
124
  try:
125
  response_obj = Settings.llm.complete(prompt)
126
  if hasattr(response_obj, 'text') and response_obj.text is not None:
127
+ final_answer = response_obj.text.strip()
128
  print(f" LLM response received for section {section_id_for_log} (first 100 chars): {final_answer[:100]}...")
129
  return f"According to Section {section_id_for_log} ('{section_title_for_prompt}'):\n{final_answer}"
130
  else:
 
154
 
155
 
156
 
157
+ def create_agent_instance():
158
+ """Create and return an agent instance for API use"""
159
+ # Section tool definitions
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  section_tool_definitions = [
161
  {
162
  "id": "1", "filename": "section_1.txt",
163
+ "title": "LE PROGRAMME ELARGI DE VACCINATION EN ALGERIE",
164
  "description": "Fournit des informations générales UNIQUEMENT de la Section 1 sur 'LE PROGRAMME ELARGI DE VACCINATION EN ALGERIE'. Utiliser pour des questions sur les objectifs, l'historique, les points forts/faibles du programme de vaccination algérien (PEV), et la justification des actualisations du calendrier."
165
  },
166
  {
167
  "id": "2", "filename": "section_2.txt",
168
+ "title": "REPERES SUR LES MALADIES CIBLES DU CALENDRIER NATIONAL DE VACCINATION",
169
  "description": "Cette section contient LE CALENDRIER NATIONAL DE VACCINATION 2023 , officiel Fournit des descriptions détaillées UNIQUEMENT de la Section 2 sur les MALADIES spécifiques ciblées par le calendrier (Diphtérie, Rougeole, Oreillons, Coqueluche, Poliomyélite, Rubéole, Tétanos, Tuberculose, Hépatite B, Hib, Pneumocoques). Utiliser pour consulter le calendrier par âge , pour des questions sur la définition, transmission, symptômes, complications, et prévention de ces MALADIES."
170
  },
171
  {
172
  "id": "3", "filename": "section_3.txt",
173
+ "title": "REPERES SUR LES VACCINS DU CALENDRIER NATIONAL DE VACCINATION 2023",
174
  "description": "Fournit des informations détaillées UNIQUEMENT de la Section 3 sur les VACCINS spécifiques du calendrier national de vaccination 2023., les méthodes d'administration (3.2), et détails sur chaque vaccin (BCG, Hépatite B, DTCaVPI-Hib-HBV, ROR, etc.) (3.3). Utiliser pour des questions sur les types de vaccins et leur administration."
175
  },
176
  {
177
  "id": "4", "filename": "section_4.txt",
178
+ "title": "RATTRAPAGE VACCINAL",
179
+ "description": (
180
+ "Fournit des informations UNIQUEMENT de la Section 4 concernant le RATTRAPAGE VACCINAL. "
181
+ "Utiliser pour déterminer les procédures, règles, et schémas de rattrapage pour des vaccins SPÉCIFIQUEMENT IDENTIFIÉS COMME MANQUANTS OU EN RETARD, "
182
+ "après avoir consulté le calendrier vaccinal standard (via l'outil de la Section 11) pour l'âge du patient."
183
+ )
184
  },
185
  {
186
  "id": "5", "filename": "section_5.txt",
187
+ "title": "VACCINATION DES POPULATIONS PARTICULIÈRES",
188
  "description": "Fournit des informations UNIQUEMENT de la Section 5 sur la VACCINATION DES POPULATIONS PARTICULIÈRES. Inclut directives pour enfant allergique (5.1, y compris œufs), prématurés, diabète, immunosuppression (y compris VIH 5.10), etc. Utiliser pour questions sur la vaccination dans ces contextes cliniques."
189
  },
190
  {
191
  "id": "6", "filename": "section_6.txt",
192
+ "title": "LES FONDAMENTAUX DE LA CHAINE DU FROID",
193
  "description": "Fournit des informations UNIQUEMENT de la Section 6 sur la CHAINE DU FROID pour les vaccins (principes, transport, gestion stocks, conservation, pannes)."
194
  },
195
  {
196
  "id": "7", "filename": "section_7.txt",
197
+ "title": "SÉCURITÉ DES INJECTIONS",
198
  "description": "Fournit des informations UNIQUEMENT de la Section 7 sur la SÉCURITÉ DES INJECTIONS (matériel, techniques, prévention blessures, élimination déchets)."
199
  },
200
  {
201
  "id": "8", "filename": "section_8.txt",
202
+ "title": "TENUE D'UNE SEANCE DE VACCINATION ET VACCINOVIGILANCE",
203
+ "description": "Fournit des informations UNIQUEMENT de la Section 8 sur la TENUE D'UNE SEANCE DE VACCINATION ET LA VACCINOVIGILANCE (préparation matériel, administration, enregistrement, surveillance MAPI/MPVI)."
204
  },
205
  {
206
  "id": "9", "filename": "section_9.txt",
207
+ "title": "PLANIFICATION DES SÉANCES DE VACCINATION",
208
  "description": "Fournit des informations UNIQUEMENT de la Section 9 sur la PLANIFICATION DES SÉANCES DE VACCINATION (carte opérationnelle, estimation besoins, gestion stocks)."
209
  },
210
  {
211
  "id": "10", "filename": "section_10.txt",
212
+ "title": "MOBILISATION SOCIALE EN FAVEUR DE LA VACCINATION",
213
  "description": "Fournit des informations UNIQUEMENT de la Section 10 sur la MOBILISATION SOCIALE (communication, gestion rumeurs, hésitation vaccinale)."
214
  },
215
+ {
216
+ "id": "11",
217
+ "filename": "section_11.txt",
218
+ "title": "Calendrier National de Vaccination Algérien 2023 (Tableau Détaillé)",
219
+ "description": (
220
+ "Source faisant autorité contenant UNIQUEMENT LE TABLEAU DÉTAILLÉ du Calendrier National de Vaccination Algérien 2023. "
221
+ "Consulter cet outil EXCLUSIVEMENT pour déterminer avec précision : les vaccins spécifiques recommandés à chaque âge (par exemple, à 2 mois, 11 mois, 18 mois, 3 ans, 6 ans), "
222
+ "le nombre de doses pour chaque vaccin, l'âge exact d'administration pour chaque dose, et les intervalles requis entre les doses. "
223
+ "C'est la référence principale pour toute question sur le schéma vaccinal standard par âge en Algérie et pour calculer les doses dues ou ce qu'un enfant aurait dû recevoir à un certain âge."
224
+ )
225
+ }
226
  ]
227
 
228
 
 
241
 
242
 
243
 
244
+
245
+ print("\n--- Creating Function Tools for API Agent ---")
246
+ tools_list = []
247
  section_files_dir = Path(SECTION_FILES_PATH)
248
 
249
  # Create tools for Algerian Protocol Sections
 
251
  for section_def in section_tool_definitions:
252
  section_file_path = section_files_dir / section_def["filename"]
253
  section_id_for_tool = section_def["id"]
 
254
  section_title_for_tool = section_def.get("title", f"Section {section_id_for_tool} Details")
255
+ tool_name = f"algerian_protocol_section_{section_id_for_tool}_tool"
256
 
257
  if not section_file_path.exists():
258
  print(f" ⚠️ Warning: Protocol section file '{section_def['filename']}' not found. Skipping tool '{tool_name}'.")
 
273
  tools_list.append(protocol_section_tool)
274
  print(f" Tool '{protocol_section_tool.metadata.name}' created.")
275
 
276
+ # Add API tools if available
277
+ if API_CALLERS_AVAILABLE:
278
+ print(" Creating .NET API Tools...")
279
+ stats_api_tool = FunctionTool.from_defaults(
280
+ fn=get_vaccination_statistics,
281
+ name="get_vaccination_statistics_tool",
282
+ description=(
283
+ "Fetches current vaccination statistics for a specified Algerian Wilaya (province/state) "
284
+ "from an external API, such as coverage rates. "
285
+ "The input should be the name of the Wilaya (e.g., 'Algiers', 'Sétif')."
286
+ )
287
  )
288
+ tools_list.append(stats_api_tool)
289
+
290
+ patient_record_api_tool = FunctionTool.from_defaults(
291
+ fn=get_patient_vaccination_record,
292
+ name="get_patient_vaccination_record_tool",
293
+ description=(
294
+ "Retrieves the vaccination record for a specific patient using their unique ID "
295
+ "from an external API. The input should be the patient's unique identifier string."
296
+ )
 
297
  )
298
+ tools_list.append(patient_record_api_tool)
299
+
300
+ image_retrieval_tool = FunctionTool.from_defaults(
301
+ fn=find_relevant_image_info,
302
+ name="image_retrieval_tool",
303
+ description=(
304
+ "Searches for and provides information about relevant images, figures, diagrams, or flowcharts "
305
+ "from the Algerian vaccination protocol document based on a textual description of the desired image. "
306
+ "Use this if the user asks for a specific figure (e.g., 'Figure 4.1'), an illustration of a concept "
307
+ "(e.g., 'diagram of cold chain levels'), or a visual representation."
308
+ "the input for the tool should be a description of the image (e.g., 'Figure 4.1', 'diagram of cold chain levels')."
309
+ )
 
 
 
 
 
310
  )
311
+ tools_list.append(image_retrieval_tool)
 
 
 
 
 
312
 
313
+ # Add WHO document tool if available
314
+ who_doc_index_dir_name = "who_guidelines_index"
 
315
  who_doc_index_path = Path(SUPPLEMENTARY_INDEXES_BASE_PATH_FOR_AGENT) / who_doc_index_dir_name
316
  who_doc_tool_name = "who_general_vaccination_guidelines_tool"
317
  who_doc_description = (
 
324
  print(f" Creating WHO Document Tool from index: {who_doc_index_path}...")
325
  try:
326
  who_storage_context = StorageContext.from_defaults(persist_dir=str(who_doc_index_path))
 
327
  who_vector_index = load_index_from_storage(who_storage_context)
328
+ who_query_engine = who_vector_index.as_query_engine(similarity_top_k=3)
 
 
 
 
329
 
330
  who_tool = QueryEngineTool.from_defaults(
331
  query_engine=who_query_engine,
 
337
  except Exception as e:
338
  print(f" ⚠️ Error creating WHO document tool from index {who_doc_index_path}: {e}")
339
  traceback.print_exc()
 
 
 
340
 
341
  if not tools_list:
342
+ raise Exception("No tools were created for the agent. Check file paths and tool definitions.")
 
 
343
 
344
 
345
 
 
360
 
361
 
362
 
363
+ # Create custom system prompt
 
 
 
364
  custom_system_prompt = f"""
365
  You are an expert assistant for Algerian vaccination protocols and related health data.
366
  Your primary goal is to answer the user's query accurately and comprehensively by strategically using the available tools.
 
384
  Always prioritize information from the Algerian national protocol tools for specific local recommendations if available.
385
  Present the final answer clearly in the user's language (likely French).
386
  """
387
+
388
+ # Create and return the agent
389
+ agent = ReActAgent.from_tools(
390
+ tools=tools_list,
391
+ llm=Settings.llm,
392
+ verbose=True,
393
+ system_prompt=custom_system_prompt
394
+ )
395
+
396
+ print(f"✅ Agent created with {len(tools_list)} tools.")
397
+ return agent
398
+
399
 
400
 
401
 
 
415
 
416
 
417
 
 
 
 
 
 
 
 
418
 
419
+
420
+
421
+
422
+
423
+ def run_direct_protocol_agent():
424
+ """Original CLI function - kept for backward compatibility"""
425
+ if not Path(SECTION_FILES_PATH).is_dir():
426
+ print(f"❌ Error: Directory for section files not found: {SECTION_FILES_PATH}")
427
+ sys.exit(1)
428
+
429
+ if not os.getenv("DOTNET_API_BASE_URL") or os.getenv("DOTNET_API_BASE_URL") == "http://localhost:5030/api/":
430
+ print("*"*60)
431
+ print("⚠️ IMPORTANT WARNING: DOTNET_API_BASE_URL environment variable is not set ")
432
+ print(" or is still the default placeholder 'http://YOUR_API_DOMAIN_OR_IP/api'.")
433
+ print(" The .NET API tools WILL NOT function correctly. ")
434
+ print(" Please set it to your actual .NET API base URL if you intend to use them.")
435
+ print("*"*60)
436
+
437
+ configure_settings()
438
+ agent = create_agent_instance()
439
+
440
  print("\n*** Enter query for Orchestrator Agent (type 'exit' to quit) ***")
 
441
  while True:
442
  user_query = input("\nQuery: ")
443
  if user_query.lower() == 'exit':
 
470
 
471
 
472
 
473
+ # Add this function for the FastAPI to use
474
+ def run_direct_protocol_agent_for_api():
475
+ """This function was referenced in the original FastAPI but not needed for the simple version"""
476
+ pass
477
 
478
  if __name__ == "__main__":
479
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
480
  run_direct_protocol_agent()
481
  except Exception as e:
482
  print(f"An fatal error occurred: {e}")
app.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from pydantic import BaseModel
3
+ import os
4
+ from pathlib import Path
5
+
6
+ # Import your existing agent functions
7
+ from agent_direct_llm_sections import configure_settings, create_agent_instance
8
+
9
+ app = FastAPI()
10
+
11
+ # Request model
12
+ class QueryRequest(BaseModel):
13
+ question: str
14
+
15
+ # Global agent variable
16
+ agent = None
17
+
18
+ @app.on_event("startup")
19
+ async def startup_event():
20
+ """Initialize the agent when API starts"""
21
+ global agent
22
+ try:
23
+ # Check if required files exist
24
+ if not Path("./data/section_files").is_dir():
25
+ raise Exception("Section files directory not found")
26
+
27
+ # Check environment variable
28
+ if not os.getenv("GOOGLE_API_KEY"):
29
+ raise Exception("GOOGLE_API_KEY not set")
30
+
31
+ # Initialize agent
32
+ configure_settings()
33
+ agent = create_agent_instance()
34
+ print("✅ Agent initialized successfully!")
35
+
36
+ except Exception as e:
37
+ print(f"❌ Failed to initialize agent: {e}")
38
+ agent = None
39
+
40
+ @app.post("/ask")
41
+ async def ask_question(request: QueryRequest):
42
+ """Send a question and get an answer"""
43
+ if agent is None:
44
+ raise HTTPException(status_code=503, detail="Agent not initialized")
45
+
46
+ if not request.question.strip():
47
+ raise HTTPException(status_code=400, detail="Question cannot be empty")
48
+
49
+ try:
50
+ # Get response from agent
51
+ response = agent.chat(request.question)
52
+ return {"answer": str(response.response)}
53
+
54
+ except Exception as e:
55
+ raise HTTPException(status_code=500, detail=f"Error: {str(e)}")
56
+
57
+ if __name__ == "__main__":
58
+ import uvicorn
59
+ # Use port 7860 for Hugging Face Spaces
60
+ port = int(os.environ.get("PORT", 7860))
61
+ uvicorn.run("main:app", host="0.0.0.0", port=port, reload=False)
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # FastAPI and server
2
+ fastapi==0.104.1
3
+ uvicorn[standard]==0.24.0
4
+
5
+
6
+ llama-index-core
7
+ llama-index-embeddings-huggingface
8
+ llama-index-llms-google-genai
9
+ sentence-transformers
10
+