| 11 | |
| 12 | @dataclass(frozen=True, slots=True) |
| 13 | class QualityFallbackPolicy: |
| 14 | min_chars: int = 48 |
| 15 | min_alpha_chars: int = 24 |
| 16 | min_source_ratio: float = 0.01 |
| 17 | max_source_ratio: float = 0.75 |
| 18 | min_query_overlap_terms: int = 0 |
| 19 | reject_markers: tuple[str, ...] = ( |
| 20 | "cannot summarize", |
| 21 | "can't summarize", |
| 22 | "insufficient information", |
| 23 | "no relevant information", |
| 24 | ) |
| 25 | |
| 26 | @classmethod |
| 27 | def from_dict( |
| 28 | cls, |
| 29 | data: Mapping[str, Any] | None, |
| 30 | *, |
| 31 | base: QualityFallbackPolicy | None = None, |
| 32 | ) -> QualityFallbackPolicy: |
| 33 | base = base or cls() |
| 34 | if not data: |
| 35 | return base |
| 36 | policy = cls( |
| 37 | min_chars=int(data.get("min_chars", base.min_chars)), |
| 38 | min_alpha_chars=int(data.get("min_alpha_chars", base.min_alpha_chars)), |
| 39 | min_source_ratio=float(data.get("min_source_ratio", base.min_source_ratio)), |
| 40 | max_source_ratio=float(data.get("max_source_ratio", base.max_source_ratio)), |
| 41 | min_query_overlap_terms=int( |
| 42 | data.get("min_query_overlap_terms", base.min_query_overlap_terms), |
| 43 | ), |
| 44 | reject_markers=tuple(data.get("reject_markers", base.reject_markers)), |
| 45 | ) |
| 46 | if policy.min_chars < 0 or policy.min_alpha_chars < 0: |
| 47 | raise ValueError("quality thresholds must be non-negative") |
| 48 | if policy.min_source_ratio < 0 or policy.max_source_ratio <= 0: |
| 49 | raise ValueError("quality source ratios must be positive") |
| 50 | if policy.max_source_ratio < policy.min_source_ratio: |
| 51 | raise ValueError("quality max_source_ratio must be >= min_source_ratio") |
| 52 | if policy.min_query_overlap_terms < 0: |
| 53 | raise ValueError("quality min_query_overlap_terms must be non-negative") |
| 54 | return policy |
| 55 | |
| 56 | def to_dict(self) -> dict[str, Any]: |
| 57 | return { |
| 58 | "min_chars": self.min_chars, |
| 59 | "min_alpha_chars": self.min_alpha_chars, |
| 60 | "min_source_ratio": self.min_source_ratio, |
| 61 | "max_source_ratio": self.max_source_ratio, |
| 62 | "min_query_overlap_terms": self.min_query_overlap_terms, |
| 63 | "reject_markers": list(self.reject_markers), |
| 64 | } |
| 65 | |
| 66 | |
| 67 | @dataclass(frozen=True, slots=True) |
no outgoing calls