phenoml 0.0.19__py3-none-any.whl → 0.1.0__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.
- phenoml/agent/client.py +4 -44
- phenoml/agent/raw_client.py +2 -38
- phenoml/agent/types/agent_create_request.py +0 -5
- phenoml/construe/__init__.py +33 -1
- phenoml/construe/client.py +577 -0
- phenoml/construe/errors/__init__.py +13 -1
- phenoml/construe/errors/not_found_error.py +10 -0
- phenoml/construe/errors/not_implemented_error.py +10 -0
- phenoml/construe/errors/service_unavailable_error.py +10 -0
- phenoml/construe/raw_client.py +1127 -84
- phenoml/construe/types/__init__.py +20 -0
- phenoml/construe/types/code_response.py +32 -0
- phenoml/construe/types/code_system_details.py +37 -0
- phenoml/construe/types/code_system_info.py +27 -0
- phenoml/construe/types/get_code_response.py +34 -0
- phenoml/construe/types/list_code_systems_response.py +20 -0
- phenoml/construe/types/list_codes_response.py +31 -0
- phenoml/construe/types/semantic_search_response.py +25 -0
- phenoml/construe/types/semantic_search_result.py +20 -0
- phenoml/construe/types/text_search_response.py +30 -0
- phenoml/construe/types/text_search_result.py +20 -0
- phenoml/core/client_wrapper.py +2 -2
- {phenoml-0.0.19.dist-info → phenoml-0.1.0.dist-info}/METADATA +1 -1
- {phenoml-0.0.19.dist-info → phenoml-0.1.0.dist-info}/RECORD +26 -13
- {phenoml-0.0.19.dist-info → phenoml-0.1.0.dist-info}/LICENSE +0 -0
- {phenoml-0.0.19.dist-info → phenoml-0.1.0.dist-info}/WHEEL +0 -0
phenoml/construe/raw_client.py
CHANGED
|
@@ -6,6 +6,7 @@ from json.decoder import JSONDecodeError
|
|
|
6
6
|
from ..core.api_error import ApiError
|
|
7
7
|
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
|
|
8
8
|
from ..core.http_response import AsyncHttpResponse, HttpResponse
|
|
9
|
+
from ..core.jsonable_encoder import jsonable_encoder
|
|
9
10
|
from ..core.pydantic_utilities import parse_obj_as
|
|
10
11
|
from ..core.request_options import RequestOptions
|
|
11
12
|
from ..core.serialization import convert_and_respect_annotation_metadata
|
|
@@ -13,11 +14,19 @@ from .errors.bad_request_error import BadRequestError
|
|
|
13
14
|
from .errors.conflict_error import ConflictError
|
|
14
15
|
from .errors.failed_dependency_error import FailedDependencyError
|
|
15
16
|
from .errors.internal_server_error import InternalServerError
|
|
17
|
+
from .errors.not_found_error import NotFoundError
|
|
18
|
+
from .errors.not_implemented_error import NotImplementedError
|
|
19
|
+
from .errors.service_unavailable_error import ServiceUnavailableError
|
|
16
20
|
from .errors.unauthorized_error import UnauthorizedError
|
|
17
21
|
from .types.construe_upload_code_system_response import ConstrueUploadCodeSystemResponse
|
|
18
22
|
from .types.extract_codes_result import ExtractCodesResult
|
|
19
23
|
from .types.extract_request_config import ExtractRequestConfig
|
|
20
24
|
from .types.extract_request_system import ExtractRequestSystem
|
|
25
|
+
from .types.get_code_response import GetCodeResponse
|
|
26
|
+
from .types.list_code_systems_response import ListCodeSystemsResponse
|
|
27
|
+
from .types.list_codes_response import ListCodesResponse
|
|
28
|
+
from .types.semantic_search_response import SemanticSearchResponse
|
|
29
|
+
from .types.text_search_response import TextSearchResponse
|
|
21
30
|
from .types.upload_request_format import UploadRequestFormat
|
|
22
31
|
|
|
23
32
|
# this is used as the default value for optional parameters
|
|
@@ -274,88 +283,882 @@ class RawConstrueClient:
|
|
|
274
283
|
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
275
284
|
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
276
285
|
|
|
286
|
+
def list_available_code_systems(
|
|
287
|
+
self, *, request_options: typing.Optional[RequestOptions] = None
|
|
288
|
+
) -> HttpResponse[ListCodeSystemsResponse]:
|
|
289
|
+
"""
|
|
290
|
+
Returns metadata about all available code systems including built-in and custom systems.
|
|
291
|
+
|
|
292
|
+
Parameters
|
|
293
|
+
----------
|
|
294
|
+
request_options : typing.Optional[RequestOptions]
|
|
295
|
+
Request-specific configuration.
|
|
296
|
+
|
|
297
|
+
Returns
|
|
298
|
+
-------
|
|
299
|
+
HttpResponse[ListCodeSystemsResponse]
|
|
300
|
+
List of available code systems
|
|
301
|
+
"""
|
|
302
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
303
|
+
"construe/codes/systems",
|
|
304
|
+
method="GET",
|
|
305
|
+
request_options=request_options,
|
|
306
|
+
)
|
|
307
|
+
try:
|
|
308
|
+
if 200 <= _response.status_code < 300:
|
|
309
|
+
_data = typing.cast(
|
|
310
|
+
ListCodeSystemsResponse,
|
|
311
|
+
parse_obj_as(
|
|
312
|
+
type_=ListCodeSystemsResponse, # type: ignore
|
|
313
|
+
object_=_response.json(),
|
|
314
|
+
),
|
|
315
|
+
)
|
|
316
|
+
return HttpResponse(response=_response, data=_data)
|
|
317
|
+
if _response.status_code == 401:
|
|
318
|
+
raise UnauthorizedError(
|
|
319
|
+
headers=dict(_response.headers),
|
|
320
|
+
body=typing.cast(
|
|
321
|
+
typing.Optional[typing.Any],
|
|
322
|
+
parse_obj_as(
|
|
323
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
324
|
+
object_=_response.json(),
|
|
325
|
+
),
|
|
326
|
+
),
|
|
327
|
+
)
|
|
328
|
+
if _response.status_code == 500:
|
|
329
|
+
raise InternalServerError(
|
|
330
|
+
headers=dict(_response.headers),
|
|
331
|
+
body=typing.cast(
|
|
332
|
+
typing.Optional[typing.Any],
|
|
333
|
+
parse_obj_as(
|
|
334
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
335
|
+
object_=_response.json(),
|
|
336
|
+
),
|
|
337
|
+
),
|
|
338
|
+
)
|
|
339
|
+
_response_json = _response.json()
|
|
340
|
+
except JSONDecodeError:
|
|
341
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
342
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
343
|
+
|
|
344
|
+
def list_codes_in_a_code_system(
|
|
345
|
+
self,
|
|
346
|
+
codesystem: str,
|
|
347
|
+
*,
|
|
348
|
+
version: typing.Optional[str] = None,
|
|
349
|
+
cursor: typing.Optional[str] = None,
|
|
350
|
+
limit: typing.Optional[int] = None,
|
|
351
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
352
|
+
) -> HttpResponse[ListCodesResponse]:
|
|
353
|
+
"""
|
|
354
|
+
Returns a paginated list of all codes in the specified code system.
|
|
355
|
+
|
|
356
|
+
Parameters
|
|
357
|
+
----------
|
|
358
|
+
codesystem : str
|
|
359
|
+
Code system name (e.g., "ICD-10-CM", "SNOMED_CT_US_LITE")
|
|
360
|
+
|
|
361
|
+
version : typing.Optional[str]
|
|
362
|
+
Specific version of the code system. Required if multiple versions exist.
|
|
363
|
+
|
|
364
|
+
cursor : typing.Optional[str]
|
|
365
|
+
Pagination cursor from previous response
|
|
366
|
+
|
|
367
|
+
limit : typing.Optional[int]
|
|
368
|
+
Maximum number of codes to return (default 20)
|
|
369
|
+
|
|
370
|
+
request_options : typing.Optional[RequestOptions]
|
|
371
|
+
Request-specific configuration.
|
|
372
|
+
|
|
373
|
+
Returns
|
|
374
|
+
-------
|
|
375
|
+
HttpResponse[ListCodesResponse]
|
|
376
|
+
Paginated list of codes
|
|
377
|
+
"""
|
|
378
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
379
|
+
f"construe/codes/{jsonable_encoder(codesystem)}",
|
|
380
|
+
method="GET",
|
|
381
|
+
params={
|
|
382
|
+
"version": version,
|
|
383
|
+
"cursor": cursor,
|
|
384
|
+
"limit": limit,
|
|
385
|
+
},
|
|
386
|
+
request_options=request_options,
|
|
387
|
+
)
|
|
388
|
+
try:
|
|
389
|
+
if 200 <= _response.status_code < 300:
|
|
390
|
+
_data = typing.cast(
|
|
391
|
+
ListCodesResponse,
|
|
392
|
+
parse_obj_as(
|
|
393
|
+
type_=ListCodesResponse, # type: ignore
|
|
394
|
+
object_=_response.json(),
|
|
395
|
+
),
|
|
396
|
+
)
|
|
397
|
+
return HttpResponse(response=_response, data=_data)
|
|
398
|
+
if _response.status_code == 400:
|
|
399
|
+
raise BadRequestError(
|
|
400
|
+
headers=dict(_response.headers),
|
|
401
|
+
body=typing.cast(
|
|
402
|
+
typing.Optional[typing.Any],
|
|
403
|
+
parse_obj_as(
|
|
404
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
405
|
+
object_=_response.json(),
|
|
406
|
+
),
|
|
407
|
+
),
|
|
408
|
+
)
|
|
409
|
+
if _response.status_code == 401:
|
|
410
|
+
raise UnauthorizedError(
|
|
411
|
+
headers=dict(_response.headers),
|
|
412
|
+
body=typing.cast(
|
|
413
|
+
typing.Optional[typing.Any],
|
|
414
|
+
parse_obj_as(
|
|
415
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
416
|
+
object_=_response.json(),
|
|
417
|
+
),
|
|
418
|
+
),
|
|
419
|
+
)
|
|
420
|
+
if _response.status_code == 404:
|
|
421
|
+
raise NotFoundError(
|
|
422
|
+
headers=dict(_response.headers),
|
|
423
|
+
body=typing.cast(
|
|
424
|
+
typing.Optional[typing.Any],
|
|
425
|
+
parse_obj_as(
|
|
426
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
427
|
+
object_=_response.json(),
|
|
428
|
+
),
|
|
429
|
+
),
|
|
430
|
+
)
|
|
431
|
+
if _response.status_code == 500:
|
|
432
|
+
raise InternalServerError(
|
|
433
|
+
headers=dict(_response.headers),
|
|
434
|
+
body=typing.cast(
|
|
435
|
+
typing.Optional[typing.Any],
|
|
436
|
+
parse_obj_as(
|
|
437
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
438
|
+
object_=_response.json(),
|
|
439
|
+
),
|
|
440
|
+
),
|
|
441
|
+
)
|
|
442
|
+
_response_json = _response.json()
|
|
443
|
+
except JSONDecodeError:
|
|
444
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
445
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
446
|
+
|
|
447
|
+
def get_a_specific_code(
|
|
448
|
+
self,
|
|
449
|
+
codesystem: str,
|
|
450
|
+
code_id: str,
|
|
451
|
+
*,
|
|
452
|
+
version: typing.Optional[str] = None,
|
|
453
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
454
|
+
) -> HttpResponse[GetCodeResponse]:
|
|
455
|
+
"""
|
|
456
|
+
Returns details for a specific code within a code system.
|
|
457
|
+
|
|
458
|
+
Parameters
|
|
459
|
+
----------
|
|
460
|
+
codesystem : str
|
|
461
|
+
Code system name
|
|
462
|
+
|
|
463
|
+
code_id : str
|
|
464
|
+
The code identifier
|
|
465
|
+
|
|
466
|
+
version : typing.Optional[str]
|
|
467
|
+
Specific version of the code system
|
|
468
|
+
|
|
469
|
+
request_options : typing.Optional[RequestOptions]
|
|
470
|
+
Request-specific configuration.
|
|
471
|
+
|
|
472
|
+
Returns
|
|
473
|
+
-------
|
|
474
|
+
HttpResponse[GetCodeResponse]
|
|
475
|
+
Code details
|
|
476
|
+
"""
|
|
477
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
478
|
+
f"construe/codes/{jsonable_encoder(codesystem)}/{jsonable_encoder(code_id)}",
|
|
479
|
+
method="GET",
|
|
480
|
+
params={
|
|
481
|
+
"version": version,
|
|
482
|
+
},
|
|
483
|
+
request_options=request_options,
|
|
484
|
+
)
|
|
485
|
+
try:
|
|
486
|
+
if 200 <= _response.status_code < 300:
|
|
487
|
+
_data = typing.cast(
|
|
488
|
+
GetCodeResponse,
|
|
489
|
+
parse_obj_as(
|
|
490
|
+
type_=GetCodeResponse, # type: ignore
|
|
491
|
+
object_=_response.json(),
|
|
492
|
+
),
|
|
493
|
+
)
|
|
494
|
+
return HttpResponse(response=_response, data=_data)
|
|
495
|
+
if _response.status_code == 400:
|
|
496
|
+
raise BadRequestError(
|
|
497
|
+
headers=dict(_response.headers),
|
|
498
|
+
body=typing.cast(
|
|
499
|
+
typing.Optional[typing.Any],
|
|
500
|
+
parse_obj_as(
|
|
501
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
502
|
+
object_=_response.json(),
|
|
503
|
+
),
|
|
504
|
+
),
|
|
505
|
+
)
|
|
506
|
+
if _response.status_code == 401:
|
|
507
|
+
raise UnauthorizedError(
|
|
508
|
+
headers=dict(_response.headers),
|
|
509
|
+
body=typing.cast(
|
|
510
|
+
typing.Optional[typing.Any],
|
|
511
|
+
parse_obj_as(
|
|
512
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
513
|
+
object_=_response.json(),
|
|
514
|
+
),
|
|
515
|
+
),
|
|
516
|
+
)
|
|
517
|
+
if _response.status_code == 404:
|
|
518
|
+
raise NotFoundError(
|
|
519
|
+
headers=dict(_response.headers),
|
|
520
|
+
body=typing.cast(
|
|
521
|
+
typing.Optional[typing.Any],
|
|
522
|
+
parse_obj_as(
|
|
523
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
524
|
+
object_=_response.json(),
|
|
525
|
+
),
|
|
526
|
+
),
|
|
527
|
+
)
|
|
528
|
+
if _response.status_code == 500:
|
|
529
|
+
raise InternalServerError(
|
|
530
|
+
headers=dict(_response.headers),
|
|
531
|
+
body=typing.cast(
|
|
532
|
+
typing.Optional[typing.Any],
|
|
533
|
+
parse_obj_as(
|
|
534
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
535
|
+
object_=_response.json(),
|
|
536
|
+
),
|
|
537
|
+
),
|
|
538
|
+
)
|
|
539
|
+
_response_json = _response.json()
|
|
540
|
+
except JSONDecodeError:
|
|
541
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
542
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
543
|
+
|
|
544
|
+
def semantic_search_embedding_based(
|
|
545
|
+
self,
|
|
546
|
+
codesystem: str,
|
|
547
|
+
*,
|
|
548
|
+
text: str,
|
|
549
|
+
version: typing.Optional[str] = None,
|
|
550
|
+
limit: typing.Optional[int] = None,
|
|
551
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
552
|
+
) -> HttpResponse[SemanticSearchResponse]:
|
|
553
|
+
"""
|
|
554
|
+
Performs semantic similarity search using vector embeddings.
|
|
555
|
+
|
|
556
|
+
**When to use**: Best for natural language queries where you want to find conceptually
|
|
557
|
+
related codes, even when different terminology is used. The search understands meaning,
|
|
558
|
+
not just keywords.
|
|
559
|
+
|
|
560
|
+
**Examples**:
|
|
561
|
+
- Query "trouble breathing at night" finds codes like "Sleep apnea", "Orthopnea",
|
|
562
|
+
"Nocturnal dyspnea" — semantically related but no exact keyword matches
|
|
563
|
+
- Query "heart problems" finds "Myocardial infarction", "Cardiac arrest", "Arrhythmia"
|
|
564
|
+
|
|
565
|
+
**Trade-offs**: Slower than text search (requires embedding generation), but finds
|
|
566
|
+
conceptually similar results that keyword search would miss.
|
|
567
|
+
|
|
568
|
+
See also: `/search/text` for faster keyword-based lookup with typo tolerance.
|
|
569
|
+
|
|
570
|
+
Parameters
|
|
571
|
+
----------
|
|
572
|
+
codesystem : str
|
|
573
|
+
Code system name
|
|
574
|
+
|
|
575
|
+
text : str
|
|
576
|
+
Natural language text to find semantically similar codes for
|
|
577
|
+
|
|
578
|
+
version : typing.Optional[str]
|
|
579
|
+
Specific version of the code system
|
|
580
|
+
|
|
581
|
+
limit : typing.Optional[int]
|
|
582
|
+
Maximum number of results (default 10, max 50)
|
|
583
|
+
|
|
584
|
+
request_options : typing.Optional[RequestOptions]
|
|
585
|
+
Request-specific configuration.
|
|
586
|
+
|
|
587
|
+
Returns
|
|
588
|
+
-------
|
|
589
|
+
HttpResponse[SemanticSearchResponse]
|
|
590
|
+
Semantic search results ordered by similarity
|
|
591
|
+
"""
|
|
592
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
593
|
+
f"construe/codes/{jsonable_encoder(codesystem)}/search/semantic",
|
|
594
|
+
method="GET",
|
|
595
|
+
params={
|
|
596
|
+
"text": text,
|
|
597
|
+
"version": version,
|
|
598
|
+
"limit": limit,
|
|
599
|
+
},
|
|
600
|
+
request_options=request_options,
|
|
601
|
+
)
|
|
602
|
+
try:
|
|
603
|
+
if 200 <= _response.status_code < 300:
|
|
604
|
+
_data = typing.cast(
|
|
605
|
+
SemanticSearchResponse,
|
|
606
|
+
parse_obj_as(
|
|
607
|
+
type_=SemanticSearchResponse, # type: ignore
|
|
608
|
+
object_=_response.json(),
|
|
609
|
+
),
|
|
610
|
+
)
|
|
611
|
+
return HttpResponse(response=_response, data=_data)
|
|
612
|
+
if _response.status_code == 400:
|
|
613
|
+
raise BadRequestError(
|
|
614
|
+
headers=dict(_response.headers),
|
|
615
|
+
body=typing.cast(
|
|
616
|
+
typing.Optional[typing.Any],
|
|
617
|
+
parse_obj_as(
|
|
618
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
619
|
+
object_=_response.json(),
|
|
620
|
+
),
|
|
621
|
+
),
|
|
622
|
+
)
|
|
623
|
+
if _response.status_code == 401:
|
|
624
|
+
raise UnauthorizedError(
|
|
625
|
+
headers=dict(_response.headers),
|
|
626
|
+
body=typing.cast(
|
|
627
|
+
typing.Optional[typing.Any],
|
|
628
|
+
parse_obj_as(
|
|
629
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
630
|
+
object_=_response.json(),
|
|
631
|
+
),
|
|
632
|
+
),
|
|
633
|
+
)
|
|
634
|
+
if _response.status_code == 404:
|
|
635
|
+
raise NotFoundError(
|
|
636
|
+
headers=dict(_response.headers),
|
|
637
|
+
body=typing.cast(
|
|
638
|
+
typing.Optional[typing.Any],
|
|
639
|
+
parse_obj_as(
|
|
640
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
641
|
+
object_=_response.json(),
|
|
642
|
+
),
|
|
643
|
+
),
|
|
644
|
+
)
|
|
645
|
+
if _response.status_code == 500:
|
|
646
|
+
raise InternalServerError(
|
|
647
|
+
headers=dict(_response.headers),
|
|
648
|
+
body=typing.cast(
|
|
649
|
+
typing.Optional[typing.Any],
|
|
650
|
+
parse_obj_as(
|
|
651
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
652
|
+
object_=_response.json(),
|
|
653
|
+
),
|
|
654
|
+
),
|
|
655
|
+
)
|
|
656
|
+
_response_json = _response.json()
|
|
657
|
+
except JSONDecodeError:
|
|
658
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
659
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
660
|
+
|
|
661
|
+
def text_search_keyword_based(
|
|
662
|
+
self,
|
|
663
|
+
codesystem: str,
|
|
664
|
+
*,
|
|
665
|
+
q: str,
|
|
666
|
+
version: typing.Optional[str] = None,
|
|
667
|
+
limit: typing.Optional[int] = None,
|
|
668
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
669
|
+
) -> HttpResponse[TextSearchResponse]:
|
|
670
|
+
"""
|
|
671
|
+
Performs fast full-text search over code IDs and descriptions.
|
|
672
|
+
|
|
673
|
+
**When to use**: Best for autocomplete UIs, code lookup, or when users know part of
|
|
674
|
+
the code ID or specific keywords. Fast response times suitable for typeahead interfaces.
|
|
675
|
+
|
|
676
|
+
**Features**:
|
|
677
|
+
- Substring matching on code IDs (e.g., "11.65" finds "E11.65")
|
|
678
|
+
- Typo tolerance on descriptions (not on code IDs)
|
|
679
|
+
- Fast response times (~10-50ms)
|
|
680
|
+
|
|
681
|
+
**Examples**:
|
|
682
|
+
- Query "E11" finds all codes starting with E11 (diabetes codes)
|
|
683
|
+
- Query "diabtes" (typo) still finds "diabetes" codes
|
|
684
|
+
|
|
685
|
+
**Trade-offs**: Faster than semantic search, but only matches keywords/substrings.
|
|
686
|
+
Won't find conceptually related codes with different terminology.
|
|
687
|
+
|
|
688
|
+
See also: `/search/semantic` for finding conceptually similar codes.
|
|
689
|
+
|
|
690
|
+
Parameters
|
|
691
|
+
----------
|
|
692
|
+
codesystem : str
|
|
693
|
+
Code system name
|
|
694
|
+
|
|
695
|
+
q : str
|
|
696
|
+
Search query (searches code IDs and descriptions)
|
|
697
|
+
|
|
698
|
+
version : typing.Optional[str]
|
|
699
|
+
Specific version of the code system
|
|
700
|
+
|
|
701
|
+
limit : typing.Optional[int]
|
|
702
|
+
Maximum number of results (default 20, max 100)
|
|
703
|
+
|
|
704
|
+
request_options : typing.Optional[RequestOptions]
|
|
705
|
+
Request-specific configuration.
|
|
706
|
+
|
|
707
|
+
Returns
|
|
708
|
+
-------
|
|
709
|
+
HttpResponse[TextSearchResponse]
|
|
710
|
+
Text search results
|
|
711
|
+
"""
|
|
712
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
713
|
+
f"construe/codes/{jsonable_encoder(codesystem)}/search/text",
|
|
714
|
+
method="GET",
|
|
715
|
+
params={
|
|
716
|
+
"q": q,
|
|
717
|
+
"version": version,
|
|
718
|
+
"limit": limit,
|
|
719
|
+
},
|
|
720
|
+
request_options=request_options,
|
|
721
|
+
)
|
|
722
|
+
try:
|
|
723
|
+
if 200 <= _response.status_code < 300:
|
|
724
|
+
_data = typing.cast(
|
|
725
|
+
TextSearchResponse,
|
|
726
|
+
parse_obj_as(
|
|
727
|
+
type_=TextSearchResponse, # type: ignore
|
|
728
|
+
object_=_response.json(),
|
|
729
|
+
),
|
|
730
|
+
)
|
|
731
|
+
return HttpResponse(response=_response, data=_data)
|
|
732
|
+
if _response.status_code == 400:
|
|
733
|
+
raise BadRequestError(
|
|
734
|
+
headers=dict(_response.headers),
|
|
735
|
+
body=typing.cast(
|
|
736
|
+
typing.Optional[typing.Any],
|
|
737
|
+
parse_obj_as(
|
|
738
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
739
|
+
object_=_response.json(),
|
|
740
|
+
),
|
|
741
|
+
),
|
|
742
|
+
)
|
|
743
|
+
if _response.status_code == 401:
|
|
744
|
+
raise UnauthorizedError(
|
|
745
|
+
headers=dict(_response.headers),
|
|
746
|
+
body=typing.cast(
|
|
747
|
+
typing.Optional[typing.Any],
|
|
748
|
+
parse_obj_as(
|
|
749
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
750
|
+
object_=_response.json(),
|
|
751
|
+
),
|
|
752
|
+
),
|
|
753
|
+
)
|
|
754
|
+
if _response.status_code == 404:
|
|
755
|
+
raise NotFoundError(
|
|
756
|
+
headers=dict(_response.headers),
|
|
757
|
+
body=typing.cast(
|
|
758
|
+
typing.Optional[typing.Any],
|
|
759
|
+
parse_obj_as(
|
|
760
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
761
|
+
object_=_response.json(),
|
|
762
|
+
),
|
|
763
|
+
),
|
|
764
|
+
)
|
|
765
|
+
if _response.status_code == 500:
|
|
766
|
+
raise InternalServerError(
|
|
767
|
+
headers=dict(_response.headers),
|
|
768
|
+
body=typing.cast(
|
|
769
|
+
typing.Optional[typing.Any],
|
|
770
|
+
parse_obj_as(
|
|
771
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
772
|
+
object_=_response.json(),
|
|
773
|
+
),
|
|
774
|
+
),
|
|
775
|
+
)
|
|
776
|
+
if _response.status_code == 501:
|
|
777
|
+
raise NotImplementedError(
|
|
778
|
+
headers=dict(_response.headers),
|
|
779
|
+
body=typing.cast(
|
|
780
|
+
typing.Optional[typing.Any],
|
|
781
|
+
parse_obj_as(
|
|
782
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
783
|
+
object_=_response.json(),
|
|
784
|
+
),
|
|
785
|
+
),
|
|
786
|
+
)
|
|
787
|
+
if _response.status_code == 503:
|
|
788
|
+
raise ServiceUnavailableError(
|
|
789
|
+
headers=dict(_response.headers),
|
|
790
|
+
body=typing.cast(
|
|
791
|
+
typing.Optional[typing.Any],
|
|
792
|
+
parse_obj_as(
|
|
793
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
794
|
+
object_=_response.json(),
|
|
795
|
+
),
|
|
796
|
+
),
|
|
797
|
+
)
|
|
798
|
+
_response_json = _response.json()
|
|
799
|
+
except JSONDecodeError:
|
|
800
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
801
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
class AsyncRawConstrueClient:
|
|
805
|
+
def __init__(self, *, client_wrapper: AsyncClientWrapper):
|
|
806
|
+
self._client_wrapper = client_wrapper
|
|
807
|
+
|
|
808
|
+
async def upload_code_system(
|
|
809
|
+
self,
|
|
810
|
+
*,
|
|
811
|
+
name: str,
|
|
812
|
+
version: str,
|
|
813
|
+
format: UploadRequestFormat,
|
|
814
|
+
file: str,
|
|
815
|
+
revision: typing.Optional[float] = OMIT,
|
|
816
|
+
code_col: typing.Optional[str] = OMIT,
|
|
817
|
+
desc_col: typing.Optional[str] = OMIT,
|
|
818
|
+
defn_col: typing.Optional[str] = OMIT,
|
|
819
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
820
|
+
) -> AsyncHttpResponse[ConstrueUploadCodeSystemResponse]:
|
|
821
|
+
"""
|
|
822
|
+
Upload a custom medical code system with codes and descriptions for use in code extraction.
|
|
823
|
+
Upon upload, construe generates embeddings for all of the codes in the code system and stores them in the vector database so you can
|
|
824
|
+
subsequently use the code system for construe/extract and lang2fhir/create (coming soon!)
|
|
825
|
+
|
|
826
|
+
Parameters
|
|
827
|
+
----------
|
|
828
|
+
name : str
|
|
829
|
+
Name of the code system
|
|
830
|
+
|
|
831
|
+
version : str
|
|
832
|
+
Version of the code system
|
|
833
|
+
|
|
834
|
+
format : UploadRequestFormat
|
|
835
|
+
Format of the uploaded file
|
|
836
|
+
|
|
837
|
+
file : str
|
|
838
|
+
The file contents as a base64-encoded string
|
|
839
|
+
|
|
840
|
+
revision : typing.Optional[float]
|
|
841
|
+
Optional revision number
|
|
842
|
+
|
|
843
|
+
code_col : typing.Optional[str]
|
|
844
|
+
Column name containing codes (required for CSV format)
|
|
277
845
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
846
|
+
desc_col : typing.Optional[str]
|
|
847
|
+
Column name containing descriptions (required for CSV format)
|
|
848
|
+
|
|
849
|
+
defn_col : typing.Optional[str]
|
|
850
|
+
Optional column name containing long definitions (for CSV format)
|
|
851
|
+
|
|
852
|
+
request_options : typing.Optional[RequestOptions]
|
|
853
|
+
Request-specific configuration.
|
|
854
|
+
|
|
855
|
+
Returns
|
|
856
|
+
-------
|
|
857
|
+
AsyncHttpResponse[ConstrueUploadCodeSystemResponse]
|
|
858
|
+
Successfully uploaded code system
|
|
859
|
+
"""
|
|
860
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
861
|
+
"construe/upload",
|
|
862
|
+
method="POST",
|
|
863
|
+
json={
|
|
864
|
+
"name": name,
|
|
865
|
+
"version": version,
|
|
866
|
+
"revision": revision,
|
|
867
|
+
"format": format,
|
|
868
|
+
"file": file,
|
|
869
|
+
"code_col": code_col,
|
|
870
|
+
"desc_col": desc_col,
|
|
871
|
+
"defn_col": defn_col,
|
|
872
|
+
},
|
|
873
|
+
headers={
|
|
874
|
+
"content-type": "application/json",
|
|
875
|
+
},
|
|
876
|
+
request_options=request_options,
|
|
877
|
+
omit=OMIT,
|
|
878
|
+
)
|
|
879
|
+
try:
|
|
880
|
+
if 200 <= _response.status_code < 300:
|
|
881
|
+
_data = typing.cast(
|
|
882
|
+
ConstrueUploadCodeSystemResponse,
|
|
883
|
+
parse_obj_as(
|
|
884
|
+
type_=ConstrueUploadCodeSystemResponse, # type: ignore
|
|
885
|
+
object_=_response.json(),
|
|
886
|
+
),
|
|
887
|
+
)
|
|
888
|
+
return AsyncHttpResponse(response=_response, data=_data)
|
|
889
|
+
if _response.status_code == 400:
|
|
890
|
+
raise BadRequestError(
|
|
891
|
+
headers=dict(_response.headers),
|
|
892
|
+
body=typing.cast(
|
|
893
|
+
typing.Optional[typing.Any],
|
|
894
|
+
parse_obj_as(
|
|
895
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
896
|
+
object_=_response.json(),
|
|
897
|
+
),
|
|
898
|
+
),
|
|
899
|
+
)
|
|
900
|
+
if _response.status_code == 401:
|
|
901
|
+
raise UnauthorizedError(
|
|
902
|
+
headers=dict(_response.headers),
|
|
903
|
+
body=typing.cast(
|
|
904
|
+
typing.Optional[typing.Any],
|
|
905
|
+
parse_obj_as(
|
|
906
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
907
|
+
object_=_response.json(),
|
|
908
|
+
),
|
|
909
|
+
),
|
|
910
|
+
)
|
|
911
|
+
if _response.status_code == 409:
|
|
912
|
+
raise ConflictError(
|
|
913
|
+
headers=dict(_response.headers),
|
|
914
|
+
body=typing.cast(
|
|
915
|
+
typing.Optional[typing.Any],
|
|
916
|
+
parse_obj_as(
|
|
917
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
918
|
+
object_=_response.json(),
|
|
919
|
+
),
|
|
920
|
+
),
|
|
921
|
+
)
|
|
922
|
+
if _response.status_code == 424:
|
|
923
|
+
raise FailedDependencyError(
|
|
924
|
+
headers=dict(_response.headers),
|
|
925
|
+
body=typing.cast(
|
|
926
|
+
typing.Optional[typing.Any],
|
|
927
|
+
parse_obj_as(
|
|
928
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
929
|
+
object_=_response.json(),
|
|
930
|
+
),
|
|
931
|
+
),
|
|
932
|
+
)
|
|
933
|
+
if _response.status_code == 500:
|
|
934
|
+
raise InternalServerError(
|
|
935
|
+
headers=dict(_response.headers),
|
|
936
|
+
body=typing.cast(
|
|
937
|
+
typing.Optional[typing.Any],
|
|
938
|
+
parse_obj_as(
|
|
939
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
940
|
+
object_=_response.json(),
|
|
941
|
+
),
|
|
942
|
+
),
|
|
943
|
+
)
|
|
944
|
+
_response_json = _response.json()
|
|
945
|
+
except JSONDecodeError:
|
|
946
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
947
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
948
|
+
|
|
949
|
+
async def extract_codes(
|
|
950
|
+
self,
|
|
951
|
+
*,
|
|
952
|
+
text: str,
|
|
953
|
+
system: typing.Optional[ExtractRequestSystem] = OMIT,
|
|
954
|
+
config: typing.Optional[ExtractRequestConfig] = OMIT,
|
|
955
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
956
|
+
) -> AsyncHttpResponse[ExtractCodesResult]:
|
|
957
|
+
"""
|
|
958
|
+
Converts natural language text into structured medical codes
|
|
959
|
+
|
|
960
|
+
Parameters
|
|
961
|
+
----------
|
|
962
|
+
text : str
|
|
963
|
+
Natural language text to extract codes from
|
|
964
|
+
|
|
965
|
+
system : typing.Optional[ExtractRequestSystem]
|
|
966
|
+
|
|
967
|
+
config : typing.Optional[ExtractRequestConfig]
|
|
968
|
+
|
|
969
|
+
request_options : typing.Optional[RequestOptions]
|
|
970
|
+
Request-specific configuration.
|
|
971
|
+
|
|
972
|
+
Returns
|
|
973
|
+
-------
|
|
974
|
+
AsyncHttpResponse[ExtractCodesResult]
|
|
975
|
+
Successfully extracted codes
|
|
976
|
+
"""
|
|
977
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
978
|
+
"construe/extract",
|
|
979
|
+
method="POST",
|
|
980
|
+
json={
|
|
981
|
+
"text": text,
|
|
982
|
+
"system": convert_and_respect_annotation_metadata(
|
|
983
|
+
object_=system, annotation=ExtractRequestSystem, direction="write"
|
|
984
|
+
),
|
|
985
|
+
"config": convert_and_respect_annotation_metadata(
|
|
986
|
+
object_=config, annotation=ExtractRequestConfig, direction="write"
|
|
987
|
+
),
|
|
988
|
+
},
|
|
989
|
+
headers={
|
|
990
|
+
"content-type": "application/json",
|
|
991
|
+
},
|
|
992
|
+
request_options=request_options,
|
|
993
|
+
omit=OMIT,
|
|
994
|
+
)
|
|
995
|
+
try:
|
|
996
|
+
if 200 <= _response.status_code < 300:
|
|
997
|
+
_data = typing.cast(
|
|
998
|
+
ExtractCodesResult,
|
|
999
|
+
parse_obj_as(
|
|
1000
|
+
type_=ExtractCodesResult, # type: ignore
|
|
1001
|
+
object_=_response.json(),
|
|
1002
|
+
),
|
|
1003
|
+
)
|
|
1004
|
+
return AsyncHttpResponse(response=_response, data=_data)
|
|
1005
|
+
if _response.status_code == 400:
|
|
1006
|
+
raise BadRequestError(
|
|
1007
|
+
headers=dict(_response.headers),
|
|
1008
|
+
body=typing.cast(
|
|
1009
|
+
typing.Optional[typing.Any],
|
|
1010
|
+
parse_obj_as(
|
|
1011
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1012
|
+
object_=_response.json(),
|
|
1013
|
+
),
|
|
1014
|
+
),
|
|
1015
|
+
)
|
|
1016
|
+
if _response.status_code == 401:
|
|
1017
|
+
raise UnauthorizedError(
|
|
1018
|
+
headers=dict(_response.headers),
|
|
1019
|
+
body=typing.cast(
|
|
1020
|
+
typing.Optional[typing.Any],
|
|
1021
|
+
parse_obj_as(
|
|
1022
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1023
|
+
object_=_response.json(),
|
|
1024
|
+
),
|
|
1025
|
+
),
|
|
1026
|
+
)
|
|
1027
|
+
if _response.status_code == 424:
|
|
1028
|
+
raise FailedDependencyError(
|
|
1029
|
+
headers=dict(_response.headers),
|
|
1030
|
+
body=typing.cast(
|
|
1031
|
+
typing.Optional[typing.Any],
|
|
1032
|
+
parse_obj_as(
|
|
1033
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1034
|
+
object_=_response.json(),
|
|
1035
|
+
),
|
|
1036
|
+
),
|
|
1037
|
+
)
|
|
1038
|
+
if _response.status_code == 500:
|
|
1039
|
+
raise InternalServerError(
|
|
1040
|
+
headers=dict(_response.headers),
|
|
1041
|
+
body=typing.cast(
|
|
1042
|
+
typing.Optional[typing.Any],
|
|
1043
|
+
parse_obj_as(
|
|
1044
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1045
|
+
object_=_response.json(),
|
|
1046
|
+
),
|
|
1047
|
+
),
|
|
1048
|
+
)
|
|
1049
|
+
_response_json = _response.json()
|
|
1050
|
+
except JSONDecodeError:
|
|
1051
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
1052
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
1053
|
+
|
|
1054
|
+
async def list_available_code_systems(
|
|
1055
|
+
self, *, request_options: typing.Optional[RequestOptions] = None
|
|
1056
|
+
) -> AsyncHttpResponse[ListCodeSystemsResponse]:
|
|
1057
|
+
"""
|
|
1058
|
+
Returns metadata about all available code systems including built-in and custom systems.
|
|
1059
|
+
|
|
1060
|
+
Parameters
|
|
1061
|
+
----------
|
|
1062
|
+
request_options : typing.Optional[RequestOptions]
|
|
1063
|
+
Request-specific configuration.
|
|
1064
|
+
|
|
1065
|
+
Returns
|
|
1066
|
+
-------
|
|
1067
|
+
AsyncHttpResponse[ListCodeSystemsResponse]
|
|
1068
|
+
List of available code systems
|
|
1069
|
+
"""
|
|
1070
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
1071
|
+
"construe/codes/systems",
|
|
1072
|
+
method="GET",
|
|
1073
|
+
request_options=request_options,
|
|
1074
|
+
)
|
|
1075
|
+
try:
|
|
1076
|
+
if 200 <= _response.status_code < 300:
|
|
1077
|
+
_data = typing.cast(
|
|
1078
|
+
ListCodeSystemsResponse,
|
|
1079
|
+
parse_obj_as(
|
|
1080
|
+
type_=ListCodeSystemsResponse, # type: ignore
|
|
1081
|
+
object_=_response.json(),
|
|
1082
|
+
),
|
|
1083
|
+
)
|
|
1084
|
+
return AsyncHttpResponse(response=_response, data=_data)
|
|
1085
|
+
if _response.status_code == 401:
|
|
1086
|
+
raise UnauthorizedError(
|
|
1087
|
+
headers=dict(_response.headers),
|
|
1088
|
+
body=typing.cast(
|
|
1089
|
+
typing.Optional[typing.Any],
|
|
1090
|
+
parse_obj_as(
|
|
1091
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1092
|
+
object_=_response.json(),
|
|
1093
|
+
),
|
|
1094
|
+
),
|
|
1095
|
+
)
|
|
1096
|
+
if _response.status_code == 500:
|
|
1097
|
+
raise InternalServerError(
|
|
1098
|
+
headers=dict(_response.headers),
|
|
1099
|
+
body=typing.cast(
|
|
1100
|
+
typing.Optional[typing.Any],
|
|
1101
|
+
parse_obj_as(
|
|
1102
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1103
|
+
object_=_response.json(),
|
|
1104
|
+
),
|
|
1105
|
+
),
|
|
1106
|
+
)
|
|
1107
|
+
_response_json = _response.json()
|
|
1108
|
+
except JSONDecodeError:
|
|
1109
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
1110
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
281
1111
|
|
|
282
|
-
async def
|
|
1112
|
+
async def list_codes_in_a_code_system(
|
|
283
1113
|
self,
|
|
1114
|
+
codesystem: str,
|
|
284
1115
|
*,
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
file: str,
|
|
289
|
-
revision: typing.Optional[float] = OMIT,
|
|
290
|
-
code_col: typing.Optional[str] = OMIT,
|
|
291
|
-
desc_col: typing.Optional[str] = OMIT,
|
|
292
|
-
defn_col: typing.Optional[str] = OMIT,
|
|
1116
|
+
version: typing.Optional[str] = None,
|
|
1117
|
+
cursor: typing.Optional[str] = None,
|
|
1118
|
+
limit: typing.Optional[int] = None,
|
|
293
1119
|
request_options: typing.Optional[RequestOptions] = None,
|
|
294
|
-
) -> AsyncHttpResponse[
|
|
1120
|
+
) -> AsyncHttpResponse[ListCodesResponse]:
|
|
295
1121
|
"""
|
|
296
|
-
|
|
297
|
-
Upon upload, construe generates embeddings for all of the codes in the code system and stores them in the vector database so you can
|
|
298
|
-
subsequently use the code system for construe/extract and lang2fhir/create (coming soon!)
|
|
1122
|
+
Returns a paginated list of all codes in the specified code system.
|
|
299
1123
|
|
|
300
1124
|
Parameters
|
|
301
1125
|
----------
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
version : str
|
|
306
|
-
Version of the code system
|
|
307
|
-
|
|
308
|
-
format : UploadRequestFormat
|
|
309
|
-
Format of the uploaded file
|
|
1126
|
+
codesystem : str
|
|
1127
|
+
Code system name (e.g., "ICD-10-CM", "SNOMED_CT_US_LITE")
|
|
310
1128
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
revision : typing.Optional[float]
|
|
315
|
-
Optional revision number
|
|
316
|
-
|
|
317
|
-
code_col : typing.Optional[str]
|
|
318
|
-
Column name containing codes (required for CSV format)
|
|
1129
|
+
version : typing.Optional[str]
|
|
1130
|
+
Specific version of the code system. Required if multiple versions exist.
|
|
319
1131
|
|
|
320
|
-
|
|
321
|
-
|
|
1132
|
+
cursor : typing.Optional[str]
|
|
1133
|
+
Pagination cursor from previous response
|
|
322
1134
|
|
|
323
|
-
|
|
324
|
-
|
|
1135
|
+
limit : typing.Optional[int]
|
|
1136
|
+
Maximum number of codes to return (default 20)
|
|
325
1137
|
|
|
326
1138
|
request_options : typing.Optional[RequestOptions]
|
|
327
1139
|
Request-specific configuration.
|
|
328
1140
|
|
|
329
1141
|
Returns
|
|
330
1142
|
-------
|
|
331
|
-
AsyncHttpResponse[
|
|
332
|
-
|
|
1143
|
+
AsyncHttpResponse[ListCodesResponse]
|
|
1144
|
+
Paginated list of codes
|
|
333
1145
|
"""
|
|
334
1146
|
_response = await self._client_wrapper.httpx_client.request(
|
|
335
|
-
"construe/
|
|
336
|
-
method="
|
|
337
|
-
|
|
338
|
-
"name": name,
|
|
1147
|
+
f"construe/codes/{jsonable_encoder(codesystem)}",
|
|
1148
|
+
method="GET",
|
|
1149
|
+
params={
|
|
339
1150
|
"version": version,
|
|
340
|
-
"
|
|
341
|
-
"
|
|
342
|
-
"file": file,
|
|
343
|
-
"code_col": code_col,
|
|
344
|
-
"desc_col": desc_col,
|
|
345
|
-
"defn_col": defn_col,
|
|
346
|
-
},
|
|
347
|
-
headers={
|
|
348
|
-
"content-type": "application/json",
|
|
1151
|
+
"cursor": cursor,
|
|
1152
|
+
"limit": limit,
|
|
349
1153
|
},
|
|
350
1154
|
request_options=request_options,
|
|
351
|
-
omit=OMIT,
|
|
352
1155
|
)
|
|
353
1156
|
try:
|
|
354
1157
|
if 200 <= _response.status_code < 300:
|
|
355
1158
|
_data = typing.cast(
|
|
356
|
-
|
|
1159
|
+
ListCodesResponse,
|
|
357
1160
|
parse_obj_as(
|
|
358
|
-
type_=
|
|
1161
|
+
type_=ListCodesResponse, # type: ignore
|
|
359
1162
|
object_=_response.json(),
|
|
360
1163
|
),
|
|
361
1164
|
)
|
|
@@ -382,8 +1185,8 @@ class AsyncRawConstrueClient:
|
|
|
382
1185
|
),
|
|
383
1186
|
),
|
|
384
1187
|
)
|
|
385
|
-
if _response.status_code ==
|
|
386
|
-
raise
|
|
1188
|
+
if _response.status_code == 404:
|
|
1189
|
+
raise NotFoundError(
|
|
387
1190
|
headers=dict(_response.headers),
|
|
388
1191
|
body=typing.cast(
|
|
389
1192
|
typing.Optional[typing.Any],
|
|
@@ -393,8 +1196,94 @@ class AsyncRawConstrueClient:
|
|
|
393
1196
|
),
|
|
394
1197
|
),
|
|
395
1198
|
)
|
|
396
|
-
if _response.status_code ==
|
|
397
|
-
raise
|
|
1199
|
+
if _response.status_code == 500:
|
|
1200
|
+
raise InternalServerError(
|
|
1201
|
+
headers=dict(_response.headers),
|
|
1202
|
+
body=typing.cast(
|
|
1203
|
+
typing.Optional[typing.Any],
|
|
1204
|
+
parse_obj_as(
|
|
1205
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1206
|
+
object_=_response.json(),
|
|
1207
|
+
),
|
|
1208
|
+
),
|
|
1209
|
+
)
|
|
1210
|
+
_response_json = _response.json()
|
|
1211
|
+
except JSONDecodeError:
|
|
1212
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
1213
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
1214
|
+
|
|
1215
|
+
async def get_a_specific_code(
|
|
1216
|
+
self,
|
|
1217
|
+
codesystem: str,
|
|
1218
|
+
code_id: str,
|
|
1219
|
+
*,
|
|
1220
|
+
version: typing.Optional[str] = None,
|
|
1221
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
1222
|
+
) -> AsyncHttpResponse[GetCodeResponse]:
|
|
1223
|
+
"""
|
|
1224
|
+
Returns details for a specific code within a code system.
|
|
1225
|
+
|
|
1226
|
+
Parameters
|
|
1227
|
+
----------
|
|
1228
|
+
codesystem : str
|
|
1229
|
+
Code system name
|
|
1230
|
+
|
|
1231
|
+
code_id : str
|
|
1232
|
+
The code identifier
|
|
1233
|
+
|
|
1234
|
+
version : typing.Optional[str]
|
|
1235
|
+
Specific version of the code system
|
|
1236
|
+
|
|
1237
|
+
request_options : typing.Optional[RequestOptions]
|
|
1238
|
+
Request-specific configuration.
|
|
1239
|
+
|
|
1240
|
+
Returns
|
|
1241
|
+
-------
|
|
1242
|
+
AsyncHttpResponse[GetCodeResponse]
|
|
1243
|
+
Code details
|
|
1244
|
+
"""
|
|
1245
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
1246
|
+
f"construe/codes/{jsonable_encoder(codesystem)}/{jsonable_encoder(code_id)}",
|
|
1247
|
+
method="GET",
|
|
1248
|
+
params={
|
|
1249
|
+
"version": version,
|
|
1250
|
+
},
|
|
1251
|
+
request_options=request_options,
|
|
1252
|
+
)
|
|
1253
|
+
try:
|
|
1254
|
+
if 200 <= _response.status_code < 300:
|
|
1255
|
+
_data = typing.cast(
|
|
1256
|
+
GetCodeResponse,
|
|
1257
|
+
parse_obj_as(
|
|
1258
|
+
type_=GetCodeResponse, # type: ignore
|
|
1259
|
+
object_=_response.json(),
|
|
1260
|
+
),
|
|
1261
|
+
)
|
|
1262
|
+
return AsyncHttpResponse(response=_response, data=_data)
|
|
1263
|
+
if _response.status_code == 400:
|
|
1264
|
+
raise BadRequestError(
|
|
1265
|
+
headers=dict(_response.headers),
|
|
1266
|
+
body=typing.cast(
|
|
1267
|
+
typing.Optional[typing.Any],
|
|
1268
|
+
parse_obj_as(
|
|
1269
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1270
|
+
object_=_response.json(),
|
|
1271
|
+
),
|
|
1272
|
+
),
|
|
1273
|
+
)
|
|
1274
|
+
if _response.status_code == 401:
|
|
1275
|
+
raise UnauthorizedError(
|
|
1276
|
+
headers=dict(_response.headers),
|
|
1277
|
+
body=typing.cast(
|
|
1278
|
+
typing.Optional[typing.Any],
|
|
1279
|
+
parse_obj_as(
|
|
1280
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1281
|
+
object_=_response.json(),
|
|
1282
|
+
),
|
|
1283
|
+
),
|
|
1284
|
+
)
|
|
1285
|
+
if _response.status_code == 404:
|
|
1286
|
+
raise NotFoundError(
|
|
398
1287
|
headers=dict(_response.headers),
|
|
399
1288
|
body=typing.cast(
|
|
400
1289
|
typing.Optional[typing.Any],
|
|
@@ -420,58 +1309,190 @@ class AsyncRawConstrueClient:
|
|
|
420
1309
|
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
421
1310
|
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
422
1311
|
|
|
423
|
-
async def
|
|
1312
|
+
async def semantic_search_embedding_based(
|
|
424
1313
|
self,
|
|
1314
|
+
codesystem: str,
|
|
425
1315
|
*,
|
|
426
1316
|
text: str,
|
|
427
|
-
|
|
428
|
-
|
|
1317
|
+
version: typing.Optional[str] = None,
|
|
1318
|
+
limit: typing.Optional[int] = None,
|
|
429
1319
|
request_options: typing.Optional[RequestOptions] = None,
|
|
430
|
-
) -> AsyncHttpResponse[
|
|
1320
|
+
) -> AsyncHttpResponse[SemanticSearchResponse]:
|
|
431
1321
|
"""
|
|
432
|
-
|
|
1322
|
+
Performs semantic similarity search using vector embeddings.
|
|
1323
|
+
|
|
1324
|
+
**When to use**: Best for natural language queries where you want to find conceptually
|
|
1325
|
+
related codes, even when different terminology is used. The search understands meaning,
|
|
1326
|
+
not just keywords.
|
|
1327
|
+
|
|
1328
|
+
**Examples**:
|
|
1329
|
+
- Query "trouble breathing at night" finds codes like "Sleep apnea", "Orthopnea",
|
|
1330
|
+
"Nocturnal dyspnea" — semantically related but no exact keyword matches
|
|
1331
|
+
- Query "heart problems" finds "Myocardial infarction", "Cardiac arrest", "Arrhythmia"
|
|
1332
|
+
|
|
1333
|
+
**Trade-offs**: Slower than text search (requires embedding generation), but finds
|
|
1334
|
+
conceptually similar results that keyword search would miss.
|
|
1335
|
+
|
|
1336
|
+
See also: `/search/text` for faster keyword-based lookup with typo tolerance.
|
|
433
1337
|
|
|
434
1338
|
Parameters
|
|
435
1339
|
----------
|
|
1340
|
+
codesystem : str
|
|
1341
|
+
Code system name
|
|
1342
|
+
|
|
436
1343
|
text : str
|
|
437
|
-
Natural language text to
|
|
1344
|
+
Natural language text to find semantically similar codes for
|
|
438
1345
|
|
|
439
|
-
|
|
1346
|
+
version : typing.Optional[str]
|
|
1347
|
+
Specific version of the code system
|
|
440
1348
|
|
|
441
|
-
|
|
1349
|
+
limit : typing.Optional[int]
|
|
1350
|
+
Maximum number of results (default 10, max 50)
|
|
442
1351
|
|
|
443
1352
|
request_options : typing.Optional[RequestOptions]
|
|
444
1353
|
Request-specific configuration.
|
|
445
1354
|
|
|
446
1355
|
Returns
|
|
447
1356
|
-------
|
|
448
|
-
AsyncHttpResponse[
|
|
449
|
-
|
|
1357
|
+
AsyncHttpResponse[SemanticSearchResponse]
|
|
1358
|
+
Semantic search results ordered by similarity
|
|
450
1359
|
"""
|
|
451
1360
|
_response = await self._client_wrapper.httpx_client.request(
|
|
452
|
-
"construe/
|
|
453
|
-
method="
|
|
454
|
-
|
|
1361
|
+
f"construe/codes/{jsonable_encoder(codesystem)}/search/semantic",
|
|
1362
|
+
method="GET",
|
|
1363
|
+
params={
|
|
455
1364
|
"text": text,
|
|
456
|
-
"
|
|
457
|
-
|
|
458
|
-
),
|
|
459
|
-
"config": convert_and_respect_annotation_metadata(
|
|
460
|
-
object_=config, annotation=ExtractRequestConfig, direction="write"
|
|
461
|
-
),
|
|
1365
|
+
"version": version,
|
|
1366
|
+
"limit": limit,
|
|
462
1367
|
},
|
|
463
|
-
|
|
464
|
-
|
|
1368
|
+
request_options=request_options,
|
|
1369
|
+
)
|
|
1370
|
+
try:
|
|
1371
|
+
if 200 <= _response.status_code < 300:
|
|
1372
|
+
_data = typing.cast(
|
|
1373
|
+
SemanticSearchResponse,
|
|
1374
|
+
parse_obj_as(
|
|
1375
|
+
type_=SemanticSearchResponse, # type: ignore
|
|
1376
|
+
object_=_response.json(),
|
|
1377
|
+
),
|
|
1378
|
+
)
|
|
1379
|
+
return AsyncHttpResponse(response=_response, data=_data)
|
|
1380
|
+
if _response.status_code == 400:
|
|
1381
|
+
raise BadRequestError(
|
|
1382
|
+
headers=dict(_response.headers),
|
|
1383
|
+
body=typing.cast(
|
|
1384
|
+
typing.Optional[typing.Any],
|
|
1385
|
+
parse_obj_as(
|
|
1386
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1387
|
+
object_=_response.json(),
|
|
1388
|
+
),
|
|
1389
|
+
),
|
|
1390
|
+
)
|
|
1391
|
+
if _response.status_code == 401:
|
|
1392
|
+
raise UnauthorizedError(
|
|
1393
|
+
headers=dict(_response.headers),
|
|
1394
|
+
body=typing.cast(
|
|
1395
|
+
typing.Optional[typing.Any],
|
|
1396
|
+
parse_obj_as(
|
|
1397
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1398
|
+
object_=_response.json(),
|
|
1399
|
+
),
|
|
1400
|
+
),
|
|
1401
|
+
)
|
|
1402
|
+
if _response.status_code == 404:
|
|
1403
|
+
raise NotFoundError(
|
|
1404
|
+
headers=dict(_response.headers),
|
|
1405
|
+
body=typing.cast(
|
|
1406
|
+
typing.Optional[typing.Any],
|
|
1407
|
+
parse_obj_as(
|
|
1408
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1409
|
+
object_=_response.json(),
|
|
1410
|
+
),
|
|
1411
|
+
),
|
|
1412
|
+
)
|
|
1413
|
+
if _response.status_code == 500:
|
|
1414
|
+
raise InternalServerError(
|
|
1415
|
+
headers=dict(_response.headers),
|
|
1416
|
+
body=typing.cast(
|
|
1417
|
+
typing.Optional[typing.Any],
|
|
1418
|
+
parse_obj_as(
|
|
1419
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1420
|
+
object_=_response.json(),
|
|
1421
|
+
),
|
|
1422
|
+
),
|
|
1423
|
+
)
|
|
1424
|
+
_response_json = _response.json()
|
|
1425
|
+
except JSONDecodeError:
|
|
1426
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
|
1427
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
|
1428
|
+
|
|
1429
|
+
async def text_search_keyword_based(
|
|
1430
|
+
self,
|
|
1431
|
+
codesystem: str,
|
|
1432
|
+
*,
|
|
1433
|
+
q: str,
|
|
1434
|
+
version: typing.Optional[str] = None,
|
|
1435
|
+
limit: typing.Optional[int] = None,
|
|
1436
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
1437
|
+
) -> AsyncHttpResponse[TextSearchResponse]:
|
|
1438
|
+
"""
|
|
1439
|
+
Performs fast full-text search over code IDs and descriptions.
|
|
1440
|
+
|
|
1441
|
+
**When to use**: Best for autocomplete UIs, code lookup, or when users know part of
|
|
1442
|
+
the code ID or specific keywords. Fast response times suitable for typeahead interfaces.
|
|
1443
|
+
|
|
1444
|
+
**Features**:
|
|
1445
|
+
- Substring matching on code IDs (e.g., "11.65" finds "E11.65")
|
|
1446
|
+
- Typo tolerance on descriptions (not on code IDs)
|
|
1447
|
+
- Fast response times (~10-50ms)
|
|
1448
|
+
|
|
1449
|
+
**Examples**:
|
|
1450
|
+
- Query "E11" finds all codes starting with E11 (diabetes codes)
|
|
1451
|
+
- Query "diabtes" (typo) still finds "diabetes" codes
|
|
1452
|
+
|
|
1453
|
+
**Trade-offs**: Faster than semantic search, but only matches keywords/substrings.
|
|
1454
|
+
Won't find conceptually related codes with different terminology.
|
|
1455
|
+
|
|
1456
|
+
See also: `/search/semantic` for finding conceptually similar codes.
|
|
1457
|
+
|
|
1458
|
+
Parameters
|
|
1459
|
+
----------
|
|
1460
|
+
codesystem : str
|
|
1461
|
+
Code system name
|
|
1462
|
+
|
|
1463
|
+
q : str
|
|
1464
|
+
Search query (searches code IDs and descriptions)
|
|
1465
|
+
|
|
1466
|
+
version : typing.Optional[str]
|
|
1467
|
+
Specific version of the code system
|
|
1468
|
+
|
|
1469
|
+
limit : typing.Optional[int]
|
|
1470
|
+
Maximum number of results (default 20, max 100)
|
|
1471
|
+
|
|
1472
|
+
request_options : typing.Optional[RequestOptions]
|
|
1473
|
+
Request-specific configuration.
|
|
1474
|
+
|
|
1475
|
+
Returns
|
|
1476
|
+
-------
|
|
1477
|
+
AsyncHttpResponse[TextSearchResponse]
|
|
1478
|
+
Text search results
|
|
1479
|
+
"""
|
|
1480
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
1481
|
+
f"construe/codes/{jsonable_encoder(codesystem)}/search/text",
|
|
1482
|
+
method="GET",
|
|
1483
|
+
params={
|
|
1484
|
+
"q": q,
|
|
1485
|
+
"version": version,
|
|
1486
|
+
"limit": limit,
|
|
465
1487
|
},
|
|
466
1488
|
request_options=request_options,
|
|
467
|
-
omit=OMIT,
|
|
468
1489
|
)
|
|
469
1490
|
try:
|
|
470
1491
|
if 200 <= _response.status_code < 300:
|
|
471
1492
|
_data = typing.cast(
|
|
472
|
-
|
|
1493
|
+
TextSearchResponse,
|
|
473
1494
|
parse_obj_as(
|
|
474
|
-
type_=
|
|
1495
|
+
type_=TextSearchResponse, # type: ignore
|
|
475
1496
|
object_=_response.json(),
|
|
476
1497
|
),
|
|
477
1498
|
)
|
|
@@ -498,8 +1519,8 @@ class AsyncRawConstrueClient:
|
|
|
498
1519
|
),
|
|
499
1520
|
),
|
|
500
1521
|
)
|
|
501
|
-
if _response.status_code ==
|
|
502
|
-
raise
|
|
1522
|
+
if _response.status_code == 404:
|
|
1523
|
+
raise NotFoundError(
|
|
503
1524
|
headers=dict(_response.headers),
|
|
504
1525
|
body=typing.cast(
|
|
505
1526
|
typing.Optional[typing.Any],
|
|
@@ -520,6 +1541,28 @@ class AsyncRawConstrueClient:
|
|
|
520
1541
|
),
|
|
521
1542
|
),
|
|
522
1543
|
)
|
|
1544
|
+
if _response.status_code == 501:
|
|
1545
|
+
raise NotImplementedError(
|
|
1546
|
+
headers=dict(_response.headers),
|
|
1547
|
+
body=typing.cast(
|
|
1548
|
+
typing.Optional[typing.Any],
|
|
1549
|
+
parse_obj_as(
|
|
1550
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1551
|
+
object_=_response.json(),
|
|
1552
|
+
),
|
|
1553
|
+
),
|
|
1554
|
+
)
|
|
1555
|
+
if _response.status_code == 503:
|
|
1556
|
+
raise ServiceUnavailableError(
|
|
1557
|
+
headers=dict(_response.headers),
|
|
1558
|
+
body=typing.cast(
|
|
1559
|
+
typing.Optional[typing.Any],
|
|
1560
|
+
parse_obj_as(
|
|
1561
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
1562
|
+
object_=_response.json(),
|
|
1563
|
+
),
|
|
1564
|
+
),
|
|
1565
|
+
)
|
|
523
1566
|
_response_json = _response.json()
|
|
524
1567
|
except JSONDecodeError:
|
|
525
1568
|
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|