👷 Update LLM translation CI, add language matrix and extra commands, prepare for scheduled run (#14529)

This commit is contained in:
Sebastián Ramírez 2025-12-16 04:40:50 -08:00 committed by GitHub
parent 4414cd849d
commit 2e7aaea524
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 104 additions and 7 deletions

View File

@ -16,7 +16,7 @@ on:
- update-outdated - update-outdated
- add-missing - add-missing
- update-and-add - update-and-add
- remove-all-removable - remove-removable
language: language:
description: Language to translate to as a letter code (e.g. "es" for Spanish) description: Language to translate to as a letter code (e.g. "es" for Spanish)
type: string type: string
@ -32,9 +32,42 @@ env:
UV_SYSTEM_PYTHON: 1 UV_SYSTEM_PYTHON: 1
jobs: jobs:
job: langs:
if: github.repository_owner == 'fastapi'
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs:
langs: ${{ steps.show-langs.outputs.langs }}
commands: ${{ steps.show-langs.outputs.commands }}
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
cache-dependency-glob: |
requirements**.txt
pyproject.toml
- name: Install Dependencies
run: uv pip install -r requirements-github-actions.txt -r requirements-translations.txt
- name: Export Language Codes
id: show-langs
run: |
echo "langs=$(python ./scripts/translate.py llm-translatable-json)" >> $GITHUB_OUTPUT
echo "commands=$(python ./scripts/translate.py commands-json)" >> $GITHUB_OUTPUT
env:
LANGUAGE: ${{ github.event.inputs.language }}
COMMAND: ${{ github.event.inputs.command }}
translate:
if: github.repository_owner == 'fastapi'
needs: langs
runs-on: ubuntu-latest
strategy:
matrix:
lang: ${{ fromJson(needs.langs.outputs.langs) }}
command: ${{ fromJson(needs.langs.outputs.commands) }}
permissions: permissions:
contents: write contents: write
steps: steps:
@ -50,8 +83,6 @@ jobs:
- name: Setup uv - name: Setup uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v7
with: with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: | cache-dependency-glob: |
requirements**.txt requirements**.txt
pyproject.toml pyproject.toml
@ -68,10 +99,11 @@ jobs:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- name: FastAPI Translate - name: FastAPI Translate
run: | run: |
python ./scripts/translate.py ${{ github.event.inputs.command }} python ./scripts/translate.py ${{ matrix.command }}
python ./scripts/translate.py make-pr python ./scripts/translate.py make-pr
env: env:
GITHUB_TOKEN: ${{ secrets.FASTAPI_TRANSLATIONS }} GITHUB_TOKEN: ${{ secrets.FASTAPI_TRANSLATIONS }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LANGUAGE: ${{ github.event.inputs.language }} LANGUAGE: ${{ matrix.lang }}
EN_PATH: ${{ github.event.inputs.en_path }} EN_PATH: ${{ github.event.inputs.en_path }}
COMMAND: ${{ matrix.command }}

View File

@ -1,3 +1,4 @@
import json
import secrets import secrets
import subprocess import subprocess
from collections.abc import Iterable from collections.abc import Iterable
@ -828,6 +829,65 @@ def translate_lang(language: Annotated[str, typer.Option(envvar="LANGUAGE")]) ->
print(f"Done translating: {p}") print(f"Done translating: {p}")
def get_llm_translatable() -> list[str]:
translatable_langs = []
langs = get_langs()
for lang in langs:
if lang == "en":
continue
lang_prompt_path = Path(f"docs/{lang}/llm-prompt.md")
if lang_prompt_path.exists():
translatable_langs.append(lang)
return translatable_langs
@app.command()
def list_llm_translatable() -> list[str]:
translatable_langs = get_llm_translatable()
print("LLM translatable languages:", translatable_langs)
return translatable_langs
@app.command()
def llm_translatable_json(
language: Annotated[str | None, typer.Option(envvar="LANGUAGE")] = None,
) -> None:
translatable_langs = get_llm_translatable()
if language:
if language in translatable_langs:
print(json.dumps([language]))
return
else:
raise typer.Exit(code=1)
print(json.dumps(translatable_langs))
@app.command()
def commands_json(
command: Annotated[str | None, typer.Option(envvar="COMMAND")] = None,
) -> None:
available_commands = [
"translate-page",
"translate-lang",
"update-outdated",
"add-missing",
"update-and-add",
"remove-removable",
]
default_commands = [
"remove-removable",
"update-outdated",
"add-missing",
]
if command:
if command in available_commands:
print(json.dumps([command]))
return
else:
raise typer.Exit(code=1)
print(json.dumps(default_commands))
@app.command() @app.command()
def list_removable(language: str) -> list[Path]: def list_removable(language: str) -> list[Path]:
removable_paths: list[Path] = [] removable_paths: list[Path] = []
@ -939,6 +999,7 @@ def update_and_add(language: Annotated[str, typer.Option(envvar="LANGUAGE")]) ->
def make_pr( def make_pr(
*, *,
language: Annotated[str | None, typer.Option(envvar="LANGUAGE")] = None, language: Annotated[str | None, typer.Option(envvar="LANGUAGE")] = None,
command: Annotated[str | None, typer.Option(envvar="COMMAND")] = None,
github_token: Annotated[str, typer.Option(envvar="GITHUB_TOKEN")], github_token: Annotated[str, typer.Option(envvar="GITHUB_TOKEN")],
github_repository: Annotated[str, typer.Option(envvar="GITHUB_REPOSITORY")], github_repository: Annotated[str, typer.Option(envvar="GITHUB_REPOSITORY")],
) -> None: ) -> None:
@ -955,6 +1016,8 @@ def make_pr(
branch_name = "translate" branch_name = "translate"
if language: if language:
branch_name += f"-{language}" branch_name += f"-{language}"
if command:
branch_name += f"-{command}"
branch_name += f"-{secrets.token_hex(4)}" branch_name += f"-{secrets.token_hex(4)}"
print(f"Creating a new branch {branch_name}") print(f"Creating a new branch {branch_name}")
subprocess.run(["git", "checkout", "-b", branch_name], check=True) subprocess.run(["git", "checkout", "-b", branch_name], check=True)
@ -965,6 +1028,8 @@ def make_pr(
message = "🌐 Update translations" message = "🌐 Update translations"
if language: if language:
message += f" for {language}" message += f" for {language}"
if command:
message += f" ({command})"
subprocess.run(["git", "commit", "-m", message], check=True) subprocess.run(["git", "commit", "-m", message], check=True)
print("Pushing branch") print("Pushing branch")
subprocess.run(["git", "push", "origin", branch_name], check=True) subprocess.run(["git", "push", "origin", branch_name], check=True)