Premiere commit - Omika
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
# ============================================================
|
||||
# Omika - Completion des packs de langue deja exportes
|
||||
# ============================================================
|
||||
# Les packs exportes avant l'introduction du vocabulaire de modele contiennent
|
||||
# quatre fichiers : encoder_model.onnx, decoder_model.onnx, source.spm,
|
||||
# target.spm. Il en manque deux, sans lesquels le moteur ne peut pas traduire
|
||||
# correctement :
|
||||
#
|
||||
# vocab.json - les identifiants REELLEMENT attendus par le modele. Le .spm
|
||||
# numerote ses pieces dans un ordre qui lui est propre : sur
|
||||
# opus-mt-es-fr, la piece <U+2581>Ho vaut 5293 pour le .spm mais
|
||||
# 584 pour le modele. Envoyer les identifiants du .spm revient a
|
||||
# faire lire un autre texte, sans la moindre erreur levee.
|
||||
# config.json - l'amorce et la fin du decodeur (74821 et 0 sur opus-mt-es-fr),
|
||||
# que le .spm ne contient pas non plus.
|
||||
#
|
||||
# Ces deux fichiers pesent quelques mega-octets : rien n'est reexporte, les poids
|
||||
# deja sur le disque (23 Gio) restent valables.
|
||||
#
|
||||
# GARDE-FOU : le modele d'origine n'est pas note dans le pack. Il est deduit du
|
||||
# code de langue et du sens (es + versFrancais -> opus-mt-es-fr), puis VERIFIE :
|
||||
# le source.spm telecharge doit etre identique, octet pour octet, a celui du
|
||||
# pack. Sans cette comparaison, on attacherait le vocabulaire d'un autre modele
|
||||
# - exactement le defaut que ce script repare, en pire.
|
||||
#
|
||||
# Usage :
|
||||
# .\scripts\Completer-Packs-Langues.ps1 -Verifier
|
||||
# .\scripts\Completer-Packs-Langues.ps1
|
||||
# .\scripts\Completer-Packs-Langues.ps1 -Codes "es,pt,it"
|
||||
# ============================================================
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
# Racine des packs. Par defaut : <racine du depot>\packs
|
||||
[string]$RacinePacks = '',
|
||||
|
||||
# N'ecrit rien : dit seulement quels packs sont deja alignes ou non.
|
||||
[switch]$Verifier,
|
||||
|
||||
# Codes de langue a traiter (ex. "es,pt"). Vide = tous les dossiers trouves.
|
||||
[string]$Codes = ''
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# --- Sortie ----------------------------------------------------------------
|
||||
function Write-Etape { param([string]$Message) Write-Host ''; Write-Host $Message -ForegroundColor Cyan }
|
||||
function Write-Info { param([string]$Message) Write-Host (' ' + $Message) }
|
||||
function Write-Ok { param([string]$Message) Write-Host (' [OK] ' + $Message) -ForegroundColor Green }
|
||||
function Write-Alerte{ param([string]$Message) Write-Host (' [ALERTE] ' + $Message) -ForegroundColor Yellow }
|
||||
function Write-Ecart { param([string]$Message) Write-Host (' [ECART] ' + $Message) -ForegroundColor DarkYellow }
|
||||
|
||||
function Stop-AvecMessage {
|
||||
param([string]$Message)
|
||||
Write-Host ''
|
||||
Write-Host '=== ARRET ===' -ForegroundColor Red
|
||||
Write-Host $Message -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Logique ---------------------------------------------------------------
|
||||
|
||||
# Nom du depot HuggingFace correspondant a un pack. Convention de l'exporteur :
|
||||
# versFrancais = <langue> -> francais, depuisFrancais = francais -> <langue>.
|
||||
function Get-NomModele {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Code,
|
||||
[Parameter(Mandatory = $true)][string]$Sens,
|
||||
[string]$Auteur = 'Helsinki-NLP'
|
||||
)
|
||||
|
||||
$codeNormalise = $Code.Trim().ToLowerInvariant()
|
||||
if ($Sens -eq 'versFrancais') {
|
||||
return ('{0}/opus-mt-{1}-fr' -f $Auteur, $codeNormalise)
|
||||
}
|
||||
|
||||
return ('{0}/opus-mt-fr-{1}' -f $Auteur, $codeNormalise)
|
||||
}
|
||||
|
||||
# Empreinte SHA-256 en minuscules, comparable telle quelle.
|
||||
function Get-Empreinte {
|
||||
param([Parameter(Mandatory = $true)][string]$Chemin)
|
||||
return (Get-FileHash -LiteralPath $Chemin -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
}
|
||||
|
||||
# Inventaire des couples (code, sens) presents sur le disque.
|
||||
function Get-PacksPresents {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Racine,
|
||||
[string[]]$CodesFiltres = @()
|
||||
)
|
||||
|
||||
$presents = New-Object 'System.Collections.Generic.List[object]'
|
||||
if (-not (Test-Path -LiteralPath $Racine -PathType Container)) {
|
||||
return $presents
|
||||
}
|
||||
|
||||
foreach ($dossierLangue in @(Get-ChildItem -LiteralPath $Racine -Directory | Sort-Object -Property Name)) {
|
||||
$code = $dossierLangue.Name
|
||||
# Dossiers techniques (.hf-cache) et fichiers d'essai : jamais des langues.
|
||||
if ($code.StartsWith('.')) { continue }
|
||||
if ($CodesFiltres.Count -gt 0 -and $CodesFiltres -notcontains $code) { continue }
|
||||
|
||||
foreach ($dossierSens in @(Get-ChildItem -LiteralPath $dossierLangue.FullName -Directory | Sort-Object -Property Name)) {
|
||||
$sens = $dossierSens.Name
|
||||
if ($sens -ne 'versFrancais' -and $sens -ne 'depuisFrancais') { continue }
|
||||
|
||||
# Un pack FAMILIAL (modele multilingue) range ses poids dans
|
||||
# <code>\commun\ et ne laisse qu'un modele.json par sens : il n'a
|
||||
# aucun source.spm par sens, donc RIEN a aligner. Sans ce garde-fou
|
||||
# on lui cherchait une paire bilingue qui n'existe pas et on le
|
||||
# declarait « ecarte » a tort.
|
||||
$spm = Join-Path $dossierSens.FullName 'source.spm'
|
||||
if (-not (Test-Path -LiteralPath $spm -PathType Leaf)) { continue }
|
||||
|
||||
$presents.Add([pscustomobject]@{
|
||||
Code = $code
|
||||
Sens = $sens
|
||||
Dossier = $dossierSens.FullName
|
||||
Source = $spm
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return $presents
|
||||
}
|
||||
|
||||
# Complete un pack. $Recuperer recoit (modele, fichier, destination) et doit
|
||||
# renvoyer $true si le fichier a ete obtenu. Il est injecte pour que les tests
|
||||
# s'executent sans reseau.
|
||||
function Invoke-Completion {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Racine,
|
||||
[Parameter(Mandatory = $true)][scriptblock]$Recuperer,
|
||||
[switch]$SansEcrire,
|
||||
[string[]]$CodesFiltres = @()
|
||||
)
|
||||
|
||||
$bilan = [pscustomobject]@{
|
||||
Packs = 0
|
||||
Alignes = 0
|
||||
Ecartes = 0
|
||||
Echecs = 0
|
||||
Ecrits = 0
|
||||
}
|
||||
|
||||
$packs = @(Get-PacksPresents -Racine $Racine -CodesFiltres $CodesFiltres)
|
||||
if ($packs.Count -eq 0) {
|
||||
Write-Alerte ("aucun pack trouve sous {0}" -f $Racine)
|
||||
return $bilan
|
||||
}
|
||||
|
||||
$bac = Join-Path ([System.IO.Path]::GetTempPath()) ('omika-completion-' + [guid]::NewGuid().ToString('N').Substring(0, 8))
|
||||
$null = New-Item -ItemType Directory -Path $bac -Force
|
||||
|
||||
try {
|
||||
foreach ($pack in $packs) {
|
||||
$bilan.Packs++
|
||||
$modele = Get-NomModele -Code $pack.Code -Sens $pack.Sens
|
||||
$nomCourt = '{0}/{1}' -f $pack.Code, $pack.Sens
|
||||
|
||||
$spmTelecharge = Join-Path $bac ('{0}-{1}-source.spm' -f $pack.Code, $pack.Sens)
|
||||
$vocabTelecharge = Join-Path $bac ('{0}-{1}-vocab.json' -f $pack.Code, $pack.Sens)
|
||||
$configTelecharge = Join-Path $bac ('{0}-{1}-config.json' -f $pack.Code, $pack.Sens)
|
||||
|
||||
$obtenus = $true
|
||||
foreach ($paire in @(
|
||||
@{ Fichier = 'source.spm'; Destination = $spmTelecharge },
|
||||
@{ Fichier = 'vocab.json'; Destination = $vocabTelecharge },
|
||||
@{ Fichier = 'config.json'; Destination = $configTelecharge })) {
|
||||
if (-not (& $Recuperer $modele $paire.Fichier $paire.Destination)) {
|
||||
$obtenus = $false
|
||||
Write-Alerte ("{0} : {1} introuvable pour {2}" -f $nomCourt, $paire.Fichier, $modele)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $obtenus) {
|
||||
$bilan.Echecs++
|
||||
continue
|
||||
}
|
||||
|
||||
# LE garde-fou : le modele deduit doit etre celui du pack.
|
||||
$empreinteLocale = Get-Empreinte -Chemin $pack.Source
|
||||
$empreinteDistante = Get-Empreinte -Chemin $spmTelecharge
|
||||
if ($empreinteLocale -ne $empreinteDistante) {
|
||||
Write-Ecart ("{0} : {1} n'est PAS le modele de ce pack (source.spm different) - non complete" -f $nomCourt, $modele)
|
||||
$bilan.Ecartes++
|
||||
continue
|
||||
}
|
||||
|
||||
$bilan.Alignes++
|
||||
if ($SansEcrire) {
|
||||
Write-Ok ("{0} : aligne sur {1}" -f $nomCourt, $modele)
|
||||
continue
|
||||
}
|
||||
|
||||
Copy-Item -LiteralPath $vocabTelecharge -Destination (Join-Path $pack.Dossier 'vocab.json') -Force
|
||||
Copy-Item -LiteralPath $configTelecharge -Destination (Join-Path $pack.Dossier 'config.json') -Force
|
||||
$bilan.Ecrits++
|
||||
Write-Ok ("{0} : vocabulaire et configuration ajoutes ({1})" -f $nomCourt, $modele)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Remove-Item -LiteralPath $bac -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
return $bilan
|
||||
}
|
||||
|
||||
# --- Execution -------------------------------------------------------------
|
||||
# Les tests dot-sourcent ce fichier pour appeler les fonctions : dans ce cas,
|
||||
# rien ne s'execute. Seul un lancement direct declenche le traitement.
|
||||
if ($MyInvocation.InvocationName -ne '.') {
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($RacinePacks)) {
|
||||
$RacinePacks = Join-Path (Split-Path -Parent $PSScriptRoot) 'packs'
|
||||
}
|
||||
|
||||
$codesFiltres = @()
|
||||
if (-not [string]::IsNullOrWhiteSpace($Codes)) {
|
||||
$codesFiltres = @($Codes -split '[,;]' | ForEach-Object { $_.Trim().ToLowerInvariant() } | Where-Object { $_ })
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host '=== Omika - Completion des packs de langue ===' -ForegroundColor Cyan
|
||||
Write-Info ('Racine des packs : {0}' -f $RacinePacks)
|
||||
Write-Info ('Mode : {0}' -f $(if ($Verifier) { 'verification seule (aucune ecriture)' } else { 'ecriture' }))
|
||||
if ($codesFiltres.Count -gt 0) { Write-Info ('Langues : {0}' -f ($codesFiltres -join ', ')) }
|
||||
|
||||
# Recuperation reelle : HuggingFace, sans jeton (les depots sont publics).
|
||||
$recuperer = {
|
||||
param($modele, $fichier, $destination)
|
||||
$uri = 'https://huggingface.co/{0}/resolve/main/{1}' -f $modele, $fichier
|
||||
try {
|
||||
Invoke-WebRequest -Uri $uri -OutFile $destination -UseBasicParsing -ErrorAction Stop
|
||||
return (Test-Path -LiteralPath $destination -PathType Leaf)
|
||||
}
|
||||
catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
$bilan = Invoke-Completion -Racine $RacinePacks -Recuperer $recuperer -SansEcrire:$Verifier -CodesFiltres $codesFiltres
|
||||
|
||||
Write-Etape '=== RESULTAT ==='
|
||||
Write-Info ('Packs examines : {0}' -f $bilan.Packs)
|
||||
Write-Info ('Alignes : {0}' -f $bilan.Alignes)
|
||||
Write-Info ('Completes : {0}' -f $bilan.Ecrits)
|
||||
Write-Info ('Ecartes (autre modele) : {0}' -f $bilan.Ecartes)
|
||||
Write-Info ('Echecs : {0}' -f $bilan.Echecs)
|
||||
|
||||
if ($bilan.Echecs -gt 0) {
|
||||
Stop-AvecMessage ("{0} pack(s) n'ont pas pu etre completes (reseau ou depots introuvables).`n" -f $bilan.Echecs +
|
||||
" Relancer la MEME commande : les packs deja completes ne sont pas retraites.")
|
||||
}
|
||||
|
||||
if ($bilan.Ecartes -gt 0) {
|
||||
Write-Alerte 'Les packs ecartes viennent d''une autre famille de modeles que celle deduite du code.'
|
||||
Write-Alerte 'Ils doivent etre reexportes avec scripts\Exporter-Packs-Langues.ps1 (le modele d''origine y sera note).'
|
||||
}
|
||||
|
||||
exit 0
|
||||
}
|
||||
Reference in New Issue
Block a user