Market Context and Motivation
Translation remains a persistent requirement across industries. While human-based translation provides quality, it involves considerable expense and time. Large language models offer a competitive alternative—faster, more scalable, and increasingly accurate. However, conventional online translation tools typically demand uploading entire files, which introduces potential privacy risks when handling confidential documents.
Approaches that mitigate exposure include:
- Using GPT via API, where documents are split into segments and streamed, avoiding full file uploads.
- Relying on OpenAI’s contractual data handling policies.
- Deploying private, self-hosted models for end-to-end control over sensitive content.
Product Scope and Feature Planning
The initial release (v1.0) focuses on core capabilities:
- Parsing PDF files to extract text and tables.
- Translating English content into Chinese.
- Integrating OpenAI and ChatGLM backends.
- Configuration through YAML files or command-line arguments.
- Modular, object-oriented code design for extensibility.
A subsequent iteration (v2.0) will extend functionality:
- Adding a graphical user interface for broader accessibility.
- Preserving the original PDF layout after translation.
- Exposing translation as an API service.
- Supporting additional language pairs.
Technical Design and PDF Processing
Architectural Overview
The system follows a pipeline architecture: document ingestion, processing with pdfplumber, content segmentation, translation via model APIs, and optional reassembly. Loose coupling between components makes it straightforward to swap models or output formats.
Working with pdfplumber
The pdfplumber library, built on pdfminer.six, excels at extracting text, tables, and visual elements from machine-generated PDFs. It provides detailed access to characters, rectangles, lines, and curves, along with utilities for visual debugging. It requires Python 3.8 through 3.11 and is not suitable for scanned image-based PDFs.
Opening a PDF File
Call pdfplumber.open(source) where source can be a file path, a bytes object, or a file-like object. The call returns an instance of pdfplumber.PDF.
Advanced options include password for encrypted files and laparams to tune layout analysis, e.g., pdfplumber.open("doc.pdf", password="secret", laparams={"line_overlap": 0.7}).
The PDF and Page Objects
pdfplumber.PDF represents the whole document, with key members:
import pdfplumber
with pdfplumber.open("sample.pdf") as doc:
print(doc.metadata)
first_page = doc.pages[0]
print(type(first_page)) # <class 'pdfplumber.page.Page'>
A pdfplumber.Page holds content properties such as page_number, width, and height, and exposes methods for extraction and visualization.
page = doc.pages[0]
print(f"Page dimensions: {page.width}, {page.height}")
image = page.to_image()
Extracting Text from a Page
The extract_text() method combines all character objects into a single string. Parameters x_tolerance and y_tolerance govern when spaces and line breaks are inserted. Setting layout=True attempts to mirror the visual layout using x_density and y_density to decide spacing.
text_flow = page.extract_text(layout=False)
structured_text = page.extract_text(layout=True)
Additional methods include extract_text_simple() for faster, less configurable results and extract_words() to retrieve words with bounding box data, configurable for text flow direction, blank character handling, and ligature expansion.
words = page.extract_words(
keep_blank_chars=False,
use_text_flow=True,
extra_attrs=["fontname", "size"]
)
The experimental search() method supports regex or literal pattern matching across the page, returning match details with coordinates and character data.
Handling Tables in PDFs
pdfplumber's table extraction detects explicit lines and implicit alignments, merges overlapping edges, finds intersections, and constructs cell grids. Cells are grouped into tables.
Key methods on pdfplumber.Page include:
find_tables()— returns a list ofTableobjects with.cells,.rows,.bbox, and an.extract()method.find_table()— returns the largest table on the page.extract_tables()— returns nested list[table][row][cell]of text.extract_table()— returns[row][cell]text for the largest table.
Example usage:
all_tables = page.extract_tables()
largest_table_data = page.extract_table()
import pandas as pd
headers = largest_table_data[0]
rows_data = largest_table_data[1:]
df = pd.DataFrame(rows_data, columns=headers)
print(df.head())
Visual Debugging and Image Handling
The .to_image() method creates a PageImage instance, configurable with resolution, width, height, and antialias.
# Render with higher resolution and anti-aliasing
rendered = page.to_image(resolution=150, antialias=True)
To handle embedded images, access the .images property of a page. Each entry contains position and size information. Crop the page to an image's bounding box, then render and save:
embedded_img = page.images[0]
bbox = (embedded_img["x0"], embedded_img["top"], embedded_img["x1"], embedded_img["bottom"])
cropped = page.crop(bbox)
final_image = cropped.to_image(antialias=True)
final_image.save("extracted_figure.png")
Page cropping and filtering methods (crop, within_bbox, outside_bbox, filter) enable precise content selection before extraction.
Module Organization
The translator is organized into distinct Python modules:
- reader: wraps
pdfplumberfor text and table extraction. - translator: encapsulates API communication with OpenAI and ChatGLM.
- config: handles YAML and CLI parsing.
- pipeline: orchestrates reading, splitting, translating, and output assembly.
This separation enables independent testing and straightforward extension with new backends or output formats.