Premiere commit - Omika
This commit is contained in:
@@ -0,0 +1,638 @@
|
||||
# Marche à suivre — Mise en production API de téléchargement des langues (modèles ONNX)
|
||||
|
||||
> **Objet** : procédure **complète** de mise en production de l'**API dédiée** de
|
||||
> téléchargement des **modèles de langue ONNX** (traduction hors-ligne pour le
|
||||
> mobile). Cette API est un **service Windows séparé** (`OmikaLanguesApi`, projet
|
||||
> `src/Omika.Langues.Api`), distinct d'`OmikaApi`. Elle sert au mobile les fichiers
|
||||
> de modèle + un manifeste versionné, **en accès anonyme** (fichiers génériques,
|
||||
> aucune donnée client). L'**URL de base reste lue en base** (`ParametreSysteme`
|
||||
> `PAS_Code = 'SRV_LANGUES'`) par `OmikaApi`, qui l'expose au bootstrap mobile.
|
||||
>
|
||||
> **Cible** : Windows Server `SRV-OMIKA`, PowerShell **administrateur**, runtime
|
||||
> .NET 10. Aucune base de données, aucune authentification, aucun service externe.
|
||||
>
|
||||
> Ce document **complète** `T15-RUNBOOK-DEPLOIEMENT-PRODUCTION.md` et
|
||||
> `MISE_EN_PRODUCTION_DIAGNOSTICS_V2.md` : il ne couvre que le **service Langues**.
|
||||
> `OmikaApi` garde uniquement la lecture `SRV_LANGUES` → `LanguesUrl` au bootstrap.
|
||||
|
||||
---
|
||||
|
||||
## 0. Vue d'ensemble de l'API Langues
|
||||
|
||||
| Composant | Rôle | Référence |
|
||||
|---|---|---|
|
||||
| `Omika.Langues.Api` | **Service dédié** : endpoints `GET /api/langues*` (manifeste + streaming). | Windows Service `OmikaLanguesApi` |
|
||||
| `Omika.Core` | `LanguageModelService` (lecture manifeste + résolution fichier) + `LanguageModelOptions` + contrats partagés. | — |
|
||||
| `Langues:RootPath` | Dossier racine des modèles + du manifeste. | variable d'env. `Langues__RootPath` |
|
||||
| `ParametreSysteme.SRV_LANGUES` | URL de base du service Langues, lue par `OmikaApi`. | HFSQL (Omika **et** Batik) |
|
||||
|
||||
Flux :
|
||||
|
||||
```
|
||||
1. GET /api/mobile/bootstrap ──> OmikaApi lit SRV_LANGUES ──> LanguesUrl (→ URL du service Langues)
|
||||
2. GET {LanguesUrl}/api/langues ──> manifeste (packs + fichiers + sha256) [anonyme]
|
||||
3. GET {LanguesUrl}/api/langues/{code}/{sens}/{fichier} ──> streaming (reprise) [anonyme]
|
||||
```
|
||||
|
||||
- `SRV_LANGUES` absent/vide → `LanguesUrl = null` → le mobile désactive la
|
||||
traduction hors-ligne (aucun appel, aucun plantage).
|
||||
- Les textes à traduire ne sortent **jamais** de l'appareil : traduction 100 %
|
||||
locale une fois le modèle téléchargé.
|
||||
|
||||
---
|
||||
|
||||
## 1. Ce qui a changé
|
||||
|
||||
1. **Nouveau service dédié** `OmikaLanguesApi` (`src/Omika.Langues.Api`) : les
|
||||
endpoints langues ne sont **plus** dans `OmikaApi`.
|
||||
2. **Accès anonyme** : aucun token requis (les modèles sont des fichiers génériques).
|
||||
3. **Nouvelle section de configuration** : `Langues` (`RootPath`, `ManifestFileName`),
|
||||
portée par le service `OmikaLanguesApi`.
|
||||
4. **`OmikaApi`** ne conserve que la lecture `SRV_LANGUES` → `MobileConfigurationDto.LanguesUrl`.
|
||||
5. **Nouveaux fichiers à déployer sur disque** : `manifest.json` + modèles ONNX
|
||||
(jamais embarqués dans l'APK/IPA ni dans un binaire).
|
||||
|
||||
> Le **client de téléchargement ONNX côté mobile** (téléchargement, reprise,
|
||||
> vérification SHA-256, stockage local) relève d'un **ticket ultérieur** : ce
|
||||
> document ne couvre que le **serveur** (service Langues + exposition `SRV_LANGUES`).
|
||||
|
||||
---
|
||||
|
||||
## 2. Prérequis
|
||||
|
||||
### Poste DEV (publication)
|
||||
```powershell
|
||||
cd D:\Avalonia\Omika
|
||||
dotnet --version # SDK 10 (global.json épingle 10.0.302)
|
||||
git pull # branche à jour
|
||||
```
|
||||
|
||||
### SRV-OMIKA (PowerShell administrateur)
|
||||
```powershell
|
||||
net session # OK sinon STOP
|
||||
dotnet --list-runtimes # Microsoft.AspNetCore.App 10.x
|
||||
Get-Service OmikaApi # Running (bootstrap métier)
|
||||
Test-Path 'C:\Omika\Data' # dossier de données (langues)
|
||||
```
|
||||
|
||||
> `OmikaLanguesApi` **n'a besoin d'aucun accès HFSQL** : uniquement du dossier de
|
||||
> fichiers `Langues:RootPath`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Publication (poste DEV)
|
||||
|
||||
```powershell
|
||||
cd D:\Avalonia\Omika
|
||||
|
||||
# Omika.Api (métier : lit SRV_LANGUES → LanguesUrl ; endpoints langues retirés)
|
||||
dotnet publish src\Omika.Api\Omika.Api.csproj `
|
||||
-c Release -r win-x64 --self-contained false -o C:\Omika\Deploy\OmikaApi-next
|
||||
|
||||
# Omika.Langues.Api (NOUVEAU service dédié)
|
||||
dotnet publish src\Omika.Langues.Api\Omika.Langues.Api.csproj `
|
||||
-c Release -r win-x64 --self-contained false -o C:\Omika\Deploy\LanguesApi-next
|
||||
```
|
||||
|
||||
**Contrôles** : chaque dossier contient son `.exe` ; `appsettings.Development.json`
|
||||
absent ; aucun secret Dev dans les publications.
|
||||
|
||||
Transférer `OmikaApi-next` et `LanguesApi-next` vers `C:\Omika\Deploy\` sur SRV-OMIKA.
|
||||
|
||||
---
|
||||
|
||||
## 4. Base HFSQL — paramètre `SRV_LANGUES`
|
||||
|
||||
`OmikaApi` lit l'URL depuis la table `ParametreSysteme` (schéma Omika **et** Batik —
|
||||
rubriques `PAS_Code` / `PAS_Valeur`, groupe `ProtectionPlus`).
|
||||
|
||||
| Rubrique | Valeur |
|
||||
|---|---|
|
||||
| `PAS_Code` | `SRV_LANGUES` |
|
||||
| `PAS_Description` | ex. « URL du service de téléchargement des modèles de langue » |
|
||||
| `PAS_Valeur` | URL de base du **service Langues**, **sans slash final** |
|
||||
|
||||
Exemples de `PAS_Valeur` (pointe vers le service `OmikaLanguesApi`) :
|
||||
|
||||
- Production derrière Apache (vhost/hôte dédié) : `https://langues.applilogik.fr`
|
||||
- Chemin dédié derrière l'Apache existant : `https://omika.applilogik.fr/langues`
|
||||
- API interne directe : `https://omika-langues.local:8443`
|
||||
|
||||
> Le slash final est toléré (l'API le normalise), mais **ne pas le mettre** évite
|
||||
> toute ambiguïté. La valeur doit être une URL **HTTPS** joignable par le mobile.
|
||||
|
||||
**Écriture** : même mécanisme que `SRV_LICENCE_MOBILE` existant — côté WinDev
|
||||
`ParametreSystemeEcrit("SRV_LANGUES", "<url>")`, ou insertion/UPDATE direct via
|
||||
l'outil de gestion HFSQL. La valeur n'est **jamais** codée en dur dans l'application.
|
||||
|
||||
---
|
||||
|
||||
## 5. Fichiers modèles + manifeste (sur disque)
|
||||
|
||||
### 5.1 Arborescence sous `RootPath`
|
||||
|
||||
```
|
||||
Langues/
|
||||
├── manifest.json
|
||||
├── es/
|
||||
│ ├── versFrancais/
|
||||
│ │ ├── encoder.onnx
|
||||
│ │ └── vocab.spm
|
||||
│ └── depuisFrancais/
|
||||
│ ├── encoder.onnx
|
||||
│ └── vocab.spm
|
||||
├── pt/
|
||||
│ ├── versFrancais/...
|
||||
│ └── depuisFrancais/...
|
||||
└── ar/ ...
|
||||
```
|
||||
|
||||
- `{code}` : code ISO de la langue (`es`, `pt`, `ar`, `ru`, `pl`, …).
|
||||
- `{sens}` : **deux valeurs canoniques** uniquement :
|
||||
- `versFrancais` → langue secondaire → français (dictée, avant insertion) ;
|
||||
- `depuisFrancais` → français → langue secondaire (lecture, affichage seul).
|
||||
|
||||
### 5.2 Fichier `manifest.json` (clés en camelCase)
|
||||
|
||||
```json
|
||||
{
|
||||
"packs": [
|
||||
{
|
||||
"code": "es",
|
||||
"libelle": "Espagnol",
|
||||
"version": "1.0.0",
|
||||
"fichiers": [
|
||||
{
|
||||
"sens": "versFrancais",
|
||||
"nomFichier": "encoder.onnx",
|
||||
"tailleOctets": 122000000,
|
||||
"sha256": "a1b2c3d4...<empreinte hexadécimale SHA-256>"
|
||||
},
|
||||
{
|
||||
"sens": "versFrancais",
|
||||
"nomFichier": "vocab.spm",
|
||||
"tailleOctets": 804000,
|
||||
"sha256": "e5f6a7b8..."
|
||||
},
|
||||
{
|
||||
"sens": "depuisFrancais",
|
||||
"nomFichier": "encoder.onnx",
|
||||
"tailleOctets": 122000000,
|
||||
"sha256": "11121314..."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- `url` n'est **pas** à renseigner : l'API la construit
|
||||
(`/api/langues/{code}/{sens}/{nomFichier}`).
|
||||
- `tailleOctets` = taille réelle en octets (progression mobile).
|
||||
- `sha256` = empreinte SHA-256 **hexadécimale** (intégrité).
|
||||
|
||||
### 5.3 Générer les empreintes SHA-256 (PowerShell)
|
||||
|
||||
```powershell
|
||||
Get-FileHash -Algorithm SHA256 .\es\versFrancais\encoder.onnx |
|
||||
ForEach-Object { $_.Hash.ToLowerInvariant() }
|
||||
```
|
||||
|
||||
### 5.4 Générer le manifeste (script — recommandé)
|
||||
|
||||
`tailleOctets` et `sha256` sont des valeurs **mesurées sur les fichiers**, jamais
|
||||
saisies à la main : une empreinte fausse ou absente ne se voit **que sur le
|
||||
téléphone**, où le pack est refusé sans qu'aucune erreur ne remonte au serveur.
|
||||
|
||||
```powershell
|
||||
# Écrit <RootPath>\manifest.json depuis les fichiers réellement présents
|
||||
.\infra\deploy\New-OmikaLanguesManifeste.ps1 -RootPathLangues C:\Omika\Data\Langues
|
||||
|
||||
# Contrôle après chaque ajout/remplacement de modèle : code 1 au moindre écart
|
||||
.\infra\deploy\New-OmikaLanguesManifeste.ps1 -Verifier
|
||||
```
|
||||
|
||||
- La racine par défaut est lue dans `Langues__RootPath` (MACHINE) : le manifeste
|
||||
est donc écrit **là où l'API le lit** (§6).
|
||||
- Le script **refuse d'écrire** (code 1) un manifeste vide, et signale en clair
|
||||
un code de langue invalide, un dossier de sens inconnu, un fichier absent, une
|
||||
taille ou une empreinte divergente. Ces cas produisent sinon un pack
|
||||
**silencieusement ignoré** (code invalide) ou **refusé** (empreinte) par le
|
||||
mobile.
|
||||
- `-Verifier` ne demande aucun droit administrateur : c'est le contrôle à passer
|
||||
dans la foulée de toute livraison de modèle.
|
||||
- `-WhatIf` affiche le manifeste qui serait écrit, sans rien modifier.
|
||||
|
||||
> Le format de §5.2 reste la référence ; le script ne fait que le remplir avec
|
||||
> des valeurs exactes. À noter : le mobile compare `sens` de façon **sensible à
|
||||
> la casse** (`versFrancais` / `depuisFrancais`) — le script normalise cette
|
||||
> casse et le signale s'il la corrige.
|
||||
|
||||
---
|
||||
|
||||
## 6. Configuration serveur (`Langues`)
|
||||
|
||||
Règle : en variable d'environnement, `:` devient `__`
|
||||
(`Langues:RootPath` ⇔ `Langues__RootPath`).
|
||||
Toute modification d'une variable du service exige un **redémarrage** d'`OmikaLanguesApi`.
|
||||
|
||||
| Variable | Défaut | Rôle |
|
||||
|---|---|---|
|
||||
| `Langues__RootPath` | `<dossier de l'application>\Langues` | Dossier racine des modèles + manifeste |
|
||||
| `Langues__ManifestFileName` | `manifest.json` | Nom du fichier manifeste |
|
||||
| `ASPNETCORE_URLS` | `http://localhost:5000` | Adresse/port d'écoute Kestrel (HTTP loopback derrière Apache) |
|
||||
| `ASPNETCORE_ENVIRONMENT` | `Production` | Environnement (recommandé) |
|
||||
|
||||
> Le défaut de `RootPath` est le **dossier de l'application** (résolu via
|
||||
> `AppContext.BaseDirectory`), jamais le répertoire de travail courant — un service
|
||||
> Windows démarre dans `C:\Windows\System32`, ce qui rendrait ce dernier inutilisable.
|
||||
>
|
||||
> **Recommandation production** : fixer `Langues__RootPath` sur **`C:\Omika\Data\Langues`**
|
||||
> (cohérent avec les autres données sous `C:\Omika\Data`). Ne **jamais** placer les
|
||||
> modèles dans `C:\Omika\Apps\LanguesApi` : ils seraient écrasés à chaque
|
||||
> redéploiement (voir §7.4).
|
||||
>
|
||||
> **Port** : voir **§6bis** — le port n'est **pas** imposé par ce document et ne
|
||||
> doit **jamais** être repris d'un exemple : il se décide contre le plan de ports
|
||||
> Apache, une fois, et s'écrit ensuite partout à l'identique.
|
||||
|
||||
---
|
||||
|
||||
## 6bis. Choix du port loopback (à décider AVANT §7.5bis)
|
||||
|
||||
**Aucun port n'est fixé par ce document.** La convention Apache/Kestrel du parc
|
||||
`omika.applilogik.fr` n'est **pas consignée dans le dépôt** : elle ne peut donc pas
|
||||
être devinée ici. Elle doit être relevée sur le serveur, puis appliquée.
|
||||
|
||||
Ports déjà connus du dépôt — à ne **pas** réutiliser :
|
||||
|
||||
| Port | Service | Source |
|
||||
|---|---|---|
|
||||
| 5097 | `Omika.Api` (développement) | `docs\start_omika_test.ps1` |
|
||||
| 5098 | `Omika.Diagnostics.Api` | `DEPLOIEMENT_PRODUCTION_DIAGNOSTICS.md` §4 |
|
||||
| 5080 | `Omika.Diagnostics.Web` | `DEPLOIEMENT_PRODUCTION_DIAGNOSTICS.md` §4 |
|
||||
| 5000 | Kestrel par défaut (si `ASPNETCORE_URLS` absente) | — |
|
||||
|
||||
### Procédure (à exécuter sur le serveur)
|
||||
|
||||
```powershell
|
||||
# <PORT_LANGUES> : à remplacer par le port candidat avant exécution.
|
||||
$portLangues = <PORT_LANGUES>
|
||||
|
||||
# 1. Le port candidat est-il déjà en écoute ?
|
||||
Get-NetTCPConnection -LocalPort $portLangues -State Listen -ErrorAction SilentlyContinue |
|
||||
Select-Object LocalAddress,LocalPort,OwningProcess
|
||||
|
||||
# 2. Tranches réservées par Hyper-V / WSL / Docker (elles peuvent être n'importe où)
|
||||
netsh int ipv4 show excludedportrange protocol=tcp
|
||||
|
||||
# 3. Plage éphémère Windows : le port fixe doit rester EN DESSOUS
|
||||
netsh int ipv4 show dynamicport tcp
|
||||
|
||||
# 4. Ports Omika réellement en écoute (vue d'ensemble)
|
||||
Get-NetTCPConnection -State Listen | Where-Object LocalPort -in 5097,5098,5080,$portLangues
|
||||
```
|
||||
|
||||
### Critères d'acceptation du port
|
||||
|
||||
1. **Libre** : aucune écoute sur `127.0.0.1` (étapes 1 et 2).
|
||||
2. **Hors plage éphémère** : en dessous de la borne basse de l'étape 3
|
||||
(49152 par défaut) — sinon une socket sortante peut le préempter.
|
||||
3. **Conforme au plan Apache** : le vhost proxy doit pointer vers **ce** port.
|
||||
4. **Un seul chiffre dans tout le déploiement** : `ASPNETCORE_URLS`, `ProxyPass` et
|
||||
`SRV_LANGUES` doivent décrire le même service. Une divergence produit un routage
|
||||
silencieux vers le mauvais service (404, ou réponse d'un autre service).
|
||||
|
||||
> **Sécurité** : Kestrel reste lié à `127.0.0.1` (HTTP), jamais à `0.0.0.0`.
|
||||
> L'exposition publique se fait **uniquement** en HTTPS par le reverse proxy Apache.
|
||||
> Le numéro choisi n'a aucune incidence sur ce point : c'est l'adresse de liaison
|
||||
> qui protège le service, pas le port.
|
||||
|
||||
---
|
||||
|
||||
## 7. Marche à suivre détaillée (fenêtre de maintenance)
|
||||
|
||||
### 7.1 Audit (lecture seule)
|
||||
|
||||
```powershell
|
||||
Get-Service OmikaLanguesApi -ErrorAction SilentlyContinue | Select-Object Name,Status
|
||||
[Environment]::GetEnvironmentVariable('Langues__RootPath','Machine')
|
||||
Test-Path 'C:\Omika\Data\Langues\manifest.json'
|
||||
```
|
||||
|
||||
### 7.2 Backup des binaires et des données (AVANT remplacement)
|
||||
|
||||
```powershell
|
||||
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||
$root = 'C:\Omika\Backups'
|
||||
# Binaires : seulement s'ils existent déjà
|
||||
if (Test-Path 'C:\Omika\Apps\LanguesApi') {
|
||||
Copy-Item 'C:\Omika\Apps\LanguesApi' -Destination "$root\LanguesApi_${stamp}" -Recurse -Force
|
||||
}
|
||||
if (Test-Path 'C:\Omika\Apps\OmikaApi') {
|
||||
Copy-Item 'C:\Omika\Apps\OmikaApi' -Destination "$root\OmikaApi_${stamp}" -Recurse -Force
|
||||
}
|
||||
# Données langues : seulement si le dossier existe déjà
|
||||
if (Test-Path 'C:\Omika\Data\Langues') {
|
||||
Copy-Item 'C:\Omika\Data\Langues' -Destination "$root\Langues_${stamp}" -Recurse -Force
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 Arrêt des services
|
||||
|
||||
```powershell
|
||||
Stop-Service OmikaLanguesApi -Force -ErrorAction SilentlyContinue
|
||||
Stop-Service OmikaApi -Force
|
||||
Get-Service OmikaApi,OmikaLanguesApi | Select-Object Name,Status
|
||||
```
|
||||
|
||||
### 7.4 Copie des binaires (préserve la config serveur existante)
|
||||
|
||||
```powershell
|
||||
robocopy 'C:\Omika\Deploy\OmikaApi-next' 'C:\Omika\Apps\OmikaApi' /E /XF appsettings.json appsettings.Production.json web.config
|
||||
robocopy 'C:\Omika\Deploy\LanguesApi-next' 'C:\Omika\Apps\LanguesApi' /E /XF appsettings.json appsettings.Production.json web.config
|
||||
```
|
||||
|
||||
> Ne **jamais** supprimer : `C:\Omika\Config\**`, `C:\Omika\Data\**` (dont
|
||||
> `C:\Omika\Data\Langues\**`), certificats TLS, variables d'environnement MACHINE.
|
||||
|
||||
### 7.5 Création du service `OmikaLanguesApi` (NOUVEAU — premier déploiement)
|
||||
|
||||
Le service se crée par le **script dédié** (recommandé : idempotent, vérifie le
|
||||
compte, le droit de connexion et la disponibilité du port, prend en charge
|
||||
`-WhatIf` et `-Desinstaller`) :
|
||||
|
||||
```powershell
|
||||
cd C:\Omika\Deploy\Deploy
|
||||
.\Install-OmikaLanguesApi.ps1 -Port <PORT_LANGUES>
|
||||
```
|
||||
|
||||
> Le script résout le compte, pose les ACL (**lecture seule** sur les modèles),
|
||||
> vérifie que `<PORT_LANGUES>` est réellement libre, puis crée le service
|
||||
> `OmikaLanguesApi` (Manual, non démarré). Il n'écrit **aucune** variable
|
||||
> d'environnement : la configuration reste l'étape §7.5bis ci-dessous.
|
||||
|
||||
Équivalent manuel (si vous préférez ne pas utiliser le script) :
|
||||
|
||||
```powershell
|
||||
$cred = Get-Credential -UserName '.\svc_omika_langues' -Message 'Compte service OmikaLanguesApi'
|
||||
New-Service -Name 'OmikaLanguesApi' -DisplayName 'Omika Langues Api' `
|
||||
-BinaryPathName '"C:\Omika\Apps\LanguesApi\Omika.Langues.Api.exe"' `
|
||||
-Credential $cred -StartupType Manual
|
||||
|
||||
# ACL sur le dossier des modèles (lecture seule suffit)
|
||||
icacls 'C:\Omika\Data\Langues' /grant:r "$env:COMPUTERNAME\svc_omika_langues:(OI)(CI)R"
|
||||
```
|
||||
|
||||
> Le compte dédié doit avoir le droit « Ouvrir une session en tant que service »
|
||||
> (le script le vérifie et avertit si le droit manque — erreur 1069 au démarrage).
|
||||
>
|
||||
> **Prérequis binaire** : le service doit embarquer `UseWindowsService()`. Sans
|
||||
> lui, il démarre puis s'arrête aussitôt avec l'erreur **1053** (« le service n'a
|
||||
> pas répondu à temps »). C'est le cas depuis l'ajout de
|
||||
> `Microsoft.Extensions.Hosting.WindowsServices` à `Omika.Langues.Api`.
|
||||
>
|
||||
> `infra\deploy\Install-OmikaServices.ps1` couvre désormais ce service, via
|
||||
> l'option `-InclureLangues` (voir §11).
|
||||
|
||||
### 7.5bis Configuration du service (variables d'environnement MACHINE)
|
||||
|
||||
**Premier déploiement uniquement** : poser la configuration en variables
|
||||
d'environnement **MACHINE** (le robocopy §7.4 a exclu `appsettings.json`, donc le
|
||||
service démarre sans fichier de config). Toute modification exige ensuite un
|
||||
**redémarrage** du service.
|
||||
|
||||
```powershell
|
||||
# <PORT_LANGUES> : port décidé en §6bis — NE PAS copier une valeur d'exemple.
|
||||
$portLangues = <PORT_LANGUES>
|
||||
|
||||
[Environment]::SetEnvironmentVariable('Langues__RootPath', 'C:\Omika\Data\Langues', 'Machine')
|
||||
[Environment]::SetEnvironmentVariable('ASPNETCORE_URLS', "http://127.0.0.1:$portLangues", 'Machine')
|
||||
[Environment]::SetEnvironmentVariable('ASPNETCORE_ENVIRONMENT', 'Production', 'Machine')
|
||||
|
||||
# Contrôle
|
||||
[Environment]::GetEnvironmentVariable('Langues__RootPath', 'Machine')
|
||||
[Environment]::GetEnvironmentVariable('ASPNETCORE_URLS', 'Machine')
|
||||
```
|
||||
|
||||
> - `Langues__RootPath` : **obligatoire** en production (défaut = dossier de
|
||||
> l'application, qui serait écrasé au prochain déploiement).
|
||||
> - `ASPNETCORE_URLS` : port loopback **explicite**, décidé en **§6bis** (ne jamais
|
||||
> recopier un exemple : le port se déduit du plan Apache, pas de ce document).
|
||||
> Sans cette variable, Kestrel écoute `http://localhost:5000`.
|
||||
> - Le reverse proxy Apache expose ensuite ce port en **HTTPS** ; `SRV_LANGUES`
|
||||
> pointe sur l'URL publique (voir §4 et §7.5ter).
|
||||
|
||||
### 7.5ter Exposition HTTPS par le reverse proxy Apache
|
||||
|
||||
Le service écoute en HTTP sur `127.0.0.1` : il est inatteignable depuis un
|
||||
téléphone. L'exposition se fait dans le vhost 443 **existant**.
|
||||
|
||||
`SRV_LANGUES` décrit l'**URL de base** seule : le mobile construit ensuite
|
||||
`{base}/api/langues` puis `{base}/api/langues/{code}/{sens}/{fichier}`
|
||||
(`LanguagePackService.ConstruireUrl`, qui concatène — un chemin dans la base est
|
||||
donc conservé). Pour `SRV_LANGUES = https://omika.applilogik.fr/langues`, Apache
|
||||
doit donc **retirer** le préfixe `/langues` avant de transmettre au service :
|
||||
|
||||
```apache
|
||||
# C:\Apache24\conf\extra\httpd-ssl.conf — dans le <VirtualHost ...:443>
|
||||
# Service Langues : /langues/api/langues -> http://127.0.0.1:5099/api/langues
|
||||
ProxyPass /langues/ http://127.0.0.1:5099/
|
||||
ProxyPassReverse /langues/ http://127.0.0.1:5099/
|
||||
ProxyPass /langues http://127.0.0.1:5099/
|
||||
ProxyPassReverse /langues http://127.0.0.1:5099/
|
||||
```
|
||||
|
||||
Puis :
|
||||
|
||||
```powershell
|
||||
& C:\Apache24\bin\httpd.exe -t # doit dire « Syntaxe OK »
|
||||
Restart-Service <service Apache>
|
||||
```
|
||||
|
||||
Contrôles (le `--resolve` évite le DNS : depuis le serveur, le nom public résout
|
||||
souvent vers une IP externe qui ne revient pas sur la machine) :
|
||||
|
||||
```powershell
|
||||
$U = 'https://omika.applilogik.fr'
|
||||
$C = @('--resolve','omika.applilogik.fr:443:127.0.0.1','-k','-s','-o','NUL','-w','%{http_code}\n')
|
||||
|
||||
curl.exe @C "$U/langues/api/langues" # 200
|
||||
curl.exe @C "$U/langues/api/langues/gl/commun/vocab.json" # 200
|
||||
curl.exe @C "$U/health" # 200 : API métier intacte
|
||||
|
||||
$j = (curl.exe -k -s --resolve omika.applilogik.fr:443:127.0.0.1 "$U/langues/api/langues") -join ''
|
||||
($j | ConvertFrom-Json).packs.Count # 31
|
||||
```
|
||||
|
||||
> - **Le préfixe `/langues` n'est pas décoratif** : la règle existante
|
||||
> `ProxyPass /api/ http://127.0.0.1:5080/api/` capte `/api/langues` et
|
||||
> l'envoie à l'API métier, qui ne sert plus les langues (404). Un préfixe
|
||||
> dédié évite de toucher à cette règle métier et de dépendre de l'ordre des
|
||||
> `ProxyPass`.
|
||||
> - Variante vhost dédié (`https://langues.applilogik.fr`) : la règle devient
|
||||
> `ProxyPass /api/langues http://127.0.0.1:5099/api/langues` (sans préfixe à
|
||||
> retirer), et `SRV_LANGUES = https://langues.applilogik.fr`.
|
||||
> - `$U/langues` seul répond `404` du service : il n'y a pas de route `/`, c'est
|
||||
> normal et sans conséquence (le mobile n'appelle que les chemins `/api/...`).
|
||||
> - Un `404` sur `$U/langues/api/langues` signifie que la règle n'a pas été
|
||||
> chargée (fichier non réécrit, ou Apache non rechargé) — ce n'est pas un
|
||||
> problème de service : `http://127.0.0.1:5099/api/langues` reste alors `200`.
|
||||
|
||||
### 7.6 Déploiement des fichiers modèles + manifeste
|
||||
|
||||
**Procédure complète : `LIVRAISON_MODELES_LANGUES.md`** (obtention des modèles,
|
||||
arborescence, dépôt, génération du manifeste, contrôles). Résumé :
|
||||
|
||||
```powershell
|
||||
$root = 'C:\Omika\Data\Langues'
|
||||
New-Item -ItemType Directory -Force -Path $root | Out-Null
|
||||
|
||||
# 1. Copier UNIQUEMENT les dossiers de langue {code}\ (pas de manifest.json
|
||||
# préparé ailleurs : il dépend des fichiers réellement présents ici)
|
||||
robocopy 'C:\Omika\Deploy\Langues\es' "$root\es" /E /R:2 /W:2
|
||||
|
||||
# 2. GÉNÉRER le manifeste sur le serveur (taille + SHA-256 de chaque fichier)
|
||||
cd C:\Omika\Deploy\Deploy
|
||||
.\New-OmikaLanguesManifeste.ps1
|
||||
|
||||
# 3. Contrôler
|
||||
.\New-OmikaLanguesManifeste.ps1 -Verifier
|
||||
```
|
||||
|
||||
> Le manifeste n'est **jamais** recopié d'une autre machine : il contient la
|
||||
> taille et l'empreinte SHA-256 des fichiers de **ce** disque. Un manifeste
|
||||
> provenant d'ailleurs fait refuser chaque pack par le mobile, sans aucune
|
||||
> erreur côté serveur.
|
||||
>
|
||||
> Le manifeste et les fichiers modèles sont relus à chaque requête : **aucun
|
||||
> redémarrage n'est nécessaire**. Le mobile, lui, garde son index mémorisé :
|
||||
> il faut « Actualiser la liste » dans Paramètres → Langue secondaire.
|
||||
|
||||
### 7.7 Création / mise à jour du paramètre `SRV_LANGUES` (HFSQL)
|
||||
|
||||
Écrire la ligne `ParametreSysteme` (voir §4) si elle n'existe pas, en pointant vers
|
||||
l'URL du service Langues. Aucun redémarrage requis : relue à chaque bootstrap mobile.
|
||||
|
||||
### 7.8 Redémarrage (consommateurs avant producteurs)
|
||||
|
||||
```powershell
|
||||
Start-Service OmikaLanguesApi # 1. service Langues (d'abord, car appelé par le mobile)
|
||||
Start-Service OmikaApi # 2. API métier (expose LanguesUrl)
|
||||
Get-Service OmikaApi,OmikaLanguesApi | Select-Object Name,Status
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Smoke tests
|
||||
|
||||
> **Accès anonyme** : aucun token requis — les réponses sont directes.
|
||||
> `<PORT_LANGUES>` = le port décidé en **§6bis** et posé en §7.5bis (aucun exemple
|
||||
> n'est fourni ici : recopier un chiffre d'exemple est précisément l'erreur à éviter).
|
||||
|
||||
```powershell
|
||||
# Racine du service
|
||||
Invoke-WebRequest 'http://127.0.0.1:<PORT_LANGUES>/' -UseBasicParsing # 200 {status:ok}
|
||||
|
||||
# Manifeste
|
||||
$manifest = Invoke-RestMethod 'http://127.0.0.1:<PORT_LANGUES>/api/langues'
|
||||
$manifest.packs | Select-Object code,libelle,version
|
||||
|
||||
# Téléchargement d'un fichier (valide le streaming + la résolution)
|
||||
Invoke-WebRequest 'http://127.0.0.1:<PORT_LANGUES>/api/langues/es/versFrancais/encoder.onnx' `
|
||||
-OutFile "$env:TEMP\encoder.onnx"
|
||||
Get-Item "$env:TEMP\encoder.onnx" | Select-Object Name,Length # taille = tailleOctets
|
||||
|
||||
# Cas d'erreur attendu
|
||||
Invoke-WebRequest 'http://127.0.0.1:<PORT_LANGUES>/api/langues/es/versFrancais/absent.onnx' -SkipHttpErrorCheck
|
||||
# → 404
|
||||
```
|
||||
|
||||
Vérifier aussi côté métier : après un bootstrap mobile, `LanguesUrl` vaut bien
|
||||
l'URL du service Langues (pas `null`).
|
||||
|
||||
---
|
||||
|
||||
## 9. Mise à jour (ajout de langue / nouvelle version de modèle)
|
||||
|
||||
### 9.1 Ajouter une nouvelle langue
|
||||
|
||||
1. Déposer les fichiers sous `C:\Omika\Data\Langues\{code}\versFrancais\` et
|
||||
`{code}\depuisFrancais\`.
|
||||
2. Ajouter l'objet `pack` dans `manifest.json` (avec `version`, `tailleOctets`, `sha256`).
|
||||
3. **Aucun redémarrage** : le manifeste est relu à chaque `GET /api/langues`.
|
||||
|
||||
### 9.2 Mettre à jour un modèle existant
|
||||
|
||||
1. Remplacer le(s) fichier(s) `.onnx` / `.spm` sous `{code}\{sens}\`.
|
||||
2. Recalculer `tailleOctets` et `sha256` (§5.3).
|
||||
3. **Incrémenter `version`** du pack (ex. `1.0.0` → `1.0.1`).
|
||||
|
||||
> Le mobile compare `version` (et `sha256`) entre son modèle local et le manifeste
|
||||
> serveur pour décider du re-téléchargement : tant que `version` et `sha256` sont
|
||||
> inchangés, le mobile considère son modèle à jour.
|
||||
|
||||
### 9.3 Retirer une langue
|
||||
|
||||
1. Supprimer l'objet `pack` de `manifest.json`.
|
||||
2. Optionnel : supprimer le dossier `{code}` de `C:\Omika\Data\Langues`.
|
||||
|
||||
---
|
||||
|
||||
## 10. Rollback
|
||||
|
||||
- **Binaires** : restaurer `C:\Omika\Backups\LanguesApi_<stamp>` (arrêt → copie →
|
||||
démarrage §7.8). Idem `OmikaApi_<stamp>` si besoin.
|
||||
- **Fichiers langues** : restaurer `C:\Omika\Backups\Langues_<stamp>` (simple copie,
|
||||
aucune migration à annuler).
|
||||
- **Paramètre HFSQL** : remettre l'ancienne valeur de `PAS_Valeur` (ou vider
|
||||
`SRV_LANGUES` → `LanguesUrl = null` → la fonctionnalité est désactivée côté mobile).
|
||||
|
||||
---
|
||||
|
||||
## 11. Écarts constatés (scripts/documents à mettre à jour)
|
||||
|
||||
1. ~~**`infra\deploy\Install-OmikaServices.ps1`** : ne crée **pas** le service
|
||||
`OmikaLanguesApi` ni ses ACL.~~ **RÉSOLU** : `infra\deploy` contient désormais
|
||||
**un script par déploiement** (`Install-OmikaApi.ps1`, `Install-OmikaWorker.ps1`,
|
||||
`Install-OmikaDiagnosticsApi.ps1`, `Install-OmikaDiagnosticsWorker.ps1`,
|
||||
`Install-OmikaDiagnosticsWeb.ps1`, `Install-OmikaLanguesApi.ps1`) partageant le
|
||||
module `Omika.Deploy.Common.psm1`. `Install-OmikaServices.ps1` devient un
|
||||
orchestrateur qui les enchaîne, avec `-InclureLangues` pour le service Langues.
|
||||
Le service embarque aussi `UseWindowsService()` (sans lui : erreur 1053 au
|
||||
démarrage).
|
||||
2. **`infra\deploy\Install-OmikaServerFiles.ps1`** : ne copie **pas** la publication
|
||||
`LanguesApi` ni le dossier de livraison des modèles — à livrer séparément
|
||||
(§3, §7.6). La livraison des modèles (obtention, arborescence, manifeste,
|
||||
contrôles) est décrite pas à pas dans `LIVRAISON_MODELES_LANGUES.md`, et le
|
||||
manifeste se génère avec `infra\deploy\New-OmikaLanguesManifeste.ps1` (§5.4).
|
||||
3. **`Omika.slnx`** ne référence **pas** `Omika.Langues.Api` (comme les projets
|
||||
Diagnostics) : on publie le `.csproj` directement.
|
||||
4. **Client mobile** : le téléchargement des modèles est **implémenté** côté
|
||||
application (voir `TRADUCTION_HORS_LIGNE_MOBILE.md`). Le **moteur d'inférence
|
||||
ONNX Runtime reste à activer** (paquet NuGet optionnel, un symbole de
|
||||
compilation) : sans lui, l'application télécharge et vérifie les modèles,
|
||||
mais annonce la traduction comme indisponible au lieu d'échouer.
|
||||
5. **Plan de ports Apache/Kestrel : non consigné dans le dépôt.** Les seuls ports
|
||||
connus sont ceux de `DEPLOIEMENT_PRODUCTION_DIAGNOSTICS.md` §4 (5097, 5098,
|
||||
5080), qui y sont eux-mêmes donnés comme « à définir / à confirmer » en
|
||||
production. Aucun document ne fixe le port de `OmikaLanguesApi` : il se décide
|
||||
sur le serveur (§6bis). Tant que ce plan n'existe pas par écrit, **tout port cité
|
||||
en exemple dans un runbook doit être traité comme un espace réservé à
|
||||
remplacer**, jamais comme une valeur à recopier.
|
||||
|
||||
---
|
||||
|
||||
## 12. Récapitulatif des points de configuration
|
||||
|
||||
1. **Base HFSQL** : ligne `ParametreSysteme` `PAS_Code = 'SRV_LANGUES'` → URL du service Langues.
|
||||
2. **Service `OmikaLanguesApi`** : variables MACHINE `Langues__RootPath` → `C:\Omika\Data\Langues` **et** `ASPNETCORE_URLS` → `http://127.0.0.1:<PORT_LANGUES>` (port décidé en **§6bis**, posé §7.5bis).
|
||||
3. **Fichiers** : arborescence `{code}/{sens}/{fichier}` sous `RootPath`, puis
|
||||
`manifest.json` **généré** par `New-OmikaLanguesManifeste.ps1` (§5.4) — jamais
|
||||
saisi à la main.
|
||||
4. **Binaires** : `Omika.Langues.Api` (nouveau) + `Omika.Api` (republication).
|
||||
5. **Accès** : anonyme — aucun token, aucun accès HFSQL.
|
||||
6. **Mise à jour** : ajouter/remplacer les fichiers puis regénérer le manifeste ;
|
||||
**aucun redémarrage** du service n'est requis (il relit le manifeste à chaque
|
||||
appel de `GET /api/langues`). Le mobile, lui, garde son index mémorisé : il
|
||||
faut un rafraîchissement de la liste des langues pour voir le changement.
|
||||
Reference in New Issue
Block a user