File size: 7,697 Bytes
6754826 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 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 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | import asyncio
import json
from datetime import datetime
import blood_rag
import reports
from rag import search_supplements as _search_supplements
# ββ Notepad state ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
_notes: list = [] # [{"id": int, "text": str, "time": str}]
_listeners: list = [] # one asyncio.Queue per connected SSE client
_counter: int = 0
def _broadcast(payload: dict):
data = json.dumps(payload)
for q in list(_listeners):
try:
q.put_nowait(data)
except asyncio.QueueFull:
pass
def add_listener(q: asyncio.Queue):
_listeners.append(q)
def remove_listener(q: asyncio.Queue):
if q in _listeners:
_listeners.remove(q)
def get_notes_snapshot() -> dict:
return {"notes": list(_notes)}
# ββ Tool implementations βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def write_to_notepad(text: str) -> str:
global _counter
_counter += 1
entry = {
"id": _counter,
"text": text.strip(),
"time": datetime.now().strftime("%I:%M:%S %p"),
}
_notes.append(entry)
_broadcast(get_notes_snapshot())
return f'Written to notepad: "{text.strip()}"'
def read_notepad() -> str:
if not _notes:
return "The notepad is empty."
lines = [f"{n['time']} β {n['text']}" for n in _notes]
return "Current notes:\n" + "\n".join(lines)
def clear_notepad() -> str:
_notes.clear()
_broadcast(get_notes_snapshot())
return "Notepad cleared."
def get_datetime() -> str:
return datetime.now().strftime("%A, %B %d %Y β %I:%M %p")
# ββ Clinical tools ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
async def get_blood_report_summary() -> str:
report = reports.get_current_report()
if not report.get("has_report"):
return (
"No blood test report has been uploaded yet. Ask the user to upload their "
"blood test report (PDF) using the Blood Test Report uploader."
)
return report["summary"]
async def search_supplements(query: str) -> str:
return await _search_supplements(query)
async def search_blood_knowledge(query: str) -> str:
"""Search the locally indexed blood test documents."""
return await blood_rag.search(query)
async def run_tool(name: str, args: dict) -> str:
if name == "write_to_notepad":
return write_to_notepad(args.get("text", ""))
if name == "read_notepad":
return read_notepad()
if name == "clear_notepad":
return clear_notepad()
if name == "get_datetime":
return get_datetime()
if name == "get_blood_report_summary":
return await get_blood_report_summary()
if name == "search_supplements":
return await search_supplements(args.get("query", ""))
if name == "search_blood_knowledge":
return await search_blood_knowledge(args.get("query", ""))
return f"Unknown tool: {name}"
# ββ OpenAI tool schemas ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
TOOLS = [
{
"type": "function",
"function": {
"name": "write_to_notepad",
"description": (
"Write a note to the live notepad. Use this whenever the user says "
"'note that', 'write down', 'remember', 'save this', 'keep track of', "
"or asks you to record anything."
),
"parameters": {
"type": "object",
"properties": {
"text": {
"type": "string",
"description": (
"The note text. Be concise β capture the key information "
"in plain language, no bullet points or markdown."
),
}
},
"required": ["text"],
},
},
},
{
"type": "function",
"function": {
"name": "read_notepad",
"description": (
"Read all notes currently on the notepad. Use when the user asks "
"'what did I note', 'read my notes', or 'what have you written down'."
),
"parameters": {"type": "object", "properties": {}, "required": []},
},
},
{
"type": "function",
"function": {
"name": "clear_notepad",
"description": "Erase all notes from the notepad. Use only when the user explicitly asks to clear or delete all notes.",
"parameters": {"type": "object", "properties": {}, "required": []},
},
},
{
"type": "function",
"function": {
"name": "get_datetime",
"description": "Get the current date and time.",
"parameters": {"type": "object", "properties": {}, "required": []},
},
},
{
"type": "function",
"function": {
"name": "get_blood_report_summary",
"description": (
"Get a summary of the user's most recently uploaded blood test report, "
"including which markers are low, high, or normal. Call this first "
"whenever the user asks about their blood test, lab results, deficiencies, "
"or what supplements they should take."
),
"parameters": {"type": "object", "properties": {}, "required": []},
},
},
{
"type": "function",
"function": {
"name": "search_blood_knowledge",
"description": (
"Search the locally indexed blood test RAG for relevant passages about "
"a patient's blood test results, markers, deficiencies, or lab values. "
"Use this when the user asks about their blood work, specific markers, "
"or what their results mean."
),
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The question or marker to search for, e.g. 'iron deficiency anemia' or 'vitamin D levels'.",
}
},
"required": ["query"],
},
},
},
{
"type": "function",
"function": {
"name": "search_supplements",
"description": (
"Search the supplement knowledge base for recommendations related to a "
"specific marker or deficiency (e.g. 'low vitamin D', 'low iron / "
"ferritin'). Call this once per abnormal marker found in the user's blood "
"report before recommending supplements."
),
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The marker or deficiency to look up, e.g. 'low vitamin D' or 'high triglycerides'.",
}
},
"required": ["query"],
},
},
},
]
|