amd-gaia 0.15.0__py3-none-any.whl → 0.15.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.1.dist-info}/METADATA +223 -223
  2. amd_gaia-0.15.1.dist-info/RECORD +178 -0
  3. {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.1.dist-info}/entry_points.txt +1 -0
  4. {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.1.dist-info}/licenses/LICENSE.md +20 -20
  5. gaia/__init__.py +29 -29
  6. gaia/agents/__init__.py +19 -19
  7. gaia/agents/base/__init__.py +9 -9
  8. gaia/agents/base/agent.py +2177 -2177
  9. gaia/agents/base/api_agent.py +120 -120
  10. gaia/agents/base/console.py +1841 -1841
  11. gaia/agents/base/errors.py +237 -237
  12. gaia/agents/base/mcp_agent.py +86 -86
  13. gaia/agents/base/tools.py +83 -83
  14. gaia/agents/blender/agent.py +556 -556
  15. gaia/agents/blender/agent_simple.py +133 -135
  16. gaia/agents/blender/app.py +211 -211
  17. gaia/agents/blender/app_simple.py +41 -41
  18. gaia/agents/blender/core/__init__.py +16 -16
  19. gaia/agents/blender/core/materials.py +506 -506
  20. gaia/agents/blender/core/objects.py +316 -316
  21. gaia/agents/blender/core/rendering.py +225 -225
  22. gaia/agents/blender/core/scene.py +220 -220
  23. gaia/agents/blender/core/view.py +146 -146
  24. gaia/agents/chat/__init__.py +9 -9
  25. gaia/agents/chat/agent.py +835 -835
  26. gaia/agents/chat/app.py +1058 -1058
  27. gaia/agents/chat/session.py +508 -508
  28. gaia/agents/chat/tools/__init__.py +15 -15
  29. gaia/agents/chat/tools/file_tools.py +96 -96
  30. gaia/agents/chat/tools/rag_tools.py +1729 -1729
  31. gaia/agents/chat/tools/shell_tools.py +436 -436
  32. gaia/agents/code/__init__.py +7 -7
  33. gaia/agents/code/agent.py +549 -549
  34. gaia/agents/code/cli.py +377 -0
  35. gaia/agents/code/models.py +135 -135
  36. gaia/agents/code/orchestration/__init__.py +24 -24
  37. gaia/agents/code/orchestration/checklist_executor.py +1763 -1763
  38. gaia/agents/code/orchestration/checklist_generator.py +713 -713
  39. gaia/agents/code/orchestration/factories/__init__.py +9 -9
  40. gaia/agents/code/orchestration/factories/base.py +63 -63
  41. gaia/agents/code/orchestration/factories/nextjs_factory.py +118 -118
  42. gaia/agents/code/orchestration/factories/python_factory.py +106 -106
  43. gaia/agents/code/orchestration/orchestrator.py +841 -841
  44. gaia/agents/code/orchestration/project_analyzer.py +391 -391
  45. gaia/agents/code/orchestration/steps/__init__.py +67 -67
  46. gaia/agents/code/orchestration/steps/base.py +188 -188
  47. gaia/agents/code/orchestration/steps/error_handler.py +314 -314
  48. gaia/agents/code/orchestration/steps/nextjs.py +828 -828
  49. gaia/agents/code/orchestration/steps/python.py +307 -307
  50. gaia/agents/code/orchestration/template_catalog.py +469 -469
  51. gaia/agents/code/orchestration/workflows/__init__.py +14 -14
  52. gaia/agents/code/orchestration/workflows/base.py +80 -80
  53. gaia/agents/code/orchestration/workflows/nextjs.py +186 -186
  54. gaia/agents/code/orchestration/workflows/python.py +94 -94
  55. gaia/agents/code/prompts/__init__.py +11 -11
  56. gaia/agents/code/prompts/base_prompt.py +77 -77
  57. gaia/agents/code/prompts/code_patterns.py +2036 -2036
  58. gaia/agents/code/prompts/nextjs_prompt.py +40 -40
  59. gaia/agents/code/prompts/python_prompt.py +109 -109
  60. gaia/agents/code/schema_inference.py +365 -365
  61. gaia/agents/code/system_prompt.py +41 -41
  62. gaia/agents/code/tools/__init__.py +42 -42
  63. gaia/agents/code/tools/cli_tools.py +1138 -1138
  64. gaia/agents/code/tools/code_formatting.py +319 -319
  65. gaia/agents/code/tools/code_tools.py +769 -769
  66. gaia/agents/code/tools/error_fixing.py +1347 -1347
  67. gaia/agents/code/tools/external_tools.py +180 -180
  68. gaia/agents/code/tools/file_io.py +845 -845
  69. gaia/agents/code/tools/prisma_tools.py +190 -190
  70. gaia/agents/code/tools/project_management.py +1016 -1016
  71. gaia/agents/code/tools/testing.py +321 -321
  72. gaia/agents/code/tools/typescript_tools.py +122 -122
  73. gaia/agents/code/tools/validation_parsing.py +461 -461
  74. gaia/agents/code/tools/validation_tools.py +806 -806
  75. gaia/agents/code/tools/web_dev_tools.py +1758 -1758
  76. gaia/agents/code/validators/__init__.py +16 -16
  77. gaia/agents/code/validators/antipattern_checker.py +241 -241
  78. gaia/agents/code/validators/ast_analyzer.py +197 -197
  79. gaia/agents/code/validators/requirements_validator.py +145 -145
  80. gaia/agents/code/validators/syntax_validator.py +171 -171
  81. gaia/agents/docker/__init__.py +7 -7
  82. gaia/agents/docker/agent.py +642 -642
  83. gaia/agents/emr/__init__.py +8 -8
  84. gaia/agents/emr/agent.py +1506 -1506
  85. gaia/agents/emr/cli.py +1322 -1322
  86. gaia/agents/emr/constants.py +475 -475
  87. gaia/agents/emr/dashboard/__init__.py +4 -4
  88. gaia/agents/emr/dashboard/server.py +1974 -1974
  89. gaia/agents/jira/__init__.py +11 -11
  90. gaia/agents/jira/agent.py +894 -894
  91. gaia/agents/jira/jql_templates.py +299 -299
  92. gaia/agents/routing/__init__.py +7 -7
  93. gaia/agents/routing/agent.py +567 -570
  94. gaia/agents/routing/system_prompt.py +75 -75
  95. gaia/agents/summarize/__init__.py +11 -0
  96. gaia/agents/summarize/agent.py +885 -0
  97. gaia/agents/summarize/prompts.py +129 -0
  98. gaia/api/__init__.py +23 -23
  99. gaia/api/agent_registry.py +238 -238
  100. gaia/api/app.py +305 -305
  101. gaia/api/openai_server.py +575 -575
  102. gaia/api/schemas.py +186 -186
  103. gaia/api/sse_handler.py +373 -373
  104. gaia/apps/__init__.py +4 -4
  105. gaia/apps/llm/__init__.py +6 -6
  106. gaia/apps/llm/app.py +173 -169
  107. gaia/apps/summarize/app.py +116 -633
  108. gaia/apps/summarize/html_viewer.py +133 -133
  109. gaia/apps/summarize/pdf_formatter.py +284 -284
  110. gaia/audio/__init__.py +2 -2
  111. gaia/audio/audio_client.py +439 -439
  112. gaia/audio/audio_recorder.py +269 -269
  113. gaia/audio/kokoro_tts.py +599 -599
  114. gaia/audio/whisper_asr.py +432 -432
  115. gaia/chat/__init__.py +16 -16
  116. gaia/chat/app.py +430 -430
  117. gaia/chat/prompts.py +522 -522
  118. gaia/chat/sdk.py +1228 -1225
  119. gaia/cli.py +5481 -5632
  120. gaia/database/__init__.py +10 -10
  121. gaia/database/agent.py +176 -176
  122. gaia/database/mixin.py +290 -290
  123. gaia/database/testing.py +64 -64
  124. gaia/eval/batch_experiment.py +2332 -2332
  125. gaia/eval/claude.py +542 -542
  126. gaia/eval/config.py +37 -37
  127. gaia/eval/email_generator.py +512 -512
  128. gaia/eval/eval.py +3179 -3179
  129. gaia/eval/groundtruth.py +1130 -1130
  130. gaia/eval/transcript_generator.py +582 -582
  131. gaia/eval/webapp/README.md +167 -167
  132. gaia/eval/webapp/package-lock.json +875 -875
  133. gaia/eval/webapp/package.json +20 -20
  134. gaia/eval/webapp/public/app.js +3402 -3402
  135. gaia/eval/webapp/public/index.html +87 -87
  136. gaia/eval/webapp/public/styles.css +3661 -3661
  137. gaia/eval/webapp/server.js +415 -415
  138. gaia/eval/webapp/test-setup.js +72 -72
  139. gaia/llm/__init__.py +9 -2
  140. gaia/llm/base_client.py +60 -0
  141. gaia/llm/exceptions.py +12 -0
  142. gaia/llm/factory.py +70 -0
  143. gaia/llm/lemonade_client.py +3236 -3221
  144. gaia/llm/lemonade_manager.py +294 -294
  145. gaia/llm/providers/__init__.py +9 -0
  146. gaia/llm/providers/claude.py +108 -0
  147. gaia/llm/providers/lemonade.py +120 -0
  148. gaia/llm/providers/openai_provider.py +79 -0
  149. gaia/llm/vlm_client.py +382 -382
  150. gaia/logger.py +189 -189
  151. gaia/mcp/agent_mcp_server.py +245 -245
  152. gaia/mcp/blender_mcp_client.py +138 -138
  153. gaia/mcp/blender_mcp_server.py +648 -648
  154. gaia/mcp/context7_cache.py +332 -332
  155. gaia/mcp/external_services.py +518 -518
  156. gaia/mcp/mcp_bridge.py +811 -550
  157. gaia/mcp/servers/__init__.py +6 -6
  158. gaia/mcp/servers/docker_mcp.py +83 -83
  159. gaia/perf_analysis.py +361 -0
  160. gaia/rag/__init__.py +10 -10
  161. gaia/rag/app.py +293 -293
  162. gaia/rag/demo.py +304 -304
  163. gaia/rag/pdf_utils.py +235 -235
  164. gaia/rag/sdk.py +2194 -2194
  165. gaia/security.py +163 -163
  166. gaia/talk/app.py +289 -289
  167. gaia/talk/sdk.py +538 -538
  168. gaia/testing/__init__.py +87 -87
  169. gaia/testing/assertions.py +330 -330
  170. gaia/testing/fixtures.py +333 -333
  171. gaia/testing/mocks.py +493 -493
  172. gaia/util.py +46 -46
  173. gaia/utils/__init__.py +33 -33
  174. gaia/utils/file_watcher.py +675 -675
  175. gaia/utils/parsing.py +223 -223
  176. gaia/version.py +100 -100
  177. amd_gaia-0.15.0.dist-info/RECORD +0 -168
  178. gaia/agents/code/app.py +0 -266
  179. gaia/llm/llm_client.py +0 -723
  180. {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.1.dist-info}/WHEEL +0 -0
  181. {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.1.dist-info}/top_level.txt +0 -0
@@ -1,475 +1,475 @@
1
- # Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
2
- # SPDX-License-Identifier: MIT
3
-
4
- """
5
- Constants and schemas for the Medical Intake Agent.
6
-
7
- This module contains database schemas, VLM prompts, and manual entry
8
- time estimation logic used by the Medical Intake Agent.
9
- """
10
-
11
- # =============================================================================
12
- # MANUAL DATA ENTRY TIME ESTIMATION
13
- # =============================================================================
14
- # Based on research: average data entry speed is 40 WPM (~200 CPM) but medical
15
- # forms require looking back and forth, finding fields in UI, and verification.
16
- #
17
- # Formula per field: (BASE_TIME + chars * TYPING_TIME) * COMPLEXITY * (1 + VERIFICATION)
18
- #
19
- # Example calculation for a typical form with 15 fields, ~300 total characters:
20
- # Base time: 15 fields * 10 sec = 150 sec
21
- # Typing: 300 chars * 0.3 sec = 90 sec
22
- # Subtotal: ~240 sec (4 min)
23
- # With verification (+15%): ~276 sec (4.6 min)
24
- #
25
- # This aligns with studies showing manual EMR data entry takes 3-8 minutes
26
- # per patient depending on form complexity.
27
-
28
- TYPING_SECONDS_PER_CHAR = 0.3 # Slower than typical typing due to form lookup
29
- BASE_SECONDS_PER_FIELD = 10 # Time to locate field, click, prepare to type
30
- VERIFICATION_OVERHEAD = 0.15 # 15% extra time for checking/verification
31
-
32
- # Field complexity multipliers (some fields take longer to enter)
33
- FIELD_COMPLEXITY = {
34
- # Simple fields - quick to enter
35
- "first_name": 1.0,
36
- "last_name": 1.0,
37
- "gender": 0.5, # Usually a dropdown
38
- "phone": 1.0,
39
- "email": 1.0,
40
- "state": 0.5, # Often a dropdown
41
- "zip_code": 0.8,
42
- # Medium complexity - require more attention
43
- "date_of_birth": 1.2, # Date formatting
44
- "address": 1.2,
45
- "city": 1.0,
46
- "insurance_provider": 1.2,
47
- "insurance_id": 1.0,
48
- "emergency_contact_name": 1.0,
49
- "emergency_contact_phone": 1.0,
50
- # Complex fields - may have multiple items, require careful reading
51
- "reason_for_visit": 1.5,
52
- "allergies": 1.8, # Critical field, needs careful entry
53
- "medications": 1.8, # May have multiple items
54
- }
55
-
56
-
57
- def estimate_manual_entry_time(extracted_data: dict) -> float:
58
- """
59
- Estimate how long manual data entry would take for extracted form data.
60
-
61
- The estimation is based on:
62
- 1. Number of fields extracted (base time per field)
63
- 2. Character count of each field (typing time)
64
- 3. Field complexity (some fields require more care)
65
- 4. Verification overhead (checking entries)
66
-
67
- Args:
68
- extracted_data: Dictionary of extracted patient data
69
-
70
- Returns:
71
- Estimated manual entry time in seconds
72
- """
73
- total_seconds = 0.0
74
- field_count = 0
75
-
76
- # Fields to skip in estimation (metadata, not user-entered)
77
- skip_fields = {
78
- "source_file",
79
- "raw_extraction",
80
- "additional_fields",
81
- "is_new_patient",
82
- "processing_time_seconds",
83
- "file_hash",
84
- "file_content",
85
- "estimated_manual_seconds",
86
- "id",
87
- "created_at",
88
- "updated_at",
89
- }
90
-
91
- for field_name, value in extracted_data.items():
92
- if value is None or value == "" or field_name in skip_fields:
93
- continue
94
-
95
- # Convert value to string for character counting
96
- value_str = str(value)
97
- char_count = len(value_str)
98
-
99
- if char_count == 0:
100
- continue
101
-
102
- field_count += 1
103
-
104
- # Get complexity multiplier (default 1.0 for unknown fields)
105
- complexity = FIELD_COMPLEXITY.get(field_name, 1.0)
106
-
107
- # Calculate time for this field
108
- field_time = (
109
- BASE_SECONDS_PER_FIELD # Base time to find and click field
110
- + (char_count * TYPING_SECONDS_PER_CHAR) # Typing time
111
- ) * complexity
112
-
113
- total_seconds += field_time
114
-
115
- # Add verification overhead (checking all entries)
116
- total_seconds *= 1 + VERIFICATION_OVERHEAD
117
-
118
- # Minimum time if we have any fields (at least 30 seconds)
119
- if field_count > 0:
120
- total_seconds = max(total_seconds, 30.0)
121
-
122
- return round(total_seconds, 1)
123
-
124
-
125
- # =============================================================================
126
- # DATABASE SCHEMA
127
- # =============================================================================
128
-
129
- PATIENT_SCHEMA = """
130
- CREATE TABLE IF NOT EXISTS patients (
131
- id INTEGER PRIMARY KEY AUTOINCREMENT,
132
- -- Patient info - basic
133
- first_name TEXT,
134
- last_name TEXT,
135
- date_of_birth TEXT,
136
- age TEXT,
137
- gender TEXT,
138
- preferred_pronouns TEXT,
139
- ssn TEXT,
140
- marital_status TEXT,
141
- spouse_name TEXT,
142
- -- Contact info
143
- phone TEXT,
144
- mobile_phone TEXT,
145
- work_phone TEXT,
146
- email TEXT,
147
- address TEXT,
148
- city TEXT,
149
- state TEXT,
150
- zip_code TEXT,
151
- -- Demographics
152
- preferred_language TEXT,
153
- race TEXT,
154
- ethnicity TEXT,
155
- contact_preference TEXT,
156
- -- Emergency contact
157
- emergency_contact_name TEXT,
158
- emergency_contact_relationship TEXT,
159
- emergency_contact_phone TEXT,
160
- -- Physicians
161
- referring_physician TEXT,
162
- referring_physician_phone TEXT,
163
- primary_care_physician TEXT,
164
- preferred_pharmacy TEXT,
165
- -- Employment
166
- employment_status TEXT,
167
- occupation TEXT,
168
- employer TEXT,
169
- employer_address TEXT,
170
- -- Primary insurance
171
- insurance_provider TEXT,
172
- insurance_id TEXT,
173
- insurance_group_number TEXT,
174
- insured_name TEXT,
175
- insured_dob TEXT,
176
- insurance_phone TEXT,
177
- billing_address TEXT,
178
- guarantor_name TEXT,
179
- -- Secondary insurance
180
- secondary_insurance_provider TEXT,
181
- secondary_insurance_id TEXT,
182
- -- Medical/Pain history
183
- reason_for_visit TEXT,
184
- date_of_injury TEXT,
185
- pain_location TEXT,
186
- pain_onset TEXT,
187
- pain_cause TEXT,
188
- pain_progression TEXT,
189
- work_related_injury TEXT,
190
- car_accident TEXT,
191
- medical_conditions TEXT,
192
- allergies TEXT,
193
- medications TEXT,
194
- -- Form metadata
195
- form_date TEXT,
196
- signature_date TEXT,
197
- -- System fields
198
- created_at TEXT DEFAULT (datetime('now')),
199
- updated_at TEXT DEFAULT (datetime('now')),
200
- source_file TEXT,
201
- raw_extraction TEXT,
202
- additional_fields TEXT,
203
- is_new_patient BOOLEAN DEFAULT TRUE,
204
- processing_time_seconds REAL,
205
- estimated_manual_seconds REAL,
206
- file_hash TEXT,
207
- file_content BLOB
208
- );
209
-
210
- CREATE INDEX IF NOT EXISTS idx_patients_name ON patients(last_name, first_name);
211
- CREATE INDEX IF NOT EXISTS idx_patients_dob ON patients(date_of_birth);
212
- CREATE INDEX IF NOT EXISTS idx_patients_hash ON patients(file_hash);
213
-
214
- -- Alerts table for tracking critical notifications
215
- CREATE TABLE IF NOT EXISTS alerts (
216
- id INTEGER PRIMARY KEY AUTOINCREMENT,
217
- patient_id INTEGER REFERENCES patients(id),
218
- alert_type TEXT NOT NULL,
219
- priority TEXT DEFAULT 'medium',
220
- message TEXT NOT NULL,
221
- data TEXT,
222
- created_at TEXT DEFAULT (datetime('now')),
223
- acknowledged BOOLEAN DEFAULT FALSE,
224
- acknowledged_by TEXT,
225
- acknowledged_at TEXT
226
- );
227
-
228
- CREATE INDEX IF NOT EXISTS idx_alerts_patient ON alerts(patient_id);
229
- CREATE INDEX IF NOT EXISTS idx_alerts_acknowledged ON alerts(acknowledged);
230
-
231
- -- Intake sessions for audit trail
232
- CREATE TABLE IF NOT EXISTS intake_sessions (
233
- id INTEGER PRIMARY KEY AUTOINCREMENT,
234
- patient_id INTEGER REFERENCES patients(id),
235
- source_file TEXT,
236
- processing_time_seconds REAL,
237
- is_new_patient BOOLEAN,
238
- changes_detected TEXT,
239
- created_at TEXT DEFAULT (datetime('now'))
240
- );
241
- """
242
-
243
-
244
- # =============================================================================
245
- # VLM EXTRACTION PROMPT
246
- # =============================================================================
247
-
248
- EXTRACTION_PROMPT = """You are a medical data extraction system. Extract ALL patient information from this intake form image.
249
-
250
- Return a JSON object with ALL fields you can extract. Use these standard field names when applicable:
251
-
252
- REQUIRED (always include):
253
- - "first_name": patient's first name
254
- - "last_name": patient's last name
255
-
256
- PATIENT INFO:
257
- - "form_date": date form was filled (YYYY-MM-DD)
258
- - "date_of_birth": YYYY-MM-DD format
259
- - "age": patient's age if listed
260
- - "gender": Male/Female/Other
261
- - "preferred_pronouns": he/him, she/her, they/them if listed
262
- - "ssn": Social Security Number (XXX-XX-XXXX)
263
- - "marital_status": Single/Married/Divorced/Widowed/Partnered
264
- - "spouse_name": spouse's name if listed
265
- - "phone": home phone number
266
- - "mobile_phone": cell/mobile phone number
267
- - "work_phone": work phone number
268
- - "email"
269
- - "address": street address
270
- - "city", "state", "zip_code"
271
- - "preferred_language": English/Spanish/etc if listed
272
- - "race", "ethnicity": if listed
273
- - "contact_preference": preferred contact method if listed
274
-
275
- EMERGENCY CONTACT:
276
- - "emergency_contact_name": name of emergency contact person
277
- - "emergency_contact_relationship": relationship to patient (e.g. Mom, Spouse, Friend)
278
- - "emergency_contact_phone": emergency contact's phone number
279
-
280
- PHYSICIANS:
281
- - "referring_physician": name of referring physician/doctor
282
- - "referring_physician_phone": phone number next to referring physician
283
- - "primary_care_physician": PCP name if different from referring
284
- - "preferred_pharmacy": pharmacy name if listed
285
-
286
- EMPLOYMENT:
287
- - "employment_status": Employed/Self Employed/Unemployed/Retired/Student/Disabled/Military
288
- - "occupation": job title if listed
289
- - "employer": employer/company name
290
- - "employer_address": employer address if listed
291
-
292
- PRIMARY INSURANCE:
293
- - "insurance_provider": insurance company name
294
- - "insurance_id": policy number
295
- - "insurance_group_number": group number
296
- - "insured_name": name of insured person (may differ from patient)
297
- - "insured_dob": DOB of insured (YYYY-MM-DD)
298
- - "insurance_phone": insurance contact number
299
- - "billing_address": billing address if different from home
300
- - "guarantor_name": person responsible for payment if listed
301
-
302
- SECONDARY INSURANCE:
303
- - "secondary_insurance_provider", "secondary_insurance_id"
304
-
305
- MEDICAL/PAIN HISTORY:
306
- - "reason_for_visit": chief complaint or reason for visit
307
- - "date_of_injury": date of injury or onset of symptoms (YYYY-MM-DD)
308
- - "pain_location": where pain is located if listed
309
- - "pain_onset": when pain began (e.g. three months ago)
310
- - "pain_cause": what caused the pain/condition
311
- - "pain_progression": Improved/Worsened/Stayed the same
312
- - "work_related_injury": Yes/No
313
- - "car_accident": Yes/No
314
- - "medical_conditions": existing medical conditions
315
- - "allergies": known allergies
316
- - "medications": current medications
317
-
318
- SIGNATURE:
319
- - "signature_date": date signed (YYYY-MM-DD)
320
-
321
- ADDITIONAL FIELDS:
322
- Extract ANY other fields visible on the form using descriptive snake_case names.
323
-
324
- IMPORTANT:
325
- - Extract EVERY field visible on the form
326
- - Use null for fields that exist but are blank
327
- - Omit fields not present on this specific form
328
- - Return ONLY the JSON object, no other text
329
- - Dates must be in YYYY-MM-DD format
330
- - For checkboxes, use Yes/No values"""
331
-
332
-
333
- # Standard columns that map to database schema
334
- STANDARD_COLUMNS = [
335
- # Patient info - basic
336
- "first_name",
337
- "last_name",
338
- "date_of_birth",
339
- "age",
340
- "gender",
341
- "preferred_pronouns",
342
- "ssn",
343
- "marital_status",
344
- "spouse_name",
345
- # Contact info
346
- "phone", # home phone
347
- "mobile_phone", # cell phone
348
- "work_phone",
349
- "email",
350
- "address",
351
- "city",
352
- "state",
353
- "zip_code",
354
- # Demographics
355
- "preferred_language",
356
- "race",
357
- "ethnicity",
358
- "contact_preference",
359
- # Emergency contact
360
- "emergency_contact_name",
361
- "emergency_contact_relationship",
362
- "emergency_contact_phone",
363
- # Physicians
364
- "referring_physician",
365
- "referring_physician_phone",
366
- "primary_care_physician",
367
- "preferred_pharmacy",
368
- # Employment
369
- "employment_status",
370
- "occupation",
371
- "employer",
372
- "employer_address",
373
- # Primary insurance
374
- "insurance_provider",
375
- "insurance_id",
376
- "insurance_group_number",
377
- "insured_name",
378
- "insured_dob",
379
- "insurance_phone",
380
- "billing_address",
381
- "guarantor_name",
382
- # Secondary insurance
383
- "secondary_insurance_provider",
384
- "secondary_insurance_id",
385
- # Medical/Pain history
386
- "reason_for_visit",
387
- "date_of_injury",
388
- "pain_location",
389
- "pain_onset",
390
- "pain_cause",
391
- "pain_progression",
392
- "work_related_injury",
393
- "car_accident",
394
- "medical_conditions",
395
- "allergies",
396
- "medications",
397
- # Form metadata
398
- "form_date",
399
- "signature_date",
400
- # System fields
401
- "source_file",
402
- "raw_extraction",
403
- "additional_fields",
404
- "is_new_patient",
405
- "processing_time_seconds",
406
- "estimated_manual_seconds",
407
- "file_hash",
408
- "file_content",
409
- ]
410
-
411
- # Columns that can be updated for returning patients
412
- UPDATABLE_COLUMNS = [
413
- # Contact info (can change)
414
- "phone", # home phone
415
- "mobile_phone", # cell phone
416
- "work_phone",
417
- "email",
418
- "address",
419
- "city",
420
- "state",
421
- "zip_code",
422
- "contact_preference",
423
- # Marital status (can change)
424
- "marital_status",
425
- "spouse_name",
426
- # Emergency contact (can change)
427
- "emergency_contact_name",
428
- "emergency_contact_relationship",
429
- "emergency_contact_phone",
430
- # Physicians (can change)
431
- "referring_physician",
432
- "referring_physician_phone",
433
- "primary_care_physician",
434
- "preferred_pharmacy",
435
- # Employment (can change)
436
- "employment_status",
437
- "occupation",
438
- "employer",
439
- "employer_address",
440
- # Insurance (can change)
441
- "insurance_provider",
442
- "insurance_id",
443
- "insurance_group_number",
444
- "insured_name",
445
- "insured_dob",
446
- "insurance_phone",
447
- "billing_address",
448
- "guarantor_name",
449
- "secondary_insurance_provider",
450
- "secondary_insurance_id",
451
- # Medical/Pain (can change each visit)
452
- "reason_for_visit",
453
- "date_of_injury",
454
- "pain_location",
455
- "pain_onset",
456
- "pain_cause",
457
- "pain_progression",
458
- "work_related_injury",
459
- "car_accident",
460
- "medical_conditions",
461
- "allergies",
462
- "medications",
463
- # Form metadata
464
- "form_date",
465
- "signature_date",
466
- # System fields
467
- "source_file",
468
- "raw_extraction",
469
- "additional_fields",
470
- "is_new_patient",
471
- "processing_time_seconds",
472
- "estimated_manual_seconds",
473
- "file_hash",
474
- "file_content",
475
- ]
1
+ # Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ """
5
+ Constants and schemas for the Medical Intake Agent.
6
+
7
+ This module contains database schemas, VLM prompts, and manual entry
8
+ time estimation logic used by the Medical Intake Agent.
9
+ """
10
+
11
+ # =============================================================================
12
+ # MANUAL DATA ENTRY TIME ESTIMATION
13
+ # =============================================================================
14
+ # Based on research: average data entry speed is 40 WPM (~200 CPM) but medical
15
+ # forms require looking back and forth, finding fields in UI, and verification.
16
+ #
17
+ # Formula per field: (BASE_TIME + chars * TYPING_TIME) * COMPLEXITY * (1 + VERIFICATION)
18
+ #
19
+ # Example calculation for a typical form with 15 fields, ~300 total characters:
20
+ # Base time: 15 fields * 10 sec = 150 sec
21
+ # Typing: 300 chars * 0.3 sec = 90 sec
22
+ # Subtotal: ~240 sec (4 min)
23
+ # With verification (+15%): ~276 sec (4.6 min)
24
+ #
25
+ # This aligns with studies showing manual EMR data entry takes 3-8 minutes
26
+ # per patient depending on form complexity.
27
+
28
+ TYPING_SECONDS_PER_CHAR = 0.3 # Slower than typical typing due to form lookup
29
+ BASE_SECONDS_PER_FIELD = 10 # Time to locate field, click, prepare to type
30
+ VERIFICATION_OVERHEAD = 0.15 # 15% extra time for checking/verification
31
+
32
+ # Field complexity multipliers (some fields take longer to enter)
33
+ FIELD_COMPLEXITY = {
34
+ # Simple fields - quick to enter
35
+ "first_name": 1.0,
36
+ "last_name": 1.0,
37
+ "gender": 0.5, # Usually a dropdown
38
+ "phone": 1.0,
39
+ "email": 1.0,
40
+ "state": 0.5, # Often a dropdown
41
+ "zip_code": 0.8,
42
+ # Medium complexity - require more attention
43
+ "date_of_birth": 1.2, # Date formatting
44
+ "address": 1.2,
45
+ "city": 1.0,
46
+ "insurance_provider": 1.2,
47
+ "insurance_id": 1.0,
48
+ "emergency_contact_name": 1.0,
49
+ "emergency_contact_phone": 1.0,
50
+ # Complex fields - may have multiple items, require careful reading
51
+ "reason_for_visit": 1.5,
52
+ "allergies": 1.8, # Critical field, needs careful entry
53
+ "medications": 1.8, # May have multiple items
54
+ }
55
+
56
+
57
+ def estimate_manual_entry_time(extracted_data: dict) -> float:
58
+ """
59
+ Estimate how long manual data entry would take for extracted form data.
60
+
61
+ The estimation is based on:
62
+ 1. Number of fields extracted (base time per field)
63
+ 2. Character count of each field (typing time)
64
+ 3. Field complexity (some fields require more care)
65
+ 4. Verification overhead (checking entries)
66
+
67
+ Args:
68
+ extracted_data: Dictionary of extracted patient data
69
+
70
+ Returns:
71
+ Estimated manual entry time in seconds
72
+ """
73
+ total_seconds = 0.0
74
+ field_count = 0
75
+
76
+ # Fields to skip in estimation (metadata, not user-entered)
77
+ skip_fields = {
78
+ "source_file",
79
+ "raw_extraction",
80
+ "additional_fields",
81
+ "is_new_patient",
82
+ "processing_time_seconds",
83
+ "file_hash",
84
+ "file_content",
85
+ "estimated_manual_seconds",
86
+ "id",
87
+ "created_at",
88
+ "updated_at",
89
+ }
90
+
91
+ for field_name, value in extracted_data.items():
92
+ if value is None or value == "" or field_name in skip_fields:
93
+ continue
94
+
95
+ # Convert value to string for character counting
96
+ value_str = str(value)
97
+ char_count = len(value_str)
98
+
99
+ if char_count == 0:
100
+ continue
101
+
102
+ field_count += 1
103
+
104
+ # Get complexity multiplier (default 1.0 for unknown fields)
105
+ complexity = FIELD_COMPLEXITY.get(field_name, 1.0)
106
+
107
+ # Calculate time for this field
108
+ field_time = (
109
+ BASE_SECONDS_PER_FIELD # Base time to find and click field
110
+ + (char_count * TYPING_SECONDS_PER_CHAR) # Typing time
111
+ ) * complexity
112
+
113
+ total_seconds += field_time
114
+
115
+ # Add verification overhead (checking all entries)
116
+ total_seconds *= 1 + VERIFICATION_OVERHEAD
117
+
118
+ # Minimum time if we have any fields (at least 30 seconds)
119
+ if field_count > 0:
120
+ total_seconds = max(total_seconds, 30.0)
121
+
122
+ return round(total_seconds, 1)
123
+
124
+
125
+ # =============================================================================
126
+ # DATABASE SCHEMA
127
+ # =============================================================================
128
+
129
+ PATIENT_SCHEMA = """
130
+ CREATE TABLE IF NOT EXISTS patients (
131
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
132
+ -- Patient info - basic
133
+ first_name TEXT,
134
+ last_name TEXT,
135
+ date_of_birth TEXT,
136
+ age TEXT,
137
+ gender TEXT,
138
+ preferred_pronouns TEXT,
139
+ ssn TEXT,
140
+ marital_status TEXT,
141
+ spouse_name TEXT,
142
+ -- Contact info
143
+ phone TEXT,
144
+ mobile_phone TEXT,
145
+ work_phone TEXT,
146
+ email TEXT,
147
+ address TEXT,
148
+ city TEXT,
149
+ state TEXT,
150
+ zip_code TEXT,
151
+ -- Demographics
152
+ preferred_language TEXT,
153
+ race TEXT,
154
+ ethnicity TEXT,
155
+ contact_preference TEXT,
156
+ -- Emergency contact
157
+ emergency_contact_name TEXT,
158
+ emergency_contact_relationship TEXT,
159
+ emergency_contact_phone TEXT,
160
+ -- Physicians
161
+ referring_physician TEXT,
162
+ referring_physician_phone TEXT,
163
+ primary_care_physician TEXT,
164
+ preferred_pharmacy TEXT,
165
+ -- Employment
166
+ employment_status TEXT,
167
+ occupation TEXT,
168
+ employer TEXT,
169
+ employer_address TEXT,
170
+ -- Primary insurance
171
+ insurance_provider TEXT,
172
+ insurance_id TEXT,
173
+ insurance_group_number TEXT,
174
+ insured_name TEXT,
175
+ insured_dob TEXT,
176
+ insurance_phone TEXT,
177
+ billing_address TEXT,
178
+ guarantor_name TEXT,
179
+ -- Secondary insurance
180
+ secondary_insurance_provider TEXT,
181
+ secondary_insurance_id TEXT,
182
+ -- Medical/Pain history
183
+ reason_for_visit TEXT,
184
+ date_of_injury TEXT,
185
+ pain_location TEXT,
186
+ pain_onset TEXT,
187
+ pain_cause TEXT,
188
+ pain_progression TEXT,
189
+ work_related_injury TEXT,
190
+ car_accident TEXT,
191
+ medical_conditions TEXT,
192
+ allergies TEXT,
193
+ medications TEXT,
194
+ -- Form metadata
195
+ form_date TEXT,
196
+ signature_date TEXT,
197
+ -- System fields
198
+ created_at TEXT DEFAULT (datetime('now')),
199
+ updated_at TEXT DEFAULT (datetime('now')),
200
+ source_file TEXT,
201
+ raw_extraction TEXT,
202
+ additional_fields TEXT,
203
+ is_new_patient BOOLEAN DEFAULT TRUE,
204
+ processing_time_seconds REAL,
205
+ estimated_manual_seconds REAL,
206
+ file_hash TEXT,
207
+ file_content BLOB
208
+ );
209
+
210
+ CREATE INDEX IF NOT EXISTS idx_patients_name ON patients(last_name, first_name);
211
+ CREATE INDEX IF NOT EXISTS idx_patients_dob ON patients(date_of_birth);
212
+ CREATE INDEX IF NOT EXISTS idx_patients_hash ON patients(file_hash);
213
+
214
+ -- Alerts table for tracking critical notifications
215
+ CREATE TABLE IF NOT EXISTS alerts (
216
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
217
+ patient_id INTEGER REFERENCES patients(id),
218
+ alert_type TEXT NOT NULL,
219
+ priority TEXT DEFAULT 'medium',
220
+ message TEXT NOT NULL,
221
+ data TEXT,
222
+ created_at TEXT DEFAULT (datetime('now')),
223
+ acknowledged BOOLEAN DEFAULT FALSE,
224
+ acknowledged_by TEXT,
225
+ acknowledged_at TEXT
226
+ );
227
+
228
+ CREATE INDEX IF NOT EXISTS idx_alerts_patient ON alerts(patient_id);
229
+ CREATE INDEX IF NOT EXISTS idx_alerts_acknowledged ON alerts(acknowledged);
230
+
231
+ -- Intake sessions for audit trail
232
+ CREATE TABLE IF NOT EXISTS intake_sessions (
233
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
234
+ patient_id INTEGER REFERENCES patients(id),
235
+ source_file TEXT,
236
+ processing_time_seconds REAL,
237
+ is_new_patient BOOLEAN,
238
+ changes_detected TEXT,
239
+ created_at TEXT DEFAULT (datetime('now'))
240
+ );
241
+ """
242
+
243
+
244
+ # =============================================================================
245
+ # VLM EXTRACTION PROMPT
246
+ # =============================================================================
247
+
248
+ EXTRACTION_PROMPT = """You are a medical data extraction system. Extract ALL patient information from this intake form image.
249
+
250
+ Return a JSON object with ALL fields you can extract. Use these standard field names when applicable:
251
+
252
+ REQUIRED (always include):
253
+ - "first_name": patient's first name
254
+ - "last_name": patient's last name
255
+
256
+ PATIENT INFO:
257
+ - "form_date": date form was filled (YYYY-MM-DD)
258
+ - "date_of_birth": YYYY-MM-DD format
259
+ - "age": patient's age if listed
260
+ - "gender": Male/Female/Other
261
+ - "preferred_pronouns": he/him, she/her, they/them if listed
262
+ - "ssn": Social Security Number (XXX-XX-XXXX)
263
+ - "marital_status": Single/Married/Divorced/Widowed/Partnered
264
+ - "spouse_name": spouse's name if listed
265
+ - "phone": home phone number
266
+ - "mobile_phone": cell/mobile phone number
267
+ - "work_phone": work phone number
268
+ - "email"
269
+ - "address": street address
270
+ - "city", "state", "zip_code"
271
+ - "preferred_language": English/Spanish/etc if listed
272
+ - "race", "ethnicity": if listed
273
+ - "contact_preference": preferred contact method if listed
274
+
275
+ EMERGENCY CONTACT:
276
+ - "emergency_contact_name": name of emergency contact person
277
+ - "emergency_contact_relationship": relationship to patient (e.g. Mom, Spouse, Friend)
278
+ - "emergency_contact_phone": emergency contact's phone number
279
+
280
+ PHYSICIANS:
281
+ - "referring_physician": name of referring physician/doctor
282
+ - "referring_physician_phone": phone number next to referring physician
283
+ - "primary_care_physician": PCP name if different from referring
284
+ - "preferred_pharmacy": pharmacy name if listed
285
+
286
+ EMPLOYMENT:
287
+ - "employment_status": Employed/Self Employed/Unemployed/Retired/Student/Disabled/Military
288
+ - "occupation": job title if listed
289
+ - "employer": employer/company name
290
+ - "employer_address": employer address if listed
291
+
292
+ PRIMARY INSURANCE:
293
+ - "insurance_provider": insurance company name
294
+ - "insurance_id": policy number
295
+ - "insurance_group_number": group number
296
+ - "insured_name": name of insured person (may differ from patient)
297
+ - "insured_dob": DOB of insured (YYYY-MM-DD)
298
+ - "insurance_phone": insurance contact number
299
+ - "billing_address": billing address if different from home
300
+ - "guarantor_name": person responsible for payment if listed
301
+
302
+ SECONDARY INSURANCE:
303
+ - "secondary_insurance_provider", "secondary_insurance_id"
304
+
305
+ MEDICAL/PAIN HISTORY:
306
+ - "reason_for_visit": chief complaint or reason for visit
307
+ - "date_of_injury": date of injury or onset of symptoms (YYYY-MM-DD)
308
+ - "pain_location": where pain is located if listed
309
+ - "pain_onset": when pain began (e.g. three months ago)
310
+ - "pain_cause": what caused the pain/condition
311
+ - "pain_progression": Improved/Worsened/Stayed the same
312
+ - "work_related_injury": Yes/No
313
+ - "car_accident": Yes/No
314
+ - "medical_conditions": existing medical conditions
315
+ - "allergies": known allergies
316
+ - "medications": current medications
317
+
318
+ SIGNATURE:
319
+ - "signature_date": date signed (YYYY-MM-DD)
320
+
321
+ ADDITIONAL FIELDS:
322
+ Extract ANY other fields visible on the form using descriptive snake_case names.
323
+
324
+ IMPORTANT:
325
+ - Extract EVERY field visible on the form
326
+ - Use null for fields that exist but are blank
327
+ - Omit fields not present on this specific form
328
+ - Return ONLY the JSON object, no other text
329
+ - Dates must be in YYYY-MM-DD format
330
+ - For checkboxes, use Yes/No values"""
331
+
332
+
333
+ # Standard columns that map to database schema
334
+ STANDARD_COLUMNS = [
335
+ # Patient info - basic
336
+ "first_name",
337
+ "last_name",
338
+ "date_of_birth",
339
+ "age",
340
+ "gender",
341
+ "preferred_pronouns",
342
+ "ssn",
343
+ "marital_status",
344
+ "spouse_name",
345
+ # Contact info
346
+ "phone", # home phone
347
+ "mobile_phone", # cell phone
348
+ "work_phone",
349
+ "email",
350
+ "address",
351
+ "city",
352
+ "state",
353
+ "zip_code",
354
+ # Demographics
355
+ "preferred_language",
356
+ "race",
357
+ "ethnicity",
358
+ "contact_preference",
359
+ # Emergency contact
360
+ "emergency_contact_name",
361
+ "emergency_contact_relationship",
362
+ "emergency_contact_phone",
363
+ # Physicians
364
+ "referring_physician",
365
+ "referring_physician_phone",
366
+ "primary_care_physician",
367
+ "preferred_pharmacy",
368
+ # Employment
369
+ "employment_status",
370
+ "occupation",
371
+ "employer",
372
+ "employer_address",
373
+ # Primary insurance
374
+ "insurance_provider",
375
+ "insurance_id",
376
+ "insurance_group_number",
377
+ "insured_name",
378
+ "insured_dob",
379
+ "insurance_phone",
380
+ "billing_address",
381
+ "guarantor_name",
382
+ # Secondary insurance
383
+ "secondary_insurance_provider",
384
+ "secondary_insurance_id",
385
+ # Medical/Pain history
386
+ "reason_for_visit",
387
+ "date_of_injury",
388
+ "pain_location",
389
+ "pain_onset",
390
+ "pain_cause",
391
+ "pain_progression",
392
+ "work_related_injury",
393
+ "car_accident",
394
+ "medical_conditions",
395
+ "allergies",
396
+ "medications",
397
+ # Form metadata
398
+ "form_date",
399
+ "signature_date",
400
+ # System fields
401
+ "source_file",
402
+ "raw_extraction",
403
+ "additional_fields",
404
+ "is_new_patient",
405
+ "processing_time_seconds",
406
+ "estimated_manual_seconds",
407
+ "file_hash",
408
+ "file_content",
409
+ ]
410
+
411
+ # Columns that can be updated for returning patients
412
+ UPDATABLE_COLUMNS = [
413
+ # Contact info (can change)
414
+ "phone", # home phone
415
+ "mobile_phone", # cell phone
416
+ "work_phone",
417
+ "email",
418
+ "address",
419
+ "city",
420
+ "state",
421
+ "zip_code",
422
+ "contact_preference",
423
+ # Marital status (can change)
424
+ "marital_status",
425
+ "spouse_name",
426
+ # Emergency contact (can change)
427
+ "emergency_contact_name",
428
+ "emergency_contact_relationship",
429
+ "emergency_contact_phone",
430
+ # Physicians (can change)
431
+ "referring_physician",
432
+ "referring_physician_phone",
433
+ "primary_care_physician",
434
+ "preferred_pharmacy",
435
+ # Employment (can change)
436
+ "employment_status",
437
+ "occupation",
438
+ "employer",
439
+ "employer_address",
440
+ # Insurance (can change)
441
+ "insurance_provider",
442
+ "insurance_id",
443
+ "insurance_group_number",
444
+ "insured_name",
445
+ "insured_dob",
446
+ "insurance_phone",
447
+ "billing_address",
448
+ "guarantor_name",
449
+ "secondary_insurance_provider",
450
+ "secondary_insurance_id",
451
+ # Medical/Pain (can change each visit)
452
+ "reason_for_visit",
453
+ "date_of_injury",
454
+ "pain_location",
455
+ "pain_onset",
456
+ "pain_cause",
457
+ "pain_progression",
458
+ "work_related_injury",
459
+ "car_accident",
460
+ "medical_conditions",
461
+ "allergies",
462
+ "medications",
463
+ # Form metadata
464
+ "form_date",
465
+ "signature_date",
466
+ # System fields
467
+ "source_file",
468
+ "raw_extraction",
469
+ "additional_fields",
470
+ "is_new_patient",
471
+ "processing_time_seconds",
472
+ "estimated_manual_seconds",
473
+ "file_hash",
474
+ "file_content",
475
+ ]