Files
wehub-resource-sync 461bf6fd40
CI / lint (3.11) (push) Has been cancelled
CI / lint (3.12) (push) Has been cancelled
CI / lint (3.13) (push) Has been cancelled
CI / shellcheck (push) Has been cancelled
CI / shfmt (push) Has been cancelled
CI / setup (3.11) (push) Has been cancelled
CI / setup (3.12) (push) Has been cancelled
CI / setup (3.13) (push) Has been cancelled
CI / check-licenses (3.12) (push) Has been cancelled
CI / test_unit (3.11) (push) Has been cancelled
CI / test_unit (3.12) (push) Has been cancelled
CI / test_unit (3.13) (push) Has been cancelled
CI / test_unit_no_extras (3.11) (push) Has been cancelled
CI / test_unit_no_extras (3.12) (push) Has been cancelled
CI / test_json_to_html (3.12) (push) Has been cancelled
CI / test_unit_no_extras (3.13) (push) Has been cancelled
CI / test_unit_dependency_extras (csv, 3.12, --extra csv) (push) Has been cancelled
CI / test_unit_dependency_extras (xlsx, 3.11, --extra xlsx) (push) Has been cancelled
CI / test_unit_dependency_extras (xlsx, 3.12, --extra xlsx) (push) Has been cancelled
CI / test_unit_dependency_extras (csv, 3.11, --extra csv) (push) Has been cancelled
CI / test_unit_dependency_extras (csv, 3.13, --extra csv) (push) Has been cancelled
CI / test_unit_dependency_extras (docx, 3.11, --extra docx) (push) Has been cancelled
CI / test_unit_dependency_extras (docx, 3.12, --extra docx) (push) Has been cancelled
CI / test_unit_dependency_extras (docx, 3.13, --extra docx) (push) Has been cancelled
CI / test_unit_dependency_extras (markdown, 3.11, --extra md) (push) Has been cancelled
CI / test_unit_dependency_extras (markdown, 3.12, --extra md) (push) Has been cancelled
CI / test_unit_dependency_extras (markdown, 3.13, --extra md) (push) Has been cancelled
CI / test_unit_dependency_extras (odt, 3.11, --extra odt) (push) Has been cancelled
CI / test_unit_dependency_extras (odt, 3.12, --extra odt) (push) Has been cancelled
CI / test_unit_dependency_extras (odt, 3.13, --extra odt) (push) Has been cancelled
CI / test_unit_dependency_extras (pdf-image, 3.11, --extra pdf --extra image --extra paddleocr) (push) Has been cancelled
CI / test_unit_dependency_extras (pdf-image, 3.12, --extra pdf --extra image --extra paddleocr) (push) Has been cancelled
CI / test_unit_dependency_extras (pdf-image, 3.13, --extra pdf --extra image --extra paddleocr) (push) Has been cancelled
CI / test_unit_dependency_extras (pptx, 3.11, --extra pptx) (push) Has been cancelled
CI / test_unit_dependency_extras (pptx, 3.12, --extra pptx) (push) Has been cancelled
CI / test_unit_dependency_extras (pptx, 3.13, --extra pptx) (push) Has been cancelled
CI / test_unit_dependency_extras (pypandoc, 3.11, --extra epub --extra org --extra rtf --extra rst) (push) Has been cancelled
CI / test_unit_dependency_extras (pypandoc, 3.12, --extra epub --extra org --extra rtf --extra rst) (push) Has been cancelled
CI / test_unit_dependency_extras (pypandoc, 3.13, --extra epub --extra org --extra rtf --extra rst) (push) Has been cancelled
Build And Push Docker Image / set-short-sha (push) Has been cancelled
Partition Benchmark / setup (push) Has been cancelled
Partition Benchmark / Measure and compare partition() runtime (push) Has been cancelled
CI / test_unit_dependency_extras (xlsx, 3.13, --extra xlsx) (push) Has been cancelled
CI / test_ingest_src (3.12) (push) Has been cancelled
CI / test_json_to_markdown (3.12) (push) Has been cancelled
CI / changelog (push) Has been cancelled
CI / test_dockerfile (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Build And Push Docker Image / build-images (linux/amd64, opensource-linux-8core) (push) Has been cancelled
Build And Push Docker Image / build-images (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Build And Push Docker Image / publish-images (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:33:56 +08:00

117 lines
4.7 KiB
Python

from __future__ import annotations
from io import BytesIO
from typing import TYPE_CHECKING, Optional
from google.cloud.vision import Image, ImageAnnotatorClient, ImageContext, Paragraph, TextAnnotation
from unstructured.logger import logger, trace_logger
from unstructured.partition.utils.config import env_config
from unstructured.partition.utils.constants import Source
from unstructured.partition.utils.ocr_models.ocr_interface import OCRAgent
if TYPE_CHECKING:
from PIL import Image as PILImage
from unstructured_inference.inference.elements import TextRegion, TextRegions
from unstructured_inference.inference.layoutelement import LayoutElements
class OCRAgentGoogleVision(OCRAgent):
"""OCR service implementation for Google Vision API."""
def __init__(self, language: Optional[str] = None) -> None:
self.language = language
client_options = {}
api_endpoint = env_config.GOOGLEVISION_API_ENDPOINT
if api_endpoint:
logger.info(f"Using Google Vision OCR with endpoint {api_endpoint}")
client_options["api_endpoint"] = api_endpoint
else:
logger.info("Using Google Vision OCR with default endpoint")
self.client = ImageAnnotatorClient(client_options=client_options)
def is_text_sorted(self) -> bool:
return True
def get_text_from_image(self, image: PILImage.Image) -> str:
image_context = ImageContext(language_hints=[self.language]) if self.language else None
with BytesIO() as buffer:
image.save(buffer, format="PNG")
response = self.client.document_text_detection(
image=Image(content=buffer.getvalue()), image_context=image_context
)
document = response.full_text_annotation
assert isinstance(document, TextAnnotation)
return document.text
def get_layout_from_image(self, image: PILImage.Image) -> TextRegions:
trace_logger.detail("Processing entire page OCR with Google Vision API...")
image_context = ImageContext(language_hints=[self.language]) if self.language else None
with BytesIO() as buffer:
image.save(buffer, format="PNG")
response = self.client.document_text_detection(
image=Image(content=buffer.getvalue()), image_context=image_context
)
document = response.full_text_annotation
assert isinstance(document, TextAnnotation)
regions = self._parse_regions(document)
return regions
def get_layout_elements_from_image(self, image: PILImage.Image) -> LayoutElements:
from unstructured.partition.pdf_image.inference_utils import (
build_layout_elements_from_ocr_regions,
)
ocr_regions = self.get_layout_from_image(
image,
)
ocr_text = self.get_text_from_image(
image,
)
return build_layout_elements_from_ocr_regions(
ocr_regions=ocr_regions,
ocr_text=ocr_text,
group_by_ocr_text=False,
)
def _parse_regions(self, ocr_data: TextAnnotation) -> TextRegions:
from unstructured_inference.inference.elements import TextRegions
from unstructured.partition.pdf_image.inference_utils import build_text_region_from_coords
text_regions: list[TextRegion] = []
for page_idx, page in enumerate(ocr_data.pages):
for block in page.blocks:
for paragraph in block.paragraphs:
vertices = paragraph.bounding_box.vertices
x1, y1 = vertices[0].x, vertices[0].y
x2, y2 = vertices[2].x, vertices[2].y
text_region = build_text_region_from_coords(
x1,
y1,
x2,
y2,
text=self._get_text_from_paragraph(paragraph),
source=Source.OCR_GOOGLEVISION,
)
text_regions.append(text_region)
return TextRegions.from_list(text_regions)
def _get_text_from_paragraph(self, paragraph: Paragraph) -> str:
breaks = TextAnnotation.DetectedBreak.BreakType
para = ""
line = ""
for word in paragraph.words:
for symbol in word.symbols:
line += symbol.text
if symbol.property.detected_break.type_ == breaks.SPACE:
line += " "
if symbol.property.detected_break.type_ == breaks.EOL_SURE_SPACE:
line += " "
para += line
line = ""
if symbol.property.detected_break.type_ == breaks.LINE_BREAK:
para += line
line = ""
return para