35 KiB
Livrer un pack de langue : obtenir les modèles, les déposer, mettre à jour le manifeste
Objet : procédure complète de livraison d'une langue (modèles ONNX + vocabulaire) sur
SRV-OMIKA, jusqu'à la mise à jour du manifeste servi parOmikaLanguesApi.Prérequis : le service
OmikaLanguesApiest installé,Langues__RootPathest posée en variable MACHINE, et le vhost Apache expose le service en HTTPS (DEPLOIEMENT_API_LANGUES.md§7).Ce document ne traite pas de la qualité de traduction (choix du modèle) ni du poids du livrable mobile : voir
VALIDATION_TRADUCTION_ONNX.md§4.
0. Vue d'ensemble
| # | Étape | Où | Qui |
|---|---|---|---|
| 1 | Exporter les modèles en ONNX | poste avec accès Internet | dev |
| 2 | Construire l'arborescence du pack | poste | dev |
| 3 | Valider le pack sur le poste | poste | dev |
| 4 | Déposer les fichiers sur le serveur | SRV-OMIKA | admin |
| 5 | Générer le manifeste sur le serveur | SRV-OMIKA | admin |
| 6 | Contrôler (disque, HTTP, empreinte) | SRV-OMIKA | admin |
| 7 | Rafraîchir et télécharger sur le téléphone | appareil | utilisateur |
Trois règles, et tout le reste en découle :
- Le manifeste n'est jamais recopié d'une autre machine. Il contient la taille et l'empreinte SHA-256 de vos fichiers : il se génère sur le serveur, à partir de ce qui est réellement sur son disque (§5).
- Les fichiers d'abord, le manifeste ensuite. Un manifeste qui décrit des fichiers absents (ou pas encore remplacés) fait refuser le pack.
- Aucun redémarrage de service n'est nécessaire — mais le mobile garde son index mémorisé : il faut un rafraîchissement explicite (§7).
1. Étape 1 — Obtenir les modèles (poste de développement)
Les modèles ne sont pas livrés avec Omika (poids + licences) et ne sont pas versionnés dans le dépôt. Le plus simple est un modèle OPUS-MT de Helsinki-NLP, exporté en ONNX :
pip install "optimum[onnxruntime]" transformers sentencepiece
# fr -> es : sert le sens « depuisFrancais » du pack « es »
optimum-cli export onnx --model Helsinki-NLP/opus-mt-fr-es .\export\fr-es
# es -> fr : sert le sens « versFrancais » du pack « es »
optimum-cli export onnx --model Helsinki-NLP/opus-mt-es-fr .\export\es-fr
⚠️
optimum-clipeut rester introuvable juste après une installation réussie. Avec le Python du Microsoft Store, pip range les programmes dans un dossier utilisateur qui n'est pas dans le PATH —pip installse termine sans erreur, puis chaque fenêtre répondoptimum-cli : commande introuvable. Pour savoir où ils sont allés :python -c "import sysconfig; print(sysconfig.get_path('scripts','nt_user'))"Le script
scripts\Exporter-Packs-Langues.ps1sait aller le chercher là tout seul (§1.1). Pour les commandes manuelles ci-dessus, utilisez le chemin complet, ou pour la session en cours :$env:Path += ';' + (python -c "import sysconfig; print(sysconfig.get_path('scripts','nt_user'))")
⚠️
ERROR: Could not install packages due to an OSError: [WinError 206] Nom de fichier ou extension trop long— l'installation s'arrête, etoptimum-clin'est jamais créé : le script d'export continuera de dire « introuvable ». Ce n'est ni un bug de pip ni un bug du script : Windows plafonne les chemins à 260 caractères, et le Python du Microsoft Store installe ses paquets dans un dossier déjà très long —…\LocalCache\local-packages\Python312\site-packages\= 140 caractères à lui seul. Ortorchembarque des fichiers de licence imbriqués profondément : le chemin du dossier atteint 249 caractères, et les fichiers qu'il contient dépassent la limite (mesuré sur ce poste,LongPathsEnabled = 0).Solution : installer dans un environnement virtuel au chemin court. Cela retire ~110 caractères au préfixe, sans droit administrateur :
python -m venv C:\OmikaPy C:\OmikaPy\Scripts\python.exe -m pip install "optimum[onnxruntime]" transformers sentencepiece C:\OmikaPy\Scripts\Activate.ps1 # à réactiver dans chaque nouvelle fenêtreLe venv est isolé : le
torchà moitié installé dans le Python du Store (resté après l'échec) ne le perturbe pas. Le script d'export trouve alorsoptimum-cliseul (§1.1) ; sans activation, indiquez l'interpréteur :-Python C:\OmikaPy\Scripts\python.exe.Autre voie, sans environnement virtuel : autoriser les chemins longs dans Windows (PowerShell en administrateur), puis relancer la même installation. C'est un réglage machine, utile à tous les outils.
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name LongPathsEnabled -Value 1 -Type DWord
L'export produit notamment :
encoder_model.onnx
decoder_model.onnx
decoder_with_past_model.onnx <-- NE PAS LIVRER (voir ci-dessous)
source.spm
target.spm
⚠️
decoder_with_past_model.onnxne doit jamais être livré. C'est un décodeur à cache de clés/valeurs destiné à la génération incrémentale : l'application l'exclut du chargement, mais s'il est présent dans le dossier il est déclaré dans le manifeste et donc téléchargé par chaque téléphone — ~120 Mo de données mobiles pour rien. Le générateur de manifeste le signale (§5).⚠️ Un modèle Marian a DEUX vocabulaires (
source.spmettarget.spm) : les livrer tous les deux est obligatoire, sinon la traduction produira du charabia (les identifiants de sortie seraient décodés dans le mauvais référentiel).
1.1 Plusieurs langues d'un coup (Europe, Est, Caucase…)
Pour livrer un ensemble de langues, le script scripts\Exporter-Packs-Langues.ps1
enchaîne tout : vérification de l'existence de chaque paire sur HuggingFace,
export ONNX, rangement dans l'arborescence du pack, rapport.
# 0. UNE SEULE FOIS : l'outil d'export. Sans lui le script s'arrête aussitôt,
# AVANT toute écriture : « rien ne se passe » = c'est ce prérequis qui manque.
pip install "optimum[onnxruntime]" transformers sentencepiece
# 1. VOIR LE PLAN avant de payer ~30 Gio (aucun réseau, rien n'est écrit)
.\scripts\Exporter-Packs-Langues.ps1 -Simulation
# 1bis. QUELLES LANGUES SONT LIVRABLES ? Internet suffit, ni Python ni optimum :
# ~100 appels d'API, une à deux minutes, RIEN n'est téléchargé.
.\scripts\Exporter-Packs-Langues.ps1 -SansExporter
# 2. Tout exporter (51 langues ≈ 102 modèles)
.\scripts\Exporter-Packs-Langues.ps1
# Sélections partielles
.\scripts\Exporter-Packs-Langues.ps1 -Zone Est,Caucase
.\scripts\Exporter-Packs-Langues.ps1 -Codes es,pt,uk,ru
.\scripts\Exporter-Packs-Langues.ps1 -Codes ar # l'arabe est en zone « Divers »
Si l'étape 0 échoue avec [WinError 206] Nom de fichier ou extension trop long, l'outil n'a pas pu être installé (limite de 260 caractères de Windows) :
voir la solution « environnement virtuel au chemin court » au §1, puis lancer le
script avec -Python C:\OmikaPy\Scripts\python.exe.
- Pour savoir à l'avance quelles langues sont livrables :
.\scripts\Exporter-Packs-Langues.ps1 -SansExporterinterroge HuggingFace pour toute la table et écrit le rapport sans rien télécharger (~100 appels d'API, une à deux minutes). Les langues sans paire finissent dans « Paires indisponibles », les autres dans « Paires disponibles (vérifiées, non exportées) ». Cette commande ne demande ni Python nioptimum-cli: elle répond donc avant même l'installation des outils. - Deux familles de modèles sont essayées, dans l'ordre :
opus-mt-<langue>-fr(petit, ~300 Mo par sens) puisopus-mt-tc-big-<langue>-fr(~1 Go par sens), publiée par Helsinki-NLP pour des paires que la première ne couvre pas. Le nom réellement retenu est inscrit au rapport. Une langue déclarée absente l'est donc après quatre vérifications (2 familles × 2 sens). - Repli familial : pour
it,es,pt,ca,gletro, le modèle multilingueopus-mt-tc-big-itc-itccouvre les deux sens en un seul export. Il n'est employé que si une paire bilingue manque (ptetgln'en ont aucune ;itn'a queit-fr), et ses 1,15 Go sont écrits une seule fois dans<code>\commun\: les deux sens le partagent (§2.1.1). - Les paires qui n'existent pas sont signalées, jamais inventées.
Helsinki-NLP ne couvre pas toutes les combinaisons avec le français : le
script teste chaque modèle sur HuggingFace avant de télécharger, et écrit
les absentes dans
RAPPORT-LANGUES.md. Prévoir que plusieurs langues de la liste (Caucase, Asie centrale) seront indisponibles. - Si HuggingFace est injoignable, le script s'arrête au lieu de déclarer les paires absentes : « je ne sais pas » n'est pas « il n'y en a pas ».
- Un pack n'est écrit que si les deux directions existent
(
-InclureDirectionsPartiellespour l'accepter malgré tout). decoder_with_past_model.onnxet les fichiers de tokenizer ne sont jamais conservés : le dossier de travail de l'export est supprimé après chaque sens.- Le script est reprenable : une langue déjà exportée est ignorée
(
-Forcerpour la refaire). Un arrêt en cours de route ne perd rien. - Volume : ~300 Mo par sens, soit ~30 Gio pour 51 langues, et plusieurs heures de téléchargement puis de conversion.
1.2 Où vont les fichiers
| Chemin | Après l'opération | |
|---|---|---|
| Packs ONNX (le livrable) | <RacinePacks>\<code>\<sens>\ (et <code>\commun\ pour un modèle familial) |
conservé — c'est ce qu'on transfère |
| Cache HuggingFace | <RacinePacks>\.hf-cache\hub\ |
supprimé après chaque export réussi |
| Travail temporaire | <RacinePacks>\.tmp-<code>-<sens>\ |
supprimé après chaque sens |
<RacinePacks> vaut packs par défaut, résolu depuis la racine du dépôt —
donc D:\Avalonia\Omika\packs sur ce poste. Pour l'écrire ailleurs (autre
disque, dossier de livraison) :
.\scripts\Exporter-Packs-Langues.ps1 -RacinePacks D:\PacksLangues
Deux points importants :
- Sans intervention, le cache HuggingFace va dans
%USERPROFILE%\.cache\huggingface(donc surC:), et chaque modèle y occupe une seconde copie de sa taille : ~29 Gio de plus. Le script force doncHF_HOMEvers<RacinePacks>\.hf-cachepour que tout reste sur le même disque, et supprime la copie du modèle après chaque export réussi (elle n'a plus d'usage). Le pic de disque réel est donc « les packs + ~300 Mo », pas le double.-GarderCacheHuggingFaceconserve le cache (utile pour enchaîner des-Forcersans retélécharger). UnHF_HOMEdéjà défini dans l'environnement est respecté. - Par défaut la sortie est dans l'arborescence des sources
(
D:\Avalonia\Omika\packs). Ce n'est pas un dépôt git ici, donc rien ne sera committé, mais 29 Gio de binaires au milieu du code n'est pas souhaitable à long terme : préférer-RacinePacks D:\PacksLangues. - Les dossiers
.hf-cacheet.tmp-*sont ignorés par le générateur de manifeste (New-OmikaLanguesManifeste.ps1) : ils ne sont jamais pris pour des langues ni signalés comme fichiers non déclarés.
Pourquoi un modèle par langue, et pas un seul modèle multilingue ? Le pipeline amorce le décodeur sur le seul jeton de début du vocabulaire (
OnnxTranslationService.GenererAsync) : il n'existe aucun mécanisme de langue cible forcée (forced_bos_token_id). Un modèle multilingue (NLLB, mBART, M2M-100) produirait donc la langue par défaut du modèle, pas celle demandée. Passer à NLLB — un seul modèle pour toutes les langues, bien plus léger au total — demanderait d'ajouter ce jeton au contrat : une option de pipeline, un champ dans le manifeste et sa résolution. Ce n'est pas un réglage de déploiement.
2. Étape 2 — Construire l'arborescence du pack
Si vous utilisez le script du §1.1, cette arborescence est produite automatiquement : cette étape sert alors de référence (et de mode opératoire manuel pour une langue isolée).
Un pack = un code de langue, contenant deux sens. La convention est imposée par l'API et par l'application ; elle n'est pas configurable.
es/
├── versFrancais/ (espagnol -> français : dictée, avant insertion)
│ ├── encoder_model.onnx <- depuis .\export\es-fr\
│ ├── decoder_model.onnx <- depuis .\export\es-fr\
│ ├── source.spm <- depuis .\export\es-fr\source.spm (ESPAGNOL)
│ ├── target.spm <- depuis .\export\es-fr\target.spm (FRANÇAIS)
│ ├── vocab.json <- depuis .\export\es-fr\ (IDENTIFIANTS)
│ └── config.json <- depuis .\export\es-fr\ (DÉCODEUR)
└── depuisFrancais/ (français -> espagnol : lecture, affichage seul)
├── encoder_model.onnx <- depuis .\export\fr-es\
├── decoder_model.onnx <- depuis .\export\fr-es\
├── source.spm <- depuis .\export\fr-es\source.spm (FRANÇAIS)
├── target.spm <- depuis .\export\fr-es\target.spm (ESPAGNOL)
├── vocab.json <- depuis .\export\fr-es\
└── config.json <- depuis .\export\fr-es\
2.1 Noms de fichiers reconnus
L'application résout les rôles par le nom, avec des replis automatiques. Les noms ci-dessous sont ceux qu'elle cherche en premier : les respecter évite tout ambiguïté.
| Fichier | Rôle | Si absent |
|---|---|---|
encoder.onnx / encoder_model.onnx |
modèle principal du sens | premier .onnx du dossier qui n'est pas un décodeur |
decoder.onnx / decoder_model.onnx |
décodeur séparé (décodage glouton) | mode « modèle unique » |
*_with_past*.onnx |
jamais utilisé | — |
vocab.spm |
vocabulaire commun (NLLB, mBART, M2M-100) | premier .spm |
source.spm |
vocabulaire d'entrée (Marian/OPUS-MT) | vocab.spm, puis premier .spm |
target.spm |
vocabulaire de sortie (Marian/OPUS-MT) | vocab.spm, puis premier .spm |
vocab.json |
identifiants du modèle (obligatoire) | numérotation du .spm — traduction fausse |
config.json |
amorce et fin du décodeur (obligatoire) | <s> / </s> du .spm — génération fausse |
modele.json |
métadonnées d'un modèle multilingue (>>fra<<) |
modèle dédié à une paire |
2.1.1 Dossier partagé commun/
Un modèle multilingue (famille de langues, type opus-mt-tc-big-itc-itc)
sert plusieurs langues avec les mêmes poids. Les déclarer dans chaque sens
ferait télécharger deux fois 1,15 Go sur chaque téléphone : ces fichiers vont
donc une seule fois dans un dossier commun/.
pt/
├── commun/ (poids PARTAGÉS par les deux sens)
│ ├── encoder_model.onnx
│ ├── decoder_model.onnx
│ ├── source.spm
│ ├── target.spm
│ ├── vocab.json
│ └── config.json
├── versFrancais/
│ └── modele.json { "jetonCible": ">>fra<<" }
└── depuisFrancais/
└── modele.json { "jetonCible": ">>por<<" }
L'application cherche d'abord dans le dossier du sens, puis dans
commun/ : un pack qui fournit son propre source.spm garde la priorité, et un
pack qui n'a que des fichiers partagés fonctionne dans les deux sens. Le
modele.json reste par sens — c'est la seule chose qui diffère (l'étiquette
de langue : >>fra<< pour traduire vers le français, >>por<< depuis le
français).
Les paires bilingues classiques (
opus-mt-es-fretopus-mt-fr-es) n'ont pas de dossiercommun: leurs poids diffèrent dans chaque sens.Un téléphone ne télécharge que la langue secondaire choisie par l'utilisateur, jamais les autres : le partage ci-dessus divise par deux ce qu'il reçoit, il ne lui impose rien de plus.
Langues servies par un modèle de famille
Un seul dépôt couvre plusieurs langues, dans les deux sens, quand aucune
paire bilingue n'existe. L'exporteur le fait pour vous (-Codes pt,gl,it
suffit) : il exporte le modèle une fois, écrit les poids dans commun/ et
les deux modele.json.
| Langue | Jeton aller | Jeton retour | Paire bilingue ? |
|---|---|---|---|
it |
>>fra<< |
>>ita<< |
it-fr seule (pas fr-it) |
es |
>>fra<< |
>>spa<< |
les deux (familial inutile) |
pt |
>>fra<< |
>>por<< |
aucune |
ca |
>>fra<< |
>>cat<< |
les deux (familial inutile) |
gl |
>>fra<< |
>>glg<< |
aucune |
ro |
>>fra<< |
>>ron<< |
les deux (familial inutile) |
Le modèle est Helsinki-NLP/opus-mt-tc-big-itc-itc (1,15 Go : encoder
451 Mo + décodeur 697 Mo). Il n'est employé que si une des deux directions
manque, et il couvre alors les deux : inutile de payer deux paires bilingues.
Le modele.json complet, tel que l'exporteur l'écrit :
{
"version": 1,
"modeleSource": "Helsinki-NLP/opus-mt-tc-big-itc-itc",
"famille": "itc",
"jetonCible": ">>por<<"
}
Sans ce jeton, le modèle écrirait sa langue par défaut (l'espagnol) : du texte parfaitement lisible, dans la mauvaise langue. C'est la seule chose qui diffère entre les deux sens d'un pack familial.
Le manifeste déclare ces fichiers avec "sens": "commun" : le générateur les
accepte, et le mobile les range dans langues/<code>/commun/.
vocab.jsonn'est pas un doublon du.spm. Le.spmdécoupe le texte ;vocab.jsondonne les identifiants que le modèle attend. Les deux numérotations diffèrent : mesuré suropus-mt-es-fr, la pièce▁Hovaut 5293 pour le.spmmais 584 pour le modèle, et,vaut 4 contre 3. Sansvocab.json, le modèle reçoit un autre texte que celui dicté et produit du charabia sans lever la moindre erreur.
config.jsonapporte deux identifiants que le.spmne contient pas : l'amorce du décodeur (74821suropus-mt-es-fr,35282suropus-mt-tc-big-itc-itc) et sa fin (0et29158). Les deviner donne un décodeur qui démarre au hasard et ne s'arrête jamais.Ces deux fichiers pèsent quelques centaines de kilo-octets : ils voyagent avec le pack comme les
.spm. Le script d'export les copie ; pour les packs exportés avant leur introduction, voir le §2.2.Un
.spmportant un autre nom (vocab-espagnol.spm) n'est pas reconnu : il serait pris comme repli « premier.spm», ce qui peut être le mauvais vocabulaire — donc une traduction sans aucun sens, sans aucune erreur. Le générateur le signale (§5).
2.2 Compléter un pack exporté avant vocab.json
Les packs déjà sur le disque ne contiennent que les quatre fichiers d'origine. Les compléter ne demande aucun réexport : les poids sont bons, seuls les deux référentiels manquent (quelques Mo par sens).
# 1. Voir où on en est, sans rien écrire
.\scripts\Completer-Packs-Langues.ps1 -Verifier
# 2. Compléter (idempotent : relancer ne refait rien)
.\scripts\Completer-Packs-Langues.ps1
# 3. Une ou deux langues seulement
.\scripts\Completer-Packs-Langues.ps1 -Codes "es,pt"
Un pack familial (§2.1.1) est ignoré par cette complétion — et c'est
volontaire : il n'a pas de source.spm par sens, donc rien à aligner. Ses
vocab.json et config.json sont déjà dans commun/, écrits par l'export.
Le script déduit le dépôt d'origine du code et du sens (es + versFrancais →
opus-mt-es-fr), puis vérifie que le source.spm téléchargé est identique,
octet pour octet, à celui du pack. Sans cette comparaison, il attacherait le
vocabulaire d'un autre modèle — exactement le défaut qu'il répare, en pire.
Un pack dont l'empreinte diffère est signalé [ÉCART] et laissé intact : il
vient d'une autre famille de modèles et doit être réexporté par le §1.1.
2.3 Nommer le dossier de langue
- minuscules, chiffres et tiret uniquement (
es,pt-br,zh) ; - 2 à 10 caractères, ni tiret au début ni à la fin.
Un code hors de ces règles fait ignorer le pack silencieusement par le mobile. Le générateur refuse de l'écrire (§5).
2.4 Vérifier le poids avant de transférer
Un modèle Marian pèse ~300 Mo pour les deux sens. C'est la contrainte la plus lourde de toute la fonctionnalité : elle se mesure ici, pas après le déploiement.
'{0:N0} Mo' -f ((Get-ChildItem .\es -Recurse -File | Measure-Object Length -Sum).Sum / 1MB)
3. Étape 3 — Valider le pack sur le poste (avant tout transfert)
On ne débogue pas un modèle de 120 Mo par déploiements successifs. Trois commandes suffisent, et elles se font toutes sur le poste :
dotnet run --project tools/Omika.LanguesProbe -- inspecter .\es\versFrancais\source.spm
dotnet run --project tools/Omika.LanguesProbe -- encoder .\es\versFrancais\source.spm "Buenos días, ¿cómo está?"
dotnet run --project tools/Omika.LanguesProbe -- traduire `
--dossier .\es\versFrancais --code es --sens versFrancais --texte "Sustitución de la pieza"
Ce qu'il faut regarder, et l'arbre de décision en cas d'anomalie, sont au §2.5 et
au §3.4 de VALIDATION_TRADUCTION_ONNX.md. En résumé : la sortie doit être une
phrase française plausible ; une suite de mots espagnols ou du texte répété
signifie un mauvais vocabulaire de sortie, pas un problème de déploiement.
4. Étape 4 — Déposer les fichiers sur le serveur
4.1 Destination
| Chemin | |
|---|---|
| Racine des modèles | C:\Omika\Data\Langues (= Langues__RootPath) |
| Cible d'un pack | C:\Omika\Data\Langues\<code>\ |
| Manifeste | C:\Omika\Data\Langues\manifest.json |
Ne jamais déposer les modèles dans
C:\Omika\Apps\LanguesApi: ce dossier est écrasé à chaque redéploiement. Vérifier la variable avant de copier :[Environment]::GetEnvironmentVariable('Langues__RootPath', 'Machine')
4.2 Copie (nouveau pack)
$root = 'C:\Omika\Data\Langues'
New-Item -ItemType Directory -Force -Path $root | Out-Null
# Depuis le dossier de livraison (ex. C:\Omika\Deploy\Langues\es)
robocopy 'C:\Omika\Deploy\Langues\es' "$root\es" /E /R:2 /W:2
- Ne copier que
es\(le dossier de la langue), jamais unmanifest.jsonpréparé ailleurs : il est généré à l'étape suivante, sur ce serveur. - Les droits NTFS sont posés par héritage (
svc_omika_languesa la lecture seule sur la racine, en(OI)(CI)R) : rien à faire pour un fichier ajouté. Contrôle rapide :(Get-Acl 'C:\Omika\Data\Langues').Access | Where-Object { $_.IdentityReference -like "*svc_omika_langues" } | Select-Object IdentityReference, FileSystemRights, InheritanceFlags
4.3 Remplacer un modèle existant (mise à jour)
Écrire le nouveau fichier à côté puis le renommer, plutôt que d'écraser directement :
# 1) Déposer la nouvelle version sous un nom temporaire, dans le MÊME dossier
Copy-Item 'C:\Omika\Deploy\Langues\es\versFrancais\encoder_model.onnx' `
'C:\Omika\Data\Langues\es\versFrancais\encoder_model.onnx.new' -Force
# 2) Renommer sur le nom définitif (instantané, même volume)
Move-Item 'C:\Omika\Data\Langues\es\versFrancais\encoder_model.onnx.new' `
'C:\Omika\Data\Langues\es\versFrancais\encoder_model.onnx' -Force
Si un téléphone est en train de télécharger ce fichier, l'étape 2 est refusée (« le processus ne peut pas accéder au fichier car il est en cours d'utilisation par un autre processus »). C'est protecteur, pas gênant : Windows empêche de produire un fichier mélangé. Réessayez dans quelques secondes — la fin du téléchargement libère le fichier.
Si le remplacement échoue malgré tout, ne pas supprimer le fichier pour « débloquer » : cela provoquerait un 404 pour les téléphones. Attendre, puis réessayer.
5. Étape 5 — Générer le manifeste (sur le serveur)
cd C:\Omika\Deploy\Deploy
.\New-OmikaLanguesManifeste.ps1
Le script lit Langues__RootPath (MACHINE), parcourt l'arborescence, calcule
taille et empreinte de chaque fichier et écrit <RootPath>\manifest.json. Il
affiche le récapitulatif des packs retenus :
es Espagnol 4 fichier(s) 283,0 Mio
pt Portugais 4 fichier(s) 275,0 Mio
Il refuse d'écrire (code 1) si aucun pack n'est exploitable, et signale
sans échouer : un dossier de sens inconnu, un code de langue invalide, un
fichier *_with_past*, un .spm au nom non reconnu, un sous-dossier
inatteignable.
Trois dossiers de sens sont reconnus : versFrancais, depuisFrancais et
commun (poids partagés d'un modèle familial, §2.1.1). Un pack familial
apparaît donc comme ceci — les 1,15 Go une seule fois, plus un modele.json
par sens :
pt Portugais 8 fichier(s) 1,15 Gio
Le manifeste précédent est conservé automatiquement en manifest.json.bak —
c'est votre point de retour (§10).
5.1 Numéroter la version
-Version (défaut 1.0.0) est écrit dans chaque pack et commandé par
l'application : c'est ce champ qui fait apparaître, sur le téléphone, la
mention « Installée (v1.0.0) — mise à jour disponible » et le bouton
Mettre à jour.
# À CHAQUE remplacement de fichier : incrémenter la version
.\New-OmikaLanguesManifeste.ps1 -Version 1.0.1
Si la version ne change pas, le bouton affiche « Réinstaller » et l'utilisateur n'a aucun signal qu'un nouveau modèle existe : il gardera l'ancien indéfiniment. Le téléchargement, lui, ne récupère de toute façon que les fichiers dont l'empreinte a changé.
6. Étape 6 — Contrôler
6.1 Sur le disque (aucun droit administrateur requis)
.\New-OmikaLanguesManifeste.ps1 -Verifier
Compare le manifeste aux fichiers réels : fichier absent, taille ou empreinte divergente, sens à la mauvaise casse, fichier déclaré inutile, fichier présent mais non déclaré. Code retour 1 au moindre écart — utilisable dans un script de livraison.
6.2 Par HTTP (bout en bout : API + Apache)
$url = 'https://<SRV_LANGUES>'
$manifeste = Invoke-RestMethod "$url/api/langues"
$manifeste.packs | Select-Object code, libelle, version,
@{ n = 'NbFichiers'; e = { $_.fichiers.Count } }
6.3 Télécharger un fichier et vérifier son empreinte
C'est le contrôle décisif : il prouve que le proxy sert bien les octets attendus, et pas une page d'erreur HTML ni un fichier tronqué.
$fichier = (Invoke-RestMethod "$url/api/langues").packs[0].fichiers[0]
$local = Join-Path $env:TEMP 'omika-controle.bin'
Invoke-WebRequest "$url$($fichier.url)" -OutFile $local
(Get-Item $local).Length -eq $fichier.tailleOctets
(Get-FileHash $local -Algorithm SHA256).Hash.ToLowerInvariant() -eq $fichier.sha256
Les deux lignes doivent renvoyer True. Sinon : problème de proxy (page
d'erreur), de troncature, ou de cache.
7. Étape 7 — Côté mobile
Aucune mise à jour de l'application n'est nécessaire.
- Paramètres → Langue secondaire → « Actualiser la liste » (le bouton recharge le manifeste depuis le serveur ; sans lui, l'application réutilise son index mémorisé et ne verra pas le nouveau pack).
- Appuyer sur Télécharger (ou Mettre à jour) sur la langue concernée : la ligne affiche le poids avant le lancement, puis la progression (« 42 Mo / 122 Mo »).
- Le téléchargement installe et sélectionne la langue en une seule action.
- Dicter dans la langue secondaire → le champ reçoit du français ; sur une note existante, « ⇄ Traduire » affiche la langue secondaire. Rien de traduit ne doit apparaître dans l'Outbox (page Synchronisation).
8. Pièges (symptôme → cause)
| Symptôme | Cause la plus probable |
|---|---|
GET /api/langues répond 404 |
Manifeste absent ou illisible — lire le log du service : il nomme le chemin cherché. Le manifeste est-il bien dans Langues__RootPath ? |
| Le pack apparaît mais le téléphone le refuse à la fin | Empreinte différente : fichier modifié après la génération du manifeste → regénérer puis -Verifier |
| Un fichier répond 404 au téléchargement | Le manifeste déclare un fichier absent du disque (les deux ont été désynchronisés) |
| La langue n'apparaît pas du tout dans la liste | Code de langue invalide → pack ignoré silencieusement par le mobile (§2.2) |
| Traduction = suite de mots de la langue source, ou texte répété | Mauvais vocabulaire de sortie : target.spm manquant ou faux (§2.1) |
Traduction = <unk>, ▁, caractères isolés |
source.spm/target.spm ne viennent pas du même modèle que les .onnx |
| Le téléphone ne propose aucune mise à jour | version non incrémentée dans le manifeste (§5.1) : le bouton reste « Réinstaller » |
| 120 Mo téléchargés pour rien | decoder_with_past_model.onnx livré dans le dossier (§1) |
| Les modèles disparaissent à chaque déploiement | Ils sont dans C:\Omika\Apps\LanguesApi au lieu de Langues__RootPath (§4.1) |
| Le script d'export ne fait rien (« rien ne se passe ») | optimum-cli absent : il s'arrête avant toute écriture (§1.1). Lancé par double-clic, la fenêtre se ferme avant qu'on lise le message — lancer depuis une fenêtre PowerShell déjà ouverte |
optimum-cli introuvable alors que pip install a réussi |
Python du Microsoft Store : pip écrit les programmes dans un dossier absent du PATH (§1). Le script d'export sait l'y trouver seul ; pour un usage manuel, ajouter ce dossier au PATH |
pip s'arrête sur [WinError 206] Nom de fichier ou extension trop long |
Windows plafonne les chemins à 260 caractères ; le Python du Store installe dans un dossier de 140 caractères et torch dépasse la limite. Installer dans un venv au chemin court (§1) — le paquet n'est alors jamais installé, donc optimum-cli reste introuvable |
Toutes les paires manquantes sont en HTTP 401 et aucune en 404 |
Un dépôt absent répond 401 avec {"error":"Repository not found"}, jamais 404 — et la page publique s'est mise à répondre 401 elle aussi, alors qu'un dépôt existant répond 200 au même instant. Plus aucun code d'erreur ne tranche. Le script ne demande donc plus « ce dépôt existe-t-il ? » : il lit une fois la liste publique des dépôts Helsinki-NLP (/api/models?author=Helsinki-NLP&limit=1000, toujours 200, paginée par l'entête Link) et l'existence devient une égalité de chaîne. « Absent » est alors une preuve (nom hors liste), citée avec la taille du catalogue consulté. La sonde par modèle et le verdict de page restent en repli si le catalogue est illisible |
| Le rapport annonce un poids total très inférieur au dossier | Corrigé : le rapport affiche désormais deux lignes — le poids des packs traités par l'exécution, et le poids réellement présent sous la racine. Auparavant -Codes it affichait 520 Mio alors que le dossier en contenait 21 Gio |
Une langue n'a qu'un seul sens (versFrancais trouvé, depuisFrancais absent) |
Helsinki-NLP ne publie pas toujours les deux directions. Le script ignore la langue ; -InclureDirectionsPartielles la construit quand même. Conséquence : la dictée fonctionne, la lecture échoue avec un message explicite (OnnxTranslationService, « Le modèle … est absent »). Rien ne bloque l'installation : LangueDisponible.EstComplet existe mais n'est utilisé nulle part |
Tous les exports échouent d'un coup en quelques secondes, Poids de cette execution : 0 octets, et le détail affiché est un simple UserWarning: … cache-system uses symlinks |
L'appel a été lancé avec le flux d'erreur redirigé sur tout le script (2>&1 | Tee-Object, *>&1 > log) : PowerShell 5.1 transforme chaque ligne de stderr d'un programme natif en erreur fatale ($ErrorActionPreference = 'Stop'). optimum-cli émet cet avertissement de huggingface_hub dès le début : l'export était tué juste après config.json, avant le moindre octet de poids. Corrigé : l'export n'est plus jugé que par son code de sortie, et stderr est neutralisé le temps de l'appel (test §9). Les rapports déjà écrits par une version antérieure sont à jeter |
Le script affiche catalogue : 2 depots publics puis déclare tout absent |
La liste des dépôts est revenue tronquée (limite ignorée, page unique). Mesure du 16/10 : 2 entrées → 66 paires « absentes », dont 11 dont le modèle est sur le disque depuis des semaines — le script se contredisait lui-même. Corrigé : en dessous de 100 dépôts le catalogue est rejeté (catalogue inutilisable) et le verdict repasse par modèle. Vérifier la réponse brute avec (Invoke-WebRequest 'https://huggingface.co/api/models?author=Helsinki-NLP&limit=1000' -UseBasicParsing).Content.Length |
Le rapport annonce des dizaines de « paires absentes » d'un coup (HTTP 401 … page impossible, HTTP 429) |
Deux causes réelles, mesurées : (1) un 429 de quota — ce n'est pas une absence ; (2) un 401 qui ne discrimine rien. Corrigé : une seule lecture du catalogue remplace 102 interrogations (donc plus de quota), et un verdict indécis interrompt le run au lieu d'écrire un rapport faux qui ferait supprimer 22 langues du produit |
| Une langue à moitié faite re-télécharge le sens qui existait déjà (500 Mo) | Le test de reprise portait sur la langue entière : avec -InclureDirectionsPartielles, le sens déjà présent était réexporté. Corrigé : reprise par sens (encoder+.spm présents ⇒ ignoré, test §4bis) |
optimum-cli écrit des avertissements alors que l'export se déroule bien |
Bénin (huggingface_hub signale un cache sans liens symboliques sous D:\…\packs\.hf-cache). Le cache fonctionne en mode dégradé — donc plus gros, jamais faux. HF_HUB_DISABLE_SYMLINKS_WARNING=1 pour le taire |
9. Retirer une langue / rollback
Retirer une langue du catalogue (les téléphones qui l'ont déjà installée la gardent : elle est locale, et le retrait du serveur ne les touche pas) :
Remove-Item 'C:\Omika\Data\Langues\pt' -Recurse -Force
.\New-OmikaLanguesManifeste.ps1
Revenir au manifeste précédent : le générateur conserve
manifest.json.bak à chaque écriture.
Copy-Item 'C:\Omika\Data\Langues\manifest.json.bak' `
'C:\Omika\Data\Langues\manifest.json' -Force
.\New-OmikaLanguesManifeste.ps1 -Verifier
Remettre l'ancien manifeste alors que les fichiers ont déjà été remplacés provoquera un refus d'empreinte : un rollback complet se fait sur les deux (fichiers et manifeste).
10. Hors périmètre
- Qualité de traduction : choix du modèle, pas de la procédure.
- Poids du livrable mobile : décision produit (80 à 300 Mo par langue).
- Reprise de téléchargement inter-fichiers : un fichier interrompu repart de zéro ; les fichiers déjà conformes ne sont pas retéléchargés.
- Transfert des 300 Mo vers le serveur : aucun mécanisme d'upload n'existe.
Le transfert se fait par partage réseau, clé USB ou dossier de livraison
(
C:\Omika\Deploy\Langues), hors de cette procédure.