Image Studio UI - interface web de generation d images (proxy stable-diffusion.cpp), stdlib Python seule
  • HTML 61%
  • Python 37.9%
  • JavaScript 0.7%
  • Batchfile 0.4%
Find a file
EmitLinks 9b2b9af8fb Presets serveurs : formulaire admin complet miroir de la page de génération
- Formulaire admin presets = miroir exact : prompt, négatif, refImage,
  largeurs (y compris 16k), hauteur, étapes, CFG, clip skip, seed, batch,
  denoise, HR (scale/steps/upscaler), sampler, scheduler, LoRAs (coche,
  poids, intervalle) + boutons Copier depuis la page / Appliquer à la page
- Bug racine « presets inutilisables » : les LoRAs d'un preset n'étaient pas
  re-cochées au chargement car le nom n'était pas sérialisé
  (readCurrentParams et readAdminPresetParams transportent désormais l.name)
- Les selects apsSampler/apsScheduler/apsHrUpscaler sont clones de la page
- Selftest : section 22 (clonage des selects, lecture/écriture du formulaire,
  round-trip LoRAs par nom) — SELFTEST PASS (22 sections)
2026-10-24 19:29:33 +02:00
vendor Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00
.gitignore UI admin modèles + durcissement sécurité 2026-10-24 17:05:24 +02:00
apple-touch-icon.png Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00
auth.py Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00
cacert.pem Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00
config.example.json UI admin modèles + durcissement sécurité 2026-10-24 17:05:24 +02:00
favicon.png Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00
icon-192.png Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00
icon-512.png Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00
index.html Presets serveurs : formulaire admin complet miroir de la page de génération 2026-10-24 19:29:33 +02:00
manifest.json Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00
README.md Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00
run_selftest.py Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00
server.py UI admin modèles + durcissement sécurité 2026-10-24 17:05:24 +02:00
start-ui.bat Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00
sw.js Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00
test_auth.py Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00
test_lora_access.py Image Studio UI (stable-diffusion.cpp proxy): source initiale, sans données sensibles (config.example.json remplace config.json) 2026-10-16 18:04:37 +02:00

Image Studio UI

Interface web de génération d'images pour llama-swap (sd-server). Serveur Python léger (stdlib uniquement, aucune dépendance à installer), sert l'UI et fait proxy vers le serveur SD en amont.

Démarrage rapide

start-ui.bat

Le batch lance python server.py en fenêtre minimisée, vérifie le port 8788 et affiche l'URL. Double-cliquer suffit.

Manuellement :

cd /chemin/vers/image-studio
python server.py

Puis ouvrir https://localhost:8788 (certificat auto-généré auto-signé, le navigateur affichera un avertissement normal).

L'UI écoute sur 0.0.0.0:8788 (HTTPS) + 8789 (redirection HTTP → HTTPS).

Configuration

Fichier config.json à côté de server.py :

{
  "port": 8788,
  "host": "0.0.0.0",
  "upstream": "http://127.0.0.1:9251",
  "trusted_reverse_proxy": false,
  "https": true,
  "auth": { ... }
}
Clé Rôle
port Port HTTPS de l'UI (8788). Le port+1 (8789) fait la redirection HTTP→HTTPS.
host Interface d'écoute. 0.0.0.0 = accessible sur le réseau.
upstream URL du serveur SD en amont (llama-swap / sd-server), ex. http://127.0.0.1:9251. L'UI ne l'expose pas : le frontend route uniquement par /api/proxy/<chemin> (routage vers l'upstream forcé, aucune option directe).
https true = HTTPS avec le certificat auto-généré du dossier .pwa/ (ou tls_cert/tls_key si fournis).
trusted_reverse_proxy false, ou une liste d'adresses (IP exactes ou CIDR) des reverse proxies autorisés. Quand la liste est non vide : seule l'IP source de la liste est acceptée (l'IP réelle du client est lue dans X-Forwarded-For), toute autre connexion reçoit un 403. Permet d'exposer l'UI via un proxy extérieur (Caddy/Nginx/tunnel) sans l'ouvrir à tous.

Priorité des options : flag CLI > variable d'env > config.json.

  • --upstream <url> ou SD_UI_UPSTREAM
  • --trusted-proxy="IP1,IP2,CIDR" ou SD_UI_TRUSTED_PROXY
  • python server.py <port> pour changer le port.

Authentification

Section auth de config.json. Désactivée par défaut (enabled: false) : l'UI est libre d'accès, aucun compte requis.

Comptes locaux (SQLite)

Avec auth.enabled: true, les mots de passe sont stockés dans users.db (hachage PBKDF2-HMAC-SHA256). Gestion en ligne de commande — fonctionne même si enabled est false dans la config :

python server.py users add <nom> <mot_de_passe>
python server.py users passwd <nom> <nouveau_mdp>
python server.py users remove <nom>
python server.py users list
  • session_ttl : durée de validité d'une session en secondes (défaut 3600).
  • cookie_name : nom du cookie de session (défaut ui_session).

SSO OpenID Connect

Actif seulement si auth.enabled: true et issuer et client_id sont renseignés. À ce moment, un bouton « Se connecter via SSO » apparaît sur la page de login.

"oidc": {
  "issuer": "https://auth.example.com/realms/MyRealm",
  "client_id": "my-image-studio-client",
  "client_secret": "<secret-fourni-par-votre-fournisseur>",
  "scope": "openid profile email",
  "base_url": "https://studio.example.com"
}
Champ Rôle
issuer URL du fournisseur OIDC. Le serveur récupère tout automatiquement via issuer/.well-known/openid-configuration (endpoints autorisation/tokens/JWKS/userinfo).
client_id Identifiant de l'app. Doit correspondre à l'aud du id_token (sinon rejet). Obligatoire.
client_secret Clé secrète. Optionnel ici : envoyé en Basic auth à l'échange du code si présent.
scope Claims demandés. openid obligatoire ; profile/email donnent nom et e-mail.
base_url URL publique du serveur (vue depuis l'internet). Détermine l'URL de callback.

URL de callback (à inscrire comme Redirect URI autorisée dans le fournisseur) :

https://studio.example.com/auth/oidc/callback

Elle est calculée comme base_url + "/auth/oidc/callback".

  • Via un reverse proxy : renseigner base_url avec l'URL publique, sinon le callback serait calculé avec l'IP interne du proxy et rejeté.
  • Accès direct sans proxy : laisser base_url vide (reconstruit depuis l'en-tête Host, schéma https).

Le flux : PKCE (S256) + state anti-CSRF + validation nonce, vérification du JWS du id_token (RS256/PS256/ES256 via le jwks_uri), contrôles iss/aud/exp. Un compte local est créé ou lié par son sub au premier login.

Note TLS (certificats expirés) : sur certains builds Windows de Python, le store de confiance système contient une version obsolète de la racine Let's Encrypt, ce qui provoque certificate has expired sur les appels sortants vers le fournisseur OIDC, alors que le certificat du fournisseur est valide. auth.py contourne en chargeant explicitement les racines ISRG X1/X2 à jour depuis le fichier cacert.pem (à côté de server.py). Si ce fichier manque, le comportement par défaut est utilisé. Pour le régénérer :

curl -fsS -o _bundle.pem https://curl.se/ca/cacert.pem
REM extraire les blocs « ISRG Root X1 » et « ISRG Root X2 » du bundle
REM dans cacert.pem (2 certificats au total)

Sessions de génération (jobs)

La génération survit à la fermeture de la page :

  • POST /api/generate crée un job exécuté en thread, persisté dans jobs/<id>.json (rétention 48 h).
  • Au retour, l'UI relit GET /api/jobs/<id> et reprend là où elle en était.

Batch 1 par 1 + progression réelle

  • Chaque image du batch est générée par une requête (batch_size: 1) et affichée immédiatement dans la grille, au fil de l'eau (pas de téléchargement de tout le lot à la fin).
  • Le serveur persiste images_done, seeds_done et progress après chaque image.
  • La barre de progression reflète la vraie progression (images faites / images demandées) via le job côté serveur.
  • Les seeds sont extraits de info (llama-swap renvoie info comme chaîne JSON, le serveur la décode).

Endpoints principaux

Méthode Chemin Rôle
GET / L'UI (redirigée vers /login si auth activée et non connecté).
GET /api/proxy-mode Indique le mode du backend (le frontend route systématiquement par /api/proxy — aucune option frontend).
GET /api/proxy/<chemin> Proxy vers l'upstream (query string relayée).
POST /api/generate Démarre un job de génération.
GET /api/jobs/<id> État d'un job + images/seeds faits.
GET /api/auth/status {"auth": bool, "oidc": bool, "user": …}.
POST /api/auth/login Connexion locale (username/password).
POST /api/auth/logout Déconnexion.
GET /auth/oidc Redirection vers le fournisseur (si OIDC actif).
GET /auth/oidc/callback Retour du fournisseur (échange du code).

Arborescence

image-studio/
├── server.py          # Serveur (stdlib Python, proxy, jobs, auth)
├── auth.py            # Module d'authentification (SQLite + OIDC)
├── config.json        # Configuration (non committée — voir config.example.json)
├── index.html         # L'UI
├── vendor/            # Bibliothèques front (Bootstrap, Font Awesome…)
├── .pwa/              # Certificats auto-générés (cert.pem, key.pem)
├── cacert.pem         # Racines ISRG X1/X2 (TLS des appels OIDC)
├── users.db           # Base SQLite des comptes (créée à la 1re use)
├── jobs/              # Jobs de génération persistés
├── start-ui.bat       # Lancement facile
└── README.md

Prérequis

  • Python 3 (stdlib seule — aucun pip install).
  • llama-swap / sd-server démarré sur le port défini dans upstream (défaut http://127.0.0.1:9251).