| """Post-processing review-risk flags for accepted classifications.""" |
|
|
| from __future__ import annotations |
|
|
| from gcmd_classifier.models import ( |
| ClassificationFinalStatus, |
| ClassificationRecord, |
| OutputWarning, |
| SupportType, |
| ) |
|
|
| REVIEW_RECOMMENDED_WEAK_SUPPORT = "REVIEW_RECOMMENDED_WEAK_SUPPORT" |
|
|
|
|
| def flag_review_risk( |
| classifications: tuple[ClassificationRecord, ...], |
| ) -> tuple[ClassificationRecord, ...]: |
| """Mark accepted classifications that should receive manual scientific review.""" |
| return tuple(_flag_record(record) for record in classifications) |
|
|
|
|
| def _flag_record(record: ClassificationRecord) -> ClassificationRecord: |
| if not _requires_review(record): |
| return record |
| warning = OutputWarning( |
| code=REVIEW_RECOMMENDED_WEAK_SUPPORT, |
| message="Manual scientific review is recommended because support is weak or inferred.", |
| stage="review_flagging", |
| details={ |
| "level": record.level, |
| "support_type": None if record.support_type is None else record.support_type.value, |
| "confidence_final": _confidence_final(record), |
| }, |
| ) |
| warnings = record.warnings |
| if not any(existing.code == REVIEW_RECOMMENDED_WEAK_SUPPORT for existing in warnings): |
| warnings = (*warnings, warning) |
| return record.model_copy(update={"review_required": True, "warnings": warnings}) |
|
|
|
|
| def _requires_review(record: ClassificationRecord) -> bool: |
| if record.final_status is not ClassificationFinalStatus.ACCEPTED: |
| return False |
| if record.support_type is None: |
| return False |
| confidence_final = _confidence_final(record) |
| if record.level == "Topic" and record.support_type in { |
| SupportType.INFERRED, |
| SupportType.MIXED, |
| }: |
| return True |
| if record.support_type is SupportType.INFERRED and record.level in { |
| "Variable_Level_2", |
| "Variable_Level_3", |
| }: |
| return True |
| if ( |
| record.support_type is SupportType.INFERRED |
| and confidence_final is not None |
| and confidence_final < 0.75 |
| ): |
| return True |
| return ( |
| record.support_type is SupportType.MIXED |
| and confidence_final is not None |
| and confidence_final < 0.70 |
| ) |
|
|
|
|
| def _confidence_final(record: ClassificationRecord) -> float | None: |
| return None if record.confidence is None else record.confidence.final |
|
|