mirror of
https://github.com/Skyvern-AI/skyvern.git
synced 2026-07-09 16:09:13 +00:00
Restore Tesseract in runtime images (#6916)
Some checks are pending
Run tests and pre-commit / Run tests and pre-commit hooks (push) Waiting to run
Run tests and pre-commit / Frontend Lint and Build (push) Waiting to run
Run tests and pre-commit / pip Package Smoke Tests (3.11) (push) Waiting to run
Run tests and pre-commit / pip Package Smoke Tests (3.13) (push) Waiting to run
Publish Fern Docs / run (push) Waiting to run
Some checks are pending
Run tests and pre-commit / Run tests and pre-commit hooks (push) Waiting to run
Run tests and pre-commit / Frontend Lint and Build (push) Waiting to run
Run tests and pre-commit / pip Package Smoke Tests (3.11) (push) Waiting to run
Run tests and pre-commit / pip Package Smoke Tests (3.13) (push) Waiting to run
Publish Fern Docs / run (push) Waiting to run
Co-authored-by: Suchintan Singh <suchintan@skyvern.com>
This commit is contained in:
parent
1451bd491f
commit
46f22cdad7
3 changed files with 106 additions and 4 deletions
62
skyvern/forge/sdk/utils/tesseract_languages.py
Normal file
62
skyvern/forge/sdk/utils/tesseract_languages.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Iterable
|
||||
|
||||
DEFAULT_TESSERACT_OCR_LANGUAGE_PACKS = (
|
||||
"eng",
|
||||
"spa",
|
||||
"fra",
|
||||
"deu",
|
||||
"ita",
|
||||
"por",
|
||||
"nld",
|
||||
"pol",
|
||||
"rus",
|
||||
"ukr",
|
||||
"ara",
|
||||
"chi-sim",
|
||||
"chi-tra",
|
||||
"jpn",
|
||||
"kor",
|
||||
"hin",
|
||||
)
|
||||
|
||||
|
||||
def tesseract_ocr_packages(language_packs: Iterable[str] = DEFAULT_TESSERACT_OCR_LANGUAGE_PACKS) -> list[str]:
|
||||
return [f"tesseract-ocr-{language_pack}" for language_pack in language_packs]
|
||||
|
||||
|
||||
def tesseract_language_arg(language_packs: Iterable[str] = DEFAULT_TESSERACT_OCR_LANGUAGE_PACKS) -> str:
|
||||
return "+".join(language_pack.replace("-", "_") for language_pack in language_packs)
|
||||
|
||||
|
||||
DEFAULT_FLAT_FILL_OCR_LANGUAGES = tesseract_language_arg()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="Print Tesseract language package metadata.")
|
||||
parser.add_argument(
|
||||
"--apt-packages",
|
||||
action="store_true",
|
||||
help="Print Debian OCR language packages for apt-get install.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--tesseract-languages",
|
||||
action="store_true",
|
||||
help="Print the Tesseract -l language argument.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.apt_packages:
|
||||
print(" ".join(tesseract_ocr_packages()))
|
||||
return
|
||||
if args.tesseract_languages:
|
||||
print(DEFAULT_FLAT_FILL_OCR_LANGUAGES)
|
||||
return
|
||||
parser.error("expected --apt-packages or --tesseract-languages")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -32,6 +32,7 @@ from skyvern.forge.sdk.db.exceptions import NotFoundError
|
|||
from skyvern.forge.sdk.experimentation.llm_prompt_config import get_llm_handler_for_prompt_type
|
||||
from skyvern.forge.sdk.schemas.files import FileInfo
|
||||
from skyvern.forge.sdk.utils.pdf_parser import render_pdf_pages_as_images, validate_pdf_file
|
||||
from skyvern.forge.sdk.utils.tesseract_languages import DEFAULT_FLAT_FILL_OCR_LANGUAGES
|
||||
from skyvern.forge.sdk.workflow.context_manager import WorkflowRunContext
|
||||
from skyvern.forge.sdk.workflow.loop_download_filter import filter_downloaded_files_for_current_iteration
|
||||
from skyvern.forge.sdk.workflow.models._jinja import render_templates_in_json_value
|
||||
|
|
@ -60,6 +61,7 @@ FLAT_FILL_OCR_TIMEOUT_SECONDS = 60
|
|||
# Outer budget across all pages so a flat PDF can't pin a worker for the full per-page timeout x max pages.
|
||||
FLAT_FILL_OCR_TOTAL_TIMEOUT_SECONDS = 300
|
||||
FLAT_FILL_MAX_PAGES = 25
|
||||
FLAT_FILL_OCR_LANGUAGES = os.getenv("FLAT_FILL_OCR_LANGUAGES", DEFAULT_FLAT_FILL_OCR_LANGUAGES).strip()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
|
@ -511,10 +513,7 @@ class PdfFillBlock(Block):
|
|||
async with aiofiles.open(image_path, "wb") as f:
|
||||
await f.write(image_bytes)
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
"tesseract",
|
||||
image_path,
|
||||
"stdout",
|
||||
"tsv",
|
||||
*self._tesseract_command(image_path),
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.DEVNULL,
|
||||
)
|
||||
|
|
@ -532,6 +531,14 @@ class PdfFillBlock(Block):
|
|||
)
|
||||
return anchors
|
||||
|
||||
@staticmethod
|
||||
def _tesseract_command(image_path: str) -> list[str]:
|
||||
command = ["tesseract", image_path, "stdout"]
|
||||
if FLAT_FILL_OCR_LANGUAGES:
|
||||
command.extend(["-l", FLAT_FILL_OCR_LANGUAGES])
|
||||
command.append("tsv")
|
||||
return command
|
||||
|
||||
@staticmethod
|
||||
def _tsv_int(row: dict[str, str], key: str) -> int | None:
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ from pypdf.generic import (
|
|||
)
|
||||
|
||||
from skyvern.forge import app
|
||||
from skyvern.forge.sdk.utils.tesseract_languages import tesseract_language_arg, tesseract_ocr_packages
|
||||
from skyvern.forge.sdk.workflow.context_manager import WorkflowRunContext
|
||||
from skyvern.forge.sdk.workflow.models import pdf_fill_block
|
||||
from skyvern.forge.sdk.workflow.models.block import PdfFillBlock, extract_file_url_from_block_output
|
||||
from skyvern.forge.sdk.workflow.models.parameter import OutputParameter
|
||||
from skyvern.forge.sdk.workflow.models.pdf_fill_block import FlatPdfAnchor, FlatPlacement, PdfFieldInventory
|
||||
|
|
@ -589,6 +591,37 @@ def test_parse_tesseract_tsv_skips_malformed_numeric_rows() -> None:
|
|||
assert [a.text for a in anchors] == ["City:"]
|
||||
|
||||
|
||||
def test_tesseract_command_includes_configured_languages(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setattr(pdf_fill_block, "FLAT_FILL_OCR_LANGUAGES", "eng+spa+fra")
|
||||
|
||||
assert PdfFillBlock._tesseract_command("/tmp/page.png") == [
|
||||
"tesseract",
|
||||
"/tmp/page.png",
|
||||
"stdout",
|
||||
"-l",
|
||||
"eng+spa+fra",
|
||||
"tsv",
|
||||
]
|
||||
|
||||
|
||||
def test_tesseract_command_allows_empty_language_override(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setattr(pdf_fill_block, "FLAT_FILL_OCR_LANGUAGES", "")
|
||||
|
||||
assert PdfFillBlock._tesseract_command("/tmp/page.png") == ["tesseract", "/tmp/page.png", "stdout", "tsv"]
|
||||
|
||||
|
||||
def test_tesseract_language_helpers_share_package_defaults() -> None:
|
||||
language_packs = ("eng", "spa", "chi-sim", "chi-tra")
|
||||
|
||||
assert tesseract_ocr_packages(language_packs) == [
|
||||
"tesseract-ocr-eng",
|
||||
"tesseract-ocr-spa",
|
||||
"tesseract-ocr-chi-sim",
|
||||
"tesseract-ocr-chi-tra",
|
||||
]
|
||||
assert tesseract_language_arg(language_packs) == "eng+spa+chi_sim+chi_tra"
|
||||
|
||||
|
||||
def test_escape_pdf_text() -> None:
|
||||
assert PdfFillBlock._escape_pdf_text("A (NM) \\ B\nC") == r"A \(NM\) \\ B C"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue