Note |
---|
This specification might evolve based on the development constraints. |
Summary
Claim AI-based Adjudication System
...
The AI input model is represented by a matrix having on each row one Medical Item/Service from a Claim. If the FHIR Claim Bundle contains multiple Claims then the AI input model will contain all Items/Services from all Claims. Each row contains the following informations (either FHIR Medical OR ActivityDefinition, representing an Item in FHIR Claim):
FHIR Medication fields | FHIR ActivityDefinition fields | FHIR Claim fields | FHIR Patient fields | FHIR HealthcareService fields |
---|
identifier (ItemUUID) | identifier (ServiceUUID) | identifier (ClaimUUID) | identifier (InsureeUUID, CHFID) | identifier (HfUUID) |
extension.unitPrice | unitPrice | billablePeriod (start, end) | birthDate (to calculate age) | location (HFLocationUUID) |
frequency | frequency | created | gender | category |
extension.useContext (ItemPatCat) | useContext (ServicePatCat) | type | extension.isHead | type |
type (always “Medication”) | type (always “ActivityDefinition”) | item.quantity | extension.povertyStatus | |
| | item.unitPrice | extension.locationCode (LocationUUID) | |
| | diagnosis.diagnosisReference (for icd_0 get ICDID) | extension.group (FamilyUUID) | |
| | diagnosis.diagnosisReference (for icd_1 get ICDID) | | |
| | enterer (ClaimAdminUUID) | | |
...
Note |
---|
In this project, the generated AI Model is only valid for Nepal openIMIS implementation. Any usage in other context/implementation will give wrong categorization responses. For other context/implementation, the retraining of the AI Model, based on already categorized Claims, is mandatory. |
Several data files are to be loaded and saved during the AI Model execution:
encoded fields data file
scalling file
AI model file
The AI Model file name with full path (or relative path) is configured in the modules configuration key ai_model_file
. Each time the model is executed, the model file is loaded, allowing to change the filename on execution in the configuration (hot-reload).
...
The following module configuration is defined:
Code Block |
---|
|
{
'authentication': [string], // Authentication key list. Default:String
[] ai'claim_modelresponse_fileurl': string'http://localhost:8000/claim_ai/ClaimResponse', // AI Model file name with full path. Default: ./ai_model.pkl
claim_response_organization: stringURL set in the ClaimResponse. String
'ai_model_file': "joblib_Voting_Model.pkl", // Value to build the insurer reference in the ClaimResponse. Default: AI Model file name, relative location to module folder. String
'ai_scaler_file': "scaler.pkl", // AI Scaler file name, relative location to module folder. String
'ai_encoder_file': "Encoder.obj", // AI Encoder file name, relative location to module folder. String
'claim_response_organization': 'openIMIS-Claim-AI
}', // Organisation name in ClaimResponse. String
'date_format': '%Y-%m-%d', // Date format to use. String
'first_date': '2016-01-01' // First date for date transformation. String
}
|
Note |
---|
The default AI Model filename will be defined after finalizing the AI Algorithm development. |
...
FHIR Contained Resources feature allows to integrate the referred resourced. Because AI-model is requiring information from other resources referenced by the Claim, these resources must to be accessible from the Claim sent by Claim-AI Quality module. In case of FHIR Claim, these are Patient, Condition, Medication, HealthcareService, Practitioner, ActivityDefinition. The mechanism to build Claim resource with Contained Resources is developed in the openIMIS FHIR R4 module. In FHIR R4 module, the inclusion of Contained Resources should be possible based on the query variable contained=true/false
(default false
).
...
Plantumlcloud |
---|
filename | ClaimStatusStateDiagram.png |
---|
data | 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 |
---|
width | |
---|
compressed | true |
---|
revision | 1014 |
---|
|
Expand |
---|
|
Code Block |
---|
@startuml
state "Enter Claim" as ClaimEntering {
[*] --> Entered : Enter Claim
Entered --> Entered : Edit\nClaim
Entered : ClaimStatus=Entered (2)
Entered : ReviewStatus=Idle (1)
Entered : ClaimItemStatus=Accepted (1)
Entered : RejectionReason=Accepted (0)
}
state "Rule Engine Checking" as RuleEngineCheck {
state RuleEngineValidation <<choice>>
Entered --> RuleEngineValidation : Submit Claim
RuleEngineValidation --> RejectedByRuleEngine : Reject\nAll Items
RejectedByRuleEngine : ClaimStatus=Rejected (1)
RejectedByRuleEngine : ClaimItemStatus=Rejected (2)
RejectedByRuleEngine : RejectionReason=[1-19]
RejectedByRuleEngine : json_ext.claim_ai_quality.was_categorized=false
RejectedByRuleEngine : json_ext.claim_ai_quality.request_time=ValidityFrom
RejectedByRuleEngine : json_ext.claim_ai_quality.response_time=ValidityFrom
RejectedByRuleEngine : json_ext.claim_ai_quality.ai_result=Rejected (2)
RejectedByRuleEngine --> [*]
RuleEngineValidation --> CheckedIdle : Accept \n Some Items
CheckedIdle : ClaimStatus=Checked (4)
CheckedIdle : json_ext.claim_ai_quality.was_categorized=false
'}
note top
of CheckedIdle : If AI modules not activated \nthen ClaimStatus=Checked (4)
}
state "AI Automatic Categorisation" as AICheck {
state AIClaimCategorisation <<choice>>
CheckedIdle --> AIClaimCategorisation
AIClaimCategorisation --> CheckedAIAccepted : Accept\nAll Items
CheckedAIAccepted : json_ext.claim_ai_quality.was_categorized=true
CheckedAIAccepted : json_ext.claim_ai_quality.ai_result=Accepted (1)
AIClaimCategorisation --> CheckedAIFlagged : Reject\nSome Items
CheckedAIFlagged : ReviewStatus=SelectedForReview (4)
CheckedAIFlagged : ClaimItemStatus=Rejected (2)
CheckedAIFlagged : RejectionReason=Rejected by AI (-2)
CheckedAIFlagged : json_ext.claim_ai_quality.was_categorized=true
CheckedAIFlagged : json_ext.claim_ai_quality.ai_result=Rejected (2)
note top of CheckedAIFlagged : Rejected Items values
}
state "Manual Review" as ManualReview {
state SelectForReview <<choice>>
CheckedAIAccepted --> SelectForReview
SelectForReview --> CheckedNotSelected : Select manually\nnot to review
CheckedNotSelected : ReviewStatus=Not Selected (2)
CheckedNotSelected : RejectionReason=Accepted (0)
SelectForReview --> CheckedSelected : Select manually\nto review
CheckedSelected : ReviewStatus=Selected (4)
CheckedSelected : RejectionReason=Accepted (0)
state RequireManualReview <<choice>>
CheckedSelected --> RequireManualReview
CheckedAIFlagged --> RequireManualReview : Selected automatically\nfor review
RequireManualReview --> CheckedRejected : Manual Review\nReject All Items
CheckedRejected: ClaimStatus=Rejected (1)
CheckedRejected: ClaimItemStatus=Rejected (2)
CheckedRejected : RejectionReason=Rejected by MO (-1)
CheckedRejected --> [*]
RequireManualReview --> CheckedAccepted : Manual Review\nAccept Some Items
CheckedAccepted : ClaimItemStatus=Accepted (1)
CheckedAccepted : RejectionReason=Accepted (0)
CheckedAccepted --> CheckedReviewed : Deliver review
CheckedReviewed : ReviewStatus=Reviewed (8)
}
state "Processing" as Process {
CheckedReviewed --> ValuatedAccepted : Process
ValuatedAccepted : ClaimStatus=Valuated (16)
CheckedNotSelected --> ValuatedAccepted : Process
CheckedAccepted --> ValuatedBypassed : Process \nwithout \ndelivering \nreview
ValuatedBypassed : ClaimStatus=Valuated (16)
ValuatedBypassed : ReviewStatus=Bypassed (16)
ValuatedBypassed --> [*]
ValuatedAccepted --> [*]
}
@enduml |
|
...
Expand |
---|
|
@startuml class Claim as "openimis.claim.models.Claim" { id: models.AutoField uuid: models.CharField code: models.CharField -- claim_ai_quality extension -- +json_ext.claim_ai_quality.was_categorized: boolean = false +json_ext.claim_ai_quality.request_time: datetime +json_ext.claim_ai_quality.response_time: datetime } class ClaimItem as "openimis.claim.models.ClaimItem" { -- claim_ai_quality extension -- +json_ext.claim_ai_quality.ai_result: integer = 0 } class ClaimService as "openimis.claim.models.ClaimService" { -- claim_ai_quality extension -- +json_ext.claim_ai_quality.ai_result: integer = 0 } class Service as "openimis.medical.models.Service" { } class Item as "openimis.medical.models.Item " { } class openimis.core.models.ExtendableModel { json_ext: FallbackJSONField } class openimis.core.models.VersionedModel { legacy_id: IntegerField } openimis.core.models.BaseVersionedModel ^-- openimis.core.models.VersionedModel openimis.core.models.VersionedModel ^-- Claim openimis.core.models.ExtendableModel ^-- .Claim Claim "0.." - "0.." Item (Claim , Item) .. ClaimItem Service "0.." - "0.." Claim (Service, Claim) .. ClaimService @enduml |
Because currently ClaimItem
and ClaimService
doesn’t support custom fields, these classes will also extend the ExtendableModel
class.
Migrations
Because the Claim-AI modules are activated after Claims have been adjudicated (the data used for the training), a migration script needs to be created to insert the JSON fields into the available data. The following initializations will be used:
If Claim.ClaimStatus == Entered (Value 2) Then don’t add Claim.json_ext.claim_ai_quality
...
@enduml
Because currently ClaimItem
and ClaimService
doesn’t support custom fields, these classes will also extend the ExtendableModel
class.
Migrations
Because the Claim-AI modules are activated after Claims have been adjudicated (the data used for the training), a migration script needs to be created to insert the JSON fields into the available data. The following initializations will be used:
If Claim.ClaimStatus == Checked (Value 4) Then add
Code Block |
---|
Claim.json_ext.claim_ai_quality.was_categorized = false
Claim.json_ext.claim_ai_quality.request_time = null
Claim.json_ext.claim_ai_quality.response_time = null |
If Claim.ClaimStatus == Entered Rejected (Value 21) Then don’t add
Code Block |
---|
Claim.json_ext.claim_ai_quality |
...
If Claim.ClaimStatus == Checked (Value 4) Then add
Code Block |
---|
.was_categorized = false
Claim.json_ext.claim_ai_quality.request_time = Claim.ValidityFrom
Claim.json_ext.claim_ai_quality.wasresponse_categorizedtime = falseClaim.ValidityFrom
ClaimClaimService.json_ext.claim_ai_quality.requestai_timeresult = nullClaimService.ClaimServiceStatus
ClaimClaimItem.json_ext.claim_ai_quality.responseai_timeresult = nullClaimItem.ClaimItemStatus |
If Claim.ClaimStatus in [Rejected (Value 1), Reviewed Reviewed/Processed (Value 8), Valuated (Value 16)] Then add
...
ClaimFilterMedicalItem
allows Medical Officers to filter the Claims list based on a specific Medical Item (only one from autocomplete list)
ClaimFilterMedicalService
allows Medical Officers to filter the Claims list based on a specific Medical Service (only one from autocomplete list)
ClaimFilterAIProcessed
allows Medical Officers to display or hide the non AI-processed Claims (checkbox, default checked)Claims (dropdown with options: Show all
, AI-Categorized Claim Only
, Not AI-Categorized Claims Only
, default AI-Categorized Claim Only
)
Custom Claim Review Search Results - Frontend
The following column will be added to the claim.Searcher
result list:
ClaimResultsAIProcessed
will display the value of Claim.json_ext.claim_ai_quality.was_categorized
as True/False.
AI Categorisation Misclassification Report
...
Plantumlcloud |
---|
filename | openIMIS-AI-Modules-Deployment.png |
---|
data | lVTLboMwEPwaSpVXbboMwDP2aSNsDUkSp+0BySJEOTtJo1pqDqX9ATdsE0tpyWTUNaH8b2A1nx2kghIBIe9vdzuBQaQqGaZEGIfU6c+IGwODiQiGrDK1PnklCGpooMSEiLElRyTD6TvJSQgzLciEKhg2t8kDDsA/fsujxTi4EKkFTK7O4O9M4Zk1HlRDLjQltxG7f8p2KvCwUOnHyILnIj0VWSxgxNbM47B2hD8WSj5pLYX5n4SzBRxd0h+VorQhlGIbz4Eg5ISm0Jhh31LUnTaMJip3GURg4UzUEEZLvPuL5ARrZxQDYvzsY2zDJuDmi1ButHo2xmFz42Z8FHGZHSzanZR8YN/5x37blYwtxmmuSwUajBdeWoMF4fBB0vTagG9hT9p0bHq+k9WlNVjE5E4JqY+2qBWMmNosLq+FdArF+HstlPQ/UTjj+Oib/mE7vPI8z+5YmjSu8iyAYgSIhKy3hXAXKMh6n5DVS3CwFWsYVzuMGieMdQzKIqeYYgs++CgjUoZ7as9BNvtuEdV2ajMjf0T2cW+afmdLvNO2Jq12j9mI8WkndFxjCdH48lucbpGgosCmlA7znRf+Shifz9/op2jpcxJzecvYW7Pz+QT+iS7H5+BwjA5uZOuhn5WQRprzrFBD45xETJ1tJf1FR4b91tzboWc09THykcGfwUAlPLjwmswRLvL5oGNGwRT4P/0FZ6XN24K9JtYXw5jRD/3+AymbVd3A0mouyWWqPNJjRotPGYTFniV1rLNZYIdo/44adbJMhZoHWFw4EtC6snXHdWE1r6HMx1UcPYSb/tIw/+ia7Hp6DxGDXclK2DflVcKKHOi4UaApdKxOS5qIS55DOH/W7vhSHGqdYgwxRKKU78Tmb4jrF/rpeCJ4FH6ncGBRU3oK9V9CWzvneqFjMmXJnhdN01MosoqAz/GX8= |
---|
width | |
---|
compressed | true |
---|
revision | 24 |
---|
|
Expand |
---|
|
database openIMISDB node openIMISImplementation as
node openIMISImplementation as "openIMIS Implementation" { |
component ClaimModule as "Claim Module" |
component ClaimAIQualityModule as "Claim AI Quality Module" |
component FHIRR4Module as "FHIR R4 Module" |
FHIRR4Module -[dashed]-> ClaimModule: <<use>> |
ClaimAIQualityModule -[dashed]-> FHIRR4Module : <<use>> |
ClaimAIQualityModule --^ ClaimModule} openIMISImplementation
ClaimAIQualityModule --^ ClaimModule
database openIMISDB
ClaimModule -[dashed]-> openIMISDB: | <<use>>node openIMISClaimAIImplementation as "openIMIS <<use>>
}
node openIMISClaimAIImplementation as "openIMIS Claim-AI Implementation" { |
component ClaimAIModule as "Claim-AI Module" |
artifact ClaimAIModel as "Claim-AI Model" |
ClaimAIModule -[dashed]-> ClaimAIModel: <<use>> |
} ClaimAIModule
}
ClaimAIModule -0)- ClaimAIQualityModule: FHIR Claim |
ClaimAIModule -(0- ClaimAIQualityModule: FHIR ClaimResponse |
node ClaimAITraining as "openIMIS Claim-AI Training" { |
component ClaimAIAlgorithm as "Claim-AI ML Algorithm" |
ClaimAIAlgorithm
artifact openIMISDBReplica as "openIMIS Claim Data"
ClaimAIAlgorithm -[dashed]-> ClaimAIModel: | <<generates>> ClaimAIAlgorithm <<generates>>
openIMISDBReplica -[dashed]-> openIMISDB: <<replicates>>
ClaimAIAlgorithm -[dashed]-> | openIMISDB openIMISDBReplica: <<use>> |
|
Testing
Testing the WebSocket from JavaScript console
...