Com traduir arxius PO amb ChatGPT

Darrera actualització:

Diuen que una de les habilitats que millor manejen les IAs conversacionals són els idiomes. Després de trastejar una estona amb ChatGPT, no puc estar més d’acord. Així que em vaig preguntar si hi hauria eines que m’ajudessin amb traduccions de text fent servir arxius amb contingut estructurat com els arxius PO.

Els arxius amb l’extensió .PO ens permeten gestionar les traduccions de WordPress, els seus temes, extensions, així com a altres aplicacions i eines. Al buscar eines de traducció d’arxius PO que fessin servir ChatGPT, vaig trobar Gpt-po de ryanhex53. Em va servir per veure el potencial i em va llançar a desenvolupar la meva pròpia eina amb la qual provar a fons les diferents opcions de l’API d’OpenAI.

Després de realitzar proves el resultat va ser tota una sorpresa.

Consideracions prèvies a l’ús de ChatGPT

Utilitzarem l’API d’OpenAI per traduir amb ChatGPT. Aquesta API funciona amb la seva pròpia bossa de USD i el seu ús es tarifica a través de tokens. En la seva versió gratuïta l’ús dels tokens està limitat.

Aquest article és bastant dens i convé aclarir prèviament certs aspectes o conceptes. La llista a continuació ens permetrà avançar més fluidament per l’article i servirà com a referència en cas de dubte:

  • Token: unitat mínima en la qual els models de llenguatge (GPT’s) d’OpenAI divideixen una paraula per després poder-la tarificar. No és uniforme en tots els models de ChatGPT, ni la mateixa paraula representa sempre el mateix nombre de tokens en el mateix model.

Si vols saber més:

Què és un token i com es mesura?

Sobre la limitació de tokens

  • Cost: Traduir amb l’API d’OpenAI té un cost per token. Això pot influir en el model de ChatGPT que volem fer servir.
  • ChatGPT fa servir un model de llenguatge creat per OpenAI. L’API que utilitzarem és la pròpia d’OpenAI.
  • gptpo és una aplicació executable en línia de comandes dissenyada per gestionar traduccions de text d’arxius en format PO, utilitzant els models de llenguatge d’intel·ligència artificial de GPT (Generative Pre-trained Transformer).

Traduint amb “Chat Completions API”

Chat Completions API, és una de les maneres que ofereix l’API d’OpenAI per accedir a ChatGPT d’OpenAI. Per realitzar experiments, vaig trobar a github l’aplicació “gpt-po“, una aplicació de línia de comandes desenvolupada en JavaScript. “gpt-po” es connecta a ChatGPT d’OpenAI i realitza trucades fent servir el procés de “Chat Completion”. És similar a obrir un xat, proporcionar instruccions perquè assumeixi el rol de traductor (“prompting”), i enviar un a un els missatges de l’arxiu PO per traduir. Més avall es descriu el procés pas a pas.

Tot apuntava cap a l’èxit, cap a una revolució…, però el resultat van ser traduccions imprecises, inconsistents i amb errors greus:

  • Algunes traduccions directament les interpretava, i algunes en format de pregunta, directament les responia saltant-se les instruccions.
  • No respectava la puntuació al final de frases, molt menys els espais en blanc.
  • Impossible trobar resultats consistents en el temps.
  • A més, les traduccions que realitzava de l’Anglès al Català, en la comunitat WordPress, estan subjectes a un bon nombre de regles. Tenim fins i tot un Glossari que imposa certa rigidesa i que ChatGPT a la data no era capaç d’interpretar.
  • Tampoc podia excedir-me en la longitud del “prompt”, ja que la modalitat “Chat completion” requereix que enviïs el “prompt” per a cada pregunta (en el nostre cas cada missatge a traduir). Com més extens el prompt, més lent es feia el procés i més s’encareixien els costos de traducció.

Després de lluitar amb diversos prompts i diferents models (gpt-3.5-turbo, gpt-4-1106-preview) vaig abandonar els meus experiments.

Els GPT Assistants, un gran avenç!

Al novembre de 2023, durant l’esdeveniment OpenAI Devday, es van presentar els Assistants, una nova forma de contextualitzar el treball amb ChatGPT. L’accés a aquests Assistants, es realitza a través d’una interfície de programació d’aplicacions (API).

Un gran avanç que podria ajudar a solucionar els nombrosos problemes amb els quals m’havia trobat fins al moment.

En poques paraules, amb els Assistants pots ajustar un prompt per després reciclar-lo al llarg del xat. I alguna cosa molt útil, pots adjuntar arxius per enriquir el prompt i el posterior procés.

El primer que vaig fer va ser construir un Assistant en el propi panell d’OpenAI.

EnCa Translator. Precise, glossary-compliant English-Catalan translations
Configuració de l’Assistant des del panell d’OpenAI.

Li vaig donar una bona llista d’instruccions i li vaig adjuntar un Glossari en format text perquè el pogués fer servir per supervisar les seves pròpies traduccions.

I els resultats, molt millors.

ChatGPT Assistant translator exemple traducció

L’”Assistant” resultant està publicat i el podeu provar en aquest enllaç https://chat.openai.com/g/g-AtqPosD0C-enca-translator

Usant Assistants d’OpenAI per traduir arxius PO

Després dels resultats obtinguts amb l’Assistant, vaig tornar a recuperar les esperances, així que em vaig proposar incorporar aquesta nova modalitat al traductor gpt-po.

Vaig fer una còpia a GitHub del traductor, bé un fork al qual vaig anomenar “gptpo“, i al poc temps ja tenia incorporat “Assistants” per provar-ho contra un arxiu PO i un bon volum de missatges.

Valorant la traducció d’arxius PO amb Assistant

Després d’avaluar el resultat de la traducció, la valoració de l’ús d’Assistant va ser: “no està malament”, podria arribar a ser útil.

Efectivament: no era un mal resultat, era un avanç, però em vaig trobar amb:

  • Imprecisions, moltes imprecisions i inconsistències. Novament els espais i signes de puntuació al final de cadena no es respectaven.
  • No sempre seguia les regles del glossari.
  • Lentitud. Per traduir 300 cadenes (amb un volum d’uns 2900 tokens) necessitava gairebé 1 hora. Potser fos l’ús del model gpt-4-1106-preview, o la càrrega afegida de supervisió de les traduccions per seguir les regles del glossari que li vaig adjuntar en forma d’arxiu.
  • Els costos es van disparar. Els tokens amb el model gpt-4 són 20 vegades més cars. No obstant això, el fet de no enviar el prompt cada vegada i poder preservar el context (thread) vaig pensar que podria ajudar. El resultat no semblava estar d’acord amb la meva teoria, la finestra de context es va fer molt gran. Per generar 2909 tokens de traducció va necessitar 169546 tokens de context:
Per retornar 2909 tokens (uns 300 missatges traduïts), va necessitar 169546 tokens de context.

De nou el resultat em va semblar estar lluny del que esperava. Potser se m’escapava algun detall d’implementació. Alguna cosa semblava no estar bé, i em vaig disposar a rellegir a fons els manuals de l’API.

Millors traduccions amb Fine-Tuning de ChatGPT

No sé com se m’havia passat per alt, el fine-tuning em va semblar de seguida l’opció interessant per intentar acotar les imprecisions i sobretot per donar-li indicacions concretes al model.

El fine-tuning permet ajustar i millorar el rendiment del model específicament per a una tasca concreta, la qual cosa ajuda a reduir imprecisions i proporcionar indicacions precises.

En concret, el fine-tuning de ChatGPT és un procés en el qual s’ajusta i personalitza el model d’intel·ligència artificial ChatGPT perquè s’adapti millor a un conjunt específic de dades o necessitats. És com ensenyar-li a ChatGPT a ser millor en una àrea específica mitjançant la pràctica amb exemples rellevants.

A la Documentació, en l’apartat de fine-tuning es diu:

El “fine-tuning” o “afinament” dels models d’OpenAI pot fer-los millors per a aplicacions específiques, però requereix una inversió de temps i esforç acurada.

Amb l’emoció, no vaig considerar la inversió de temps i esforç com a alguna cosa important, així que vaig decidir ajustar un model sense pensar-ho gaire.

Podeu trobar informació detallada a la documentació d’OpenAI, i també més endavant, en aquest mateix post, un pas a pas del procés.

Millorant “gptpo” amb el “fine-tuning” de ChatGPT

Per facilitar el procés vaig afegir les comandes per fer “fine-tuning” a l’aplicació “gptpo”. D’aquesta manera amb “gptpo” podem afinar un model, per després usar-lo en la traducció d’arxius PO.

gptpo és una aplicació executable en línia de comandes que fa servir el motor Node.js, i que està dissenyada per gestionar traduccions d’arxius PO utilitzant models de llenguatge d’OpenAI a través de la seva API.

Instal·lar gptpo per gestionar traduccions

Si no disposes de Node.js al teu ordinador. A la pàgina oficial trobaràs els instal·ladors: https://nodejs.org/en/download

Una vegada disposem de Node.js, ja podem instal·lar l’aplicació gptpo amb la comanda:

sudo npm install -g @sitamet/gptpo

Per a més detalls podeu consultar el “Readme” del repositori de github: https://github.com/sitamet/gptpo

A partir d’ara, ja tens a la teva disposició la comanda gptpo. Verifica que tot ha anat bé provant-ho amb un simple gptpo --help

~ » gptpo --help

Usage: @sitamet/gptpo [options] [command]

Translation command line tool for gettext (po) files that supports pre-translation and chat-gpt translations with assitant and fine tunning of models.

Options:
  -V, --version                  output the version number
  -h, --help                     display help for command

Commands:
  translate [options]            translate po file with completions (default command)
  translate-assistant [options]  translate po file with assistant
  fine-tuning [options]          launch a new fine-tune task to customize your OpenAI model
  fine-tuning-jobs [options]     list fine-tune jobs
  preprocess [options]           update po from previous translated po files (origin po will incorporate translations from previous po files)
  help [command]                 display help for command

Necessitaràs una API Key d’OpenAI

Per usar gptpo i fer traduccions usant l’API d’OpenAI, és precís autoritzar les trucades amb una clau única. Per obtenir l’API Key, dirigiu-vos a https://platform.openai.com/api-keys

Identifica’t i després a la pàgina API keys usa el botó “+ Create new secret key”:

Create openAI key

Cada vegada que fem servir gptpo per traduir, haurem d’aportar la nostra API key. Per evitar haver de “arrossegar” l’API key en totes les crides del comandament, la guardarem en una variable d’entorn:

export OPENAI_API_KEY=sk-F***********************************vGL

Traduir un arxiu PO amb els models d’OpenAI

Encara que acabarem traduint amb un model “afinat”, començarem usant un dels models estàndard d’OpenAI. La idea és recollir tots els errors que cometi el “model” per ajustar-lo a continuació mitjançant “fine-tuning”.

OpenAI posa diferents límits i preus a cadascun dels seus models.

Més informació sobre models disponibles a https://platform.openai.com/docs/models/overview

En el meu cas em vaig decantar per usar gpt-3.5-turbo-1106, per dos motius:

  1. L’objectiu és poder traduir volums elevats de cadenes sense haver de pagar molt per això.
  2. Al fer-lo servir amb fine-tuning i amb una mida de context no molt àmplia, 3.5-turbo-1106 podia equiparar els resultats de gpt-4 i fins i tot ser més ràpid.

Encara que aquest escenari pot canviar conforme OpenAI va lliurant nous models.

Guardar el model en variable d’entorn

Igual que amb l’API Key, per no arrossegar el model en les crides al comandament gptpo, el guardem en una variable d’entorn:

export OPENAI_API_MODEL=gpt-3.5-turbo-1106

Definir un “system prompt” concís

És important remarcar que, a diferència del “system prompt” que construiríem usant un model estàndard, és a dir: un “prompt” refinat, extens detallat,… com anem a treballar amb “fine-tuning”, anem a usar un “system prompt” concís. I ja ens ocuparem de polir i donar forma a les respostes usant l’afinament o “fine-tuning”.

Guardarem el text del nostre “system prompt” a systemprompt.txt al directori de treball des d’on anem a llançar el comandament gptpo:

cd demo
echo 'You are a machine translating English to Catalan text.' > systemprompt.txt

Traduir un arxiu PO amb gptpo

Si volem traduir les cadenes de text de `test.po`, com ja tenim les variables d’entorn definides, el comandament a llançar és relativament senzill:

gptpo translate --po ./test.po --verbose

░░░░░░░░░░░░░░░░░░░░ 0% 0/1 
==> The plugin will load as a regular plugin
==> El plugin es carregarà com un plugin regular.
████████████████████ 100% 1/1 done.

El paràmetre --verbose mostra sobre la marxa les cadenes que va traduint

Traduir un arxiu PO amb un model afinat

En traduir cadenes usant el model estàndard i un prompt escuet, donarem amb un munt de casos que haurem de corregir. És el moment de perfilar el model perquè respongui adequadament.

El fine-tuning consisteix en aportar un conjunt d’entrades i “respostes desitjades”, perquè el model s’ajusti a les nostres especificacions

Més informació a: https://platform.openai.com/docs/guides/fine-tuning

Fine-tuning amb l’ajuda de gptpo

Encara que disposes d’un apartat a la web d’OpenAI específic per treballar el fine-tuning, vaig decidir incorporar les comandes a l’aplicació gptpo i així poder operar des de la línia de comanda. Més endavant veurem com usar-lo.

El primer pas per a un fine-tuning, consisteix a elaborar l’arxiu de tipus JSONL amb tots els missatges a usar per ajustar el model.

Construir un dataset per afinar el model

L’afinament consisteix a enviar un conjunt de dades o “dataset” on posarem el text a traduir i el resultat que desitgem, un nombre finit de vegades, contemplant tots els casos on el model no respon al resultat que desitgem.

Per construir el model de dades o “dataset”, disposes d’informació detallada de com preparar el teu “dataset” en aquesta secció de la documentació. Però no és res complicat, més endavant ho veuràs clar amb l’exemple que et mostrem.

Coses a tenir en compte:

  • L’arxiu s’escriu en un format específic JSON Lines que hem de respectar.
  • El prompt actuarà com un “disparador”. És com aquella frase que fan servir els hipnotitzadors per passar a controlar la ment de l’hipnotitzat. Escollirem una frase curta, significativa i la repetirem sempre igual.
  • Cada línia a l’arxiu és un missatge, on trobarem seccions etiquetades per “role”.
  • Tenim 3 roles:
    • system: aquí va el “prompt” i indicarem sempre la mateixa frase.
    • “user”: aquí va directament el text que nosaltres volem traduir,
    • “assistant”: aquí ve l’entrenament perquè indicarem amb exactitud com hauria de ser la traducció.
  • No et limitis a uns pocs missatges. La documentació menciona un mínim de 10. En el meu cas vaig enviar al voltant de 150. L’objectiu és reforçar el model amb exemples ben fets i fent èmfasi en tots els casos on ChatGPT comete errors i imprecisions.
  • Utilitza el xat amb el seu model estàndard per veure on es donen errors i treballar específicament amb aquests errors per perfilar el model.

Per construir l’arxiu d’afinament, amb l’ajuda d’un editor de text, prepara un arxiu de text i construeix el que seria un motlle. Així podràs concentrar-te en les correccions, ja que només hauràs d’anar omplint els forats amb els missatges de “user” i “assistant”:

{"messages": [{"role": "system", "content": "You are a machine translating English to Catalan text."}, {"role": "user", "content": ""}, {"role": "assistant", "content": ""}]}
{"messages": [{"role": "system", "content": "You are a machine translating English to Catalan text."}, {"role": "user", "content": ""}, {"role": "assistant", "content": ""}]}
{"messages": [{"role": "system", "content": "You are a machine translating English to Catalan text."}, {"role": "user", "content": ""}, {"role": "assistant", "content": ""}]}
{"messages": [{"role": "system", "content": "You are a machine translating English to Catalan text."}, {"role": "user", "content": ""}, {"role": "assistant", "content": ""}]}
{"messages": [{"role": "system", "content": "You are a machine translating English to Catalan text."}, {"role": "user", "content": ""}, {"role": "assistant", "content": ""}]}
{"messages": [{"role": "system", "content": "You are a machine translating English to Catalan text."}, {"role": "user", "content": ""}, {"role": "assistant", "content": ""}]}
{"messages": [{"role": "system", "content": "You are a machine translating English to Catalan text."}, {"role": "user", "content": ""}, {"role": "assistant", "content": ""}]}
...

A continuació, amb paciència i precisió anirem omplint línia a línia inserint el camp “content” de “user” i “assistant”:

{"messages": [{"role": "system", "content": "You are a machine translating English to Catalan text."}, {"role": "user", "content": "File does not exist."}, {"role": "assistant", "content": "El fitxer no existeix."}]}
{"messages": [{"role": "system", "content": "You are a machine translating English to Catalan text."}, {"role": "user", "content": "Skipping malware scan "}, {"role": "assistant", "content": "Omet l'escaneig de malware "}]}
{"messages": [{"role": "system", "content": "You are a machine translating English to Catalan text."}, {"role": "user", "content": "Stop Ignoring"}, {"role": "assistant", "content": "Deixa d’ignorar"}]}
{"messages": [{"role": "system", "content": "You are a machine translating English to Catalan text."}, {"role": "user", "content": "No IPs blocked yet."}, {"role": "assistant", "content": "Encara no hi ha IPs blocades."}]}
{"messages": [{"role": "system", "content": "You are a machine translating English to Catalan text."}, {"role": "user", "content": "Error Activating 2FA"}, {"role": "assistant", "content": "Error en activar el 2FA"}]}
...

Disparar una tasca d’afinament

Per indicar-li a OpenAI que ens “entreni” el model amb els missatges de fine-tuning-ca.jsonl indicarem:

gptpo fine-tuning --suffix cat01 --file ./fine-tuning-ca.json

El --suffix ens ajudarà a versionar el model resultant. Si més endavant entrenem models prèviament afinats, el versionat ens ajudarà a ordenar la col·lecció de models resultant.

Veure l’estat d’afinament del meu model

Després d’executar el comandament d’afinament, OpenAI el posa en cua i t’avisa al cap d’uns minuts per correu electrònic

Amb l’ajuda de gptpo podem llistar els models i veure l’estat del fine-tuning de la següent manera:

gptpo fine-tuning-jobs

[
   {
    object: 'fine_tuning.job',
    id: 'ftjob-2u8sMZaK82tKXpmIr9Rt1iXM',
    model: 'gpt-3.5-turbo-1106',
    created_at: 1704570847,
    finished_at: 1704571377,
    fine_tuned_model: 'ft:gpt-3.5-turbo-1106:wetopi:cat01:8e7AgzNb',
    organization_id: 'org-iMMKhtTcRklst7guwU9LzPr6',
    result_files: [ 'file-bg27iX6hYBIN2rCtDlkkZon6' ],
    status: 'succeeded',
    validation_file: null,
    training_file: 'file-7vDQosGoZ48fni1ekm0TBJE3',
    hyperparameters: { n_epochs: 3, batch_size: 1, learning_rate_multiplier: 2 },
    trained_tokens: 12555,
    error: null
  }
]

El resultat és un objecte JSON. Entre les dades rellevants tenim:

  • model: el model d’entrada que volem ajustar.
  • status: ens indica l’estat del procés de fine-tuning.
  • fine_tuned_model: el nom del model resultant del fine-tuning.

Recorda que pots seguir ajustant un model prèviament afinat.

Si els resultats de la traducció encara retornen imprecisions i errors, envia un nou dataset al model préviament afinat per seguir refinant-lo.

Al panell de control d’OpenAI també podem veure el resultat de l’afinat del model:

Traduir un arxiu po amb gptpo usant un model afinat

Ja tenim un model afinat al qual OpenAI ha donat el nom de ft:gpt-3.5-turbo-1106:wetopi:cat01:8e7AgzNb

El comandament que usarem a gptpo no canvia. Això sí, haurem d’indicar-li el nou model. Per això podem passar-li al comandament el nom del nou model com un paràmetre --model=ft:gpt… o com hem fet amb anterioritat, guardar-lo a la variable d’entorn OPENAI_API_MODEL

export OPENAI_API_MODEL=ft:gpt-3.5-turbo-1106:wetopi:cat01:8e7AgzNb

I llançar com abans el comandament gptpo translate

cd demo
gptpo translate --po ./test.po --verbose

░░░░░░░░░░░░░░░░░░░░ 0% 0/1 
==> The plugin will load as a regular plugin
==> L'extensió es carregarà com una extensió
████████████████████ 100% 1/1 done.

Valorant el resultat de la traducció

Després d’afinar el model amb un total de 145 missatges cuidadosament triats, vaig avaluar el model “afinat” llançant la traducció de 1050 cadenes.

La valoració final és molt positiva. El model ajustat, és capaç de centrar-se en el to; és estricte quant a respectar el codi, les puntuacions, els espais en blanc al final de text.

Comparant amb el model estàndard, el resultat és sorprenent. La traducció és gairebé perfecta en la semàntica, el to i persona emprats. Això sí: segueix sent imprescindible revisar el resultat. En alguns casos inventa termes, o expressa mal conceptes tècnics. En el meu cas vaig refinar el model diverses vegades per anar ajustant els errors.

Anàlisi de costos

El resultat és bo, però a quin cost?

El fine-tuning de 145 missatges va consumir un total de 12.555 tokens el que va representar un cost de 0,10$

costos del fine-tuning

Per a la traducció dels 1.050 missatges, es van utilitzar 87.418 tokens costant 0,37$ (he descomptat el fine-tuning del dia 6/1)

Traducció d’arxius PO a partir de textos anteriorment traduïts

Al marge de poder obtenir bones traduccions, una de les funcionalitats més desitjades és el poder aprofitar traduccions prèviament ja realitzades i validades. Aquí el comandament gptpo també ens serà de gran ajuda.

Al teu directori de treball crea un subdirectori i anomena’l p.ex previous. Dins, guarda tots els arxius “po” que puguin tenir relació amb la temàtica que estàs abordant en les teves traduccions.

gptpo intentarà omplir totes les traduccions pendents amb les coincidències que pugui trobar en tots els arxius:

cd demo
gptpo preprocess --po my-plugin.po --prev ./previous

Preprocessing PO file: my-plugin.po
· Get translations from: previous/wordpress-tm.po
· Get translations from: previous/wordpress_plugins-tm.po
· Preprocessed 2 files, translated 31 messages.

Per finalitzar

Em vaig abordar aquest projecte com un experiment per ajudar en la traducció durant les jornades de col·laboració WordPress dins del marc Five for the Future que els divendres duem a terme entre amics. El resultat, gptpo està disponible perquè el puguis fer servir, llençar, desbrossar, refactoritzar,… I si et ve de gust col·laborar per millorar-lo, la teva ajuda serà sempre benvinguda.

Resumidament, som uns techies apassionats per WordPress que hem creat Wetopi, un Hosting WordPress Gestionat, per minimitzar la fricció a la que tot professional s’enfronta en treballar i allotjar projectes WordPress.

Inclou servidors de desenvolupament Gratis.
No cal tarjeta de crèdit.

Compara Wetopi amb el teu hosting actual

Dóna’t d’alta, demana una migració i compara.

Sense cap compromís ni esforç per part teva, migrem una còpia del teu web.

Sense lletra petita.
Sense compromisos.
Sense targeta de crèdit.