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 tiktokenGitã³ãã³ãã§æ¬ãããžã§ã¯ãã®ãã¡ã€ã«ãããŠã³ããŒãããŸãã
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.1Loading 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ã¯ã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ã¯ã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ã¯ã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ã«æž¡ãããã³ããã¯ã¹ã¯ãªããå ã«ããŒãã³ãŒããããŠããã®ã§ãé©å®ä¿®æ£ããŠäœ¿ã£ãŠãã ããã倱æããã¡ãªãã¿ãŒã³ãããã°ãããã解決ããäŸãè¶³ããšç²ŸåºŠãäžãããŸãã
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 8000webãã£ã¬ã¯ããªã®äžã«ãã 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/booksWebãµãŒãã®è©²åœ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ã¯ãä»»æã®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ã¯ã察蚳JSONããŒã¿ãèªãã§EPUBãã¡ã€ã«ãçæããæ©èœã§ããEPUBãã¡ã€ã«ã¯ãXHTMLãCSSã§é»åæžç±ã®å 容ã衚çŸããXMLã®ã¡ã¿ããŒã¿ãšåãããŠç¹å®ã®ãã£ã¬ã¯ããªæ§é ã«é 眮ããããŒã¿ããZIP圢åŒã§ã¢ãŒã«ã€ããããã®ã§ãã察蚳JSONãã¡ã€ã«ãæå®ããŠå®è¡ãããšããã®æ¡åŒµåãæã㊠"-epub" ãä»ãããã£ã¬ã¯ããªã®äžã«EPUBã®ããŒã¿ãäœæããã"-epub" ã ".epub" ã«å€ããã¢ãŒã«ã€ããã¡ã€ã«ãäœæãããŸãã
./scripts/make_parallel_epub.py basic-parallel.jsonmake_parallel_epub.pyã¯ä»¥äžã®ãªãã·ã§ã³ãåããŸãã
- --output OUTPUT : åºåãã¡ã€ã«ãæç€ºçã«æå®ããŸãã
- --working OUTPUT : äœæ¥çšãã£ã¬ã¯ããªãæç€ºçã«æå®ããŸãã
- --renew-id : æ¯åæ°ããæžç±IDãçæããŸãã
- --title : æžç±ã®é¡åãäžæžãããŸãã
- --author : æžç±ã®èè åãäžæžãããŸãã
- --cover FILE : 衚çŽç»åã®ãã¡ã€ã«åãæå®ããŸãã
åºåãã¡ã€ã«ã®ããã©ã«ãã¯ãå ¥åãã¡ã€ã«ã® ".json" ã ".epub" ã«å€ãããã®ã§ããäœæ¥çšãã£ã¬ã¯ããªã®ããã©ã«ãã¯ãå ¥åãã¡ã€ã«ã® ".json" ã "-epub" ã«å€ãããã®ã§ãã
make_cover_image.pyã¯ãEPUBãªã©ã®é»åæžç±ã®è¡šçŽç»åãäœãæ©èœã§ããåŒæ°ã«åºåãã¡ã€ã«åãæå®ããŸãããªãã·ã§ã³ãšããŠãé¡åãèè åãæå®ããŸããåºæ¬çã«ã¯ã察蚳JSONããŒã¿ãæå®ããŠã以äžã®ããã«å®è¡ããŸãã
/scripts/make_cover_image.py basic-cover.svg --book basic-parallel.jsonmake_parallel_epub.pyã¯ä»¥äžã®ãªãã·ã§ã³ãåããŸãã
- --title TITLE : é¡åãæå®ããŸãã
- --author AUTHOR : èè åãäžæžãããŸãã
- --book FILE : é¡åãšèè åãèªã¿èŸŒã察蚳JSONãã¡ã€ã«ãæå®ããŸãã
çæãããç»åã¯SVG圢åŒã§ããå€ãã®é»åæžç±ãªãŒãã¯SVGã«å¯Ÿå¿ããŠããªãã®ã§ãImageMagickãªã©ã®äœããã®æ¹æ³ã§JPEGãPNGã«å€æããŠãã ããã
extract_parallel_tsv.pyã¯ã察蚳JSONããŒã¿ãèªãã§ãåæãšãã®å¯Ÿèš³ã®çµãTSVïŒã¿ãåºåãããã¹ãïŒãšããŠåºåãããŸãã以äžã®ä»¥äžã®ã³ãã³ããå®è¡ãããšãæšæºåºåã«TSVããŒã¿ãåºåãããŸãã
./scripts/make_parallel_epub.py basic-parallel.json