diff --git a/.fern/metadata.json b/.fern/metadata.json index 69b204f..4dfb574 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -1,5 +1,5 @@ { - "cliVersion": "5.50.4", + "cliVersion": "5.58.0", "generatorName": "fernapi/fern-python-sdk", "generatorVersion": "5.14.13", "generatorConfig": { @@ -8,10 +8,10 @@ "enabled": true } }, - "originGitCommit": "e2c477c4583f8f9e7d0d1a5b5591c1aa8cabef10", + "originGitCommit": "5275e24c43b267315ba69ed879018e66367384c7", "originGitCommitIsDirty": true, "invokedBy": "ci", "requestedVersion": "AUTO", "ciProvider": "unknown", - "sdkVersion": "16.4.0" + "sdkVersion": "16.5.0" } \ No newline at end of file diff --git a/.fern/replay.lock b/.fern/replay.lock index ae7ed39..e9ac0bc 100644 --- a/.fern/replay.lock +++ b/.fern/replay.lock @@ -60,7 +60,13 @@ generations: cli_version: unknown generator_versions: fernapi/fern-python-sdk: 5.14.13 -current_generation: e0932f75557c87fc1914f6c54c5917b59231d3a1 + - commit_sha: ffeab989db2f60074e6a9729138a22838004244a + tree_hash: 10bd3d11c71be90c70bf190795dad68e68a9d7d7 + timestamp: 2026-06-30T15:41:39.002Z + cli_version: unknown + generator_versions: + fernapi/fern-python-sdk: 5.14.13 +current_generation: ffeab989db2f60074e6a9729138a22838004244a patches: - id: patch-6516695e content_hash: sha256:d2b3264c983a6bb7ce6db1b48d80d28aa93b1f5c838f654cd489a6e8569bee20 @@ -197,3 +203,4 @@ patches: [tool.poetry.extras] aiohttp=["aiohttp", "httpx-aiohttp"] + status: unresolved diff --git a/changelog.md b/changelog.md index dfb6bc0..c9a1ce5 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,11 @@ +## [16.5.0] - 2026-06-30 +### Added +- **`CareSiteRow`, `DeathRow`, `LocationRow`, `ObservationPeriodRow`, `ProviderRow`** — five new OMOP CDM v5.4 row types exported from `phenoml.fhir2omop`, covering care sites, deaths, locations, observation periods, and providers. +- **`OmopTables.location`, `.care_site`, `.provider`, `.death`, `.observation_period`** — new optional list fields on `OmopTables` populated when the corresponding OMOP tables are produced by the FHIR-to-OMOP conversion. +- **`provider_id` field** — added as an optional field to `ConditionOccurrenceRow`, `DrugExposureRow`, `MeasurementRow`, `ObservationRow`, `ProcedureOccurrenceRow`, and `VisitOccurrenceRow` to link clinical events to their ordering provider. +- **`PersonRow.location_id` and `VisitOccurrenceRow.care_site_id`** — new optional linkage fields connecting persons to their location and visits to their care site. +- **`CreateMultiResponseResourcesItem.source_pages`** — new optional `List[int]` field containing 1-indexed page numbers indicating which source document pages a FHIR resource was extracted from (populated by `/lang2fhir/document/multi` only). + ## [16.4.0] - 2026-06-23 ### Added - **`client.voice.voice.transcribe(...)`** — new sync and async method that accepts raw audio bytes (WAV, FLAC, MP3, OGG/WebM Opus) and returns a `TranscribeResponse` with the full transcript, supporting up to ~5 minutes of audio per request. diff --git a/code-examples.json b/code-examples.json index a84c5de..5159d1c 100644 --- a/code-examples.json +++ b/code-examples.json @@ -2,8 +2,8 @@ "metadata": { "language": "python", "packageName": "phenoml", - "sdkVersion": "16.4.0", - "specCommit": "e2c477c4583f8f9e7d0d1a5b5591c1aa8cabef10", + "sdkVersion": "16.5.0", + "specCommit": "5275e24c43b267315ba69ed879018e66367384c7", "generatorName": "fernapi/fern-python-sdk" }, "renderRules": { @@ -2999,19 +2999,28 @@ "tempId": "urn:uuid:patient-001", "resourceType": "Patient", "description": "John Doe, born 1979-03-15", - "originalText": "John Doe, DOB 1979-03-15" + "originalText": "John Doe, DOB 1979-03-15", + "sourcePages": [ + 1 + ] }, { "tempId": "urn:uuid:condition-001", "resourceType": "Condition", "description": "Type 2 Diabetes Mellitus diagnosis", - "originalText": "diagnosed with Type 2 Diabetes" + "originalText": "diagnosed with Type 2 Diabetes", + "sourcePages": [ + 1 + ] }, { "tempId": "urn:uuid:medication-001", "resourceType": "MedicationRequest", "description": "Metformin 500mg prescription", - "originalText": "Prescribed Metformin 500mg" + "originalText": "Prescribed Metformin 500mg", + "sourcePages": [ + 2 + ] } ] } diff --git a/poetry.lock b/poetry.lock index 2250508..5c4bc25 100644 --- a/poetry.lock +++ b/poetry.lock @@ -188,14 +188,14 @@ files = [ [[package]] name = "anyio" -version = "4.14.0" +version = "4.14.1" description = "High-level concurrency and networking framework on top of asyncio or Trio" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "anyio-4.14.0-py3-none-any.whl", hash = "sha256:dd9b7a2a9799ed6552fde617b2c5df02b7fdd7d88392fc48101e51bae46164d9"}, - {file = "anyio-4.14.0.tar.gz", hash = "sha256:b47c1f9ccf73e67021df785332508f99379c68fa7d0684e8e3492cb1d4b23f89"}, + {file = "anyio-4.14.1-py3-none-any.whl", hash = "sha256:4e5533c5b8ff0a24f5d7a176cbe6877129cd183893f66b537f8f227d10527d72"}, + {file = "anyio-4.14.1.tar.gz", hash = "sha256:8d648a3544c1a700e3ff78615cd679e4c5c3f149904287e73687b2596963629e"}, ] [package.dependencies] diff --git a/pyproject.toml b/pyproject.toml index 6c649b6..7204936 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ dynamic = ["version"] [tool.poetry] name = "phenoml" -version = "16.4.0" +version = "16.5.0" description = "" readme = "README.md" authors = [] diff --git a/src/phenoml/core/client_wrapper.py b/src/phenoml/core/client_wrapper.py index 536cb52..eb404b1 100644 --- a/src/phenoml/core/client_wrapper.py +++ b/src/phenoml/core/client_wrapper.py @@ -29,12 +29,12 @@ def get_headers(self) -> typing.Dict[str, str]: import platform headers: typing.Dict[str, str] = { - "User-Agent": "phenoml/16.4.0", + "User-Agent": "phenoml/16.5.0", "X-Fern-Language": "Python", "X-Fern-Runtime": f"python/{platform.python_version()}", "X-Fern-Platform": f"{platform.system().lower()}/{platform.release()}", "X-Fern-SDK-Name": "phenoml", - "X-Fern-SDK-Version": "16.4.0", + "X-Fern-SDK-Version": "16.5.0", **(self.get_custom_headers() or {}), } token = self._get_token() diff --git a/src/phenoml/fhir2omop/__init__.py b/src/phenoml/fhir2omop/__init__.py index fa39886..8906ff1 100644 --- a/src/phenoml/fhir2omop/__init__.py +++ b/src/phenoml/fhir2omop/__init__.py @@ -7,33 +7,43 @@ if typing.TYPE_CHECKING: from .types import ( + CareSiteRow, ConditionOccurrenceRow, CreateOmopResponse, + DeathRow, DroppedResource, DrugExposureRow, + LocationRow, MappingEntry, MeasurementRow, + ObservationPeriodRow, ObservationRow, OmopTables, PersonRow, ProcedureOccurrenceRow, + ProviderRow, Summary, VisitOccurrenceRow, ) from .errors import BadRequestError, InternalServerError, ServiceUnavailableError, UnauthorizedError _dynamic_imports: typing.Dict[str, str] = { "BadRequestError": ".errors", + "CareSiteRow": ".types", "ConditionOccurrenceRow": ".types", "CreateOmopResponse": ".types", + "DeathRow": ".types", "DroppedResource": ".types", "DrugExposureRow": ".types", "InternalServerError": ".errors", + "LocationRow": ".types", "MappingEntry": ".types", "MeasurementRow": ".types", + "ObservationPeriodRow": ".types", "ObservationRow": ".types", "OmopTables": ".types", "PersonRow": ".types", "ProcedureOccurrenceRow": ".types", + "ProviderRow": ".types", "ServiceUnavailableError": ".errors", "Summary": ".types", "UnauthorizedError": ".errors", @@ -64,17 +74,22 @@ def __dir__(): __all__ = [ "BadRequestError", + "CareSiteRow", "ConditionOccurrenceRow", "CreateOmopResponse", + "DeathRow", "DroppedResource", "DrugExposureRow", "InternalServerError", + "LocationRow", "MappingEntry", "MeasurementRow", + "ObservationPeriodRow", "ObservationRow", "OmopTables", "PersonRow", "ProcedureOccurrenceRow", + "ProviderRow", "ServiceUnavailableError", "Summary", "UnauthorizedError", diff --git a/src/phenoml/fhir2omop/types/__init__.py b/src/phenoml/fhir2omop/types/__init__.py index 693397b..669a67a 100644 --- a/src/phenoml/fhir2omop/types/__init__.py +++ b/src/phenoml/fhir2omop/types/__init__.py @@ -6,29 +6,39 @@ from importlib import import_module if typing.TYPE_CHECKING: + from .care_site_row import CareSiteRow from .condition_occurrence_row import ConditionOccurrenceRow from .create_omop_response import CreateOmopResponse + from .death_row import DeathRow from .dropped_resource import DroppedResource from .drug_exposure_row import DrugExposureRow + from .location_row import LocationRow from .mapping_entry import MappingEntry from .measurement_row import MeasurementRow + from .observation_period_row import ObservationPeriodRow from .observation_row import ObservationRow from .omop_tables import OmopTables from .person_row import PersonRow from .procedure_occurrence_row import ProcedureOccurrenceRow + from .provider_row import ProviderRow from .summary import Summary from .visit_occurrence_row import VisitOccurrenceRow _dynamic_imports: typing.Dict[str, str] = { + "CareSiteRow": ".care_site_row", "ConditionOccurrenceRow": ".condition_occurrence_row", "CreateOmopResponse": ".create_omop_response", + "DeathRow": ".death_row", "DroppedResource": ".dropped_resource", "DrugExposureRow": ".drug_exposure_row", + "LocationRow": ".location_row", "MappingEntry": ".mapping_entry", "MeasurementRow": ".measurement_row", + "ObservationPeriodRow": ".observation_period_row", "ObservationRow": ".observation_row", "OmopTables": ".omop_tables", "PersonRow": ".person_row", "ProcedureOccurrenceRow": ".procedure_occurrence_row", + "ProviderRow": ".provider_row", "Summary": ".summary", "VisitOccurrenceRow": ".visit_occurrence_row", } @@ -56,16 +66,21 @@ def __dir__(): __all__ = [ + "CareSiteRow", "ConditionOccurrenceRow", "CreateOmopResponse", + "DeathRow", "DroppedResource", "DrugExposureRow", + "LocationRow", "MappingEntry", "MeasurementRow", + "ObservationPeriodRow", "ObservationRow", "OmopTables", "PersonRow", "ProcedureOccurrenceRow", + "ProviderRow", "Summary", "VisitOccurrenceRow", ] diff --git a/src/phenoml/fhir2omop/types/care_site_row.py b/src/phenoml/fhir2omop/types/care_site_row.py new file mode 100644 index 0000000..e60c4d2 --- /dev/null +++ b/src/phenoml/fhir2omop/types/care_site_row.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class CareSiteRow(UniversalBaseModel): + care_site_id: typing.Optional[int] = None + care_site_name: typing.Optional[str] = None + place_of_service_concept_id: typing.Optional[int] = None + location_id: typing.Optional[int] = None + care_site_source_value: typing.Optional[str] = None + place_of_service_source_value: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/phenoml/fhir2omop/types/condition_occurrence_row.py b/src/phenoml/fhir2omop/types/condition_occurrence_row.py index 22edfe9..0e7d829 100644 --- a/src/phenoml/fhir2omop/types/condition_occurrence_row.py +++ b/src/phenoml/fhir2omop/types/condition_occurrence_row.py @@ -15,6 +15,7 @@ class ConditionOccurrenceRow(UniversalBaseModel): condition_end_date: typing.Optional[str] = None condition_type_concept_id: typing.Optional[int] = None visit_occurrence_id: typing.Optional[int] = None + provider_id: typing.Optional[int] = None condition_source_value: typing.Optional[str] = None condition_source_concept_id: typing.Optional[int] = None condition_status_source_value: typing.Optional[str] = None diff --git a/src/phenoml/fhir2omop/types/death_row.py b/src/phenoml/fhir2omop/types/death_row.py new file mode 100644 index 0000000..0afd6ce --- /dev/null +++ b/src/phenoml/fhir2omop/types/death_row.py @@ -0,0 +1,25 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class DeathRow(UniversalBaseModel): + person_id: typing.Optional[int] = None + death_date: typing.Optional[str] = None + death_datetime: typing.Optional[str] = None + death_type_concept_id: typing.Optional[int] = None + cause_concept_id: typing.Optional[int] = None + cause_source_value: typing.Optional[str] = None + cause_source_concept_id: typing.Optional[int] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/phenoml/fhir2omop/types/drug_exposure_row.py b/src/phenoml/fhir2omop/types/drug_exposure_row.py index 69ea538..48803cb 100644 --- a/src/phenoml/fhir2omop/types/drug_exposure_row.py +++ b/src/phenoml/fhir2omop/types/drug_exposure_row.py @@ -17,6 +17,7 @@ class DrugExposureRow(UniversalBaseModel): stop_reason: typing.Optional[str] = None sig: typing.Optional[str] = None visit_occurrence_id: typing.Optional[int] = None + provider_id: typing.Optional[int] = None drug_source_value: typing.Optional[str] = None drug_source_concept_id: typing.Optional[int] = None diff --git a/src/phenoml/fhir2omop/types/location_row.py b/src/phenoml/fhir2omop/types/location_row.py new file mode 100644 index 0000000..395a274 --- /dev/null +++ b/src/phenoml/fhir2omop/types/location_row.py @@ -0,0 +1,36 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class LocationRow(UniversalBaseModel): + location_id: typing.Optional[int] = None + address1: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="address_1"), pydantic.Field(alias="address_1") + ] = None + address2: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="address_2"), pydantic.Field(alias="address_2") + ] = None + city: typing.Optional[str] = None + state: typing.Optional[str] = None + zip: typing.Optional[str] = None + county: typing.Optional[str] = None + location_source_value: typing.Optional[str] = None + country_concept_id: typing.Optional[int] = None + country_source_value: typing.Optional[str] = None + latitude: typing.Optional[float] = None + longitude: typing.Optional[float] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/phenoml/fhir2omop/types/measurement_row.py b/src/phenoml/fhir2omop/types/measurement_row.py index d48243d..169fc17 100644 --- a/src/phenoml/fhir2omop/types/measurement_row.py +++ b/src/phenoml/fhir2omop/types/measurement_row.py @@ -24,6 +24,7 @@ class MeasurementRow(UniversalBaseModel): range_low: typing.Optional[float] = None range_high: typing.Optional[float] = None visit_occurrence_id: typing.Optional[int] = None + provider_id: typing.Optional[int] = None measurement_source_value: typing.Optional[str] = None measurement_source_concept_id: typing.Optional[int] = None unit_source_value: typing.Optional[str] = None diff --git a/src/phenoml/fhir2omop/types/observation_period_row.py b/src/phenoml/fhir2omop/types/observation_period_row.py new file mode 100644 index 0000000..8dc956f --- /dev/null +++ b/src/phenoml/fhir2omop/types/observation_period_row.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ObservationPeriodRow(UniversalBaseModel): + observation_period_id: typing.Optional[int] = None + person_id: typing.Optional[int] = None + observation_period_start_date: typing.Optional[str] = None + observation_period_end_date: typing.Optional[str] = None + period_type_concept_id: typing.Optional[int] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/phenoml/fhir2omop/types/observation_row.py b/src/phenoml/fhir2omop/types/observation_row.py index 43df628..8a1732f 100644 --- a/src/phenoml/fhir2omop/types/observation_row.py +++ b/src/phenoml/fhir2omop/types/observation_row.py @@ -18,6 +18,7 @@ class ObservationRow(UniversalBaseModel): value_as_concept_id: typing.Optional[int] = None unit_concept_id: typing.Optional[int] = None visit_occurrence_id: typing.Optional[int] = None + provider_id: typing.Optional[int] = None observation_source_value: typing.Optional[str] = None observation_source_concept_id: typing.Optional[int] = None unit_source_value: typing.Optional[str] = None diff --git a/src/phenoml/fhir2omop/types/omop_tables.py b/src/phenoml/fhir2omop/types/omop_tables.py index 906c038..10f0cba 100644 --- a/src/phenoml/fhir2omop/types/omop_tables.py +++ b/src/phenoml/fhir2omop/types/omop_tables.py @@ -4,12 +4,17 @@ import pydantic from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .care_site_row import CareSiteRow from .condition_occurrence_row import ConditionOccurrenceRow +from .death_row import DeathRow from .drug_exposure_row import DrugExposureRow +from .location_row import LocationRow from .measurement_row import MeasurementRow +from .observation_period_row import ObservationPeriodRow from .observation_row import ObservationRow from .person_row import PersonRow from .procedure_occurrence_row import ProcedureOccurrenceRow +from .provider_row import ProviderRow from .visit_occurrence_row import VisitOccurrenceRow @@ -18,7 +23,12 @@ class OmopTables(UniversalBaseModel): OMOP CDM v5.4 rows grouped by destination table. """ + location: typing.Optional[typing.List[LocationRow]] = None + care_site: typing.Optional[typing.List[CareSiteRow]] = None + provider: typing.Optional[typing.List[ProviderRow]] = None person: typing.Optional[typing.List[PersonRow]] = None + death: typing.Optional[typing.List[DeathRow]] = None + observation_period: typing.Optional[typing.List[ObservationPeriodRow]] = None visit_occurrence: typing.Optional[typing.List[VisitOccurrenceRow]] = None condition_occurrence: typing.Optional[typing.List[ConditionOccurrenceRow]] = None drug_exposure: typing.Optional[typing.List[DrugExposureRow]] = None diff --git a/src/phenoml/fhir2omop/types/person_row.py b/src/phenoml/fhir2omop/types/person_row.py index 2ed1a8f..39c31ee 100644 --- a/src/phenoml/fhir2omop/types/person_row.py +++ b/src/phenoml/fhir2omop/types/person_row.py @@ -15,6 +15,7 @@ class PersonRow(UniversalBaseModel): birth_datetime: typing.Optional[str] = None race_concept_id: typing.Optional[int] = None ethnicity_concept_id: typing.Optional[int] = None + location_id: typing.Optional[int] = None person_source_value: typing.Optional[str] = None gender_source_value: typing.Optional[str] = None race_source_value: typing.Optional[str] = None diff --git a/src/phenoml/fhir2omop/types/procedure_occurrence_row.py b/src/phenoml/fhir2omop/types/procedure_occurrence_row.py index 3266117..ace4167 100644 --- a/src/phenoml/fhir2omop/types/procedure_occurrence_row.py +++ b/src/phenoml/fhir2omop/types/procedure_occurrence_row.py @@ -14,6 +14,7 @@ class ProcedureOccurrenceRow(UniversalBaseModel): procedure_datetime: typing.Optional[str] = None procedure_type_concept_id: typing.Optional[int] = None visit_occurrence_id: typing.Optional[int] = None + provider_id: typing.Optional[int] = None procedure_source_value: typing.Optional[str] = None procedure_source_concept_id: typing.Optional[int] = None diff --git a/src/phenoml/fhir2omop/types/provider_row.py b/src/phenoml/fhir2omop/types/provider_row.py new file mode 100644 index 0000000..4ba4745 --- /dev/null +++ b/src/phenoml/fhir2omop/types/provider_row.py @@ -0,0 +1,31 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ProviderRow(UniversalBaseModel): + provider_id: typing.Optional[int] = None + provider_name: typing.Optional[str] = None + npi: typing.Optional[str] = None + dea: typing.Optional[str] = None + specialty_concept_id: typing.Optional[int] = None + care_site_id: typing.Optional[int] = None + year_of_birth: typing.Optional[int] = None + gender_concept_id: typing.Optional[int] = None + provider_source_value: typing.Optional[str] = None + specialty_source_value: typing.Optional[str] = None + specialty_source_concept_id: typing.Optional[int] = None + gender_source_value: typing.Optional[str] = None + gender_source_concept_id: typing.Optional[int] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/phenoml/fhir2omop/types/visit_occurrence_row.py b/src/phenoml/fhir2omop/types/visit_occurrence_row.py index 901160d..c7b6a1a 100644 --- a/src/phenoml/fhir2omop/types/visit_occurrence_row.py +++ b/src/phenoml/fhir2omop/types/visit_occurrence_row.py @@ -15,6 +15,8 @@ class VisitOccurrenceRow(UniversalBaseModel): visit_end_date: typing.Optional[str] = None visit_end_datetime: typing.Optional[str] = None visit_type_concept_id: typing.Optional[int] = None + provider_id: typing.Optional[int] = None + care_site_id: typing.Optional[int] = None visit_source_value: typing.Optional[str] = None if IS_PYDANTIC_V2: diff --git a/src/phenoml/lang2fhir/types/create_multi_response_resources_item.py b/src/phenoml/lang2fhir/types/create_multi_response_resources_item.py index 8a2594b..e7cdcec 100644 --- a/src/phenoml/lang2fhir/types/create_multi_response_resources_item.py +++ b/src/phenoml/lang2fhir/types/create_multi_response_resources_item.py @@ -29,6 +29,14 @@ class CreateMultiResponseResourcesItem(UniversalBaseModel): FieldMetadata(alias="originalText"), pydantic.Field(alias="originalText", description="Verbatim text excerpt from the original clinical document"), ] = None + source_pages: typing_extensions.Annotated[ + typing.Optional[typing.List[int]], + FieldMetadata(alias="sourcePages"), + pydantic.Field( + alias="sourcePages", + description="1-indexed source document page number(s) this resource was extracted from. Populated only by the /lang2fhir/document/multi endpoint; omitted when the source page could not be determined (e.g. raw-text create/multi, or a resource with no verbatim source text).", + ), + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/phenoml/openapi/openapi.json b/src/phenoml/openapi/openapi.json index 979abe8..e20ac06 100644 --- a/src/phenoml/openapi/openapi.json +++ b/src/phenoml/openapi/openapi.json @@ -2,7 +2,7 @@ "openapi": "3.0.3", "info": { "title": "Phenoml API", - "version": "e2c477c4583f8f9e7d0d1a5b5591c1aa8cabef10" + "version": "5275e24c43b267315ba69ed879018e66367384c7" }, "x-services": [ { @@ -4994,19 +4994,28 @@ "tempId": "urn:uuid:patient-001", "resourceType": "Patient", "description": "John Doe, born 1979-03-15", - "originalText": "John Doe, DOB 1979-03-15" + "originalText": "John Doe, DOB 1979-03-15", + "sourcePages": [ + 1 + ] }, { "tempId": "urn:uuid:condition-001", "resourceType": "Condition", "description": "Type 2 Diabetes Mellitus diagnosis", - "originalText": "diagnosed with Type 2 Diabetes" + "originalText": "diagnosed with Type 2 Diabetes", + "sourcePages": [ + 1 + ] }, { "tempId": "urn:uuid:medication-001", "resourceType": "MedicationRequest", "description": "Metformin 500mg prescription", - "originalText": "Prescribed Metformin 500mg" + "originalText": "Prescribed Metformin 500mg", + "sourcePages": [ + 2 + ] } ] } @@ -8674,12 +8683,42 @@ "type": "object", "description": "OMOP CDM v5.4 rows grouped by destination table.", "properties": { + "location": { + "type": "array", + "items": { + "$ref": "#/components/schemas/fhir2omop_LocationRow" + } + }, + "care_site": { + "type": "array", + "items": { + "$ref": "#/components/schemas/fhir2omop_CareSiteRow" + } + }, + "provider": { + "type": "array", + "items": { + "$ref": "#/components/schemas/fhir2omop_ProviderRow" + } + }, "person": { "type": "array", "items": { "$ref": "#/components/schemas/fhir2omop_PersonRow" } }, + "death": { + "type": "array", + "items": { + "$ref": "#/components/schemas/fhir2omop_DeathRow" + } + }, + "observation_period": { + "type": "array", + "items": { + "$ref": "#/components/schemas/fhir2omop_ObservationPeriodRow" + } + }, "visit_occurrence": { "type": "array", "items": { @@ -8718,6 +8757,127 @@ } } }, + "fhir2omop_LocationRow": { + "type": "object", + "properties": { + "location_id": { + "type": "integer", + "format": "int64" + }, + "address_1": { + "type": "string" + }, + "address_2": { + "type": "string" + }, + "city": { + "type": "string" + }, + "state": { + "type": "string" + }, + "zip": { + "type": "string" + }, + "county": { + "type": "string" + }, + "location_source_value": { + "type": "string" + }, + "country_concept_id": { + "type": "integer", + "format": "int64" + }, + "country_source_value": { + "type": "string" + }, + "latitude": { + "type": "number", + "format": "double" + }, + "longitude": { + "type": "number", + "format": "double" + } + } + }, + "fhir2omop_CareSiteRow": { + "type": "object", + "properties": { + "care_site_id": { + "type": "integer", + "format": "int64" + }, + "care_site_name": { + "type": "string" + }, + "place_of_service_concept_id": { + "type": "integer", + "format": "int64" + }, + "location_id": { + "type": "integer", + "format": "int64" + }, + "care_site_source_value": { + "type": "string" + }, + "place_of_service_source_value": { + "type": "string" + } + } + }, + "fhir2omop_ProviderRow": { + "type": "object", + "properties": { + "provider_id": { + "type": "integer", + "format": "int64" + }, + "provider_name": { + "type": "string" + }, + "npi": { + "type": "string" + }, + "dea": { + "type": "string" + }, + "specialty_concept_id": { + "type": "integer", + "format": "int64" + }, + "care_site_id": { + "type": "integer", + "format": "int64" + }, + "year_of_birth": { + "type": "integer" + }, + "gender_concept_id": { + "type": "integer", + "format": "int64" + }, + "provider_source_value": { + "type": "string" + }, + "specialty_source_value": { + "type": "string" + }, + "specialty_source_concept_id": { + "type": "integer", + "format": "int64" + }, + "gender_source_value": { + "type": "string" + }, + "gender_source_concept_id": { + "type": "integer", + "format": "int64" + } + } + }, "fhir2omop_PersonRow": { "type": "object", "properties": { @@ -8749,6 +8909,10 @@ "type": "integer", "format": "int64" }, + "location_id": { + "type": "integer", + "format": "int64" + }, "person_source_value": { "type": "string" }, @@ -8763,6 +8927,59 @@ } } }, + "fhir2omop_DeathRow": { + "type": "object", + "properties": { + "person_id": { + "type": "integer", + "format": "int64" + }, + "death_date": { + "type": "string" + }, + "death_datetime": { + "type": "string" + }, + "death_type_concept_id": { + "type": "integer", + "format": "int64" + }, + "cause_concept_id": { + "type": "integer", + "format": "int64" + }, + "cause_source_value": { + "type": "string" + }, + "cause_source_concept_id": { + "type": "integer", + "format": "int64" + } + } + }, + "fhir2omop_ObservationPeriodRow": { + "type": "object", + "properties": { + "observation_period_id": { + "type": "integer", + "format": "int64" + }, + "person_id": { + "type": "integer", + "format": "int64" + }, + "observation_period_start_date": { + "type": "string" + }, + "observation_period_end_date": { + "type": "string" + }, + "period_type_concept_id": { + "type": "integer", + "format": "int64" + } + } + }, "fhir2omop_VisitOccurrenceRow": { "type": "object", "properties": { @@ -8794,6 +9011,14 @@ "type": "integer", "format": "int64" }, + "provider_id": { + "type": "integer", + "format": "int64" + }, + "care_site_id": { + "type": "integer", + "format": "int64" + }, "visit_source_value": { "type": "string" } @@ -8831,6 +9056,10 @@ "type": "integer", "format": "int64" }, + "provider_id": { + "type": "integer", + "format": "int64" + }, "condition_source_value": { "type": "string" }, @@ -8881,6 +9110,10 @@ "type": "integer", "format": "int64" }, + "provider_id": { + "type": "integer", + "format": "int64" + }, "drug_source_value": { "type": "string" }, @@ -8919,6 +9152,10 @@ "type": "integer", "format": "int64" }, + "provider_id": { + "type": "integer", + "format": "int64" + }, "procedure_source_value": { "type": "string" }, @@ -8982,6 +9219,10 @@ "type": "integer", "format": "int64" }, + "provider_id": { + "type": "integer", + "format": "int64" + }, "measurement_source_value": { "type": "string" }, @@ -9041,6 +9282,10 @@ "type": "integer", "format": "int64" }, + "provider_id": { + "type": "integer", + "format": "int64" + }, "observation_source_value": { "type": "string" }, @@ -10220,6 +10465,16 @@ "type": "string", "description": "Verbatim text excerpt from the original clinical document", "example": "diagnosed with Type 2 Diabetes" + }, + "sourcePages": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "1-indexed source document page number(s) this resource was extracted from. Populated only by the /lang2fhir/document/multi endpoint; omitted when the source page could not be determined (e.g. raw-text create/multi, or a resource with no verbatim source text).\n", + "example": [ + 2 + ] } } } diff --git a/wiremock/wiremock-mappings.json b/wiremock/wiremock-mappings.json index de3b3de..c728123 100644 --- a/wiremock/wiremock-mappings.json +++ b/wiremock/wiremock-mappings.json @@ -1092,7 +1092,7 @@ }, "response": { "status": 200, - "body": "{\n \"success\": true,\n \"message\": \"FHIR resources mapped to OMOP CDM v5.4\",\n \"tables\": {\n \"person\": [\n {\n \"person_id\": 1,\n \"gender_concept_id\": 0,\n \"year_of_birth\": 1985,\n \"month_of_birth\": 7,\n \"day_of_birth\": 22,\n \"birth_datetime\": \"1985-07-22\",\n \"race_concept_id\": 0,\n \"ethnicity_concept_id\": 0,\n \"person_source_value\": \"patient-1\",\n \"gender_source_value\": \"female\"\n }\n ],\n \"visit_occurrence\": [\n {}\n ],\n \"condition_occurrence\": [\n {\n \"condition_occurrence_id\": 1,\n \"person_id\": 1,\n \"condition_concept_id\": 201826,\n \"condition_start_date\": \"2024-01-15\",\n \"condition_start_datetime\": \"2024-01-15\",\n \"condition_type_concept_id\": 32817,\n \"condition_source_value\": \"http://snomed.info/sct#44054006\",\n \"condition_source_concept_id\": 201826\n }\n ],\n \"drug_exposure\": [\n {\n \"drug_exposure_id\": 1,\n \"person_id\": 1,\n \"drug_concept_id\": 40163924,\n \"drug_exposure_start_date\": \"2024-01-16\",\n \"drug_exposure_start_datetime\": \"2024-01-16\",\n \"drug_type_concept_id\": 32817,\n \"drug_source_value\": \"http://www.nlm.nih.gov/research/umls/rxnorm#860975\",\n \"drug_source_concept_id\": 40163924\n }\n ],\n \"procedure_occurrence\": [\n {}\n ],\n \"measurement\": [\n {}\n ],\n \"observation\": [\n {}\n ]\n },\n \"mappings\": [\n {\n \"resource_type\": \"Condition\",\n \"resource_id\": \"condition-1\",\n \"omop_table\": \"condition_occurrence\",\n \"omop_id\": 1,\n \"source_system\": \"http://snomed.info/sct\",\n \"source_code\": \"44054006\",\n \"source_name\": \"Type 2 diabetes mellitus\",\n \"target_vocabulary\": \"SNOMED\",\n \"target_code\": \"44054006\",\n \"target_name\": \"Type 2 diabetes mellitus\",\n \"mapping_status\": \"ALREADY_STANDARD\",\n \"note\": \"note\"\n },\n {\n \"resource_type\": \"MedicationRequest\",\n \"resource_id\": \"medreq-1\",\n \"omop_table\": \"drug_exposure\",\n \"omop_id\": 1,\n \"source_system\": \"http://www.nlm.nih.gov/research/umls/rxnorm\",\n \"source_code\": \"860975\",\n \"source_name\": \"metformin hydrochloride 500 MG\",\n \"target_vocabulary\": \"RXNORM\",\n \"target_code\": \"860975\",\n \"target_name\": \"metformin hydrochloride 500 MG\",\n \"mapping_status\": \"ALREADY_STANDARD\",\n \"note\": \"note\"\n }\n ],\n \"dropped\": [\n {\n \"resource_type\": \"resource_type\",\n \"resource_id\": \"resource_id\",\n \"reason\": \"reason\"\n }\n ],\n \"vocab_version\": \"v20240229\",\n \"summary\": {\n \"codes_already_standard\": 2,\n \"codes_normalized\": 0,\n \"codes_unmapped\": 0,\n \"off_vocab_rate\": 0\n }\n}", + "body": "{\n \"success\": true,\n \"message\": \"FHIR resources mapped to OMOP CDM v5.4\",\n \"tables\": {\n \"location\": [\n {}\n ],\n \"care_site\": [\n {}\n ],\n \"provider\": [\n {}\n ],\n \"person\": [\n {\n \"person_id\": 1,\n \"gender_concept_id\": 0,\n \"year_of_birth\": 1985,\n \"month_of_birth\": 7,\n \"day_of_birth\": 22,\n \"birth_datetime\": \"1985-07-22\",\n \"race_concept_id\": 0,\n \"ethnicity_concept_id\": 0,\n \"person_source_value\": \"patient-1\",\n \"gender_source_value\": \"female\"\n }\n ],\n \"death\": [\n {}\n ],\n \"observation_period\": [\n {}\n ],\n \"visit_occurrence\": [\n {}\n ],\n \"condition_occurrence\": [\n {\n \"condition_occurrence_id\": 1,\n \"person_id\": 1,\n \"condition_concept_id\": 201826,\n \"condition_start_date\": \"2024-01-15\",\n \"condition_start_datetime\": \"2024-01-15\",\n \"condition_type_concept_id\": 32817,\n \"condition_source_value\": \"http://snomed.info/sct#44054006\",\n \"condition_source_concept_id\": 201826\n }\n ],\n \"drug_exposure\": [\n {\n \"drug_exposure_id\": 1,\n \"person_id\": 1,\n \"drug_concept_id\": 40163924,\n \"drug_exposure_start_date\": \"2024-01-16\",\n \"drug_exposure_start_datetime\": \"2024-01-16\",\n \"drug_type_concept_id\": 32817,\n \"drug_source_value\": \"http://www.nlm.nih.gov/research/umls/rxnorm#860975\",\n \"drug_source_concept_id\": 40163924\n }\n ],\n \"procedure_occurrence\": [\n {}\n ],\n \"measurement\": [\n {}\n ],\n \"observation\": [\n {}\n ]\n },\n \"mappings\": [\n {\n \"resource_type\": \"Condition\",\n \"resource_id\": \"condition-1\",\n \"omop_table\": \"condition_occurrence\",\n \"omop_id\": 1,\n \"source_system\": \"http://snomed.info/sct\",\n \"source_code\": \"44054006\",\n \"source_name\": \"Type 2 diabetes mellitus\",\n \"target_vocabulary\": \"SNOMED\",\n \"target_code\": \"44054006\",\n \"target_name\": \"Type 2 diabetes mellitus\",\n \"mapping_status\": \"ALREADY_STANDARD\",\n \"note\": \"note\"\n },\n {\n \"resource_type\": \"MedicationRequest\",\n \"resource_id\": \"medreq-1\",\n \"omop_table\": \"drug_exposure\",\n \"omop_id\": 1,\n \"source_system\": \"http://www.nlm.nih.gov/research/umls/rxnorm\",\n \"source_code\": \"860975\",\n \"source_name\": \"metformin hydrochloride 500 MG\",\n \"target_vocabulary\": \"RXNORM\",\n \"target_code\": \"860975\",\n \"target_name\": \"metformin hydrochloride 500 MG\",\n \"mapping_status\": \"ALREADY_STANDARD\",\n \"note\": \"note\"\n }\n ],\n \"dropped\": [\n {\n \"resource_type\": \"resource_type\",\n \"resource_id\": \"resource_id\",\n \"reason\": \"reason\"\n }\n ],\n \"vocab_version\": \"v20240229\",\n \"summary\": {\n \"codes_already_standard\": 2,\n \"codes_normalized\": 0,\n \"codes_unmapped\": 0,\n \"off_vocab_rate\": 0\n }\n}", "headers": { "Content-Type": "application/json" } @@ -1352,7 +1352,7 @@ }, "response": { "status": 200, - "body": "{\n \"success\": true,\n \"message\": \"Successfully extracted 3 resources\",\n \"bundle\": {\n \"resourceType\": \"Bundle\",\n \"type\": \"transaction\",\n \"entry\": [\n {\n \"fullUrl\": \"urn:uuid:patient-001\",\n \"resource\": {\n \"resourceType\": \"Patient\",\n \"name\": [\n {\n \"given\": [\n \"John\"\n ],\n \"family\": \"Smith\"\n }\n ],\n \"gender\": \"male\"\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Patient\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:condition-001\",\n \"resource\": {\n \"resourceType\": \"Condition\",\n \"code\": {\n \"text\": \"Type 2 Diabetes\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Condition\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:medication-001\",\n \"resource\": {\n \"resourceType\": \"MedicationRequest\",\n \"medicationCodeableConcept\": {\n \"text\": \"Metformin 500mg\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"MedicationRequest\"\n }\n }\n ]\n },\n \"resources\": [\n {\n \"tempId\": \"urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8\",\n \"resourceType\": \"Patient\",\n \"description\": \"John Smith (DOB 1980-05-12) was diagnosed with Type 2 Diabetes during office visit on 2025-03-01 with Dr. Chen\",\n \"originalText\": \"diagnosed with Type 2 Diabetes\"\n }\n ],\n \"validation\": {\n \"passes\": [\n {}\n ],\n \"fixed\": true,\n \"attempts\": 1,\n \"summary\": \"summary\"\n }\n}", + "body": "{\n \"success\": true,\n \"message\": \"Successfully extracted 3 resources\",\n \"bundle\": {\n \"resourceType\": \"Bundle\",\n \"type\": \"transaction\",\n \"entry\": [\n {\n \"fullUrl\": \"urn:uuid:patient-001\",\n \"resource\": {\n \"resourceType\": \"Patient\",\n \"name\": [\n {\n \"given\": [\n \"John\"\n ],\n \"family\": \"Smith\"\n }\n ],\n \"gender\": \"male\"\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Patient\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:condition-001\",\n \"resource\": {\n \"resourceType\": \"Condition\",\n \"code\": {\n \"text\": \"Type 2 Diabetes\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Condition\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:medication-001\",\n \"resource\": {\n \"resourceType\": \"MedicationRequest\",\n \"medicationCodeableConcept\": {\n \"text\": \"Metformin 500mg\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"MedicationRequest\"\n }\n }\n ]\n },\n \"resources\": [\n {\n \"tempId\": \"urn:uuid:a842c4bc-f6cb-4555-9741-ac3aec4ef0b8\",\n \"resourceType\": \"Patient\",\n \"description\": \"John Smith (DOB 1980-05-12) was diagnosed with Type 2 Diabetes during office visit on 2025-03-01 with Dr. Chen\",\n \"originalText\": \"diagnosed with Type 2 Diabetes\",\n \"sourcePages\": [\n 2\n ]\n }\n ],\n \"validation\": {\n \"passes\": [\n {}\n ],\n \"fixed\": true,\n \"attempts\": 1,\n \"summary\": \"summary\"\n }\n}", "headers": { "Content-Type": "application/json" } @@ -1456,7 +1456,7 @@ }, "response": { "status": 200, - "body": "{\n \"success\": true,\n \"message\": \"Successfully extracted 3 resources\",\n \"bundle\": {\n \"resourceType\": \"Bundle\",\n \"type\": \"transaction\",\n \"entry\": [\n {\n \"fullUrl\": \"urn:uuid:patient-001\",\n \"resource\": {\n \"resourceType\": \"Patient\",\n \"name\": [\n {\n \"given\": [\n \"John\"\n ],\n \"family\": \"Doe\"\n }\n ],\n \"gender\": \"male\",\n \"birthDate\": \"1979-03-15\"\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Patient\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:condition-001\",\n \"resource\": {\n \"resourceType\": \"Condition\",\n \"code\": {\n \"text\": \"Type 2 Diabetes Mellitus\"\n },\n \"subject\": {\n \"reference\": \"urn:uuid:patient-001\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Condition\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:medication-001\",\n \"resource\": {\n \"resourceType\": \"MedicationRequest\",\n \"medicationCodeableConcept\": {\n \"text\": \"Metformin 500mg\"\n },\n \"subject\": {\n \"reference\": \"urn:uuid:patient-001\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"MedicationRequest\"\n }\n }\n ]\n },\n \"resources\": [\n {\n \"tempId\": \"urn:uuid:patient-001\",\n \"resourceType\": \"Patient\",\n \"description\": \"John Doe, born 1979-03-15\",\n \"originalText\": \"John Doe, DOB 1979-03-15\"\n },\n {\n \"tempId\": \"urn:uuid:condition-001\",\n \"resourceType\": \"Condition\",\n \"description\": \"Type 2 Diabetes Mellitus diagnosis\",\n \"originalText\": \"diagnosed with Type 2 Diabetes\"\n },\n {\n \"tempId\": \"urn:uuid:medication-001\",\n \"resourceType\": \"MedicationRequest\",\n \"description\": \"Metformin 500mg prescription\",\n \"originalText\": \"Prescribed Metformin 500mg\"\n }\n ],\n \"validation\": {\n \"passes\": [\n {}\n ],\n \"fixed\": true,\n \"attempts\": 1,\n \"summary\": \"summary\"\n },\n \"page_classifications\": [\n {\n \"page_number\": 1,\n \"include\": true,\n \"reason\": \"clinical notes with diagnoses\"\n }\n ]\n}", + "body": "{\n \"success\": true,\n \"message\": \"Successfully extracted 3 resources\",\n \"bundle\": {\n \"resourceType\": \"Bundle\",\n \"type\": \"transaction\",\n \"entry\": [\n {\n \"fullUrl\": \"urn:uuid:patient-001\",\n \"resource\": {\n \"resourceType\": \"Patient\",\n \"name\": [\n {\n \"given\": [\n \"John\"\n ],\n \"family\": \"Doe\"\n }\n ],\n \"gender\": \"male\",\n \"birthDate\": \"1979-03-15\"\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Patient\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:condition-001\",\n \"resource\": {\n \"resourceType\": \"Condition\",\n \"code\": {\n \"text\": \"Type 2 Diabetes Mellitus\"\n },\n \"subject\": {\n \"reference\": \"urn:uuid:patient-001\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"Condition\"\n }\n },\n {\n \"fullUrl\": \"urn:uuid:medication-001\",\n \"resource\": {\n \"resourceType\": \"MedicationRequest\",\n \"medicationCodeableConcept\": {\n \"text\": \"Metformin 500mg\"\n },\n \"subject\": {\n \"reference\": \"urn:uuid:patient-001\"\n }\n },\n \"request\": {\n \"method\": \"POST\",\n \"url\": \"MedicationRequest\"\n }\n }\n ]\n },\n \"resources\": [\n {\n \"tempId\": \"urn:uuid:patient-001\",\n \"resourceType\": \"Patient\",\n \"description\": \"John Doe, born 1979-03-15\",\n \"originalText\": \"John Doe, DOB 1979-03-15\",\n \"sourcePages\": [\n 1\n ]\n },\n {\n \"tempId\": \"urn:uuid:condition-001\",\n \"resourceType\": \"Condition\",\n \"description\": \"Type 2 Diabetes Mellitus diagnosis\",\n \"originalText\": \"diagnosed with Type 2 Diabetes\",\n \"sourcePages\": [\n 1\n ]\n },\n {\n \"tempId\": \"urn:uuid:medication-001\",\n \"resourceType\": \"MedicationRequest\",\n \"description\": \"Metformin 500mg prescription\",\n \"originalText\": \"Prescribed Metformin 500mg\",\n \"sourcePages\": [\n 2\n ]\n }\n ],\n \"validation\": {\n \"passes\": [\n {}\n ],\n \"fixed\": true,\n \"attempts\": 1,\n \"summary\": \"summary\"\n },\n \"page_classifications\": [\n {\n \"page_number\": 1,\n \"include\": true,\n \"reason\": \"clinical notes with diagnoses\"\n }\n ]\n}", "headers": { "Content-Type": "application/json" }