feat: add OCR result and transport types
This commit is contained in:
@@ -201,6 +201,68 @@ class GlobalLimits:
|
|||||||
raise ValueError("全局限额不能为负(0 表示不启用)")
|
raise ValueError("全局限额不能为负(0 表示不启用)")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class OcrLayoutElement:
|
||||||
|
"""版面单元(M3 设计 §3.1): 来自 `_middle.json` para_blocks 的带类型块。
|
||||||
|
|
||||||
|
type 为开放字符串(实测 table/image/text,不枚举锁死——零业务假设);
|
||||||
|
bbox 为 OCR 原生页面坐标 (x1, y1, x2, y2),几何映射留业务侧(D9)。
|
||||||
|
"""
|
||||||
|
|
||||||
|
type: str
|
||||||
|
bbox: tuple[float, float, float, float]
|
||||||
|
page_index: int
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class OcrTextResult:
|
||||||
|
"""一次治理 OCR 文本转录的统一响应(/ocr/text;M3 设计 §3.1)。
|
||||||
|
|
||||||
|
text 空串 = 合法"无文字";行过滤/去重/拼帧留业务侧(VT 迁移 §3)。
|
||||||
|
"""
|
||||||
|
|
||||||
|
text: str
|
||||||
|
source_name: str
|
||||||
|
usage: Usage # OCR 无计费: Usage(0, 0);耗时由 latency_ms 承载
|
||||||
|
latency_ms: int
|
||||||
|
call_id: str
|
||||||
|
raw: dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class OcrLayoutResult:
|
||||||
|
"""一次治理版面解析的统一响应(/parse → ZIP;M3 设计 §3.1)。
|
||||||
|
|
||||||
|
elements 空 = 合法"无元素";CHS 首表 = 首个 type=="table" 元素。
|
||||||
|
page_sizes 按 page_index 索引。
|
||||||
|
"""
|
||||||
|
|
||||||
|
elements: list[OcrLayoutElement]
|
||||||
|
page_sizes: list[tuple[float, float]]
|
||||||
|
source_name: str
|
||||||
|
usage: Usage
|
||||||
|
latency_ms: int
|
||||||
|
call_id: str
|
||||||
|
raw: dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class OcrTextTransportResult:
|
||||||
|
"""transport 单次 /ocr/text 调用产物;治理字段由 OcrClient 补齐。"""
|
||||||
|
|
||||||
|
text: str
|
||||||
|
raw: dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class OcrLayoutTransportResult:
|
||||||
|
"""transport 单次 /parse 两段调用产物;治理字段由 OcrClient 补齐。"""
|
||||||
|
|
||||||
|
elements: list[OcrLayoutElement]
|
||||||
|
page_sizes: list[tuple[float, float]]
|
||||||
|
raw: dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class EmbeddingTransportResult:
|
class EmbeddingTransportResult:
|
||||||
"""一次原始 embedding 调用的解析结果(M2 设计 §7.2;transport → client)。"""
|
"""一次原始 embedding 调用的解析结果(M2 设计 §7.2;transport → client)。"""
|
||||||
|
|||||||
@@ -154,3 +154,61 @@ class TestAuxTypes:
|
|||||||
raw={"id": "x"},
|
raw={"id": "x"},
|
||||||
)
|
)
|
||||||
assert s.raw["id"] == "x"
|
assert s.raw["id"] == "x"
|
||||||
|
|
||||||
|
|
||||||
|
class TestOcrTypes:
|
||||||
|
"""M3 OCR 五类型(设计 §3.1): 可构造、frozen、全必填无默认。"""
|
||||||
|
|
||||||
|
def _element(self):
|
||||||
|
from polygateway.types import OcrLayoutElement
|
||||||
|
|
||||||
|
return OcrLayoutElement(type="table", bbox=(41.0, 48.0, 218.0, 282.0), page_index=0)
|
||||||
|
|
||||||
|
def test_layout_element_fields(self):
|
||||||
|
el = self._element()
|
||||||
|
assert el.type == "table" and el.bbox == (41.0, 48.0, 218.0, 282.0) and el.page_index == 0
|
||||||
|
with pytest.raises(dataclasses.FrozenInstanceError):
|
||||||
|
el.type = "text"
|
||||||
|
|
||||||
|
def test_text_result_provenance(self):
|
||||||
|
from polygateway.types import OcrTextResult
|
||||||
|
|
||||||
|
r = OcrTextResult(
|
||||||
|
text="TOSHIBA",
|
||||||
|
source_name="monkey_1",
|
||||||
|
usage=Usage(0, 0),
|
||||||
|
latency_ms=3200,
|
||||||
|
call_id="cid",
|
||||||
|
raw={"success": True},
|
||||||
|
)
|
||||||
|
assert r.text == "TOSHIBA" and r.usage.prompt_tokens == 0
|
||||||
|
with pytest.raises(dataclasses.FrozenInstanceError):
|
||||||
|
r.text = "x"
|
||||||
|
|
||||||
|
def test_layout_result_provenance(self):
|
||||||
|
from polygateway.types import OcrLayoutResult
|
||||||
|
|
||||||
|
r = OcrLayoutResult(
|
||||||
|
elements=[self._element()],
|
||||||
|
page_sizes=[(759.0, 540.0)],
|
||||||
|
source_name="monkey_1",
|
||||||
|
usage=Usage(0, 0),
|
||||||
|
latency_ms=8000,
|
||||||
|
call_id="cid",
|
||||||
|
raw={"has_table": True},
|
||||||
|
)
|
||||||
|
assert r.elements[0].type == "table" and r.page_sizes[0] == (759.0, 540.0)
|
||||||
|
|
||||||
|
def test_transport_results(self):
|
||||||
|
from polygateway.types import OcrLayoutTransportResult, OcrTextTransportResult
|
||||||
|
|
||||||
|
t = OcrTextTransportResult(text="", raw={})
|
||||||
|
assert t.text == "" # 空串 = 合法"无文字"
|
||||||
|
lt = OcrLayoutTransportResult(elements=[], page_sizes=[(1.0, 1.0)], raw={})
|
||||||
|
assert lt.elements == [] # 空 elements = 合法"无元素"
|
||||||
|
|
||||||
|
def test_all_fields_required(self):
|
||||||
|
from polygateway.types import OcrTextResult
|
||||||
|
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
OcrTextResult(text="x") # 溯源件不可省略
|
||||||
|
|||||||
Reference in New Issue
Block a user