python - Gemini を使用した自動翻訳ツール

webベースの自動翻訳ツールにおいてコピペの手間を省く

  • 論文翻訳時にpdfから 日本訳pdfを直接生成するツール を作成

  • 現在版は、 Gemini を使用.

    • エンジン部分でGeminiを使用

    • そのうち拡張予定.

制約

  • ネットへの接続が必要.

    • ただし、今のところ、公共無線LANから接続している(IPが都度変わる)からか、制約をくらったことはない.


使用方法 (1例)

  • pathが通る場所 ( e.g. /usr/local/bin/ ) に translator__usingGemini.py を置いておく.

  • importする他のコード( nkTextProcess.convert__text2pdf.py, nkTextProcess.extract__textFromPDF.py ) はpython path の通ったところにおいておく( nkTextProcess )、もしくは、同一ファイル内に入れておく.

  • 実行権限を付与しておく

    • $ sudo chmod +x translator__usingGemini.py をしておく

    • shebang ( = pythonファイルの先頭のおまじない) はすでに設定.適宜変更.

実行コマンド

$ translator__usingGemini.py --input_pdf pdf/sample.pdf

$ translator__usingGemini.py --input_pdf pdf/sample.pdf --output_pdf pdf/output.pdf --english_text text_en.txt --japanese_text text_ja.txt --intermediate True --fontsize 8.0 --show True

コード

github

$ git clone https://github.com/wfw-pgr/nkTextProcess.git

nkTextProcess 参照ver.

translator__usingGemini.py

#!/usr/bin/env python3
import os, sys, re
import google.generativeai as genai
import nkTextProcess.extract__textFromPDF as etp
import nkTextProcess.convert__text2pdf    as t2p

# ========================================================= #
# ===  translator__usingGemini.py                       === #
# ========================================================= #

def translator__usingGemini( text_en=None, input_pdfFile=None, output_pdfFile=None, \
                             input_txtFile=None, \
                             english_txtFile=None, japanese_txtFile=None, chunksize=800, \
                             fontsize=9.0, silent=True ):

    # ------------------------------------------------- #
    # --- [1] load text from pdf                    --- #
    # ------------------------------------------------- #
    if ( input_pdfFile is not None ):
        if ( output_pdfFile is     None ):
            output_pdfFile = input_pdfFile.replace( ".pdf", "_ja.pdf" )
        text_en  = etp.extract__textFromPDF( inpFile=input_pdfFile, outFile=english_txtFile, \
                                             remove_return=True )
        
    # ------------------------------------------------- #
    # --- [2] load text from text file              --- #
    # ------------------------------------------------- #
    if ( input_txtFile is not None ):
        # -- read file -- #
        with open( input_txtFile, "r" ) as f:
            text  = f.read()
        text      = " ".join( text.split() )
        sentences = re.split( r"(?<=[.!?])\s+", text )
        
        # -- chunking -- #
        text_en, stack = [], []
        count          =  0
        for sentence in sentences:
            stack += [ sentence ]
            count += len( sentence.split() )
            if ( ( count > chunksize ) and ( count > 0 ) ):
                text_en += [ " ".join( stack ) ]
                stack    = []
                count    = 0
        if ( len( stack ) > 0 ):
            text_en += [ " ".join( stack ) ]

        # -- output pdf name -- #
        if ( output_pdfFile is None ):
            base_name, extension = os.path.splitext( input_txtFile )
            output_pdfFile       = base_name + "_ja.pdf"

    if ( text_en is None ):
        sys.exit( " text_en == ???, input_pdf / input_txt must be given" )
            
    # ------------------------------------------------- #
    # --- [3] prepare gemini                        --- #
    # ------------------------------------------------- #
    #  -- Gemini APIの設定                          --  #
    #  -- export GEMINI_API_KEY="api key"           --  #
    my_api_key = os.environ.get( "GEMINI_API_KEY" )
    genai.configure( api_key=my_api_key )
    # model      = genai.GenerativeModel('gemini-pro')
    model      = genai.GenerativeModel()
    # prompt     = f"以下の英語論文の文章を日本語訳してください.pdfから抜き出した文字列のため、ページ番号や図のキャプションが途中に混じっている場合があります.それらは、適宜、無視するなどし、本文として一連の意味が通じるように翻訳してください.:\n\n{stack_en}"

    # ------------------------------------------------- #
    # --- [4] translator into japanese              --- #
    # ------------------------------------------------- #
    text_stack = []
    print( len( text_en ) )
    for ik,piece in enumerate( text_en ):
        prompt     = f"以下の英語論文の文章を日本語訳してください.pdfから抜き出した文字列のため、ページ番号や図のキャプションが途中に混じっている場合があります.それらは、適宜、無視するなどし、本文として一連の意味が通じるように翻訳してください.:\n\n{piece}"
        response    = model.generate_content( prompt )
        piece_ja    = response.text
        text_stack += [ piece_ja ]
    text_ja = " ".join( text_stack )
    
    # ------------------------------------------------- #
    # --- [5] save in a file                        --- #
    # ------------------------------------------------- #
    if ( not( silent ) ):
        print( "\n" + "-"*70 +"\n"  )
        print( text_ja )
        print( "\n" + "-"*70 +"\n"  )
        
    if ( japanese_txtFile is not None ):
        with open( japanese_txtFile, "w" ) as f:
            f.write( text_ja )

    # ------------------------------------------------- #
    # --- [5] convert into japanese pdf             --- #
    # ------------------------------------------------- #
    t2p.convert__text2pdf( outFile=output_pdfFile, texts=text_stack, fontsize=fontsize )
    
    # ------------------------------------------------- #
    # --- [6] return                                --- #
    # ------------------------------------------------- #
    return( text_ja )


# ========================================================= #
# ===   Execution of Pragram                            === #
# ========================================================= #

if ( __name__=="__main__" ):

    # ------------------------------------------------- #
    # --- [1] arguments                             --- #
    # ------------------------------------------------- #
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument( "--input_pdf"     , default=None, help="input pdf file"     )
    parser.add_argument( "--input_txt"     , default=None, help="input text file"    )
    parser.add_argument( "--output_pdf"    , default=None, help="output pdf file"    )
    parser.add_argument( "--chunksize"     , default= 800, help="text chunk size"    )
    parser.add_argument( "--english_text"  , default=None, help="english_text_file"  )
    parser.add_argument( "--japanese_text" , default=None, help="japanese_text_file" )
    parser.add_argument( "--fontsize"      , type=float, default=9.0, help="font size"        )
    parser.add_argument( "--show"          , type=bool , default=False, help="display or not" )
    parser.add_argument( "--intermediate"  , type=bool , default=False, help="intermidiate file out" )
    
    args   = parser.parse_args()

    if   ( args.input_pdf ):
        input_file = str( args.input_pdf )
    elif ( args.input_txt ):
        input_file = str( args.input_txt )
    else:
        print( "[ How to use ] python translator__usingGemini.py --input_pdf xxx.pdf " )
        sys.exit()
        
    if ( args.intermediate ):
        if ( args.english_text  is None ): args.english_text  = "text_en.txt"
        if ( args.japanese_text is None ): args.japanese_text = "text_ja.txt"

    # ------------------------------------------------- #
    # --- [2] call translator                       --- #
    # ------------------------------------------------- #
    print( "[translator__usingGemini.py] translation of {}".format( input_file ) )
    translator__usingGemini( input_pdfFile=args.input_pdf, output_pdfFile=args.output_pdf, \
                             input_txtFile=args.input_txt, chunksize=args.chunksize, \
                             english_txtFile=args.english_text, \
                             japanese_txtFile=args.japanese_text,\
                             fontsize=args.fontsize, silent=not( args.show ) )