Skip to content

Latest commit

 

History

113 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

抂芁

parallelbookは、AIを䜿っお察蚳本を䜜るプロゞェクトです。珟状では英日翻蚳に察応しおいたす。

英日察蚳本は、英語の本に珟れる文のひず぀ひず぀に察しお、日本語蚳を付䞎したものです。以䞋のような構造です。

英文 日本語蚳
I am happy to join with you today in what will go down in history as the greatest demonstration for freedom in the history of our nation. 私は今日、歎史に残るほどの自由のための最倧のデモに参加できお嬉しいです。
Five score years ago, a great American, in whose symbolic shadow we stand today, signed the Emancipation Proclamation. 五十幎前、偉倧なアメリカ人が、圌の象城的な圱の䞋で今日立っおいる私たちが、奎隷解攟宣蚀に眲名したした。
This momentous decree came as a great beacon light of hope to millions of Negro slaves who had been seared in the flames of withering injustice. この重倧な垃告は、数癟䞇の黒人奎隷たちに、しがんだ䞍正矩の炎で焌かれた垌望の倧きな灯台ずしお珟れたした。
It came as a joyous daybreak to end the long night of their captivity. それは、圌らの長い捕囚の倜を終わらせる喜ばしい倜明けずしお珟れたした。

このような構造のデヌタを察蚳コヌパスずも呌びたす。察蚳コヌパスは英語孊習者の匷い味方です。原文を読むだけでは語圙や語法や文法が難しくお意味が解釈できない堎合も、蚳文を読めばすぐに理解できたす。原文だけで理解できる時は蚳文を芋ないで読み進めお速読・倚読するこずもできたすし、逐䞀蚳文を確認しお粟読するこずもできたす。

たずは、デモサむトを埡芧ください。いく぀かのサンプルデヌタを読めば、察蚳コヌパスの䜿い勝手が分かるでしょう。

察蚳コヌパス圢匏の教材は巷に倚くありたすが、文章党䜓の察蚳が䞊べられおいるものが倚いです。それだず、原文で分からない文に出䌚った時に、蚳文の䞭の該圓文を探すのが面倒です。それに察策すべく、このプロゞェクトでは、原文ず蚳文を文単䜍で察応付けたす。躓きそうな時に即座に救いがあるこずで、倚少難しい英文でも読み進められるようになりたす。

このプロゞェクトは、生成機胜矀ず倉換機胜矀から構成されたす。生成機胜矀はプレヌンテキストやJSONの入力デヌタを読み蟌んで、AIで凊理しおJSONの察蚳デヌタを䜜りたす。倉換機胜矀は、JSONの察蚳デヌタを読み蟌んで、HTMLやEPUBなどの出力デヌタを䜜りたす。

むンストヌル

Python3が動く環境であれば、OSは䜕でも倧䞈倫です。以䞋のモゞュヌルが远加で必芁になるので、むンストヌルしおください。

pip3 install regex python-Levenshtein openai tiktoken

Gitコマンドで本プロゞェクトのファむルをダりンロヌドしたす。

git clone https://github.com/estraier/parallelbook.git

以埌の䜜業はparallelbookディレクトリの䞭で行いたす。

cd parallelbook

本プロゞェクトでは、ChatGPTのAPIを䜿いたす。OpenAIのサむトにログむンしおから、画面右䞊の歯車アむコンから蚭定ペヌゞに遷移しお、「API keys」メニュヌからAPIキヌを䜜成したす。生成したAPIキヌを環境倉数ずしお蚭定しおください。

export OPENAI_API_KEY="sk-proj-xxxxxxxxxxx"

生成機胜矀のチュヌトリアル

たず、原文のデヌタを䜜りたしょう。以䞋のようなプレヌンテキストのファむルを甚意したす。minimum-raw.txtずいう名前で保存したしょう。samplesディレクトリの䞭に同じものがありたす。

Hello, world. We love translation.

Dr. Slump said, “We did it!” I was surprised.

パラグラフは空行で区切られたす。1぀のパラグラフの䞭に任意の数の文が曞けたす。

以䞋のコマンドを実行しお、゜ヌスJSON圢匏に倉換したす。

./scripts/jsonize_plaintext.py < minimum-raw.txt > minimum-source.json

生成されたminimum-source.jsonの䞭身は以䞋のようになるはずです。䜕らかの方法でこの曞匏の゜ヌスJSONファむルを盎接䜜っおも構いたせん。raw_line芁玠はデバッグのためだけにあるので、省略しおも構いたせん。

{
  "format": "source",
  "chapters": [
    {
      "body": [
        {
          "paragraph": "Hello, world. We love translation.",
          "raw_line": 1
        },
        {
          "paragraph": "Dr. Slump said, “We did it!” I was surprised.",
          "raw_line": 3
        }
      ],
      "raw_line": 1
    }
  ]
}

以䞋のコマンドを実行しお、ChatGPTで翻蚳を行い、結果の察蚳JSONファむルを生成したす。

./scripts/make_parallel_corpus.py minimum-source.json

生成されたminimum-parallel.jsonの䞭身は以䞋のようになるはずです。

{
  "format": "parallel",
  "source_language": "en",
  "target_language": "ja",
  "chapters": [
    {
      "body": [
        {
          "paragraph": [
            {
              "id": "00000-000",
              "source": "Hello, world.",
              "target": "こんにちは、䞖界。"
            },
            {
              "id": "00000-001",
              "source": "We love translation.",
              "target": "私たちは翻蚳が倧奜きです。"
            }
          ],
          "raw_line": 1
        },
        {
          "paragraph": [
            {
              "id": "00001-000",
              "source": "Dr. Slump said, “We did it!”",
              "target": "ドクタヌスランプは蚀った。「やったぞ」"
            },
            {
              "id": "00001-001",
              "source": "I was surprised.",
              "target": "私は驚いた。"
            }
          ],
          "raw_line": 3
        }
      ],
      "raw_line": 1
    }
  ],
  "cost": 0.001,
  "timestamp": "2025-06-08T07:12:50.282068Z"
}

ChatGPTによっお、パラグラフは文単䜍に区切られ、その文単䜍で翻蚳が付䞎されたす。たた、cost属性は、ChatGPTを動かすために䜿った費甚を瀺したす。ここでは0.001 USドルなので、1ドル150円換算で、このタスクの実行によっお0.15円くらいが請求されるこずがわかりたす。

凊理を途䞭で終わらせたい堎合にはCtrl-Cを抌しおください。プロセスは安党に停止し、次回の実行時には途䞭から再開されたす。実行時に毎回最初からやり盎したい堎合には、--resetオプションを付けたす。

もう少し実践的な䟋も芋おみたしょう。以䞋の内容をbasic-raw.txtずしお保存しおください。samplesディレクトリの䞭に同じものがありたす。

# How to Make Parallel Books

- @id sample01: How to Make Parallel Books
- @author Mikio Hirabayashi

## Basics

Parallel corpora are powerful tools to learn languages.  With them, you can learn foreign languages easily by reading your favorite stories.  Each sentence in the original corpus is associated with its translation in your mother tongue.

This project provides scripts to make parallel books from arbitrary contents.  All you have to do is to prepare the original corpus and run some commands to make parallel books in various formats.  Translation is done by AI platforms like ChatGPT and Gemini.

## License

This software is distributed under the terms of Apache License version 2.0.  Sample data in this project are in public domain.  So, both can be redestributed freely without additional permissions.

以䞋のコマンドを実行しお、゜ヌスJSON圢匏に倉換したす。

./scripts/jsonize_plaintext.py < basic-raw.txt > basic-source.json

生成されたbasic-source.jsonの䞭身は以䞋のようになるはずです。タむトルなどのメタデヌタが反映され、章ごずにタむトルずパラグラフのリストが保持されおいるこずを確認しおください。

{
  "format": "parallel",
  "title": "How to Make Parallel Books",
  "id": "sample01: How to Make Parallel Books",
  "author": "Mikio Hirabayashi",
  "chapters": [
    {
      "title": "Basics",
      "body": [
        {
          "paragraph": "Parallel corpora are powerful tools to learn languages.  With them, you can learn foreign languages easily by reading your favorite stories.  Each sentence in the original corpus is associated with its translation in your mother tongue.",
          "raw_line": 8
        },
        {
          "paragraph": "This project provides scripts to make parallel books from arbitrary contents.  All you have to do is to prepare the original corpus and run some commands to make parallel books in various formats.  Translation is done by AI platforms like ChatGPT and Gemini.",
          "raw_line": 10
        }
      ],
      "raw_line": 6
    },
    {
      "title": "License",
      "body": [
        {
          "paragraph": "This software is distributed under the terms of Apache License version 2.0.  Sample data in this project are in public domain.  So, both can be redestributed freely without additional permissions.",
          "raw_line": 14
        }
      ],
      "raw_line": 12
    }
  ]
}

以䞋のコマンドを実行しお、ChatGPTで翻蚳を行い、結果の察蚳JSONファむルを生成したす。

./scripts/make_parallel_corpus.py basic-source.json

生成されたbasic-parallel.jsonの䞭身は以䞋のようになるはずです。

{
  "format": "parallel",
  "id": "sample01: How to Make Parallel Books",
  "source_language": "en",
  "target_language": "ja",
  "title": {
    "id": "00000-000",
    "source": "How to Make Parallel Books",
    "target": "平行曞籍の䜜り方"
  },
  "author": {
    "id": "00001-000",
    "source": "Mikio Hirabayashi",
    "target": "平林幹倫"
  },
  "chapters": [
    {
      "title": {
        "id": "00002-000",
        "source": "Basics",
        "target": "基本"
      },
      "body": [
        {
          "paragraph": [
            {
              "id": "00003-000",
              "source": "Parallel corpora are powerful tools to learn languages.",
              "target": "平行コヌパスは蚀語を孊ぶための匷力なツヌルです。"
            },
            {
              "id": "00003-001",
              "source": "With them, you can learn foreign languages easily by reading your favorite stories.",
              "target": "それらを䜿えば、お気に入りの物語を読むこずで倖囜語を簡単に孊ぶこずができたす。"
            },
            {
              "id": "00003-002",
              "source": "Each sentence in the original corpus is associated with its translation in your mother tongue.",
              "target": "元のコヌパスの各文は、母囜語の翻蚳ず関連付けられおいたす。"
            }
          ],
          "raw_line": 8
        },
        {
          "paragraph": [
            {
              "id": "00004-000",
              "source": "This project provides scripts to make parallel books from arbitrary contents.",
              "target": "このプロゞェクトでは、任意のコンテンツから平行な曞籍を䜜成するためのスクリプトが提䟛されおいたす。"
            },
            {
              "id": "00004-001",
              "source": "All you have to do is to prepare the original corpus and run some commands to make parallel books in various formats.",
              "target": "必芁なのは元のコヌパスを準備し、いく぀かのコマンドを実行しおさたざたな圢匏の平行な曞籍を䜜成するだけです。"
            },
            {
              "id": "00004-002",
              "source": "Translation is done by AI platforms like ChatGPT and Gemini.",
              "target": "翻蚳はChatGPTやGeminiなどのAIプラットフォヌムによっお行われたす。"
            }
          ],
          "raw_line": 10
        }
      ],
      "raw_line": 6
    },
    {
      "title": {
        "id": "00005-000",
        "source": "License",
        "target": "ラむセンス"
      },
      "body": [
        {
          "paragraph": [
            {
              "id": "00006-000",
              "source": "This software is distributed under the terms of Apache License version 2.0.",
              "target": "この゜フトりェアはApache License バヌゞョン2.0の条件の䞋で配垃されおいたす。"
            },
            {
              "id": "00006-001",
              "source": "Sample data in this project are in public domain.",
              "target": "このプロゞェクトのサンプルデヌタはパブリックドメむンです。"
            },
            {
              "id": "00006-002",
              "source": "So, both can be redistributed freely without additional permissions.",
              "target": "そのため、远加の蚱可なしに自由に再配垃するこずができたす。"
            }
          ],
          "raw_line": 14
        }
      ],
      "raw_line": 12
    }
  ],
  "cost": 0.004,
  "timestamp": "2025-06-08T07:12:55.169844Z"
}

本のタむトルや章のタむトルも含めお、ちゃんず翻蚳がなされおいたす。今回の費甚は0.004ドルなので、0.6円くらいが請求されるこずになりたす。

実行時のログを芋おみたしょう。党おが正垞に進む堎合、以䞋のようなログが出たす。

Loading data from basic-source.json
Total tasks: 7
Title: How to Make Parallel Books
GPT models: gpt-4.1-mini
Task 0: book_title - How to Make Parallel Books
Task 1: book_author - Mikio Hirabayashi
Task 2: chapter_title - Basics
Task 3: paragraph - Parallel corpora are powerful tools to learn languages. With the
Task 4: paragraph - This project provides scripts to make parallel books from arbitr
Task 5: chapter_title - License
Task 6: paragraph - This software is distributed under the terms of Apache License v
Done: tasks=7, total_cost=$0.0045 (Y0.68)
Postprocessing the output
Validating the output
Writing data into basic-parallel.json
Finished

デフォルトでは、gpt-4.1-miniずいうモデルが䜿われたす。これは倚くのタスクで十分な粟床で、か぀安いのが利点です。より高粟床な結果が欲しいのであれば、費甚は倚くかかりたすが、gpt-4.1を䜿うのも良いでしょう。以䞋のように実行したす。

./scripts/make_parallel_corpus.py basic-source.json --model gpt-4.1
Loading data from basic-source.json
Total tasks: 7
Title: How to Make Parallel Books
GPT models: gpt-4.1
Task 0: book_title - How to Make Parallel Books
Task 1: book_author - Mikio Hirabayashi
Task 2: chapter_title - Basics
Task 3: paragraph - Parallel corpora are powerful tools to learn languages. With the
Task 4: paragraph - This project provides scripts to make parallel books from arbitr
Task 5: chapter_title - License
Task 6: paragraph - This software is distributed under the terms of Apache License v
Done: tasks=7, total_cost=$0.0206 (Y3.09)
Postprocessing the output
Validating the output
Writing data into basic-parallel.json
Finished

gpt-4.1-miniでは$0.00450.68円だったのに、gpt-4.1だず$0.02063.09円になっおいたす。長い文章を扱うには、ちょっず高いですね。よっお、たずはgpt-4.1-miniで党䜓のタスクを終わらせおから、気に入らない郚分だけをgpt-4.1で再詊行するのが良いでしょう。どのタスクを再詊行するかを把握するには、生成したJSONデヌタに含たれるタスクIDを芋たす。以䞋の䟋の堎合、原文ず翻蚳が党く合っおいたせん。

{
  "id": "00035-004",
  "source": "Fetch me my hat.",
  "target": "寝る子は育぀。"
}

その堎合、タスク35をやり盎すこずになるでしょう。--redoオプションに、タスクIDを指定したす。35,128,247のように、耇数のタスクIDを指定するこずもできたす。

./scripts/make_parallel_corpus.py basic-source.json --model gpt-4.1 --redo 35

タスクの䞭には、ChatGPTがうたく扱えないものもあるかもしれたせん。ChatGPTにはJSONの結果を返すように指瀺しおいたすが、その生成がうたくいかない堎合には、プロンプトやパラメヌタを調敎しお自動的に再詊行がなされたす。6回の再詊行を経おも倱敗する堎合には、モデルを倉えおさらに6回の再詊行を行い、凊理を完遂させたす。

Loading data from basic-source.json
Total tasks: 7
Title: How to Make Parallel Books
GPT models: gpt-4.1-mini
Task 0: book_title - How to Make Parallel Books
Task 1: book_author - Mikio Hirabayashi
Task 2: chapter_title - Basics
Task 3: paragraph - Parallel corpora are powerful tools to learn languages.  With th
Task 4: paragraph - This project provides scripts to make parallel books from arbitr
Attempt 1 failed (model=gpt-4.1-mini, temperature=0.0, jsonize=True): Extra data: line 8 column 2 (char 585)
Attempt 2 failed (model=gpt-4.1-mini, temperature=0.0, jsonize=False): Extra data: line 8 column 2 (char 587)
Attempt 3 failed (model=gpt-4.1-mini, temperature=0.4, jsonize=True): Extra data: line 8 column 2 (char 582)
Attempt 4 failed (model=gpt-4.1-mini, temperature=0.4, jsonize=False): Extra data: line 8 column 2 (char 587)
Attempt 5 failed (model=gpt-4.1-mini, temperature=0.8, jsonize=True): Extra data: line 8 column 2 (char 614)
Attempt 6 failed (model=gpt-4.1-mini, temperature=0.8, jsonize=False): Extra data: line 8 column 2 (char 605)
Task 5: chapter_title - License
Task 6: paragraph - This software is distributed under the terms of Apache License v
Done: tasks=7, total_cost=$0.0094 (Y1.41)
Validating output
Writing data into basic-parallel.json
Finished

プロンプトやパラメヌタやモデルを倉えお合蚈12回の詊行をしおもうたくいかない堎合、その堎で凊理が停止したす。

Loading data from basic-source.json
Total tasks: 7
Title: How to Make Parallel Books
GPT models: gpt-4.1-mini
Task 0: book_title - How to Make Parallel Books
Task 1: book_author - Mikio Hirabayashi
Task 2: chapter_title - Basics
Task 3: paragraph - Parallel corpora are powerful tools to learn languages.  With th
Task 4: paragraph - This project provides scripts to make parallel books from arbitr
Attempt 1 failed (model=gpt-4.1-mini, temperature=0.0, jsonize=True): Extra data: line 8 column 2 (char 718)
Attempt 2 failed (model=gpt-4.1-mini, temperature=0.0, jsonize=False): Extra data: line 8 column 2 (char 766)
Attempt 3 failed (model=gpt-4.1-mini, temperature=0.4, jsonize=True): Extra data: line 8 column 2 (char 573)
Attempt 4 failed (model=gpt-4.1-mini, temperature=0.4, jsonize=False): Extra data: line 8 column 2 (char 645)
Attempt 5 failed (model=gpt-4.1-mini, temperature=0.8, jsonize=True): Extra data: line 8 column 2 (char 616)
Attempt 6 failed (model=gpt-4.1-mini, temperature=0.8, jsonize=False): Extra data: line 8 column 2 (char 614)
Attempt 1 failed (model=gpt-4.1, temperature=0.0, jsonize=True): Extra data: line 8 column 2 (char 607)
Attempt 2 failed (model=gpt-4.1, temperature=0.0, jsonize=False): Extra data: line 8 column 2 (char 601)
Attempt 3 failed (model=gpt-4.1, temperature=0.4, jsonize=True): Extra data: line 8 column 2 (char 551)
Attempt 4 failed (model=gpt-4.1, temperature=0.4, jsonize=False): Extra data: line 8 column 2 (char 572)
Attempt 5 failed (model=gpt-4.1, temperature=0.8, jsonize=True): Extra data: line 17 column 2 (char 614)
Attempt 6 failed (model=gpt-4.1, temperature=0.8, jsonize=False): Extra data: line 17 column 2 (char 605)
Traceback (most recent call last):
  File "/Users/mikio/dev/parallelbook/./scripts/make_parallel_corpus.py", line 637, in <module>
    main()
  File "/Users/mikio/dev/parallelbook/./scripts/make_parallel_corpus.py", line 611, in main
    response = execute_task_by_chatgpt_enja(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/mikio/dev/parallelbook/./scripts/make_parallel_corpus.py", line 514, in execute_task_by_chatgpt_enja
    raise RuntimeError("All retries failed: unable to parse valid JSON with required fields")
RuntimeError: All retries failed: unable to parse valid JSON with required fields

AIモデルにずっお郜合の悪いデヌタを入力すれば、この事態は起こり埗たす。異垞に長いパラグラフや、プロンプトが玛らわしくなるような蚘号などを含んでいる堎合が兞型的です。いずれにせよ、再詊行しおも状況が改善されないでしょう。その堎合、入力デヌタを曞き換えるのが無難です。--redoオプションを指定するず、指定したタスクの入力デヌタにおける該圓パラグラフを再読み蟌みするので、郜合の悪いデヌタを排陀できたす。ただし、パラグラフの数を増枛させないように泚意しおください。そうするずタスクIDがずれるので、党䜓をやり盎す必芁が生じたす。

゚ラヌが出る床に凊理が止たるず面倒くさいずいう堎合には、--failsoftオプションを䜿いたす。これを指定するず、倱敗したタスクはダミヌデヌタで埋めお凊理を進めたす。結果ずしお、以䞋のようなレコヌドが出力に含たれるこずになりたす。入力を修正しおから再詊行するなり、出力を盎接手で修正するなりの察凊をするず良いでしょう。

{
  "id": "00001-000",
  "source": "This is the end of the world.",
  "target": "[*FAILSOFT*]",
  "error": true
}

特定のタスクの文分割や翻蚳が意図通りじゃないずいった堎合でには、--redoでそのタスクだけやり盎すず同時に、--extra-hintで远加のヒント情報を䞎えるず回埩できる堎合がありたす。

./scripts/make_parallel_corpus.py books/anne02-source.json --redo 0 --extra-hint="「Anne of the Island」は、「島のアン」ず蚳しおください。" --debug

その堎合、タスク35をやり盎すこずになるでしょう。--redoオプションに、タスクIDを指定したす。35,128,247のように、耇数のタスクIDを指定するこずもできたす。

./scripts/make_parallel_corpus.py basic-source.json --model gpt-4.1 --redo 35

生成機胜矀の仕様

jsonize_plaintext.py

jsonize_plaintext.pyは、Markdown颚のテキストファむルを読んで、その内容を元に察蚳凊理の入力甚のJSONデヌタを生成するスクリプトです。このデヌタ圢匏を゜ヌスJSON圢匏ず呌びたす。入力デヌタは暙準入力から読み蟌み、出力デヌタは暙準出力に曞き蟌みたす。よっお、以䞋のように実行したす。

jsonize_plaintext.py < sample-raw.txt > sample-source.json

入力の圢匏は、Markdownのサブセットです。以䞋のデヌタはその党おの機胜を䜿っおいたす。

# Book Title

- @id sample02: book title
- @author John Doe

## Chapter1's Title

### Header in the chapter

This is paragraph one. "Baby steps to giant strides!", he said.
Contiguous lines are concatened
into one paragraph. So, you can fold them by a single linefeed.

I replied, "This is the second paragraph. I'm not sure though."
Brank lines separate paragraphs.

- @macro image https://dbmx.net/parallelbook/logo.png
- @macro comment Macros are not translated but kept intact to the output.

## Chapter2's Title

> Lines in blockquotes are also concatenated
> and translated. A whitespace must follow ">".

- Hop. Step. Jump! Each item in the list are not segmented.
- Saitama, Saitama? A whitespace must follow "-".

|symbol|name|number|
|Au|gold|79|
|Ag|silver|47|

```text
one
two two

three three three

普通に英文を曞くず、段萜になりたす。段萜は空行で区切りたす。段萜の途䞭の改行は空癜ず同等ずみなされるので、文の間や文の途䞭で単䞀の改行を入れお折り返しおも倧䞈倫です。

以䞋の特殊蚘法がありたす。倚くの特殊蚘法は、蚘号の埌ろに空癜が必芁です。「#1」「-1」で始たっおも特殊蚘法にはなりたせんが、「# 1」や「- 1」で始たれば特殊蚘法になりたす。

-「#」ず空癜で始たる行は本のタむトルを瀺したす。通垞は文章の冒頭に曞きたす。 -「##」ず空癜で始たる行は章のタむトルを瀺したす。章を区切るにはこれを甚いたす。 -「###」ず空癜で始たる行はヘッダを瀺したす。 -「- @id」ず空癜で始たる行は文曞のIDを瀺したす。 -「- @author」ず空癜で始たる行は文曞の著者を瀺したす。 -「- @macro」ず空癜で始たる行はマクロを瀺したす。マクロは翻蚳されずにそのたた出力に枡りたす。 -「-」ず空癜で始たる行はリストの項目になりたす。連続した項目は1぀のリストになりたす。 -「>」ず空癜で始たる行は匕甚になりたす。連続した匕甚は1぀の匕甚ブロックになりたす。 -「|」で始たり「|」で終わる行は衚の行になりたす。連続した衚の行は1぀の衚になりたす。 -「」で始たる行から次の「」の行たでは、コヌドブロックになりたす。コヌドブロックは翻蚳されたせん。

make_parallel_corpus.py

make_parallel_corpus.pyは、jsonize_plaintext.pyが生成した゜ヌスJSONファむルを読んで、その内容を元に察蚳デヌタを生成するスクリプトです。察蚳デヌタの生成にはChatGPTを甚いたす。

前提ずしお、環境倉数OPENAI_API_KEYの倀にOpenAIのAPIキヌが蚭定されおいる必芁がありたす。そのうえで、゜ヌスJSONファむルを指定しお実行するず、そのファむル名から拡匵子ず "-source" を抜いた文字列に "-parallel.json" を぀けた名前で翻蚳デヌタのJSONファむルが生成されたす。以䞋のコマンドを実行するず、sample-parallel.jsonが生成されたす。

make_parallel_corpus.py sample-source.json

本スクリプトは、パラグラフ単䜍でChatGPTを呌び出しお翻蚳を行いたす。文単䜍ではなくパラグラフ単䜍で翻蚳するこずで、文脈を加味した翻蚳が可胜になりたす。語圙の曖昧性や代名詞の曖昧性を解決するには、ある皋床倧きい単䜍で翻蚳するのが有利です。さらに、プロンプトの䞭に文脈情報ずしお以䞋のものを加えおいたす。

  • 前のパラグラフの500文字皋床の文のリスト
  • 次のパラグラフの200文字皋床の文のリスト
  • 珟圚の堎面の芁玄

プロンプトの䟋を以䞋に瀺したす。

あなたは『I Have a Dream』の英日翻蚳を担圓しおいたす。
以䞋の情報をもずに、䞎えられたパラグラフを自然な日本語に翻蚳しおください。
----
{
  "珟圚の堎面の芁玄": "マヌティン・ルヌサヌ・キング・ゞュニアは奎隷解攟宣蚀に眲名された堎所で挔説を行い、アメリカの建囜者たちが党おのアメリカ人が盞続人ずなる玄束手圢に眲名したこず、そしおその玄束が有色人皮の垂民に察しお果たされおいないこずが述べられおいたす。次の段萜では、キング牧垫がアラバマ州での人皮差別に぀いお語りかけおいたす。",
  "盎前のパラグラフ": [
    "With this faith, we will be able to transform the jangling discords of our nation into a beautiful symphony of brotherhood.",
    "With this faith, we will be able to work together, to pray together, to struggle together, to go to jail together, to stand up for freedom together, knowing that we will be free one day.",
    "And this will be the day -- this will be the day when all of God's children will be able to sing with new meaning:",
    "My country 'tis of thee, sweet land of liberty, of thee I sing.",
    "Land where my fathers died, land of the Pilgrim's pride,    From every mountainside, let freedom ring!"
  ],
  "盎埌のパラグラフ": [
    "But not only that: Let freedom ring from Stone Mountain of Georgia.",
    "Let freedom ring from Lookout Mountain of Tennessee.",
    "Let freedom ring from every hill and molehill of Mississippi.",
    "From every mountainside, let freedom ring."
  ],
  "翻蚳察象のパラグラフ": "And if America is to be a great nation, this must become true. And so let freedom ring from the prodigious hilltops of New Hampshire. Let freedom ring from the mighty mountains of New York. Let freedom ring from the heightening Alleghenies of Pennsylvania. Let freedom ring from the snow-capped Rockies of Colorado. Let freedom ring from the curvaceous slopes of California."
}


----
出力圢匏はJSONずし、次の芁玠を含めおください:
{
  "translations": [
    { "en": "原文の文1", "ja": "察応する蚳文1" },
    { "en": "原文の文2", "ja": "察応する蚳文2" }
    // ...
  ],
  "context_hint": "この段萜を含めた珟圚の堎面の芁玄、登堎人物、心情、堎の倉化などを1文100トヌクン皋床で簡朔に蚘述しおください。",
}

----
英文は意味的に自然な単䜍で文分割しおください。たずえ短い文でも、文ずみなせれば独立させおください。
ただし、分割の際に元の英文を1文字も倉曎しないでください。句読点や匕甚笊も含めお党お保持しおください。
日本語蚳は文䜓・語調に配慮し぀぀も、できるだけ盎蚳調にずどめ、構文や語順の察応関係が分かるようにしおください。
context_hintは次の段萜の翻蚳時に圹立぀ような背景情報を含めおください䟋誰が話しおいるか、舞台の倉化、話題の掚移など。
䞍芁な解説や装食、サマリヌ文などは含めず、必ず䞊蚘JSON構造のみを出力しおください。

䞊述のプロンプトに察するレスポンスは以䞋のようになりたす。

{
  "translations": [
    { "en": "And if America is to be a great nation, this must become true.", "ja": "もしアメリカが偉倧な囜であり続けるなら、この蚀葉は実珟しなければならない。" },
    { "en": "Let freedom ring from the prodigious hilltops of New Hampshire.", "ja": "ニュヌハンプシャヌ州の雄倧な䞘から自由の鐘を鳎らそう。" },
    { "en": "Let freedom ring from the mighty mountains of New York.", "ja": "ニュヌペヌクの偉倧な山々から自由の鐘を鳎らそう。" },
    { "en": "Let freedom ring from the heightening Alleghenies of Pennsylvania.", "ja": "ペンシルベニア州の高いアレゲニヌ山脈から自由の鐘を鳎らそう。" },
    { "en": "Let freedom ring from the snow-capped Rockies of Colorado.", "ja": "コロラド州の雪を被ったロッキヌ山脈から自由の鐘を鳎らそう。" },
    { "en": "Let freedom ring from the curvaceous slopes of California.", "ja": "カリフォルニアの曲線矎ある斜面から自由の鐘を鳎らそう。" }
  ],
  "context_hint": "キング牧垫はアメリカが偉倧な囜であり続けるためには、党おの州から自由の鐘が鳎らされるべきだず蚎えおいたす。"
}

前埌のパラグラフを文脈情報ずしお䞎えるだけではなく、前のパラグラフの翻蚳䜜業で埗られた堎面のヒント情報を次のパラグラフの翻蚳にリレヌしおいくこずにより、翻蚳粟床を高めるこずを䌁図しおいたす。文単䜍での翻蚳よりもパラグラフ単䜍の翻蚳の方が有利であり、珟圚のパラグラフだけを芋る翻蚳よりも、前埌の文ずリレヌされた文脈情報を加味した翻蚳の方が有利であるず仮定しおいたす。

AIは間違いたす。特に、指瀺通りのJSONフォヌマットを出力しなかったり、指瀺通りの内容を出さなかったりするこずがよくありたす。よっお、埌凊理ずしお敎合性を確認し、䞍敎合であれば、自動的に再詊行が行われたす。敎合性の確認ずしおは、たずJSONが適切に構築できるかを怜査したす。さらに、文分割した結果を結合した文字列ず、元のパラグラフの間の差分レヌベンシュタむン線集距離を調べ、その割合が10%を超えおいたら䞍敎合ずみなしたす。たた、匕甚笊が維持されおいるかどうかも怜査しおいたす。

再詊行の際にはtemperatureパラメヌタを増やしお出力のランダム性を䞊げるほか、プロンプトに埮調敎をしたす。特にプロンプト内の入力デヌタを疑䌌JSON圢匏ずプレヌンテキストで切り替えるのが効果がありたす。

パラメヌタやプロンプトを倉えお6回の詊行をしおもうたくいかない堎合、モデルを切り替えおさらに6回の詊行をしたす。gpt-4.1モデルを䜿っおいる堎合、gpt-4.1-miniモデルに切り替え、gpt-4.1モデルを以倖を䜿っおいる堎合、gpt-4.1モデルに切り替えたす。それでもうたく行かない堎合、凊理が停止したす。ただし、--failsoftオプションを぀けおいる堎合、ダミヌデヌタを出力しお凊理が続行されたす。

ChatGPTのAPIを叩くず、費甚がかかりたす。2025幎6月珟圚、デフォルトのgpt-4.1-miniモデルだず、入力には1000トヌクンあたり0.0004ドルかかり、出力には1000トヌクンあたり0.0016ドルかかりたす。gpt-4.1モデルだずその5倍で、入力には1000トヌクンあたり0.00200ドルかかり、出力には1000トヌクンあたり0.00800ドルかかりたす。

䟋えば、「Anne of Green Gables」を蚳すずしたしょう。平均するず、各パラグラフの翻蚳には、入力で800トヌクン、出力で400トヌクン皋床が䜿われたす。よっお、gpt-4.1-miniモデルだず、入力には0.80.0004=0.00032ドルかかり、出力には0.40.0016=0.00064ドルかかりたす。合蚈で0.00096ドルです。それを1826パラグラフの分だけやるので、1.752ドルかかりたす。実際には再詊行の分がかかるので、その1.3倍くらい芋おおくず良いでしょう。぀たり2.3ドルくらいです。gpt-4.1モデルだず、その5倍の11.39ドルくらいかかりたす。

本スクリプトの手法では文脈情報を入力するために倚くのトヌクン数が費やされおいたすが、入力トヌクンの費甚が出力トヌクンの費甚よりも小さいので、文脈情報を付加するこずによる総合的な費甚の向䞊は倧きくありたせん。パラグラフ単䜍での翻蚳ず文分割を同時に行うこずでの出力トヌクン数の増加の方が問題ですが、䜿いやすい察蚳本を䜜る䞊ではそこは譲れたせん。

ChatGPTによる凊理には時間がかかり、たたサヌバ偎やネットワヌクの䞍調などで凊理が止たるこずも倚々ありたす。したがっお、途䞭経過の保存のそこからの再開をする機胜が必須ずなりたす。本スクリプトでは、途䞭経過をSQLiteのデヌタベヌスに保存するこずで䞭断ず再開の機胜を実珟しおいたす。凊理䞭にCtrl-Cを入力するなどしお任意のタむミングでプロセスを終了しおも、同じコマンドを実行すれば凊理を再開するこずができたす。途䞭経過のデヌタベヌスは、入力ファむル名に "-state.db" を぀けた名前のファむルで管理されたす。

make_parallel_corpus.pyは以䞋のオプションを備えたす。

  • --output OUTPUT : 出力ファむルを明瀺的に指定したす。
  • --state STATE : 状態ファむルを明瀺的に指定したす。
  • --reset : 最初からタスクをやり盎したす。
  • --num-tasks NUM_TASKS : 凊理する最倧タスク数を指定したす。
  • --force-finish : 党郚のタスクが終わらなくおも、出力ファむルを生成したす。
  • --failsoft : 倱敗したタスクがあっおも凊理を続けたす。
  • --model GPT_MODEL : ChatGPTのモデル名を指定したす。
  • --no-fallback : 倱敗時に別モデルを䜿う凊理を抑制したす。
  • --extra-hint : プロンプトに远加するヒント情報を指定したす。
  • --make-batch-input : バッチAPIを利甚するためのJSONL入力ファむルを䜜成したす。
  • --use-batch-output BATCHOUT : バッチAPIのJSONL出力ファむルを利甚したす。
  • --debug : 各タスクのプロンプトず応答などのデバッグ情報をログ衚瀺したす。

ChatGPTに枡すプロンプトはスクリプト内にハヌドコヌドされおいるので、適宜修正しお䜿っおください。衚蚘揺れを防ぐために固有名詞ずその翻蚳のリストを䞎えたり、䜜品の背景知識を埋め蟌んだりするこずも有甚です。

make_parallel_corpus.pyの出力は以䞋のような圢匏になりたす。

{
  "format": "parallel",
  "id": "sample02: book title",
  "source_language": "en",
  "target_language": "ja",
  "title": {
    "id": "00000-000",
    "source": "Book Title",
    "target": "本の題名"
  },
  "author": {
    "id": "00001-000",
    "source": "John Doe",
    "target": "ゞョン・ドり"
  },
  "chapters": [
    {
      "title": {
        "id": "00002-000",
        "source": "Chapter1's Title",
        "target": "第1章のタむトル"
      },
      "body": [
        {
          "header": {
            "id": "00003-000",
            "source": "Header in the chapter",
            "target": "章のヘッダヌ"
          }
        },
        {
          "paragraph": [
            {
              "id": "00004-000",
              "source": "This is paragraph one.",
              "target": "これは1぀目の段萜です。"
            },
            {
              "id": "00004-001",
              "source": "\"Baby steps to giant strides!\", he said.",
              "target": "「小さな䞀歩から倧きな飛躍ぞ」ず圌は蚀いたした。"
            },
            {
              "id": "00004-002",
              "source": "Contiguous lines are concatened into one paragraph.",
              "target": "隣接する行は1぀の段萜に結合されたす。"
            },
            {
              "id": "00004-003",
              "source": "So, you can fold them by a single linefeed.",
              "target": "そのため、1぀の改行で折りたたむこずができたす。"
            }
          ],
          "raw_line": 10
        },
        {
          "paragraph": [
            {
              "id": "00005-000",
              "source": "I replied, \"This is the second paragraph. I'm not sure though.\"",
              "target": "私は答えたした。「これが2番目の段萜です。でも、確信はありたせん。」"
            },
            {
              "id": "00005-001",
              "source": "Brank lines separate paragraphs.",
              "target": "空行が段萜を区切りたす。"
            }
          ],
          "raw_line": 14
        },
        {
          "macro": {
            "id": "00006-000",
            "name": "image",
            "value": "https://dbmx.net/parallelbook/logo.png"
          },
          "raw_line": 17
        },
        {
          "macro": {
            "id": "00007-000",
            "name": "comment",
            "value": "Macros are not translated but kept intact to the output."
          },
          "raw_line": 18
        }
      ],
      "raw_line": 6
    },
    {
      "title": {
        "id": "00008-000",
        "source": "Chapter2's Title",
        "target": "第2章のタむトル"
      },
      "body": [
        {
          "list": [
            {
              "id": "00009-000",
              "source": "Hop. Step. Jump! Each item in the list are not segmented.",
              "target": "ホップ。ステップ。ゞャンプリスト内の各項目は分割されたせん。"
            },
            {
              "id": "00010-000",
              "source": "Saitama, Saitama? A whitespace must follow \"-\".",
              "target": "埌玉、埌玉「-」の埌には空癜が必芁です。"
            }
          ],
          "raw_line": 25
        },
        {
          "table": [
            [
              {
                "id": "00011-000",
                "source": "symbol",
                "target": "蚘号"
              },
              {
                "id": "00011-001",
                "source": "name",
                "target": "名前"
              },
              {
                "id": "00011-002",
                "source": "number",
                "target": "番号"
              }
            ],
            [
              {
                "id": "00012-000",
                "source": "Au",
                "target": "Au"
              },
              {
                "id": "00012-001",
                "source": "gold",
                "target": "金"
              },
              {
                "id": "00012-002",
                "source": "79",
                "target": "79"
              }
            ],
            [
              {
                "id": "00013-000",
                "source": "Ag",
                "target": "Ag"
              },
              {
                "id": "00013-001",
                "source": "silver",
                "target": "銀"
              },
              {
                "id": "00013-002",
                "source": "47",
                "target": "47"
              }
            ]
          ],
          "raw_line": 28
        },
        {
          "code": {
            "id": "00014-000",
            "text": "one\ntwo two\n\nthree three three"
          },
          "raw_line": 32
        }
      ],
      "raw_line": 20
    }
  ],
  "cost": 0.004,
  "timestamp": "2025-06-13T15:36:35.768991Z"
}

analyze_parallel_corpus.py

analyze_parallel_corpus.pyは、make_parallel_corpusが生成した察蚳JSONファむルを読んで、構文解析の泚釈を付䞎した察蚳JSONファむルを生成するスクリプトです。構文解析にはChatGPTを甚いたす。

前提ずしお、環境倉数OPENAI_API_KEYの倀にOpenAIのAPIキヌが蚭定されおいる必芁がありたす。そのうえで、゜ヌスJSONファむルを指定しお実行するず、そのファむル名から拡匵子ず "-parallel" を抜いた文字列に "-analized.json" を぀けた名前で泚釈付きのJSONファむルが生成されたす。以䞋のコマンドを実行するず、sample-analyzed.jsonが生成されたす。

analyze_parallel_corpus.py sample-parallel.json

本スクリプトは、文単䜍でChatGPTを呌び出しお構文解析を行いたす。構文解析のヒントずしお察蚳が䞎えられ、その察蚳は文脈を芋お生成されおいるので、文単䜍で凊理しおも曖昧性の問題は起きにくいです。

ここで蚀う構文解析ずは、以䞋の5぀の文型を刀定するずずもに、文型の構成芁玠を抜出しお圹割を刀定するこずです。

  • SV第1文型䞻語ず動詞からなる。䟋I slept.
  • SVO第2文型䞻語ず動詞ず目的語からなる。䟋I love you.
  • SVC第3文型䞻語ず動詞ず補語からなる。䟋This is a pen.
  • SVOO第4文型䞻語ず動詞ず間接目的語ず盎接目的語からなる。䟋He gave me chocolate.
  • SVOC第5文型䞻語ず動詞ず目的語ず補語からなる。䟋You make me happy.

各タスクでは、察蚳JSONデヌタの各々の察蚳文を凊理したす。原文ず蚳文を取り出し、以䞋のような入力デヌタを䜜りたす。実際には、その前に長倧なむンストラクションが付きたす。

{
  "source": "I'm a teacher and love every kid.",
  "target": "私は教垫であり、党おの子どもを愛する。"
}

分析結果はJSON内の察蚳のオブゞェクトに "analysis" ずいう属性ずしお付䞎されたす。本スクリプトは入力が文単䜍であるこずを前提ずしたすが、"Yes, you can. Do it now." のように実際には耇数の文が含たれおいたり、"I'm a teacher and love every kid." のように耇数の文が結合した文であるかもしれたせん。そのため、分析結果はJSONは配列であり、文分割埌の耇数の文の分析結果が栌玍されたす。

{
  "source": "I'm a teacher and love every kid.",
  "target": "私は教垫であり、党おの子どもを愛する。"
  "analysis": [
    {
      "id": "00000-000-000",
      "text": "I'm a teacher",
      "pattern": "SVC",
      "elements": [
        { "type": "S", "text": "I", "translation": "私は" },
        { "type": "V", "text": "am", "translation": "存圚だ",
          "tense": "present", "aspect": "simple", "mood": "indicative", "voice": "none" },
        { "type": "C", "text": "a teacher", "translation": "教垫ずいう" }
      ]
    },
    {
      "id": "00000-001-000",
      "text": "and love every kid.",
      "pattern": "SVO",
      "elements": [
        { "type": "M", "text": "and", "translation": "だから" },
        { "type": "V", "text": "love", "translation": "愛する",
          "tense": "present", "aspect": "simple", "mood": "indicative", "voice": "active" },
        { "type": "O", "text": "everykid", "translation": "党おの子どもを" }
      ]
    }
  ]
}

抜出された文には、以䞋の属性が付きたす。

  • text : その文の文字列。
  • pattern : 文型分類。
  • elements : 文型を構成する芁玠の配列。
  • subsentences : 盎接話法の副文の配列。各々の副文も構文解析される。
  • subclauses : 文党䜓にかかる埓属節。各々の埓属節も構文解析される。

文型を構成する芁玠には、以䞋の属性が付きたす。

  • type : 芁玠の圹割。䞻語はS、動詞はV、目的語はO、補語はC、修食語はM。
  • text : その芁玠の文字列。
  • translation : その芁玠の蚳文。
  • subclauses : 芁玠が含む埓属節。各々の埓属節も構文解析される。

動詞である芁玠には、以䞋の属性が远加されたす。

  • tense : 時制。珟圚はpresent、過去はpast。
  • aspect : 盞。単玔盞はsimple、進行盞はprogressive、完了盞はperfect、完了進行盞はperfect progressive。
  • mood : 法。盎説法はindicative、呜什法はimperative、仮定法はsubjunctive、条件法はconditional。
  • voice : 態。胜動態はactive、受動態はpassive。SVCでは態無し扱いでnone。

文党䜓の埓属節副詞節や文型芁玠の埓属節には文型があるので、それも抜出されたす。その差異、文の属性に加えお、以䞋の属性が付きたす。

  • relation : 䞻節ずの関係。内容節はcontent、同栌節はapposition。その他、time、place、reasonなど。

AIは間違いたす。特に、指瀺通りのJSONフォヌマットを出力しなかったり、指瀺通りの内容を出さなかったりするこずがよくありたす。よっお、埌凊理ずしお敎合性を確認し、䞍敎合であれば、自動的に再詊行が行われたす。敎合性の確認ずしおは、たずJSONが適切に構築できるかを怜査したす。さらに、結果の個々の芁玠が䞊述の属性を持っおいるかどうかを調べたす。内容に関する敎合性の怜査は行わないので、時に奇劙な結果が含たれるこずがありたす。"SVO" ず刀定しおおきながら芁玠に補語が含たれおいたり、初歩的な䞍敎合が含たれるこずがありたす。

パラメヌタやプロンプトを倉えお6回の詊行をしおもうたくいかない堎合、モデルを切り替えおさらに6回の詊行をしたす。gpt-4.1モデルを䜿っおいる堎合、gpt-4.1-miniモデルに切り替え、gpt-4.1モデルを以倖を䜿っおいる堎合、gpt-4.1モデルに切り替えたす。それでもうたく行かない堎合、凊理が停止したす。ただし、--failsoftオプションを぀けおいる堎合、ダミヌデヌタを出力しお凊理が続行されたす。

ChatGPTのAPIの費甚に぀いおはmake_parallel_corpus.pyの説明を読んでください。䟋えば、「Anne of Green Gables」を蚳すずしたしょう。平均するず、各パラグラフの翻蚳には、入力で10000トヌクン、出力で500トヌクン皋床が䜿われたす。よっお、gpt-4.1-miniモデルだず、入力には100.0004=0.004ドルかかり、出力には0.50.0016=0.0008ドルかかりたす。合蚈で0.00575ドルです。それを6402文の分だけやるので、30.72ドルかかりたす。実際には再詊行の分がかかるので、その1.1倍くらい芋おおくず良いでしょう。぀たり34ドルくらいです。gpt-4.1モデルだず、その5倍の153ドルくらいかかりたす。

本スクリプトの手法ではむンストラクションに膚倧な䟋を掲茉しおいるので、そのせいで入力トヌクン数が15000近くにもなり、それが実行費甚を増倧させおいたす。䟋を省けば費甚を削枛できたすが、その分だけ粟床が䞋がりたす。文型に基づく構文解析の耇雑性ず、その解析䜜業の孊習デヌタがネット䞊に流垃されおいないこずにより、AIモデルに倚数の䟋を䞎えないず十分な粟床が出ないのが珟状です。

文単䜍で解析タスクを実行するず、毎回むンストラクションを入力しお入力トヌクンのコストが嵩むため、耇数の文をたずめおバッチ凊理がなされたす。最倧16文か1000トヌクンになるたでバッチに詰め蟌むこずで、コストを15%皋床に抑えおいたす。

ChatGPTによる凊理には時間がかかり、たたサヌバ偎やネットワヌクの䞍調などで凊理が止たるこずも倚々ありたす。したがっお、途䞭経過の保存のそこからの再開をする機胜が必須ずなりたす。本スクリプトでは、途䞭経過をSQLiteのデヌタベヌスに保存するこずで䞭断ず再開の機胜を実珟しおいたす。凊理䞭にCtrl-Cを入力するなどしお任意のタむミングでプロセスを終了しおも、同じコマンドを実行すれば凊理を再開するこずができたす。途䞭経過のデヌタベヌスは、入力ファむル名に "-state-analyze.db" を぀けた名前のファむルで管理されたす。

analyze_parallel_corpus.pyは以䞋のオプションを備えたす。

  • --output OUTPUT : 出力ファむルを明瀺的に指定したす。
  • --state STATE : 状態ファむルを明瀺的に指定したす。
  • --reset : 最初からタスクをやり盎したす。
  • --num-tasks NUM_TASKS : 凊理する最倧タスク数を指定したす。
  • --force-finish : 党郚のタスクが終わらなくおも、出力ファむルを生成したす。
  • --failsoft : 倱敗したタスクがあっおも凊理を続けたす。
  • --model GPT_MODEL : ChatGPTのモデル名を指定したす。
  • --no-fallback : 倱敗時に別モデルを䜿う凊理を抑制したす。
  • --extra-hint : プロンプトに远加するヒント情報を指定したす。
  • --make-batch-input : バッチAPIを利甚するためのJSONL入力ファむルを䜜成したす。
  • --use-batch-output BATCHOUT : バッチAPIのJSONL出力ファむルを利甚したす。
  • --debug : 各タスクのプロンプトず応答などのデバッグ情報をログ衚瀺したす。

ChatGPTに枡すプロンプトはスクリプト内にハヌドコヌドされおいるので、適宜修正しお䜿っおください。倱敗しがちなパタヌンがあれば、それを解決する䟋を足すず粟床が䞊がりたす。

バッチAPI察応

analyze_parallel_corpus.pyは、ChatGPTのバッチAPIを䜵甚するこずで、より安䟡に実行できるようになりたす。バッチAPIでは、入力トヌクンの費甚ず出力トヌクンの費甚の双方が、通垞のAPIの半額になりたす。ただし、バッチAPIでは、個々のタスクの出力を即座に怜蚌するこずができたせん。よっお、通垞APIでは䞍敎合があるタスクを再詊行するこずで結果の敎合性を担保できたすが、バッチAPIだずそれが困難です。そこで、バッチAPIず通垞APIを䜵甚したす。バッチAPIの結果を読み蟌んで、通垞APIの詊行の1回目の結果ずすり替えるのです。そこで䞍敎合があれば2回目以降の詊行は通垞APIを䜿っお行われたす。この方法だず、1回目の詊行で完了する倚くのタスクはバッチAPIの費甚だけで枈むので、総合的な費甚はバッチAPIだけを䜿った堎合ずそれほど倉わりたせん。それでいお、敎合性は通垞APIを䜿った堎合ず同皋床に担保できたす。

バッチAPIず通垞APIを利甚する際の䜜業手順を以䞋に瀺したす。

  • --make-batch-inputオプションを぀けおスクリプトを実行し、バッチAPIの入力JSONLファむルを䜜る。
  • chatgpt_batch.py createコマンドで、入力JSONLファむルを指定しおバッチを䜜成し、バッチIDを埗る。
  • chatgpt_batch.py checkコマンドで、バッチIDを指定しお、状態を調べる。
    • 状態にcompletedに倉わるたで、たたに実行しながら埅぀。
  • chatgpt_batch.py saveコマンドで、バッチIDを指定しお、出力JSONLファむルを䜜る。
  • --use-batch-outputオプションを぀けおスクリプトを実行し、最終出力を生成する。

analyze_parallel_corpus.pyでの実行䟋を瀺したす。たず、入力デヌタのJSONファむルを指定しお、バッチAPIの入力JSONLファむルを䜜りたす。入力ファむルの "-parallel.json" の郚分を "-batch-input-analyze.jsonl" に倉えた名前のファむルが生成されたす。

$ ./scripts/analyze_parallel_corpus.py samples/minimum-parallel.json --make-batch-input
Loading data from samples/minimum-parallel.json
Total tasks: 1
Total tokens: 19808
Total input cost: $0.0040 (Y0.59)
Writing batch input data into samples/minimum-batch-input-analyze.jsonl
Finished

生成されたminimum-batch-input-analyze.jsonの䞭身はこんな感じです。JSONLずは、配列の芁玠を改行抜きのJSON圢匏にしたものを改行区切りで䞊べたものです。

{"method": "POST", "url": "/v1/chat/completions", "body": {"messages": [{"role": "user", "content": "あなたは英文法の構文解析の詊隓を受けおいる孊生です...以䞋略..."}], "model": "gpt-4.1-mini"}, "custom_id": "analyze-parallel-corpus-e91011362cdb413f93e0630832be7442-00000"}

バッチ甚入力ファむルを、バッチAPIに投げたす。chatgpt_batch.py createはファむルアップロヌドずバッチの開始を自動的に行い、バッチIDを出力したす。

$ ./scripts/chatgpt_batch.py create samples/minimum-batch-input-analyze.jsonl
created: batch_686d1378324c8190874a9a158ec57cd5

印字にされたバッチIDを䜿っお以埌の管理を行いたす。バッチの状態は以䞋のようなコマンドで分かりたす。

$ ./scripts/chatgpt_batch.py check batch_686d1378324c8190874a9a158ec57cd5
status: in_progress

しばらく埅っおから状態を確認するず、バッチが終了しおいるこずが確認できたす。最倧24時間埅぀可胜性がありたすが、倚くの堎合で12時間以内に結果が埗られたす。

$ ./scripts/chatgpt_batch.py check batch_686d1378324c8190874a9a158ec57cd5
status: completed

バッチの終了を確認したら、ダりンロヌドしお保存したす。

$ ./chatgpt_batch.py save batch_686d1378324c8190874a9a158ec57cd5 minimum-batch-output-analyze.jsonl

なお、バッチ投入埌でも、そのバッチが開始される前ならば、キャンセルできたす。キャンセルした堎合には料金はかからりたせん。

$ ./scripts/chatgpt_batch.py cancel batch_686d1378324c8190874a9a158ec57cd5
canceled: batch_686d1378324c8190874a9a158ec57cd5

既存のゞョブの䞀芧を芋る機胜もありたす。

$ ./scripts/chatgpt_batch.py list
batch_id                                status        created_at
batch_686f75f080208190bf4c87cd1e0047d2  completed     2025-07-10 08:12:32
batch_686f6e50575881908def569ec159b31a  failed        2025-07-10 07:40:00
batch_686e047a31048190b330965a1b4ffa86  cancelled     2025-07-09 05:56:10
batch_686d1378324c8190874a9a158ec57cd5  completed     2025-07-08 12:47:52
batch_686d12edd9908190b7cecaee7b27f5ef  failed        2025-07-08 12:45:33

保存されたminimum-batch-output-analyze.jsonlの䞭身はこんな感じです。

{"id": "batch_req_686d139704f08190a751168eac4050db", "custom_id": "analyze-parallel-corpus-e91011362cdb413f93e0630832be7442-00000", "response": {"status_code": 200, "request_id": "9bd0abfcb194ceb1ad233e8ba326d20c", "body": {"id": "chatcmpl-Br21lvVPHDfi4RSOlGFaqewok9meD", "object": "chat.completion", "created": 1751978877, "model": "gpt-4.1-mini-2025-04-14", "choices": [{"index": 0, "message": {"role": "assistant", "content": "ここに解析結果のJSONが入る", "refusal": null, "annotations": []}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 17800, "completion_tokens": 1062, "total_tokens": 18862, "prompt_tokens_details": {"cached_tokens": 0, "audio_tokens": 0}, "completion_tokens_details": {"reasoning_tokens": 0, "audio_tokens": 0, "accepted_prediction_tokens": 0, "rejected_prediction_tokens": 0}}, "service_tier": "default", "system_fingerprint": "fp_6f2eabb9a5"}}, "error": null}

このデヌタを泚入しお、解析パむプラむンを実行したす。--use-batch-result=autoを指定するず、入力ファむル名の-parallel.jsonを-batch-output-analyze.jsonlに倉えたものを読み蟌みたす。

$ ./scripts/analyze_parallel_corpus.py samples/minimum-parallel.json --use-batch-output=auto
Loading data from samples/minimum-parallel.json
Reading batch output data from samples/minimum-batch-output-analyze.jsonl
Batch info: tasks=1, input_tokens=17800,, output_tokens=1062
Total tasks: 1
GPT model: gpt-4.1-mini
Task 0: Hello, world. I graduated from the world. We love translation. I come up with a
Reusing: Hello, world. I graduated from the world. We love translation. I come up with a
Done: tasks=1, total_cost=$0.0000 (Y0.00)
Postprocessing the output
Validating the output
Writing data into samples/minimum-analyzed.json
Finished

バッチAPIでのミニバッチが党お成功しおいたため、今回の実行では䞀床もChatGPTにアクセスせずに䞀瞬で党タスクが完了したした。バッチAPIの結果に䞍敎合を含むタスクがあれば、そのタスクは通垞APIで自動的に再実行されたす。

chatgpt_batch.pyは以䞋のサブコマンドを備えたす。

  • create INPUT : 入力JSONLファむルを指定しおバッチを䜜りたす。
  • check ID : バッチIDを指定しおバッチの状態を調べたす
  • save ID OUTPUT : バッチIDを指定しおバッチ結果を出力JSONLファむルに保存したす。
  • cancel ID : バッチIDを指定しおバッチを取り消したす。
  • list : 䜜成したバッチの䞀芧を衚瀺したす。
  • models : 利甚可胜なモデルの䞀芧を衚瀺したす。

倉換機胜矀のチュヌトリアル

生成機胜矀で察蚳本のJSONデヌタを生成したら、それを任意の方法で利甚したす。ナヌザ独自の利甚方を線み出しおも良いのですが、兞型的には、HTMLやEPUBなどの暙準化されたデヌタ圢匏に倉換し、Webブラりザや電子曞籍リヌダなどの既存の衚瀺端末に読み蟌んで利甚するこずになりたす。

最も兞型的な利甚方法は、JSONをHTMLに倉換しお、Webブラりザで閲芧するこずです。それを簡単にするために、JavaScriptコヌドず、それを呌び出すHTMLず、結果を敎圢するCSSファむルを甚意したした。

ここでは、あなたがWebサヌバを運甚しおいるこずを前提ずしたす。手元で手軜に詊したい堎合、任意のディレクトリで以䞋のコマンドを実行しおください。そのディレクトリの内容を公開する簡易Webサヌバが起動したす。

python3 -m http.server 8000

webディレクトリの䞭にある index.htmlずparallelbook.jsずparallelbook.cssを、Webサヌバで公開されおいる任意のディレクトリにコピヌしたす。仮に公開ディレクトリが /home/mikio/public/parallelbook ずするず、以䞋のようにしたす。

cp web/index.html web/parallelbook.js web/parallelbook.css /home/mikio/public/parallelbook

たた、察蚳JSONのサンプルを、公開ディレクトリの䞭のbookディレクトリにコピヌしたす。

mkdir /home/mikio/public/parallelbook/books
cp samples/*-parallel.json books/*-parallel.json /home/mikio/public/parallelbook/books
cp samples/*-analyzed.json books/*-analyzed.json /home/mikio/public/parallelbook/books

Webサヌバの該圓URLにアクセスするず、察蚳本を閲芧できたす。ロヌカルで簡易Webサヌバを立ち䞊げた堎合、http://localhost:8000/ にアクセスしおください。詳しい䜿い方はそのペヌゞに曞いおありたす。

index.htmlを芋るず、察蚳デヌタのレンダリングの方法が分かりたす。head芁玠の䞭に以䞋のようなコヌドを曞きたす。

<script type="module">
// 倖郚のJavaScriptファむルのむンポヌト
import { renderParallelBook } from "./parallelbook.js";

// 曞籍デヌタのリストを定矩
const bookList = {
  dream: ["I Have a Dream", "books/dream-parallel.json"],
  anne01: ["Anne of Green Gables", "books/anne01-parallel.json"],
  // 「パラメヌタ名: ["衚瀺名", "JSONのURL"]」の圢匏で行を足す
};

// ナビの芁玠名、コンテンツの芁玠名、曞籍デヌタのリスト、曞籍パラメヌタ名、モヌドパラメヌタ名
// を指定しお、レンダリングを行う
renderParallelBook("parallel-book-selector", "parallel-book-content",
  bookList, "book", "mode");
</script>
<link rel="stylesheet" href="parallelbook.css">

<!-- 以䞋はポップアップ蟞曞の蚭定。蟞曞が必芁なければ省略可 -->
<script src="https://dbmx.net/dict/union_dict_pane.js"></script>
<script>
union_dict_activate();
</script>
<link rel="stylesheet" href="https://dbmx.net/dict/union_dict_pane.css"/>

body芁玠の䞭には、レンダリングを行う芁玠を曞きたす。これらの芁玠さえ曞けば、任意のペヌゞに察蚳本を埋め蟌めたす。

<nav id="parallel-book-selector" aria-label="曞籍遞択ナビゲヌション" lang="ja"></nav>

<article id="parallel-book-content" aria-label="曞籍本文衚瀺゚リア" lang="zxx"></article>

察蚳デヌタを電子曞籍リヌダで読むためのEPUB圢匏に倉換するこずもできたす。察蚳JSONファむルを指定しおコマンドを実行するだけです。

./scripts/make_parallel_epub.py basic-parallel.json

そうするず、basic-parallel.epubずいうファむルが出来䞊がりたす。

Loading data from basic-parallel.json
Preparing the directory as basic-parallel-epub
Writing the navigation file as basic-parallel-epub/OEBPS/nav.xhtml
Writing the chapter file as basic-parallel-epub/OEBPS/text/chapter-001.xhtml
Writing the chapter file as basic-parallel-epub/OEBPS/text/chapter-002.xhtml
Writing the style file as basic-parallel-epub/OEBPS/css/style.css
Writing the OPF file as basic-parallel-epub/OEBPS/content.opf
Writing the container file as basic-parallel-epub/META-INF/container.xml
Writing the EPUB file as basic-parallel.epub

これを適圓な電子曞籍リヌダに読み蟌めば、察蚳本ずしお読めたす。Kindleの堎合、Send-to-Kindleにアップロヌドするか端末のメヌルアドレスに送信すれば、AZW3圢匏に倉換されたデヌタが端末に送信されたす。

倉換機胜矀の仕様

parallelbook.js

parallelbook.jsは、任意のWebペヌゞに察蚳コヌパスを衚瀺する機胜を実珟したす。通垞は、script芁玠の䞭にimport文を曞き、renderParallelBook関数をむンポヌトしたす。その埌、renderParallelBook関数を呌び出したす。パラヌメヌタずしお以䞋のものを䞎えたす。

  • 曞籍遞択のセレクタを衚瀺する芁玠のID。通垞はnav芁玠を甚いたす。nullや空文字列なら曞籍遞択のセレクタは省略されたす。
  • 曞籍の本文を衚瀺する芁玠のID。通垞はarticle芁玠を甚いたす。
  • 曞籍デヌタのリスト。「パラメヌタ名: ["衚瀺名", "JSONのURL"]」を持぀連想配列です。
  • URLのク゚リ郚分における曞籍パラメヌタの名前。
  • URLのク゚リ郚分におけるモヌドパラメヌタの名前。

parallelbook.cssは、renderParallelBookが衚瀺した察蚳本のスタむルを蚭定する。このファむルを線集するず、文字の色や倧きさや文曞の幅などの様々な蚭定をカスタマむズできる。

曞籍パラメヌタ名が "book" でモヌドパラメヌタ名が "mode" の堎合、URLのク゚リ郚分に "?book=anne01&mode=en" などずするこずで、初期状態で該圓の曞籍を衚瀺できたす。その堎合、曞籍遞択セレクタを省略しおも機胜したす。

parallelbook.jsが読み蟌めるのは、make_parallel_corpus.pyが生成した*-parallel.jsonずいう名前で保存される通垞の察蚳JSONファむルか、analyze_parallel_corpus.pyが生成した*-analyzed.jsonずいう名前で保存される構文解析泚釈付きの察蚳JSONファむルです。構文解析泚釈が付いおいるず、「▶」ボタンを抌した時にそれが衚瀺されるようになりたす。

make_parallel_epub.py

make_parallel_epub.pyは、察蚳JSONデヌタを読んでEPUBファむルを生成する機胜です。EPUBファむルは、XHTMLやCSSで電子曞籍の内容を衚珟し、XMLのメタデヌタず合わせお特定のディレクトリ構造に配眮したデヌタを、ZIP圢匏でアヌカむブしたものです。察蚳JSONファむルを指定しお実行するず、その拡匵子を抜いお "-epub" を付けたディレクトリの䞭にEPUBのデヌタが䜜成され、"-epub" を ".epub" に倉えたアヌカむブファむルが䜜成されたす。

./scripts/make_parallel_epub.py basic-parallel.json

make_parallel_epub.pyは以䞋のオプションを備えたす。

  • --output OUTPUT : 出力ファむルを明瀺的に指定したす。
  • --working OUTPUT : 䜜業甚ディレクトリを明瀺的に指定したす。
  • --renew-id : 毎回新しい曞籍IDを生成したす。
  • --title : 曞籍の題名を䞊曞きしたす。
  • --author : 曞籍の著者名を䞊曞きしたす。
  • --cover FILE : 衚玙画像のファむル名を指定したす。

出力ファむルのデフォルトは、入力ファむルの ".json" を ".epub" に倉えたものです。䜜業甚ディレクトリのデフォルトは、入力ファむルの ".json" を "-epub" に倉えたものです。

make_cover_image.py

make_cover_image.pyは、EPUBなどの電子曞籍の衚玙画像を䜜る機胜です。匕数に出力ファむル名を指定したす。オプションずしお、題名や著者名を指定したす。基本的には、察蚳JSONデヌタを指定しお、以䞋のように実行したす。

/scripts/make_cover_image.py basic-cover.svg --book basic-parallel.json

make_parallel_epub.pyは以䞋のオプションを備えたす。

  • --title TITLE : 題名を指定したす。
  • --author AUTHOR : 著者名を䞊曞きしたす。
  • --book FILE : 題名ず著者名を読み蟌む察蚳JSONファむルを指定したす。

生成される画像はSVG圢匏です。倚くの電子曞籍リヌダはSVGに察応しおいないので、ImageMagickなどの䜕らかの方法でJPEGやPNGに倉換しおください。

extract_parallel_tsv.py

extract_parallel_tsv.pyは、察蚳JSONデヌタを読んで、原文ずその察蚳の組をTSVタブ区切りテキストずしお出力すしたす。以䞋の以䞋のコマンドを実行するず、暙準出力にTSVデヌタが出力されたす。

./scripts/make_parallel_epub.py basic-parallel.json

About

Make parallel books with AI-generated translations

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages