From 2a6537289b2a69417faa8c983f70ce8aae686f34 Mon Sep 17 00:00:00 2001 From: Christoph Auer Date: Tue, 6 May 2025 16:40:02 +0200 Subject: [PATCH] Introduce mean_score and low_score, consistent aggregate computations Signed-off-by: Christoph Auer --- docling/datamodel/base_models.py | 71 ++++++++++++++++++++--- docling/models/page_assemble_model.py | 13 ----- docling/pipeline/standard_pdf_pipeline.py | 7 --- 3 files changed, 62 insertions(+), 29 deletions(-) diff --git a/docling/datamodel/base_models.py b/docling/datamodel/base_models.py index 027e165a..8fc4a9a9 100644 --- a/docling/datamodel/base_models.py +++ b/docling/datamodel/base_models.py @@ -315,29 +315,82 @@ class QualityGrade(str, Enum): class PageConfidenceScores(BaseModel): - overall_score: ScoreValue = np.nan - parse_score: ScoreValue = np.nan layout_score: ScoreValue = np.nan table_score: ScoreValue = np.nan ocr_score: ScoreValue = np.nan - @computed_field # type: ignore - @property - def grade(self) -> QualityGrade: - if self.overall_score < 0.5: + def _score_to_grade(self, score: ScoreValue) -> QualityGrade: + if score < 0.5: return QualityGrade.POOR - elif self.overall_score < 0.8: + elif score < 0.8: return QualityGrade.FAIR - elif self.overall_score < 0.9: + elif score < 0.9: return QualityGrade.GOOD - elif self.overall_score >= 0.9: + elif score >= 0.9: return QualityGrade.EXCELLENT return QualityGrade.UNSPECIFIED + @computed_field # type: ignore + @property + def mean_grade(self) -> QualityGrade: + return self._score_to_grade(self.mean_score) + + @computed_field # type: ignore + @property + def low_grade(self) -> QualityGrade: + return self._score_to_grade(self.low_score) + + @computed_field # type: ignore + @property + def mean_score(self) -> ScoreValue: + return ScoreValue( + np.nanmean( + [ + self.ocr_score, + self.table_score, + self.layout_score, + self.parse_score, + ] + ) + ) + + @computed_field # type: ignore + @property + def low_score(self) -> ScoreValue: + return ScoreValue( + np.nanquantile( + [ + self.ocr_score, + self.table_score, + self.layout_score, + self.parse_score, + ], + q=0.05, + ) + ) + class ConfidenceReport(PageConfidenceScores): pages: Dict[int, PageConfidenceScores] = Field( default_factory=lambda: defaultdict(PageConfidenceScores) ) + + @computed_field # type: ignore + @property + def mean_score(self) -> ScoreValue: + return ScoreValue( + np.nanmean( + [c.mean_score for c in self.pages.values()], + ) + ) + + @computed_field # type: ignore + @property + def low_score(self) -> ScoreValue: + return ScoreValue( + np.nanmean( + [c.low_score for c in self.pages.values()], + ) + ) diff --git a/docling/models/page_assemble_model.py b/docling/models/page_assemble_model.py index 208c20a0..bc5589eb 100644 --- a/docling/models/page_assemble_model.py +++ b/docling/models/page_assemble_model.py @@ -153,17 +153,4 @@ class PageAssembleModel(BasePageModel): elements=elements, headers=headers, body=body ) - # Aggregate page score - scores = conv_res.confidence.pages[page.page_no] - scores.overall_score = float( - np.nanmean( - [ - scores.ocr_score, - scores.table_score, - scores.layout_score, - scores.parse_score, - ] - ) - ) - yield page diff --git a/docling/pipeline/standard_pdf_pipeline.py b/docling/pipeline/standard_pdf_pipeline.py index 1497f6b8..4269900c 100644 --- a/docling/pipeline/standard_pdf_pipeline.py +++ b/docling/pipeline/standard_pdf_pipeline.py @@ -269,13 +269,6 @@ class StandardPdfPipeline(PaginatedPipeline): ) ) - conv_res.confidence.overall_score = float( - np.nanquantile( - [c.overall_score for c in conv_res.confidence.pages.values()], - q=0.05, # overall score should relate to worst 5% of page scores. - ) - ) - return conv_res @classmethod