fix: label PDF uploads by content instead of a fixed image name

The service dispatches on the upload filename extension. A PDF sent as image.jpg made /ocr/text return a success response with hallucinated text. Only PDFs are relabelled; everything else keeps the legacy image label.
This commit is contained in:
2026-10-21 23:26:49 -04:00
parent 398b16e136
commit c13c4fd28f
2 changed files with 131 additions and 4 deletions
+82
View File
@@ -23,6 +23,8 @@ from polygateway.transports.monkey_ocr import (
MonkeyOcrTransport,
_classify_status,
_parse_middle_json,
_sniff_media,
_upload_part,
)
from polygateway.types import SourceConfig
@@ -167,6 +169,86 @@ class TestRecognizeText:
assert b'filename="image.jpg"' in seen["body"] # CHS invokers.py:496 固定名
_PDF_BODY = b"%PDF-1.4\n%synthetic body"
_JUNK = b"x" * 200
class TestSniffMedia:
"""上传类型按内容判定(#34 设计 §3 Q2): 图片魔数优先 → 前 1KB 内 `%PDF-` → 未知。"""
@pytest.mark.parametrize(
("data", "expected"),
[
pytest.param(_PDF_BODY, "pdf", id="pdf"),
pytest.param(_JUNK + _PDF_BODY, "pdf", id="pdf-with-junk-prefix"),
pytest.param(b"\xff\xd8\xff\xe0" + b"0" * 20, "image", id="jpeg"),
pytest.param(b"\x89PNG\r\n\x1a\n" + b"0" * 20, "image", id="png"),
pytest.param(b"II*\x00" + b"0" * 20, "image", id="tiff-le"),
pytest.param(b"MM\x00*" + b"0" * 20, "image", id="tiff-be"),
pytest.param(b"BM" + b"0" * 20, "image", id="bmp"),
pytest.param(b"GIF89a" + b"0" * 20, "image", id="gif89a"),
pytest.param(b"GIF87a" + b"0" * 20, "image", id="gif87a"),
pytest.param(b"RIFF\x00\x00\x00\x00WEBPVP8 ", "image", id="webp"),
# 图片魔数优先: 含 XMP 元数据的图片可能在 1KB 内带 `%PDF-` 字样
pytest.param(b"\xff\xd8\xff\xe0" + b"<xmp>%PDF-</xmp>", "image", id="jpeg-mentions-pdf"),
pytest.param(b"<html><body>paywall</body></html>", "unknown", id="html"),
pytest.param(b"GARBAGE-NOT-AN-IMAGE", "unknown", id="garbage"),
pytest.param(b"", "unknown", id="empty"),
# 1KB 窗口之外的 `%PDF-` 不算
pytest.param(b"x" * 1100 + b"%PDF-", "unknown", id="header-beyond-window"),
],
)
def test_sniff(self, data, expected):
assert _sniff_media(data) == expected
def test_upload_part_labels_pdf_only(self):
assert _upload_part(_PDF_BODY) == ("doc.pdf", _PDF_BODY, "application/pdf")
assert _upload_part(_JUNK + _PDF_BODY)[0] == "doc.pdf"
@pytest.mark.parametrize("data", [b"\xff\xd8\xff\xe0abc", b"\x89PNG\r\n\x1a\nabc", b"junk", b""])
def test_everything_else_keeps_the_legacy_label(self, data):
"""非 PDF 路径字节级不变: 服务对图片按内容解码(2026-10-21 实测 PNG/TIFF/BMP 标 image.jpg 成功)。"""
assert _upload_part(data) == ("image.jpg", data, "image/jpeg")
class TestUploadLabelPerMethod:
"""三个调用点共用同一个标签点: 漏掉任何一个,E4 的静默错误结果就在那里复活。"""
@staticmethod
def _capturing_transport(seen):
def handler(request: httpx.Request) -> httpx.Response:
if request.url.path == "/ocr/text":
seen["body"] = request.read()
return httpx.Response(200, json=_text_body())
if request.url.path == "/parse":
seen["body"] = request.read()
return httpx.Response(200, json=_parse_body())
return httpx.Response(200, content=_zip_bytes())
return _transport_for(handler)
async def test_recognize_text_labels_pdf_as_pdf(self):
seen = {}
t = self._capturing_transport(seen)
await t.recognize_text(image=_PDF_BODY, source=_source(), call_id="c1")
assert b'filename="doc.pdf"' in seen["body"]
assert b"Content-Type: application/pdf" in seen["body"]
async def test_parse_layout_labels_pdf_as_pdf(self):
seen = {}
t = self._capturing_transport(seen)
await t.parse_layout(image=_PDF_BODY, source=_source(), call_id="c1")
assert b'filename="doc.pdf"' in seen["body"]
assert b"Content-Type: application/pdf" in seen["body"]
async def test_parse_layout_keeps_image_label_for_images(self):
seen = {}
t = self._capturing_transport(seen)
await t.parse_layout(image=b"\xff\xd8\xff\xe0abc", source=_source(), call_id="c1")
assert b'filename="image.jpg"' in seen["body"]
assert b"Content-Type: image/jpeg" in seen["body"]
class TestParseLayout:
async def test_full_chain_relative_url(self):
t = _transport_for(