Views
No views yet
1import json
2import os
3import pickle
4import time
5from datetime import datetime, timedelta ,time as time_1
6from threading import Thread
7from typing import TypedDict, Dict, List, Any
8from urllib.request import Request
9
10import pytz
11import torch
12from duckduckgo_search import DDGS
13from google_auth_oauthlib.flow import InstalledAppFlow
14from googleapiclient.discovery import build
15from langchain_community.tools import TavilySearchResults
16from langgraph.constants import START, END
17from langgraph.graph import StateGraph
18from regex import regex, search
19from smolagents import DuckDuckGoSearchTool
20from sympy.physics.units.definitions.dimension_definitions import information
21from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
22from dotenv import load_dotenv
23from tzlocal import get_localzone
24
25load_dotenv()
26
27torch.manual_seed(11)
28model_name = "aldsouza/health-agent"
29pattern = r'''
30 \{ # Opening brace of the function block
31 \s*"name"\s*:\s*"([^"]+)"\s*, # Capture the function name
32 \s*"arguments"\s*:\s*(\{ # Capture the arguments JSON object starting brace
33 (?:[^{}]++ | (?2))*? # Recursive matching for balanced braces (PCRE syntax)
34 \}) # Closing brace of arguments
35 \s*\} # Closing brace of the function block
36 '''
37
38tokenizer = AutoTokenizer.from_pretrained(model_name)
39model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.float16).to("cuda")
40# model_1 = AutoModelForCausalLM.from_pretrained("deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B",torch_dtype=torch.float16).to("cuda")
41
42medical_tools = [
43 {
44 "name": "symptom_checker",
45 "description": "Analyze symptoms and provide possible conditions.",
46 "parameters": {
47 "symptoms": {
48 "description": "List of symptoms reported by the patient.",
49 "type": "list[str]",
50 "default": ["headache", "fever"]
51 }
52 }
53 },
54 {
55 "name": "medication_lookup",
56 "description": "Look up details about a medication by its name.",
57 "parameters": {
58 "medication_name": {
59 "description": "Name of the medication to look up.",
60 "type": "str",
61 "default": "Aspirin"
62 }
63 }
64 },
65 {
66 "name": "book_appointment",
67 "description": "Schedule a medical appointment with a doctor.",
68 "parameters": {
69 "patient_name": {
70 "description": "Name of the patient.",
71 "type": "str",
72 "default": "John Doe"
73 },
74 "doctor_specialty": {
75 "description": "Specialty of the doctor to book.",
76 "type": "str",
77 "default": "general practitioner"
78 },
79 "date": {
80 "description": "Preferred date of appointment (YYYY-MM-DD).",
81 "type": "str",
82 "default": "2025-08-20"
83 }
84 }
85 },
86 {
87 "name": "get_lab_results",
88 "description": "Retrieve lab test results for a patient by test ID.",
89 "parameters": {
90 "patient_id": {
91 "description": "Unique patient identifier.",
92 "type": "str",
93 "default": "123456"
94 },
95 "test_id": {
96 "description": "Lab test identifier.",
97 "type": "str",
98 "default": "cbc"
99 }
100 }
101 },
102 {
103 "name": "request_missing_info",
104 "description": "Ask the user for missing or incomplete information needed to fulfill their request.",
105 "parameters": {
106 "missing_fields": {
107 "description": "List of missing required fields to be clarified by the user.",
108 "type": "list[str]",
109 "default": []
110 },
111 "context": {
112 "description": "Optional context or explanation to help the user provide the missing information.",
113 "type": "str",
114 "default": ""
115 }
116 }
117 },
118 {
119 "name": "medical_device_info",
120 "description": "Retrieve detailed information about a medical device by its name or model number.",
121 "parameters": {
122 "device_name": {
123 "description": "The name or model number of the medical device to look up.",
124 "type": "str",
125 "default": "Blood Pressure Monitor"
126 }
127 }
128 }, {
129 "name": "record_blood_pressure",
130 "description": "Record a patient's blood pressure reading with systolic, diastolic, and pulse rate values.",
131 "parameters": {
132 "patient_id": {
133 "description": "Unique identifier of the patient.",
134 "type": "str",
135 "default": "123456"
136 },
137 "systolic": {
138 "description": "Systolic blood pressure value (mmHg).",
139 "type": "int",
140 "default": 120
141 },
142 "diastolic": {
143 "description": "Diastolic blood pressure value (mmHg).",
144 "type": "int",
145 "default": 80
146 },
147 "pulse_rate": {
148 "description": "Pulse rate in beats per minute.",
149 "type": "int",
150 "default": 70
151 },
152 "measurement_time": {
153 "description": "Timestamp of the measurement (YYYY-MM-DD HH:MM).",
154 "type": "str",
155 "default": "2025-08-12 09:00"
156 }
157 }
158 }, {
159 "name": "start_blood_pressure_test",
160 "description": "Initiate a blood pressure measurement test for a patient using a connected device.",
161 "parameters": {
162 "patient_id": {
163 "description": "Unique identifier of the patient.",
164 "type": "str",
165 "default": "123456"
166 },
167 "device_id": {
168 "description": "Identifier or model of the blood pressure measuring device.",
169 "type": "str",
170 "default": "BP-Device-001"
171 }
172 }
173 }
174]
175# Compose the system prompt embedding the tools JSON
176system_prompt = f"""
177You are an intelligent AI assistant that uses available tools (functions) to help users achieve their medical-related goals. Your job is to understand the user's intent, identify missing information if needed, and then select and call the most appropriate function(s) to solve the task.
178
179# Rules:
180- ALWAYS use the tools provided to answer the user's request, unless explicitly told not to.
181- Ask clarifying questions ONLY if the user's request is ambiguous or lacks required input parameters.
182- If multiple tools are needed, use them in sequence.
183- DO NOT make up data or assume values — request any missing input clearly.
184
185# Output Format:
186- Respond using a JSON list of function calls in the following format:
187 [
188 {{
189 "name": "function_name",
190 "arguments": {{
191 "param1": "value1",
192 "param2": "value2"
193 }}
194 ]
195- Only include the functions needed to complete the task.
196- If no function is needed or the input is unclear, ask a clarifying question instead of guessing.
197- Do NOT respond with explanations or natural language outside the JSON block unless explicitly instructed.
198
199Following are the tools provided to you:
200{json.dumps(medical_tools, indent=2)}
201"""
202SCOPES = ['https://www.googleapis.com/auth/calendar']
203
204def symptom_checker(kwargs):
205 print(f"Checking diseases for following symptoms on the web:")
206 symptoms = kwargs.get("symptoms",[])
207 print(symptoms)
208 for i, arg in enumerate(symptoms):
209 print(f"{i}. {arg}")
210 results = TavilySearchResults()
211 information = ""
212 for result in results.invoke(f"What causes {''.join(symptoms)}"):
213 information = information + result["content"] + "\n"
214 return {
215 "status":200,
216 "message":information
217 }
218
219def medication_lookup(kwargs):
220 medication_name = kwargs.get("medication_name")
221 print(f"Looking up the web for information on {medication_name}....")
222 results = TavilySearchResults()
223 information = ""
224 for result in results.invoke(f"What is {medication_name}?"):
225 information = information + result["content"] + "\n"
226 return {
227 "status": 200,
228 "message": information
229 }
230
231
232def create_google_calendar_meeting(
233 summary: str,
234 start_datetime: str,
235 end_datetime: str,
236 attendees_emails: list,
237 timezone: str = 'America/Chicago'
238):
239 """
240 Creates a Google Calendar event.
241
242 Args:
243 summary (str): Event title.
244 start_datetime (str): Start datetime in ISO format, e.g., "2025-08-18T10:00:00-06:00".
245 end_datetime (str): End datetime in ISO format.
246 attendees_emails (list): List of attendee emails.
247 timezone (str): Timezone string, default 'America/Chicago'.
248 """
249
250 creds = None
251 # Load saved credentials if available
252 if os.path.exists('token.pickle'):
253 with open('token.pickle', 'rb') as token:
254 creds = pickle.load(token)
255
256 # Authenticate if necessary
257 if not creds or not creds.valid:
258 if creds and creds.expired and creds.refresh_token:
259 creds.refresh(Request())
260 else:
261 flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)
262 creds = flow.run_local_server(port=0)
263 with open('token.pickle', 'wb') as token:
264 pickle.dump(creds, token)
265
266 service = build('calendar', 'v3', credentials=creds)
267
268 event = {
269 'summary': summary,
270 'location': 'Virtual / Google Meet',
271 'description': f'{summary} meeting.',
272 'start': {'dateTime': start_datetime, 'timeZone': timezone},
273 'end': {'dateTime': end_datetime, 'timeZone': timezone},
274 'attendees': [{'email': email} for email in attendees_emails],
275 'reminders': {'useDefault': True},
276 }
277
278 created_event = service.events().insert(
279 calendarId='primary', body=event, sendUpdates='all'
280 ).execute()
281
282 print(f"Event created: {created_event.get('htmlLink')}")
283 return created_event
284def book_appointment(kwargs):
285 patient_name = kwargs.get("patient_name")
286 doctor_specialty = kwargs.get("doctor_specialty")
287 date_str = kwargs.get("date")
288 parsed_date = datetime.strptime(date_str, "%Y-%m-%d").date()
289
290 # Default time 9:00 AM Mountain Time
291 mountain_tz = pytz.timezone("America/Denver")
292 dt_mt = datetime.combine(parsed_date, time_1(9, 0))
293 dt_mt = mountain_tz.localize(dt_mt)
294
295 # Autodetect local timezone
296 local_tz = get_localzone()
297 dt_local = dt_mt.astimezone(local_tz)
298 dt_local_end = dt_local + timedelta(hours=1)
299 result = create_google_calendar_meeting(
300 f"Meeting for {patient_name}",
301 dt_local.isoformat(),
302 dt_local_end.isoformat(),
303 ["altondsouza02@gmail.com", "aldsouza@ualberta.ca"]
304 )
305 return {
306 "status":200,
307 "message": f"Event Created:{result}"
308 }
309
310
311function_execution_map = {
312 "symptom_checker": symptom_checker,
313 "medication_lookup": medication_lookup,
314 "book_appointment": book_appointment
315}
316
317
318# Example prompt using the medical tools
319# messages = [
320# {
321# "content": system_prompt,
322# "role": "system"
323# },
324# {
325# "content": (
326# "I have a headache and mild fever. What could be the possible conditions? "
327# "Also, lookup medication details for 'Ibuprofen'. "
328# "Please book an appointment for patient 'Alice Smith' with a neurologist on 2025-09-01."
329# ),
330# "role": "user"
331# }
332# ]
333
334# streamer = TextStreamer(tokenizer, skip_prompt=True)
335# streamer = TextIteratorStreamer(tokenizer, skip_prompt=True)
336# inputs = tokenizer.apply_chat_template(
337# messages,
338# add_generation_prompt=True,
339# tokenize=True,
340# return_dict=True,
341# return_tensors="pt",
342# ).to(model.device)
343# inputs = tokenizer.apply_chat_template(
344# messages,
345# add_generation_prompt=True,
346# tokenize=True,
347# return_dict=True,
348# return_tensors="pt",
349# ).to(mo)
350
351# generation_kwargs = dict(inputs,streamer=streamer,
352# max_new_tokens=4096,
353# temperature=0.7,)
354# thread = Thread(target=model.generate, kwargs=generation_kwargs,daemon=True)
355# thread.start()
356# for new_text in streamer:
357# print(new_text, end="")
358# with torch.no_grad():
359# outputs = model.generate(
360# **inputs,streamer=streamer,
361# max_new_tokens=4096,
362# temperature=0.7,
363# )
364
365class State(TypedDict):
366 messages: List[Dict[str, Any]]
367 plan: List[Dict[str, Any]]
368 task: str
369
370
371graph_builder = StateGraph(State)
372
373PLANNING_AGENT = "PLANNING_AGENT"
374
375
376def planning(state: State):
377 print("Coming up with Plan")
378 messages = state.get("messages", [])
379 inputs = tokenizer.apply_chat_template(
380 messages,
381 add_generation_prompt=True,
382 tokenize=True,
383 return_dict=True,
384 return_tensors="pt",
385 ).to(model.device)
386 streamer = TextIteratorStreamer(tokenizer, skip_prompt=True)
387 generation_kwargs = dict(inputs, streamer=streamer,
388 max_new_tokens=4096,
389 temperature=0.7, )
390 thread = Thread(target=model.generate, kwargs=generation_kwargs, daemon=True)
391 thread.start()
392 generated_text = ""
393 for new_text in streamer:
394 print(new_text, end="")
395 generated_text = generated_text + new_text
396 generated_text = generated_text.replace("<|end▁of▁sentence|>","").replace("</think>","")
397
398 matches = regex.findall(pattern, generated_text, regex.VERBOSE)
399 plan = state.get("plan", [])
400
401 for i, (func_name, args_json) in enumerate(matches, 1):
402 plan_entry = dict()
403 plan_entry["function_name"] = func_name
404 plan_entry["arguments"] = json.loads(args_json)
405 plan.append(plan_entry)
406
407 messages.append({"role": "assistant", "content": generated_text})
408
409 return {"messages":messages, "plan": plan}
410
411
412ROUTER = "ROUTER"
413
414
415def router(state: State):
416 plan = state.get("plan", [])
417 if len(plan) > 0:
418 return "execute_plan"
419 return "respond"
420
421
422def execute_plan(state: State):
423 print("Executing")
424 plan = state.get("plan", [])
425 for plan_entry in plan:
426 plan_entry["status"] = dict()
427 print(f"Executing {plan_entry['function_name']} with details {plan_entry['arguments']}")
428 print("Approve Execution?(y/n)")
429 response = input()
430 response = response.strip().lower()
431
432 if response == "y":
433 print("Approved.")
434 if plan_entry["function_name"] in function_execution_map.keys():
435 function = function_execution_map[plan_entry["function_name"]]
436 result = function(plan_entry["arguments"])
437 plan_entry["status"] = result
438 else:
439 print(f"Capability not implemented for {plan_entry['function_name']}")
440 print("Done with task.")
441 print("Proceeding with next.")
442
443 elif response == "n":
444 print("Not approved.")
445 else:
446 print("Invalid input, please enter 'y' or 'n'.")
447
448
449 return {"plan": plan}
450
451
452def respond(state: State):
453 print(state.get("messages")[-1]["content"])
454 return {"plan": state.get("plan")}
455
456
457def summarize(state: State):
458 plan = state.get("plan")
459 messages = state.get("messages")
460 summary_prompt = []
461 summary_prompt.append({
462 "role": "user","content": f"Summarize the results obtained from the following tool executions:\n {json.dumps(plan,indent=2)}"
463 })
464 inputs = tokenizer.apply_chat_template(
465 summary_prompt,
466 add_generation_prompt=True,
467 tokenize=True,
468 return_dict=True,
469 return_tensors="pt",
470 ).to(model.device)
471 streamer = TextIteratorStreamer(tokenizer, skip_prompt=True)
472 generation_kwargs = dict(inputs, streamer=streamer,
473 max_new_tokens=4096,
474 temperature=0.7, )
475 thread = Thread(target=model.generate, kwargs=generation_kwargs, daemon=True)
476 thread.start()
477 generated_text = ""
478 for new_text in streamer:
479 print(new_text, end="")
480 generated_text = generated_text + new_text
481
482 messages.append({"role": "assistant", "content": generated_text})
483
484 return {"messages":messages}
485
486
487EXECUTE_PLAN = "EXECUTE_PLAN"
488RESPOND = "RESPOND"
489SUMMARIZE = "SUMMARIZE"
490graph_builder.add_node(PLANNING_AGENT, planning)
491graph_builder.add_node(EXECUTE_PLAN, execute_plan)
492graph_builder.add_node(RESPOND, respond)
493graph_builder.add_node(SUMMARIZE, summarize)
494
495graph_builder.add_edge(START, PLANNING_AGENT)
496graph_builder.add_conditional_edges(PLANNING_AGENT, router, {
497 "execute_plan": EXECUTE_PLAN, "respond": RESPOND
498})
499graph_builder.add_edge(EXECUTE_PLAN, SUMMARIZE)
500graph_builder.add_edge(SUMMARIZE, RESPOND)
501graph_builder.add_edge(RESPOND, END)
502compiled_graph = graph_builder.compile()
503png_bytes = compiled_graph.get_graph().draw_mermaid_png()
504
505# Save to file
506with open("graph.png", "wb") as f:
507 f.write(png_bytes)
508
509print("Graph saved as graph.png")
510
511messages = [
512 {
513 "content": system_prompt,
514 "role": "system"
515 },
516 {
517 "content": (
518 "I have a headache and mild fever. What could be the possible conditions? "
519 "Also, lookup medication details for 'Ibuprofen'. "
520 "Please book an appointment for patient 'Alice Smith' with a neurologist on 2025-08-18."
521 ),
522 "role": "user"
523 }
524]
525different_user_prompt = [
526 {
527 "content": system_prompt,
528 "role": "system"
529 },
530 {
531 "content": (
532 "My mother has chest pain and shortness of breath. "
533 "Can you analyze her symptoms? "
534 "Also, please look up information about 'Nitroglycerin' medication. "
535 "Finally, get lab results for patient ID '987654' for the test 'lipid_panel'."
536 ),
537 "role": "user"
538 }
539]
540compiled_graph.invoke({"messages": messages})
541# compiled_graph.invoke({"messages": different_user_prompt})
5421accelerate==1.9.0
2aiohappyeyeballs==2.6.1
3aiohttp==3.12.15
4aiosignal==1.4.0
5annotated-types==0.7.0
6anyio==4.10.0
7attrs==25.3.0
8auto_gptq==0.7.1
9autolab-core==1.1.1
10beautifulsoup4==4.13.4
11bitsandbytes==0.46.1
12cachetools==5.5.2
13certifi==2025.7.14
14charset-normalizer==3.4.2
15click==8.2.1
16colorama==0.4.6
17colorlog==6.9.0
18contourpy==1.3.3
19cycler==0.12.1
20dataclasses-json==0.6.7
21datasets==4.0.0
22dateparser==1.2.2
23ddgs==9.5.4
24dill==0.3.8
25dotenv==0.9.9
26duckduckgo_search==8.1.1
27duckling==1.8.0
28filelock==3.13.1
29fonttools==4.59.0
30freetype-py==2.5.1
31frozenlist==1.7.0
32fsspec==2024.6.1
33gekko==1.3.0
34google-api-core==2.25.1
35google-api-python-client==2.179.0
36google-auth==2.40.3
37google-auth-httplib2==0.2.0
38google-auth-oauthlib==1.2.2
39googleapis-common-protos==1.70.0
40greenlet==3.2.4
41h11==0.16.0
42hf-xet==1.1.7
43httpcore==1.0.9
44httplib2==0.22.0
45httpx==0.28.1
46httpx-sse==0.4.1
47huggingface-hub==0.34.3
48idna==3.10
49imageio==2.37.0
50Jinja2==3.1.4
51joblib==1.5.1
52jpype1==1.6.0
53jsonpatch==1.33
54jsonpointer==3.0.0
55jsonschema==4.25.0
56jsonschema-specifications==2025.4.1
57kiwisolver==1.4.8
58langchain==0.3.27
59langchain-community==0.3.27
60langchain-core==0.3.74
61langchain-huggingface==0.3.1
62langchain-text-splitters==0.3.9
63langgraph==0.6.5
64langgraph-checkpoint==2.1.1
65langgraph-prebuilt==0.6.4
66langgraph-sdk==0.2.0
67langsmith==0.4.14
68lazy_loader==0.4
69lxml==6.0.0
70manifold3d==3.2.1
71mapbox_earcut==1.0.3
72markdown-it-py==3.0.0
73markdownify==1.1.0
74MarkupSafe==2.1.5
75marshmallow==3.26.1
76matplotlib==3.10.5
77mdurl==0.1.2
78mpmath==1.3.0
79multidict==6.6.3
80multiprocess==0.70.16
81mypy_extensions==1.1.0
82networkx==3.3
83numpy==2.1.2
84oauthlib==3.3.1
85opencv-python==4.12.0.88
86optimum==1.27.0
87orjson==3.11.2
88ormsgpack==1.10.0
89packaging==25.0
90pandas==2.3.1
91peft==0.17.0
92pillow==11.0.0
93primp==0.15.0
94propcache==0.3.2
95proto-plus==1.26.1
96protobuf==6.32.0
97psutil==7.0.0
98pyarrow==21.0.0
99pyasn1==0.6.1
100pyasn1_modules==0.4.2
101pycollada==0.9.2
102pydantic==2.11.7
103pydantic-settings==2.10.1
104pydantic_core==2.33.2
105pyglet==2.1.8
106Pygments==2.19.2
107PyOpenGL==3.1.0
108pyparsing==3.2.3
109pyreadline==2.1
110pyrender==0.1.45
111python-dateutil==2.9.0.post0
112python-dotenv==1.1.1
113pytz==2025.2
114PyYAML==6.0.2
115referencing==0.36.2
116regex==2025.7.34
117requests==2.32.4
118requests-oauthlib==2.0.0
119requests-toolbelt==1.0.0
120rich==14.1.0
121rouge==1.0.1
122rpds-py==0.27.0
123rsa==4.9.1
124rtree==1.4.1
125ruamel.yaml==0.18.14
126ruamel.yaml.clib==0.2.12
127safetensors==0.5.3
128scikit-image==0.25.2
129scikit-learn==1.7.1
130scipy==1.16.1
131sentencepiece==0.2.1
132setproctitle==1.3.6
133shapely==2.1.1
134six==1.17.0
135smolagents==1.20.0
136sniffio==1.3.1
137soupsieve==2.7
138SQLAlchemy==2.0.43
139svg.path==7.0
140sympy==1.13.3
141tenacity==9.1.2
142threadpoolctl==3.6.0
143tifffile==2025.6.11
144tokenizers==0.21.4
145torch==2.7.1+cu126
146torchaudio==2.7.1+cu126
147torchvision==0.22.1+cu126
148tqdm==4.67.1
149transformers==4.54.1
150trimesh==4.7.4
151trl==0.20.0
152typing-inspect==0.9.0
153typing-inspection==0.4.1
154typing_extensions==4.14.1
155tzdata==2025.2
156tzlocal==5.3.1
157uritemplate==4.2.0
158urllib3==2.5.0
159vhacdx==0.0.8.post2
160visualization==1.0.0
161xxhash==3.5.0
162yarl==1.20.1
163zstandard==0.24.01from transformers import AutoModelForCausalLM, AutoTokenizer
2import torch
3
4import json
5
6torch.manual_seed(42)
7model_name = "aldsouza/health-agent"
8
9tokenizer = AutoTokenizer.from_pretrained(model_name)
10model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.float16).to("cuda")
11
12medical_tools = [
13 {
14 "name": "symptom_checker",
15 "description": "Analyze symptoms and provide possible conditions.",
16 "parameters": {
17 "symptoms": {
18 "description": "List of symptoms reported by the patient.",
19 "type": "list[str]",
20 "default": ["headache", "fever"]
21 }
22 }
23 },
24 {
25 "name": "medication_lookup",
26 "description": "Look up details about a medication by its name.",
27 "parameters": {
28 "medication_name": {
29 "description": "Name of the medication to look up.",
30 "type": "str",
31 "default": "Aspirin"
32 }
33 }
34 },
35 {
36 "name": "book_appointment",
37 "description": "Schedule a medical appointment with a doctor.",
38 "parameters": {
39 "patient_name": {
40 "description": "Name of the patient.",
41 "type": "str",
42 "default": "John Doe"
43 },
44 "doctor_specialty": {
45 "description": "Specialty of the doctor to book.",
46 "type": "str",
47 "default": "general practitioner"
48 },
49 "date": {
50 "description": "Preferred date of appointment (YYYY-MM-DD).",
51 "type": "str",
52 "default": "2025-08-20"
53 }
54 }
55 },
56 {
57 "name": "get_lab_results",
58 "description": "Retrieve lab test results for a patient by test ID.",
59 "parameters": {
60 "patient_id": {
61 "description": "Unique patient identifier.",
62 "type": "str",
63 "default": "123456"
64 },
65 "test_id": {
66 "description": "Lab test identifier.",
67 "type": "str",
68 "default": "cbc"
69 }
70 }
71 },
72 {
73 "name": "request_missing_info",
74 "description": "Ask the user for missing or incomplete information needed to fulfill their request.",
75 "parameters": {
76 "missing_fields": {
77 "description": "List of missing required fields to be clarified by the user.",
78 "type": "list[str]",
79 "default": []
80 },
81 "context": {
82 "description": "Optional context or explanation to help the user provide the missing information.",
83 "type": "str",
84 "default": ""
85 }
86 }
87 },
88 {
89 "name": "medical_device_info",
90 "description": "Retrieve detailed information about a medical device by its name or model number.",
91 "parameters": {
92 "device_name": {
93 "description": "The name or model number of the medical device to look up.",
94 "type": "str",
95 "default": "Blood Pressure Monitor"
96 }
97 }
98 }, {
99 "name": "record_blood_pressure",
100 "description": "Record a patient's blood pressure reading with systolic, diastolic, and pulse rate values.",
101 "parameters": {
102 "patient_id": {
103 "description": "Unique identifier of the patient.",
104 "type": "str",
105 "default": "123456"
106 },
107 "systolic": {
108 "description": "Systolic blood pressure value (mmHg).",
109 "type": "int",
110 "default": 120
111 },
112 "diastolic": {
113 "description": "Diastolic blood pressure value (mmHg).",
114 "type": "int",
115 "default": 80
116 },
117 "pulse_rate": {
118 "description": "Pulse rate in beats per minute.",
119 "type": "int",
120 "default": 70
121 },
122 "measurement_time": {
123 "description": "Timestamp of the measurement (YYYY-MM-DD HH:MM).",
124 "type": "str",
125 "default": "2025-08-12 09:00"
126 }
127 }
128 }, {
129 "name": "start_blood_pressure_test",
130 "description": "Initiate a blood pressure measurement test for a patient using a connected device.",
131 "parameters": {
132 "patient_id": {
133 "description": "Unique identifier of the patient.",
134 "type": "str",
135 "default": "123456"
136 },
137 "device_id": {
138 "description": "Identifier or model of the blood pressure measuring device.",
139 "type": "str",
140 "default": "BP-Device-001"
141 }
142 }
143 }
144 ]
145 # Compose the system prompt embedding the tools JSON
146 system_prompt = f"""
147You are an intelligent AI assistant that uses available tools (functions) to help users achieve their medical-related goals. Your job is to understand the user's intent, identify missing information if needed, and then select and call the most appropriate function(s) to solve the task.
148
149# Rules:
150- ALWAYS use the tools provided to answer the user's request, unless explicitly told not to.
151- Ask clarifying questions ONLY if the user's request is ambiguous or lacks required input parameters.
152- If multiple tools are needed, use them in sequence.
153- DO NOT make up data or assume values — request any missing input clearly.
154
155# Output Format:
156- Respond using a JSON list of function calls in the following format:
157 [
158 {{
159 "name": "function_name",
160 "arguments": {{
161 "param1": "value1",
162 "param2": "value2"
163 }}
164 ]
165- Only include the functions needed to complete the task.
166- If no function is needed or the input is unclear, ask a clarifying question instead of guessing.
167- Do NOT respond with explanations or natural language outside the JSON block unless explicitly instructed.
168
169Following are the tools provided to you:
170{json.dumps(medical_tools, indent=2)}
171"""
172
173 # Example prompt using the medical tools
174messages = [
175 {
176 "content": system_prompt,
177 "role": "system"
178 },
179 {
180 "content": (
181 "I have a headache and mild fever. What could be the possible conditions? "
182 "Also, lookup medication details for 'Ibuprofen'. "
183 "Please book an appointment for patient 'Alice Smith' with a neurologist on 2025-09-01."
184 ),
185 "role": "user"
186 }
187 ]
188
189inputs = tokenizer.apply_chat_template(
190 messages,
191 add_generation_prompt=True,
192 tokenize=True,
193 return_dict=True,
194 return_tensors="pt",
195 ).to(model.device)
196
197 with torch.no_grad():
198 outputs = model.generate(
199 **inputs,
200 max_new_tokens=4096,
201 temperature=0.7,
202 )
203
204 response = tokenizer.decode(outputs[0])
205
206print(tokenizer.decode(outputs[0], skip_special_tokens=True))