amd-gaia 0.15.0__py3-none-any.whl → 0.15.2__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 (185) hide show
  1. {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.2.dist-info}/METADATA +222 -223
  2. amd_gaia-0.15.2.dist-info/RECORD +182 -0
  3. {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.2.dist-info}/WHEEL +1 -1
  4. {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.2.dist-info}/entry_points.txt +1 -0
  5. {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.2.dist-info}/licenses/LICENSE.md +20 -20
  6. gaia/__init__.py +29 -29
  7. gaia/agents/__init__.py +19 -19
  8. gaia/agents/base/__init__.py +9 -9
  9. gaia/agents/base/agent.py +2132 -2177
  10. gaia/agents/base/api_agent.py +119 -120
  11. gaia/agents/base/console.py +1967 -1841
  12. gaia/agents/base/errors.py +237 -237
  13. gaia/agents/base/mcp_agent.py +86 -86
  14. gaia/agents/base/tools.py +88 -83
  15. gaia/agents/blender/__init__.py +7 -0
  16. gaia/agents/blender/agent.py +553 -556
  17. gaia/agents/blender/agent_simple.py +133 -135
  18. gaia/agents/blender/app.py +211 -211
  19. gaia/agents/blender/app_simple.py +41 -41
  20. gaia/agents/blender/core/__init__.py +16 -16
  21. gaia/agents/blender/core/materials.py +506 -506
  22. gaia/agents/blender/core/objects.py +316 -316
  23. gaia/agents/blender/core/rendering.py +225 -225
  24. gaia/agents/blender/core/scene.py +220 -220
  25. gaia/agents/blender/core/view.py +146 -146
  26. gaia/agents/chat/__init__.py +9 -9
  27. gaia/agents/chat/agent.py +809 -835
  28. gaia/agents/chat/app.py +1065 -1058
  29. gaia/agents/chat/session.py +508 -508
  30. gaia/agents/chat/tools/__init__.py +15 -15
  31. gaia/agents/chat/tools/file_tools.py +96 -96
  32. gaia/agents/chat/tools/rag_tools.py +1744 -1729
  33. gaia/agents/chat/tools/shell_tools.py +437 -436
  34. gaia/agents/code/__init__.py +7 -7
  35. gaia/agents/code/agent.py +549 -549
  36. gaia/agents/code/cli.py +377 -0
  37. gaia/agents/code/models.py +135 -135
  38. gaia/agents/code/orchestration/__init__.py +24 -24
  39. gaia/agents/code/orchestration/checklist_executor.py +1763 -1763
  40. gaia/agents/code/orchestration/checklist_generator.py +713 -713
  41. gaia/agents/code/orchestration/factories/__init__.py +9 -9
  42. gaia/agents/code/orchestration/factories/base.py +63 -63
  43. gaia/agents/code/orchestration/factories/nextjs_factory.py +118 -118
  44. gaia/agents/code/orchestration/factories/python_factory.py +106 -106
  45. gaia/agents/code/orchestration/orchestrator.py +841 -841
  46. gaia/agents/code/orchestration/project_analyzer.py +391 -391
  47. gaia/agents/code/orchestration/steps/__init__.py +67 -67
  48. gaia/agents/code/orchestration/steps/base.py +188 -188
  49. gaia/agents/code/orchestration/steps/error_handler.py +314 -314
  50. gaia/agents/code/orchestration/steps/nextjs.py +828 -828
  51. gaia/agents/code/orchestration/steps/python.py +307 -307
  52. gaia/agents/code/orchestration/template_catalog.py +469 -469
  53. gaia/agents/code/orchestration/workflows/__init__.py +14 -14
  54. gaia/agents/code/orchestration/workflows/base.py +80 -80
  55. gaia/agents/code/orchestration/workflows/nextjs.py +186 -186
  56. gaia/agents/code/orchestration/workflows/python.py +94 -94
  57. gaia/agents/code/prompts/__init__.py +11 -11
  58. gaia/agents/code/prompts/base_prompt.py +77 -77
  59. gaia/agents/code/prompts/code_patterns.py +2034 -2036
  60. gaia/agents/code/prompts/nextjs_prompt.py +40 -40
  61. gaia/agents/code/prompts/python_prompt.py +109 -109
  62. gaia/agents/code/schema_inference.py +365 -365
  63. gaia/agents/code/system_prompt.py +41 -41
  64. gaia/agents/code/tools/__init__.py +42 -42
  65. gaia/agents/code/tools/cli_tools.py +1138 -1138
  66. gaia/agents/code/tools/code_formatting.py +319 -319
  67. gaia/agents/code/tools/code_tools.py +769 -769
  68. gaia/agents/code/tools/error_fixing.py +1347 -1347
  69. gaia/agents/code/tools/external_tools.py +180 -180
  70. gaia/agents/code/tools/file_io.py +845 -845
  71. gaia/agents/code/tools/prisma_tools.py +190 -190
  72. gaia/agents/code/tools/project_management.py +1016 -1016
  73. gaia/agents/code/tools/testing.py +321 -321
  74. gaia/agents/code/tools/typescript_tools.py +122 -122
  75. gaia/agents/code/tools/validation_parsing.py +461 -461
  76. gaia/agents/code/tools/validation_tools.py +806 -806
  77. gaia/agents/code/tools/web_dev_tools.py +1758 -1758
  78. gaia/agents/code/validators/__init__.py +16 -16
  79. gaia/agents/code/validators/antipattern_checker.py +241 -241
  80. gaia/agents/code/validators/ast_analyzer.py +197 -197
  81. gaia/agents/code/validators/requirements_validator.py +145 -145
  82. gaia/agents/code/validators/syntax_validator.py +171 -171
  83. gaia/agents/docker/__init__.py +7 -7
  84. gaia/agents/docker/agent.py +643 -642
  85. gaia/agents/emr/__init__.py +8 -8
  86. gaia/agents/emr/agent.py +1504 -1506
  87. gaia/agents/emr/cli.py +1322 -1322
  88. gaia/agents/emr/constants.py +475 -475
  89. gaia/agents/emr/dashboard/__init__.py +4 -4
  90. gaia/agents/emr/dashboard/server.py +1972 -1974
  91. gaia/agents/jira/__init__.py +11 -11
  92. gaia/agents/jira/agent.py +894 -894
  93. gaia/agents/jira/jql_templates.py +299 -299
  94. gaia/agents/routing/__init__.py +7 -7
  95. gaia/agents/routing/agent.py +567 -570
  96. gaia/agents/routing/system_prompt.py +75 -75
  97. gaia/agents/summarize/__init__.py +11 -0
  98. gaia/agents/summarize/agent.py +885 -0
  99. gaia/agents/summarize/prompts.py +129 -0
  100. gaia/api/__init__.py +23 -23
  101. gaia/api/agent_registry.py +238 -238
  102. gaia/api/app.py +305 -305
  103. gaia/api/openai_server.py +575 -575
  104. gaia/api/schemas.py +186 -186
  105. gaia/api/sse_handler.py +373 -373
  106. gaia/apps/__init__.py +4 -4
  107. gaia/apps/llm/__init__.py +6 -6
  108. gaia/apps/llm/app.py +184 -169
  109. gaia/apps/summarize/app.py +116 -633
  110. gaia/apps/summarize/html_viewer.py +133 -133
  111. gaia/apps/summarize/pdf_formatter.py +284 -284
  112. gaia/audio/__init__.py +2 -2
  113. gaia/audio/audio_client.py +439 -439
  114. gaia/audio/audio_recorder.py +269 -269
  115. gaia/audio/kokoro_tts.py +599 -599
  116. gaia/audio/whisper_asr.py +432 -432
  117. gaia/chat/__init__.py +16 -16
  118. gaia/chat/app.py +428 -430
  119. gaia/chat/prompts.py +522 -522
  120. gaia/chat/sdk.py +1228 -1225
  121. gaia/cli.py +5659 -5632
  122. gaia/database/__init__.py +10 -10
  123. gaia/database/agent.py +176 -176
  124. gaia/database/mixin.py +290 -290
  125. gaia/database/testing.py +64 -64
  126. gaia/eval/batch_experiment.py +2332 -2332
  127. gaia/eval/claude.py +542 -542
  128. gaia/eval/config.py +37 -37
  129. gaia/eval/email_generator.py +512 -512
  130. gaia/eval/eval.py +3179 -3179
  131. gaia/eval/groundtruth.py +1130 -1130
  132. gaia/eval/transcript_generator.py +582 -582
  133. gaia/eval/webapp/README.md +167 -167
  134. gaia/eval/webapp/package-lock.json +875 -875
  135. gaia/eval/webapp/package.json +20 -20
  136. gaia/eval/webapp/public/app.js +3402 -3402
  137. gaia/eval/webapp/public/index.html +87 -87
  138. gaia/eval/webapp/public/styles.css +3661 -3661
  139. gaia/eval/webapp/server.js +415 -415
  140. gaia/eval/webapp/test-setup.js +72 -72
  141. gaia/installer/__init__.py +23 -0
  142. gaia/installer/init_command.py +1275 -0
  143. gaia/installer/lemonade_installer.py +619 -0
  144. gaia/llm/__init__.py +10 -2
  145. gaia/llm/base_client.py +60 -0
  146. gaia/llm/exceptions.py +12 -0
  147. gaia/llm/factory.py +70 -0
  148. gaia/llm/lemonade_client.py +3421 -3221
  149. gaia/llm/lemonade_manager.py +294 -294
  150. gaia/llm/providers/__init__.py +9 -0
  151. gaia/llm/providers/claude.py +108 -0
  152. gaia/llm/providers/lemonade.py +118 -0
  153. gaia/llm/providers/openai_provider.py +79 -0
  154. gaia/llm/vlm_client.py +382 -382
  155. gaia/logger.py +189 -189
  156. gaia/mcp/agent_mcp_server.py +245 -245
  157. gaia/mcp/blender_mcp_client.py +138 -138
  158. gaia/mcp/blender_mcp_server.py +648 -648
  159. gaia/mcp/context7_cache.py +332 -332
  160. gaia/mcp/external_services.py +518 -518
  161. gaia/mcp/mcp_bridge.py +811 -550
  162. gaia/mcp/servers/__init__.py +6 -6
  163. gaia/mcp/servers/docker_mcp.py +83 -83
  164. gaia/perf_analysis.py +361 -0
  165. gaia/rag/__init__.py +10 -10
  166. gaia/rag/app.py +293 -293
  167. gaia/rag/demo.py +304 -304
  168. gaia/rag/pdf_utils.py +235 -235
  169. gaia/rag/sdk.py +2194 -2194
  170. gaia/security.py +183 -163
  171. gaia/talk/app.py +287 -289
  172. gaia/talk/sdk.py +538 -538
  173. gaia/testing/__init__.py +87 -87
  174. gaia/testing/assertions.py +330 -330
  175. gaia/testing/fixtures.py +333 -333
  176. gaia/testing/mocks.py +493 -493
  177. gaia/util.py +46 -46
  178. gaia/utils/__init__.py +33 -33
  179. gaia/utils/file_watcher.py +675 -675
  180. gaia/utils/parsing.py +223 -223
  181. gaia/version.py +100 -100
  182. amd_gaia-0.15.0.dist-info/RECORD +0 -168
  183. gaia/agents/code/app.py +0 -266
  184. gaia/llm/llm_client.py +0 -723
  185. {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.2.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
+ ]