Building a PDF Translation Pipeline with LangChain and Gradio

Core Concepts: Chat Models and Role-Based Prompting

LangChain's ChatModel abstraction extends beyond conversational interfaces by natively supporting multi-role message structures. Unlike standard text-completion models, chat architectures process structured sequences containing distinct roles such as System, Human, AI, and Tool. Managing these sequences manually becomes cumbersome as applications scale, which is where ChatPromptTemplate provides a robust abstraction. It allows developers to define, version, and inject variables into structured message templates efficiently.

To illustrate, initializing a chat-based language model requires defining the message history explicitly:

from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage, SystemMessage

inference_engine = ChatOpenAI(model="gpt-3.5-turbo")
conversation_history = [
    SystemMessage(content="Act as a technical consultant."),
    HumanMessage(content="Explain the difference between SQL and NoSQL."),
]
inference_engine(conversation_history)

Constructing Translation Prompts

For automated translation workflows, structuring the prompt with explicit system directives and user inputs ensures consistent behavior. The ChatPromptTemplate.from_messages method streamlines this by combining role-specific templates into a single executable object.

Define the system instruction to establish the assistant's persona:

from langchain.prompts.chat import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
    SystemMessagePromptTemplate,
)

role_definition = """You are a linguistic specialist capable of accurate, context-aware translation.
Convert the provided text from English to Chinese while preserving technical terminology."""
sys_template = SystemMessagePromptTemplate.from_template(role_definition)

Capture the user's raw text input:

input_template = "{input_text}"
user_template = HumanMessagePromptTemplate.from_template(input_template)

Combine these components into a unified template:

translation_prompt = ChatPromptTemplate.from_messages([sys_template, user_template])

Render the template and pass it to the model:

formatted_messages = translation_prompt.format_prompt(input_text="I love programming.").to_messages()

Execute the translation with deterministic output settings:

translation_llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
result = translation_llm(formatted_messages)

Streamlining with LLM Chains

Repeatedly calling format_prompt() and to_messages() adds unnecessary boilerplate. LangChain's LLMChain abstracts this pipeline, directly mapping input dictionaries to model responses.

from langchain.chains import LLMChain

streamlined_chain = LLMChain(llm=translation_llm, prompt=translation_prompt)
translated_output = streamlined_chain.run({"input_text": "I love programming."})

Supporting Dynamic Language Pairs

Hardcoding language constraints limits flexibility. By parameterizing both the source and target languages within the system template, the chain becomes adaptable to any translation requirement.

dynamic_system_template = """You are a professional translator.
Translate the following content from {source_lang} to {target_lang}."""

dynamic_sys_prompt = SystemMessagePromptTemplate.from_template(dynamic_system_template)
dynamic_user_prompt = HumanMessagePromptTemplate.from_template("{content_to_translate}")

flexible_prompt = ChatPromptTemplate.from_messages([dynamic_sys_prompt, dynamic_user_prompt])
multi_lang_chain = LLMChain(llm=translation_llm, prompt=flexible_prompt)

Architecture v2.0: Integrating a Gradio Interface

To operationalize this pipeline for PDF processing, a web interface bridges user interaction with backend translation logic. The following implementation sets up a Gradio applicasion that handles file uploads, invokes the translation engine, and returns the processed document.

import os
import sys
import gradio as gr

# Adjust path to include local modules
project_root = os.path.dirname(os.path.abspath(__file__))
if project_root not in sys.path:
    sys.path.append(project_root)

from configuration import ArgumentParser, Logger
from engine import PDFProcessor, AppSettings

def process_document(file_obj, src_lang, tgt_lang):
    Logger.info(f"Initiating translation: {file_obj.name} | {src_lang} -> {tgt_lang}")
    output_path = document_engine.convert_pdf(
        file_path=file_obj.name,
        origin_language=src_lang,
        destination_language=tgt_lang
    )
    return output_path

def start_web_interface():
    app = gr.Interface(
        fn=process_document,
        title="LangChain PDF Translator",
        description="Upload a document to generate a translated version using LLM-powered chains.",
        inputs=[
            gr.File(file_types=[".pdf"], label="Upload Source PDF"),
            gr.Textbox(value="English", label="Source Language"),
            gr.Textbox(value="Chinese", label="Target Language"),
        ],
        outputs=[
            gr.File(label="Download Translated PDF")
        ],
        allow_flagging="never"
    )
    app.launch(share=True, server_name="0.0.0.0")

def bootstrap():
    parser = ArgumentParser()
    cli_args = parser.get_arguments()
    
    global document_engine
    settings = AppSettings()
    settings.load_config(cli_args)
    document_engine = PDFProcessor(model_identifier=settings.active_model)

if __name__ == "__main__":
    bootstrap()
    start_web_interface()

Tags: LangChain Gradio llm-applications pdf-translation python

Posted on Sun, 13 Sep 2026 16:18:29 +0000 by john-iom