基于大模型 Prompt + LangChain 架构的 AI 翻译系统全流程解析(二)系统设计- UML类图、 技术要点

二、系统设计- UML类图

为了更直观地展示文档翻译系统的类关系,以下是该系统的UML类图:

在这个类图中:

  • PDFTranslator 使用 PDFParser 解析 PDF 文件。

  • PDFTranslator 使用 TranslationChain 进行翻译。

  • PDFTranslator 使用 Writer 保存翻译后的文档。

  • Writer 使用 Book 类来组织文档内容。

  • Book 类包含多个 Page 对象。

  • Page 类包含多个 Content 对象。

  • Content 类使用 ContentType 枚举和 TableContent 类来表示不同类型的内容。

三、 技术要点

3.1 大模型的应用

利用大型语言模型进行自然语言处理和翻译是该方案的核心。GPT等大模型通过大量的语料训练,能够理解并生成高质量的翻译文本。通过LangChain框架接手大模型的管理,系统能够更加高效地与大模型进行交互,开发者也能专注于Prompt的优化和设计。

3.2 模块化设计

系统采用模块化设计,各个模块职责明确,便于维护和扩展。例如,PDFParser负责解析文档,Writer负责输出结果,Logger负责记录日志。这种设计方式提高了系统的可维护性和可扩展性。

import yaml

class TranslationConfig:
    _instance = None
    
    def __new__(cls):
        """
        实现单例模式的构造方法。
        返回:
            TranslationConfig的单例实例。
        """
        if cls._instance is None:
            cls._instance = super(TranslationConfig, cls).__new__(cls)
            cls._instance._config = None
        return cls._instance
    
    def initialize(self, args):
        """
        初始化配置,读取配置文件并允许通过命令行参数覆盖配置。
        参数:
            args: 包含配置文件路径的命名空间(argparse的返回值)。
        """
        with open(args.config_file, "r") as f:
            config = yaml.safe_load(f)

        # 使用命令行参数覆盖配置文件中的值
        overridden_values = {
            key: value for key, value in vars(args).items() if key in config and value is not None
        }
        config.update(overridden_values)    
        
        # 存储原始配置字典
        self._instance._config = config

    def __getattr__(self, name):
        """
        重写getattr方法,从配置字典中获取属性值。
        参数:
            name: 尝试获取的属性名。
        返回:
            如果属性存在于配置字典中,则返回其值;否则抛出AttributeError。
        """
        # 尝试从_config中获取属性
        if self._instance._config and name in self._instance._config:
            return self._instance._config[name]
        raise AttributeError(f"'TranslationConfig' object has no attribute '{name}'")
from typing import Optional
from translator.pdf_parser import PDFParser
from translator.writer import Writer
from translator.translation_chain import TranslationChain
from utils import LOG

class PDFTranslator:
    """
    PDFTranslator类用于将PDF文档从一种语言翻译成另一种语言。
    
    参数:
    - model_name: str,翻译模型的名称。
    """
    def __init__(self, model_name: str):
        """
        初始化PDFTranslator实例。
        
        参数:
        - model_name: str,翻译模型的名称。
        """
        self.translate_chain = TranslationChain(model_name)  # 创建翻译链实例
        self.pdf_parser = PDFParser()  # 创建PDF解析器实例
        self.writer = Writer()  # 创建写入器实例

    def translate_pdf(self,
                    input_file: str,
                    output_file_format: str = 'markdown',
                    source_language: str = "English",
                    target_language: str = 'Chinese',
                    pages: Optional[int] = None):
        """
        翻译PDF文档并将其保存为指定格式的文件。
        
        参数:
        - input_file: str,输入的PDF文件路径。
        - output_file_format: str,输出文件的格式,默认为'markdown'。
        - source_language: str,源语言,默认为'English'。
        - target_language: str,目标语言,默认为'Chinese'。
        - pages: Optional[int],要翻译的PDF页面范围,可以是单个页面或页面范围,None表示所有页面。
        
        返回:
        - str,翻译后文件的保存路径。
        """
        
        self.book = self.pdf_parser.parse_pdf(input_file, pages)  # 解析PDF文档

        # 遍历并翻译每一页的内容
        for page_idx, page in enumerate(self.book.pages):
            for content_idx, content in enumerate(page.contents):
                # 对内容进行翻译
                translation, status = self.translate_chain.run(content, source_language, target_language)
                # 将翻译结果直接更新到页面内容中
                self.book.pages[page_idx].contents[content_idx].set_translation(translation, status)
        
        return self.writer.save_translated_book(self.book, output_file_format)  # 保存翻译后的文档
import pdfplumber
from typing import Optional
from book import Book, Page, Content, ContentType, TableContent
from translator.exceptions import PageOutOfRangeException
from utils import LOG


class PDFParser:
    """
    PDF解析器类,用于解析PDF文件并提取文本和表格内容。
    """

    def __init__(self):
        """
        初始化PDF解析器。
        """
        pass

    def parse_pdf(self, pdf_file_path: str, pages: Optional[int] = None) -> Book:
        """
        解析PDF文件,提取每页的文本和表格内容。

        参数:
        - pdf_file_path: str,PDF文件的路径。
        - pages: Optional[int],要解析的页面数,若为None则解析所有页面。

        返回:
        - Book,包含解析得到的文本和表格内容的书对象。
        """
        book = Book(pdf_file_path)

        with pdfplumber.open(pdf_file_path) as pdf:
            # 检查指定页面范围是否超出PDF实际页面数
            if pages is not None and pages > len(pdf.pages):
                raise PageOutOfRangeException(len(pdf.pages), pages)

            # 根据是否指定了页面数,确定要解析的页面范围
            if pages is None:
                pages_to_parse = pdf.pages
            else:
                pages_to_parse = pdf.pages[:pages]

            for pdf_page in pages_to_parse:
                page = Page()

                # 提取原始文本内容和表格
                raw_text = pdf_page.extract_text()
                tables = pdf_page.extract_tables()

                # 从原始文本中移除表格内容
                for table_data in tables:
                    for row in table_data:
                        for cell in row:
                            raw_text = raw_text.replace(cell, "", 1)

                # 处理文本内容
                if raw_text:
                    # 清理文本,移除空行和首尾空白字符
                    raw_text_lines = raw_text.splitlines()
                    cleaned_raw_text_lines = [line.strip() for line in raw_text_lines if line.strip()]
                    cleaned_raw_text = "\n".join(cleaned_raw_text_lines)

                    text_content = Content(content_type=ContentType.TEXT, original=cleaned_raw_text)
                    page.add_content(text_content)
                    LOG.debug(f"[raw_text]\n {cleaned_raw_text}")

                # 处理表格内容
                if tables:
                    table = TableContent(tables)
                    page.add_content(table)
                    LOG.debug(f"[table]\n{table}")

                book.add_page(page)

        return book
import os
from reportlab.lib import colors, pagesizes, units
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak
)

from book import Book, ContentType
from utils import LOG

class Writer:
    """
    Writer类用于将书籍内容导出为不同格式的文件,目前支持PDF和Markdown格式。
    """
    def __init__(self):
        pass

    def save_translated_book(self, book: Book, ouput_file_format: str):
        """
        根据指定的输出文件格式,保存翻译后的书籍内容。
        
        :param book: 书籍对象,包含翻译后的内容。
        :param ouput_file_format: 输出文件格式,支持"pdf"和"markdown"。
        :return: 保存成功则返回输出文件路径,否则返回空字符串。
        """
        LOG.debug(ouput_file_format)

        if ouput_file_format.lower() == "pdf":
            output_file_path = self._save_translated_book_pdf(book)
        elif ouput_file_format.lower() == "markdown":
            output_file_path = self._save_translated_book_markdown(book)
        else:
            LOG.error(f"不支持文件类型: {ouput_file_format}")
            return ""

        LOG.info(f"翻译完成,文件保存至: {output_file_path}")

        return output_file_path


    def _save_translated_book_pdf(self, book: Book, output_file_path: str = None):
        """
        将翻译后的书籍内容导出为PDF文件。
        
        :param book: 书籍对象,包含翻译后的内容。
        :param output_file_path: 输出PDF文件路径,默认为None,如果为None则自动生成。
        :return: 输出PDF文件的路径。
        """
        
        output_file_path = book.pdf_file_path.replace('.pdf', f'_translated.pdf')

        LOG.info(f"开始导出: {output_file_path}")

        # 注册中文字体
        font_path = "../fonts/simsun.ttc"  # 字体文件路径,请根据实际情况修改
        pdfmetrics.registerFont(TTFont("SimSun", font_path))

        # 创建PDF文档样式
        simsun_style = ParagraphStyle('SimSun', fontName='SimSun', fontSize=12, leading=14)

        # 创建PDF文档
        doc = SimpleDocTemplate(output_file_path, pagesize=pagesizes.letter)
        styles = getSampleStyleSheet()
        story = []

        # 遍历页面和内容,将翻译后的内容添加到PDF中
        for page in book.pages:
            for content in page.contents:
                if content.status:
                    if content.content_type == ContentType.TEXT:
                        # 添加翻译的文本到PDF
                        text = content.translation
                        para = Paragraph(text, simsun_style)
                        story.append(para)

                    elif content.content_type == ContentType.TABLE:
                        # 添加表格到PDF
                        table = content.translation
                        table_style = TableStyle([
                            ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
                            ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
                            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
                            ('FONTNAME', (0, 0), (-1, 0), 'SimSun'),  # 表头字体设置为 "SimSun"
                            ('FONTSIZE', (0, 0), (-1, 0), 14),
                            ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
                            ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
                            ('FONTNAME', (0, 1), (-1, -1), 'SimSun'),  # 表格中的字体设置为 "SimSun"
                            ('GRID', (0, 0), (-1, -1), 1, colors.black)
                        ])
                        pdf_table = Table(table.values.tolist())
                        pdf_table.setStyle(table_style)
                        story.append(pdf_table)
            # 在每个页面后添加分页符,除了最后一页
            if page != book.pages[-1]:
                story.append(PageBreak())

        # 生成并保存PDF文件
        doc.build(story)
        return output_file_path


    def _save_translated_book_markdown(self, book: Book, output_file_path: str = None):
        """
        将翻译后的书籍内容导出为Markdown文件。
        
        :param book: 书籍对象,包含翻译后的内容。
        :param output_file_path: 输出Markdown文件路径,默认为None,如果为None则自动生成。
        :return: 输出Markdown文件的路径。
        """
        
        output_file_path = book.pdf_file_path.replace('.pdf', f'_translated.md')

        LOG.info(f"开始导出: {output_file_path}")
        with open(output_file_path, 'w', encoding='utf-8') as output_file:
            # 遍历页面和内容,将翻译后的内容添加到Markdown文件中
            for page in book.pages:
                for content in page.contents:
                    if content.status:
                        if content.content_type == ContentType.TEXT:
                            # 添加翻译的文本到Markdown文件
                            text = content.translation
                            output_file.write(text + '\n\n')

                        elif content.content_type == ContentType.TABLE:
                            # 添加表格到Markdown文件
                            table = content.translation
                            header = '| ' + ' | '.join(str(column) for column in table.columns) + ' |' + '\n'
                            separator = '| ' + ' | '.join(['---'] * len(table.columns)) + ' |' + '\n'
                            body = '\n'.join(['| ' + ' | '.join(str(cell) for cell in row) + ' |' for row in table.values.tolist()]) + '\n\n'
                            output_file.write(header + separator + body)

                # 在每个页面后添加分页符(水平线),除了最后一页
                if page != book.pages[-1]:
                    output_file.write('---\n\n')

        return output_file_path

3.3 灵活的Prompt模板

PromptTemplate模块的设计使得系统能够根据不同的翻译任务生成相应的Prompt,提高了翻译的灵活性和适用性。通过动态调整Prompt,可以满足用户的个性化翻译需求。

3.4 TranslationChain

通过TranslationChain,实现了翻译接口的简洁化和统一化配置管理。TranslationChain提供了标准化的接口,用户可以方便地进行配置和调用,简化了翻译流程的管理和维护。


from langchain.chains import LLMChain
from langchain.chat_models import ChatOpenAI #直接访问OpenAI的GPT服务
import os
# 加载 .env 文件
from dotenv import load_dotenv, find_dotenv
import openai
from langchain.prompts.chat import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
)
from utils import LOG

class TranslationChain:
    """
    TranslationChain 类用于创建和管理一个语言翻译链。
    
    参数:
    - model_name: str, 指定用于翻译的 OpenAI 模型名称,默认为 "gpt-3.5-turbo"。
    - verbose: bool, 是否在执行过程中输出详细信息,默认为 True。
    """
    
    def __init__(self, model_name: str = "gpt-3.5-turbo", verbose: bool = True):
        
        # 从环境变量中加载 OpenAI 的 API Key 和 URL
        load_dotenv(find_dotenv())
        openai.api_key = os.getenv('OPENAI_API_KEY')
        openai.api_base = os.getenv('OPENAI_API_URL')
        model = os.getenv('OPENAI_API_MODEL')

        # 初始化翻译任务的 ChatPromptTemplate,定义系统和用户之间的对话模式
        template = (
            """You are a translation expert, proficient in various languages. \n
            Translates {source_language} to {target_language}."""
        )
        system_message_prompt = SystemMessagePromptTemplate.from_template(template)

        # 初始化待翻译文本的提示模板,由用户输入
        human_template = "{text}"
        human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)

        # 将系统和用户提示模板组合成完整的 ChatPromptTemplate
        chat_prompt_template = ChatPromptTemplate.from_messages(
            [system_message_prompt, human_message_prompt]
        )

        # 初始化 ChatOpenAI 对象,用于实际的翻译任务执行,设置 temperature 为 0 以确保结果稳定性
        chat = ChatOpenAI(model_name=model_name, temperature=0, verbose=verbose)

        # 创建 LLMChain 对象,将聊天模型和提示模板封装起来,用于实际的对话流程执行
        self.chain = LLMChain(llm=chat, prompt=chat_prompt_template, verbose=verbose)

    def run(self, text: str, source_language: str, target_language: str) -> (str, bool): # type: ignore
        """
        执行翻译任务。
        
        参数:
        - text: str, 待翻译的文本。
        - source_language: str, 源语言代码。
        - target_language: str, 目标语言代码。
        
        返回:
        - result: str, 翻译后的文本。
        - success: bool, 任务执行是否成功。
        """
        result = ""
        try:
            # 执行翻译流程
            result = self.chain.run({
                "text": text,
                "source_language": source_language,
                "target_language": target_language,
            })
        except Exception as e:
            # 记录翻译过程中出现的异常
            LOG.error(f"An error occurred during translation: {e}")
            return result, False

        # 正常完成翻译,返回结果
        return result, True

3.5 自动化处理

整个翻译过程高度自动化,从文档加载、解析、翻译到输出,减少了人工干预,提高了翻译效率。用户只需提供待翻译的文档和基本参数,系统便能自动完成翻译任务。

3.6 Gradio图形化界面

为了提升用户体验,文档翻译系统的功能特性研发基于Gradio的图形化界面设计。用户可以通过直观的图形界面进行操作,轻松完成文档加载、翻译设置和结果输出等一系列操作,大幅提升了系统的易用性和用户友好性。


import sys
import os
import gradio as gr

sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from utils import ArgumentParser, LOG
from translator import PDFTranslator, TranslationConfig


def translation(input_file, source_language, target_language):
    """
    将PDF文件从源语言翻译成目标语言。
    
    参数:
    - input_file: 包含待翻译PDF的文件对象。
    - source_language: 源语言代码(字符串)。
    - target_language: 目标语言代码(字符串)。
    
    返回:
    - 翻译后PDF文件的路径(字符串)。
    """
    # 记录翻译任务的开始,包括输入文件和语言信息
    LOG.debug(f"[翻译任务]\n源文件: {input_file.name}\n源语言: {source_language}\n目标语言: {target_language}")
    
    # 调用Translator类的translate_pdf方法进行翻译,并获取翻译后的文件路径
    output_file_path = Translator.translate_pdf(
        input_file.name, source_language=source_language, target_language=target_language)

    return output_file_path

def launch_gradio():
    """
    启动Gradio界面,提供用户友好的翻译服务界面。
    """
    # 创建Gradio界面,设置功能描述、界面元素和输出
    iface = gr.Interface(
        fn=translation,
        title="智能体AI-Translator(PDF 电子书翻译工具)",
        inputs=[            
            gr.File(label="上传PDF文件"),
            gr.Textbox(label="源语言(默认:英文)", placeholder="English", value="English"),
            gr.Textbox(label="目标语言(默认:中文)", placeholder="Chinese", value="Chinese")
        ],
        outputs=[            
            gr.File(label="下载翻译文件")
        ],
        allow_flagging="never"
    )

    # 启动Gradio界面,设置为分享模式,并指定服务器地址
    iface.launch(share=True, server_name="0.0.0.0")

def initialize_translator():
    """
    初始化翻译器,包括解析命令行参数和配置翻译模型。
    """
    # 解析启动参数
    argument_parser = ArgumentParser()
    args = argument_parser.parse_arguments()
    
    # 初始化翻译配置
    config = TranslationConfig()
    config.initialize(args)    
    # 实例化PDF翻译器,并准备进行翻译
    global Translator
    Translator = PDFTranslator(config.model_name)


if __name__ == "__main__":
    # 初始化翻译器实例
    initialize_translator()
    # 启动Gradio翻译服务界面
    launch_gradio()

四、应用场景

4.1 跨语言文档翻译

该系统适用于需要将大批量文档从一种语言翻译成另一种语言的场景。例如企业内部文件翻译、学术论文翻译等。通过大模型的智能化处理,能够在保证翻译质量的同时大幅提升效率。

4.2 动态格式转换

系统支持多种文件格式的输入和输出,能够根据用户需求动态调整,适应不同的文档处理要求。例如,用户可以输入PDF文件,输出翻译后的Word文档,满足不同场景下的文档格式需求。

4.3 智能文档处理

结合大模型的智能化处理能力,系统不仅限于简单翻译,还可以进行语义理解、内容提取等高级处理。例如,在翻译过程中识别并保留文档的格式和结构,提高翻译结果的可读性和一致性。

五、 总结

基于大模型和LangChain的文档翻译技术方案,通过模块化设计、灵活的Prompt模板、TranslationChain和自动化处理,实现了高效、准确的跨语言文档翻译。该方案不仅适用于企业内部文件翻译、学术论文翻译等大批量文档处理场景,还支持多种文件格式的动态转换,适应不同的文档处理需求。通过Gradio图形化界面的设计,进一步提升了用户体验,使得文档翻译过程更加直观、便捷。


最后分享

AI大模型作为人工智能领域的重要技术突破,正成为推动各行各业创新和转型的关键力量。抓住AI大模型的风口,掌握AI大模型的知识和技能将变得越来越重要。

学习AI大模型是一个系统的过程,需要从基础开始,逐步深入到更高级的技术。

这里给大家精心整理了一份全面的AI大模型学习资源,包括:AI大模型全套学习路线图(从入门到实战)、精品AI大模型学习书籍手册、视频教程、实战学习、面试题等,资料免费分享!

1. 成长路线图&学习规划

要学习一门新的技术,作为新手一定要先学习成长路线图方向不对,努力白费

这里,我们为新手和想要进一步提升的专业人士准备了一份详细的学习成长路线图和规划。可以说是最科学最系统的学习成长路线。
在这里插入图片描述

2. 大模型经典PDF书籍

书籍和学习文档资料是学习大模型过程中必不可少的,我们精选了一系列深入探讨大模型技术的书籍和学习文档,它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础。(书籍含电子版PDF)

在这里插入图片描述

3. 大模型视频教程

对于很多自学或者没有基础的同学来说,书籍这些纯文字类的学习教材会觉得比较晦涩难以理解,因此,我们提供了丰富的大模型视频教程,以动态、形象的方式展示技术概念,帮助你更快、更轻松地掌握核心知识

在这里插入图片描述

4. 大模型项目实战

学以致用 ,当你的理论知识积累到一定程度,就需要通过项目实战,在实际操作中检验和巩固你所学到的知识,同时为你找工作和职业发展打下坚实的基础。

在这里插入图片描述

5. 大模型面试题

面试,不仅是技术的较量,更需要充分的准备。在你已经掌握了大模型技术之后,就需要开始准备面试,我们将提供精心整理的大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。

在这里插入图片描述

全套的AI大模型学习资源已经整理打包,有需要的小伙伴可以微信扫描下方CSDN官方认证二维码,免费领取【保证100%免费


如有侵权,请联系删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值