Enrich French to English phrasebooks with OpenAI API.
Project description
phrasebook-fr-to-en
phrasebook-fr-to-en is a CLI that uses the OpenAI API to enrich
French to English phrasebooks with AI generated translations, audios,
and images.
Installing and running
It's a Python program. You can install it as an uv tool like this:
uv tool install phrasebook-fr-to-en
After you generate an OpenAI API key, and with your original French to
English translations in the file my-phrasebook.tsv, you can generate
new ones, along with audios and images, by running this:
export OPENAI_API_KEY=<your-api-key>
phrasebook-fr-to-en my-phrasebook.tsv
This creates the file enriched_phrasebook.tsv with all translations.
It also saves the audios and images in the directory media.
Both enriched_phrasebook.tsv and media sit next to your phrasebook
file.
Your original phrasebook is left unchanged.
Run the following to list the options and their documentation:
phrasebook-fr-to-en --help
OpenAI API [IMPORTANT]
This program uses the OpenAI API with the following models:
- https://platform.openai.com/docs/models/gpt-5.2
- https://platform.openai.com/docs/models/gpt-4o-mini-tts
- https://platform.openai.com/docs/models/gpt-image-1.5
To use it, you need to register with OpenAI. You also need to be verified as an organization (required for the image model). Then create an API key: https://platform.openai.com.
Once you've done this, set OPENAI_API_KEY as an environment variable
before you run the program, like this:
export OPENAI_API_KEY=<your-api-key>
Format of your original phrasebook
Your original phrasebook must be a TSV file (TAB separation) with the
columns date, french, and english, like in this example:
date french english
2025-11-15 Montez les escaliers. Climb the stairs.
2025-11-16 Il est beau. He is handsome.
2025-01-17 Il est moche. He is ugly.
Full example
phrasebook-fr-to-en takes a TSV (TAB separation) file as input.
Each row is a French to English translation. It uses the following
columns: date, french, english.
For each translation (each row), two new related translations are generated. The goal is to show:
- An English grammar point, or
- Useful nouns, verbs, or
- Alternative phrasing (formality, slang, etc.).
These new translations, along with the original, are saved in the file
enriched_phrasebook.tsv. It sits next to your phrasebook file.
Records in your original phrasebook whose english field matches a
record in the enriched phrasebook are skipped.
Your original phrasebook is left unchanged.
For all translations (original and AI generated), an English audio and
an image are generated. They are saved in a media directory next to
the original phrasebook file.
For instance, if my-phrasebook.tsv contains the following record
(columns separated by tabs)
date french english
2025-11-15 Montez les escaliers. Climb the stairs.
and you run the following commands:
export OPENAI_API_KEY=<your-api-key>
phrasebook-fr-to-en my-phrasebook.tsv
This produces the file enriched_phrasebook.tsv with AI generated
translations. It has the following columns: french, english,
anki_audio, anki_img, generated_from, id, audio_filename,
img_filename, date.
french english anki_audio anki_img generated_from id audio_filename img_filename date
Montez les escaliers. Climb the stairs. [sound:phrasebook-fr-to-en-1.mp3] "<img src=""phrasebook-fr-to-en-1.png"">" 1 phrasebook-fr-to-en-1.mp3 phrasebook-fr-to-en-1.png 2025-11-15
Montez les escaliers jusqu’au premier étage. Climb the stairs up to the first floor. [sound:phrasebook-fr-to-en-2.mp3] "<img src=""phrasebook-fr-to-en-2.png"">" 1 2 phrasebook-fr-to-en-2.mp3 phrasebook-fr-to-en-2.png 2025-11-15
Prenez les escaliers, c’est juste à gauche. Take the stairs; it’s just on the left. [sound:phrasebook-fr-to-en-3.mp3] "<img src=""phrasebook-fr-to-en-3.png"">" 1 3 phrasebook-fr-to-en-3.mp3 phrasebook-fr-to-en-3.png 2025-11-15
This also generates 3 audios and 3 images.
Your directory then looks like this:
.
├── enriched_phrasebook.tsv
├── my-phrasebook.tsv
└── media
├── phrasebook-fr-to-en-1.mp3
├── phrasebook-fr-to-en-1.png
├── phrasebook-fr-to-en-2.mp3
├── phrasebook-fr-to-en-2.png
├── phrasebook-fr-to-en-3.mp3
└── phrasebook-fr-to-en-3.png
For Anki users
In the previous example, did you notice the columns anki_audio and
anki_img? They contain formatted fields for audio and image that
you can use directly in your Anki decks:
[sound:phrasebook-fr-to-en-1.mp3]
<img src="phrasebook-fr-to-en-1.png">
This way you can import enhanced_phrasebook.tsv directly into Anki.
No changes are needed to get audio played and images displayed.
Note that this only works:
- If you enable "Allow HTML" option when importing the enriched file,
- If you copy the audios and images from the
mediadirectory to your Ankicollection.mediadirectory.
See Anki docs:
- https://docs.ankiweb.net/importing/text-files.html#importing-media
- https://docs.ankiweb.net/files.html
Dev
Installing and running from source
To run phrasebook-fr-to-en from the source, run this:
uv run src/phrasebook_fr_to_en/cli.py phrasebook.tsv
Alternatively, phrasebook-fr-to-en can be installed as an uv tool
from the source like this:
uv tool install .
Then run it like this:
phrasebook-fr-to-en my-phrasebook.tsv
Running the tests
Run the tests like this:
uv run pytest
To run the tests with real calls to the OpenAI API, run this:
OPENAI_LIVE=1 uv run pytest
For this to work, the OPENAI_API_KEY environment variable must be
set using an OpenAI API key. This variable can also be declared in a
.env file.
Test coverage
This software has 100% test coverage.
To check this, you can run the following commands:
OPENAI_LIVE=1 uv run coverage run -m pytest
uv run coverage report
As mentioned above, OPENAI_API_KEY must be set prior to running the
tests with coverage.
Linter + formating
ty and ruff must be installed first:
ty check
ruff format
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file phrasebook_fr_to_en-0.3.0.tar.gz.
File metadata
- Download URL: phrasebook_fr_to_en-0.3.0.tar.gz
- Upload date:
- Size: 9.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63e946fbf8cdd1e2ff6a6fffe1c4b2e8369784307e4904dc5df3c593f2145b41
|
|
| MD5 |
73503ff7a33c7f6905a97eec94e29088
|
|
| BLAKE2b-256 |
0b7dee1702e2dd1cb64dea13c991235b45048b1df81fe73f565447917537ec4f
|
File details
Details for the file phrasebook_fr_to_en-0.3.0-py3-none-any.whl.
File metadata
- Download URL: phrasebook_fr_to_en-0.3.0-py3-none-any.whl
- Upload date:
- Size: 12.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a0bca89365117bf50a5722cecbf628247fb29b7552751c5584ba64eb3dc8f57f
|
|
| MD5 |
54c6a7e21b7e506bfc1293cd35cdfee2
|
|
| BLAKE2b-256 |
5a05b6efeeeb22f1e7c4d6bf81414a18e195ca0393a2de96015ce4b8f3401d30
|