Deploiement Docker Local des Services GenAI

Navigation : Index | << Précédent

Ce notebook vous guide pour deployer les services de generation d’images localement sur votre machine.

Services disponibles

Service Description Port local GPU requis VRAM min
ComfyUI-Qwen Edition d’images avec Qwen VL 8188 Oui 20GB+
Forge-Turbo Stable Diffusion WebUI Forge 1111 Oui 8GB+
Z-Image Generation text-to-image (vLLM) 8001 Oui 15GB+

Prerequis

  1. Docker Desktop installe avec support GPU NVIDIA
  2. NVIDIA Driver >= 535.x
  3. CUDA compatible avec votre GPU
  4. GPU NVIDIA avec suffisamment de VRAM (voir tableau ci-dessus)

Mode de fonctionnement

Ce notebook permet de basculer entre : - Mode REMOTE : Utilise les services heberges sur myia.io (par defaut) - Mode LOCAL : Utilise vos services Docker locaux

La variable LOCAL_MODE=true dans le .env active automatiquement les URLs locales.

# Import guards - availability flags for external dependencies

try:
    from dotenv import load_dotenv
    DOTENV_AVAILABLE = True
except ImportError:
    DOTENV_AVAILABLE = False
    print(f'  dotenv non disponible - certaines fonctionnalites seront limitees')

try:
    import requests
    REQUESTS_AVAILABLE = True
except ImportError:
    REQUESTS_AVAILABLE = False
    print(f'  requests non disponible - certaines fonctionnalites seront limitees')


# =============================================================================
# 1. CONFIGURATION ET IMPORTS
# =============================================================================

import os
import sys
import subprocess
import json
import time
import shutil
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Optional, Tuple

try:
    import requests
    from dotenv import load_dotenv, set_key, dotenv_values
except ImportError:
    print("Installation des dependances...")
    subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", "requests", "python-dotenv"])
    import requests
    from dotenv import load_dotenv, set_key, dotenv_values

# Chemins
NOTEBOOK_DIR = Path(os.getcwd())
GENAI_DIR = NOTEBOOK_DIR.parent
REPO_ROOT = GENAI_DIR.parent.parent.parent
DOCKER_CONFIG_DIR = REPO_ROOT / "docker-configurations" / "services"
ENV_FILE = GENAI_DIR / ".env"
ENV_EXAMPLE = GENAI_DIR / ".env.example"

print("=" * 60)
print("   DEPLOIEMENT DOCKER LOCAL - Services GenAI")
print("=" * 60)
print(f"\nDate: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"\nChemins:")
print(f"  GenAI:  {GENAI_DIR}")
print(f"  Docker: {DOCKER_CONFIG_DIR}")
print(f"  .env:   {ENV_FILE}")
============================================================
   DEPLOIEMENT DOCKER LOCAL - Services GenAI
============================================================

Date: 2026-05-10 00:50:19

Chemins:
  GenAI:  D:\Dev\CoursIA\MyIA.AI.Notebooks\GenAI
  Docker: D:\Dev\docker-configurations\services
  .env:   D:\Dev\CoursIA\MyIA.AI.Notebooks\GenAI\.env

2. Configuration des Services

Definition des services disponibles et leurs configurations.

# =============================================================================
# 2. DEFINITION DES SERVICES
# =============================================================================

SERVICES = {
    "comfyui-qwen": {
        "name": "ComfyUI Qwen Image Edit",
        "description": "Edition d'images avec modele Qwen VL + Lightning",
        "docker_dir": DOCKER_CONFIG_DIR / "comfyui-qwen",
        "local_port": 8188,
        "local_url": "http://localhost:8188",
        "remote_url": "https://qwen-image-edit.myia.io",
        "health_endpoint": "/",
        "env_var_url": "COMFYUI_API_URL",
        "vram_required": "20GB+",
        "gpu_id": 0,
        "requires_auth": True,
    },
    "forge-turbo": {
        "name": "Stable Diffusion WebUI Forge",
        "description": "Generation Stable Diffusion (SDXL, SD 1.5, Turbo)",
        "docker_dir": DOCKER_CONFIG_DIR / "forge-turbo",
        "local_port": 1111,
        "local_url": "http://localhost:1111",
        "remote_url": "https://turbo.stable-diffusion-webui-forge.myia.io",
        "health_endpoint": "/sdapi/v1/options",
        "env_var_url": "FORGE_API_URL",
        "vram_required": "8GB+",
        "gpu_id": 1,
        "requires_auth": True,
    },
    "vllm-zimage": {
        "name": "Z-Image Turbo (vLLM)",
        "description": "Generation text-to-image via API OpenAI-compatible",
        "docker_dir": DOCKER_CONFIG_DIR / "vllm-zimage",
        "local_port": 8001,
        "local_url": "http://localhost:8001",
        "remote_url": "https://z-image.myia.io",
        "health_endpoint": "/health",
        "env_var_url": "ZIMAGE_API_URL",
        "vram_required": "15GB+",
        "gpu_id": 1,
        "requires_auth": False,
    },
}

# Affichage des services
print("\nSERVICES DISPONIBLES")
print("=" * 60)
for key, svc in SERVICES.items():
    print(f"\n{svc['name']}")
    print(f"  ID:        {key}")
    print(f"  Port:      {svc['local_port']}")
    print(f"  VRAM:      {svc['vram_required']}")
    print(f"  GPU:       {svc['gpu_id']}")
    print(f"  Local:     {svc['local_url']}")
    print(f"  Remote:    {svc['remote_url']}")

SERVICES DISPONIBLES
============================================================

ComfyUI Qwen Image Edit
  ID:        comfyui-qwen
  Port:      8188
  VRAM:      20GB+
  GPU:       0
  Local:     http://localhost:8188
  Remote:    https://qwen-image-edit.myia.io

Stable Diffusion WebUI Forge
  ID:        forge-turbo
  Port:      1111
  VRAM:      8GB+
  GPU:       1
  Local:     http://localhost:1111
  Remote:    https://turbo.stable-diffusion-webui-forge.myia.io

Z-Image Turbo (vLLM)
  ID:        vllm-zimage
  Port:      8001
  VRAM:      15GB+
  GPU:       1
  Local:     http://localhost:8001
  Remote:    https://z-image.myia.io

3. Verification des prerequis

Verifions que Docker et les GPUs sont disponibles.

# =============================================================================
# 3. VERIFICATION DES PREREQUIS
# =============================================================================

def check_docker() -> Tuple[bool, str]:
    """Verifie que Docker est installe et fonctionne."""
    try:
        result = subprocess.run(
            ["docker", "--version"],
            capture_output=True, text=True, timeout=10
        )
        if result.returncode == 0:
            return True, result.stdout.strip()
        return False, "Docker non fonctionnel"
    except FileNotFoundError:
        return False, "Docker non installe"
    except subprocess.TimeoutExpired:
        return False, "Docker timeout"

def check_docker_compose() -> Tuple[bool, str]:
    """Verifie que Docker Compose est disponible."""
    try:
        # Essayer docker compose (v2)
        result = subprocess.run(
            ["docker", "compose", "version"],
            capture_output=True, text=True, timeout=10
        )
        if result.returncode == 0:
            return True, result.stdout.strip()
        
        # Fallback docker-compose (v1)
        result = subprocess.run(
            ["docker-compose", "--version"],
            capture_output=True, text=True, timeout=10
        )
        if result.returncode == 0:
            return True, result.stdout.strip()
        return False, "Docker Compose non fonctionnel"
    except FileNotFoundError:
        return False, "Docker Compose non installe"

def check_nvidia_gpu() -> Tuple[bool, List[Dict]]:
    """Verifie les GPUs NVIDIA disponibles."""
    try:
        result = subprocess.run(
            ["nvidia-smi", "--query-gpu=index,name,memory.total,memory.free", "--format=csv,noheader,nounits"],
            capture_output=True, text=True, timeout=10
        )
        if result.returncode == 0:
            gpus = []
            for line in result.stdout.strip().split("\n"):
                if line:
                    parts = [p.strip() for p in line.split(",")]
                    if len(parts) >= 4:
                        gpus.append({
                            "index": int(parts[0]),
                            "name": parts[1],
                            "total_mb": int(parts[2]),
                            "free_mb": int(parts[3]),
                        })
            return True, gpus
        return False, []
    except FileNotFoundError:
        return False, []

def check_docker_nvidia() -> Tuple[bool, str]:
    """Verifie que Docker peut acceder aux GPUs."""
    try:
        result = subprocess.run(
            ["docker", "run", "--rm", "--gpus", "all", "nvidia/cuda:12.1.0-base-ubuntu22.04", "nvidia-smi", "-L"],
            capture_output=True, text=True, timeout=60
        )
        if result.returncode == 0:
            return True, result.stdout.strip()
        return False, result.stderr
    except Exception as e:
        return False, str(e)

# Verification
print("\nVERIFICATION DES PREREQUIS")
print("=" * 60)

# Docker
docker_ok, docker_info = check_docker()
print(f"\nDocker: {'OK' if docker_ok else 'ERREUR'}")
print(f"  {docker_info}")

# Docker Compose
compose_ok, compose_info = check_docker_compose()
print(f"\nDocker Compose: {'OK' if compose_ok else 'ERREUR'}")
print(f"  {compose_info}")

# GPUs
gpu_ok, gpus = check_nvidia_gpu()
print(f"\nGPUs NVIDIA: {'OK' if gpu_ok else 'ERREUR'}")
if gpus:
    for gpu in gpus:
        print(f"  [{gpu['index']}] {gpu['name']}")
        print(f"      VRAM: {gpu['total_mb']}MB total, {gpu['free_mb']}MB libre")
else:
    print("  Aucun GPU detecte")

# Docker + NVIDIA
if docker_ok and gpu_ok:
    print("\nDocker + NVIDIA: Verification en cours...")
    docker_nvidia_ok, nvidia_info = check_docker_nvidia()
    print(f"  {'OK - Docker peut acceder aux GPUs' if docker_nvidia_ok else 'ERREUR'}")
    if not docker_nvidia_ok:
        print(f"  {nvidia_info}")
        print("\n  Pour resoudre:")
        print("  1. Installez nvidia-container-toolkit")
        print("  2. Redemarrez Docker Desktop")

# Resume
all_ok = docker_ok and compose_ok and gpu_ok
print("\n" + "=" * 60)
if all_ok:
    print("TOUS LES PREREQUIS SONT SATISFAITS")
    print("Vous pouvez deployer les services localement.")
else:
    print("CERTAINS PREREQUIS MANQUENT")
    print("Installez les composants manquants ou utilisez le mode REMOTE.")

VERIFICATION DES PREREQUIS
============================================================

Docker: OK
  Docker version 29.4.1, build 055a478

Docker Compose: OK
  Docker Compose version v5.1.3

GPUs NVIDIA: OK
  [0] NVIDIA GeForce RTX 3080 Ti Laptop GPU
      VRAM: 16384MB total, 83MB libre
  [1] NVIDIA GeForce RTX 3090
      VRAM: 24576MB total, 18910MB libre

Docker + NVIDIA: Verification en cours...
  OK - Docker peut acceder aux GPUs

============================================================
TOUS LES PREREQUIS SONT SATISFAITS
Vous pouvez deployer les services localement.

Interpretation de la verification des prerequis

La verification a teste les composants necessaires au deploiement local.

Composantes verifiees : 1. Docker : Installation et fonctionnement 2. Docker Compose : Disponibilite pour orchestrer les conteneurs 3. GPUs NVIDIA : Detection et quantite de VRAM disponible 4. Docker + NVIDIA : Capacite de Docker a acceder aux GPUs

Résultats attendus : - Tous les prerequis satisfaits : Vous pouvez deployer les services localement - Prerequis manquants : Utilisez le mode REMOTE (services myia.io)

Note technique : L’installation de nvidia-container-toolkit est necessaire pour que Docker puisse acceder aux GPUs NVIDIA. Sans cela, les conteneurs ne pourront pas utiliser le GPU pour la generation d’images.

4. Gestion du mode LOCAL/REMOTE

Basculer entre les services locaux et distants.

Interpretation du mode LOCAL/REMOTE

Le mode determine si les notebooks utilisent les services locaux ou distants.

Mode LOCAL : - URLs locales : http://localhost:PORT - Necessite les services Docker demarres - Plus rapide (pas de latence reseau) - Consomme des ressources locales (GPU, RAM)

Mode REMOTE : - URLs distantes : https://SERVICE.myia.io - Pas de requis locaux (sauf connexion internet) - Latence reseau - Pas de consommation de ressources GPU locales

Bascule de mode : - La fonction set_mode(mode) met a jour le fichier .env - Les notebooks utilisent ensuite les URLs configurees - Le mode est persistant entre les sessions

Note technique : Le mode LOCAL est recommande pour le développement et les tests frequentes. Le mode REMOTE est preferable pour les demonstrations ou lorsque les ressources GPU locales sont insuffisantes.

# =============================================================================
# 4. GESTION DU MODE LOCAL/REMOTE
# =============================================================================

def get_current_mode() -> str:
    """Retourne le mode actuel (local ou remote)."""
    if not ENV_FILE.exists():
        return "remote"  # Par defaut
    
    load_dotenv(ENV_FILE, override=True)
    local_mode = os.getenv("LOCAL_MODE", "false").lower()
    return "local" if local_mode in ("true", "1", "yes") else "remote"

def set_mode(mode: str) -> None:
    """Configure le mode local ou remote.
    
    Args:
        mode: 'local' ou 'remote'
    """
    if not ENV_FILE.exists():
        if ENV_EXAMPLE.exists():
            shutil.copy(ENV_EXAMPLE, ENV_FILE)
            print(f"Fichier .env cree depuis .env.example")
        else:
            ENV_FILE.touch()
            print(f"Fichier .env cree (vide)")
    
    # Mettre a jour LOCAL_MODE
    local_value = "true" if mode == "local" else "false"
    set_key(str(ENV_FILE), "LOCAL_MODE", local_value)
    
    # Mettre a jour les URLs des services
    for key, svc in SERVICES.items():
        url = svc["local_url"] if mode == "local" else svc["remote_url"]
        set_key(str(ENV_FILE), svc["env_var_url"], url)
    
    # URLs supplementaires pour Z-Image
    if mode == "local":
        set_key(str(ENV_FILE), "ZIMAGE_API_BASE", "http://localhost:8001/v1")
    else:
        set_key(str(ENV_FILE), "ZIMAGE_API_BASE", "https://z-image.myia.io/v1")
    
    print(f"\nMode configure: {mode.upper()}")
    print(f"\nURLs configurees:")
    for key, svc in SERVICES.items():
        url = svc["local_url"] if mode == "local" else svc["remote_url"]
        print(f"  {svc['env_var_url']}: {url}")

def get_service_urls() -> Dict[str, str]:
    """Retourne les URLs actuelles des services."""
    load_dotenv(ENV_FILE, override=True)
    urls = {}
    for key, svc in SERVICES.items():
        urls[key] = os.getenv(svc["env_var_url"], svc["remote_url"])
    return urls

# Afficher le mode actuel
current_mode = get_current_mode()
print(f"\nMODE ACTUEL: {current_mode.upper()}")
print("=" * 60)

urls = get_service_urls()
for key, url in urls.items():
    print(f"  {SERVICES[key]['name']}: {url}")

MODE ACTUEL: LOCAL
============================================================
  ComfyUI Qwen Image Edit: http://127.0.0.1:8188
  Stable Diffusion WebUI Forge: http://localhost:17861
  Z-Image Turbo (vLLM): http://localhost:8001

Bascule de mode

Le mode actuel est affiche ci-dessus. Pour changer de mode, decommentez l’une des cellules suivantes et executez-la. En mode LOCAL, les URLs pointent vers vos conteneurs Docker locaux. En mode REMOTE, elles pointent vers les services heberges sur myia.io.

# =============================================================================
# BASCULER EN MODE LOCAL
# =============================================================================
# Decommentez la ligne ci-dessous pour activer le mode local

# set_mode("local")
# =============================================================================
# BASCULER EN MODE REMOTE
# =============================================================================
# Decommentez la ligne ci-dessous pour activer le mode remote

# set_mode("remote")

5. Gestion des services Docker

Demarrer, arreter et verifier les services.

Interpretation du statut des services

Le statut affiche l’etat de chaque service GenAI.

Indicateurs : - Container UP : Le conteneur Docker est en cours d’exécution - Container DOWN : Le conteneur n’est pas demarre - API OK : Le service repond aux requêtes HTTP - API X : Le service n’est pas accessible

Actions possibles : - Si Container DOWN mais service demarre : Le service a peut-etre plante - Si API X mais Container UP : Verifiez les ports et la configuration reseau - Si tout est OK : Le service est pret a etre utilise

Note technique : Un statut “Container DOWN” est normal si vous utilisez le mode REMOTE. Seuls les services locaux demontrent un container UP.

# =============================================================================
# 5. GESTION DES SERVICES DOCKER
# =============================================================================

def get_docker_compose_cmd() -> List[str]:
    """Retourne la commande docker compose appropriee."""
    # Essayer docker compose (v2) d'abord
    try:
        result = subprocess.run(["docker", "compose", "version"], capture_output=True, timeout=5)
        if result.returncode == 0:
            return ["docker", "compose"]
    except:
        pass
    return ["docker-compose"]

COMPOSE_CMD = get_docker_compose_cmd()

def start_service(service_id: str) -> Tuple[bool, str]:
    """Demarre un service Docker.
    
    Args:
        service_id: ID du service (comfyui-qwen, forge-turbo, vllm-zimage)
    
    Returns:
        Tuple (succes, message)
    """
    if service_id not in SERVICES:
        return False, f"Service inconnu: {service_id}"
    
    svc = SERVICES[service_id]
    docker_dir = svc["docker_dir"]
    
    if not docker_dir.exists():
        return False, f"Repertoire Docker non trouve: {docker_dir}"
    
    compose_file = docker_dir / "docker-compose.yml"
    if not compose_file.exists():
        return False, f"docker-compose.yml non trouve: {compose_file}"
    
    print(f"\nDemarrage de {svc['name']}...")
    print(f"  Repertoire: {docker_dir}")
    
    try:
        # Pull des images
        print("  Pull des images Docker...")
        result = subprocess.run(
            COMPOSE_CMD + ["-f", str(compose_file), "pull"],
            cwd=docker_dir,
            capture_output=True, text=True, timeout=300
        )
        
        # Demarrage
        print("  Demarrage du conteneur...")
        result = subprocess.run(
            COMPOSE_CMD + ["-f", str(compose_file), "up", "-d"],
            cwd=docker_dir,
            capture_output=True, text=True, timeout=120
        )
        
        if result.returncode == 0:
            return True, f"Service {svc['name']} demarre sur port {svc['local_port']}"
        else:
            return False, f"Erreur: {result.stderr}"
    except subprocess.TimeoutExpired:
        return False, "Timeout lors du demarrage"
    except Exception as e:
        return False, str(e)

def stop_service(service_id: str) -> Tuple[bool, str]:
    """Arrete un service Docker."""
    if service_id not in SERVICES:
        return False, f"Service inconnu: {service_id}"
    
    svc = SERVICES[service_id]
    docker_dir = svc["docker_dir"]
    compose_file = docker_dir / "docker-compose.yml"
    
    if not compose_file.exists():
        return False, f"docker-compose.yml non trouve"
    
    print(f"\nArret de {svc['name']}...")
    
    try:
        result = subprocess.run(
            COMPOSE_CMD + ["-f", str(compose_file), "down"],
            cwd=docker_dir,
            capture_output=True, text=True, timeout=60
        )
        
        if result.returncode == 0:
            return True, f"Service {svc['name']} arrete"
        else:
            return False, f"Erreur: {result.stderr}"
    except Exception as e:
        return False, str(e)

def get_service_status(service_id: str) -> Dict:
    """Retourne le statut d'un service Docker."""
    svc = SERVICES.get(service_id)
    if not svc:
        return {"status": "unknown", "error": "Service inconnu"}
    
    # Verifier le conteneur
    try:
        result = subprocess.run(
            ["docker", "ps", "--filter", f"name={service_id}", "--format", "{{.Status}}"],
            capture_output=True, text=True, timeout=10
        )
        container_status = result.stdout.strip()
    except:
        container_status = ""
    
    # Verifier la connectivite
    load_dotenv(ENV_FILE, override=True)
    url = os.getenv(svc["env_var_url"], svc["remote_url"])
    
    try:
        resp = requests.get(f"{url}{svc['health_endpoint']}", timeout=5)
        # 200 ou 401 (auth requise) = service fonctionne
        api_ok = resp.status_code in [200, 401]
    except:
        api_ok = False
    
    return {
        "service_id": service_id,
        "name": svc["name"],
        "container_status": container_status or "not running",
        "api_reachable": api_ok,
        "url": url,
        "port": svc["local_port"],
    }

print("Fonctions de gestion Docker definies:")
print("  - start_service(service_id)")
print("  - stop_service(service_id)")
print("  - get_service_status(service_id)")
Fonctions de gestion Docker definies:
  - start_service(service_id)
  - stop_service(service_id)
  - get_service_status(service_id)
# =============================================================================
# STATUT DE TOUS LES SERVICES
# =============================================================================

print("\nSTATUT DES SERVICES")
print("=" * 60)

for service_id in SERVICES:
    status = get_service_status(service_id)
    
    container_icon = "UP" if "Up" in status["container_status"] else "DOWN"
    api_icon = "OK" if status["api_reachable"] else "X"
    
    print(f"\n{status['name']}")
    print(f"  Container: [{container_icon}] {status['container_status']}")
    print(f"  API:       [{api_icon}] {status['url']}")
    print(f"  Port:      {status['port']}")

STATUT DES SERVICES
============================================================

ComfyUI Qwen Image Edit
  Container: [UP] Up 12 hours (healthy)
  API:       [OK] http://127.0.0.1:8188
  Port:      8188

Stable Diffusion WebUI Forge
  Container: [UP] Up 13 hours
  API:       [OK] http://localhost:17861
  Port:      1111

Z-Image Turbo (vLLM)
  Container: [UP] Up 12 hours (healthy)
  API:       [OK] http://localhost:8001
  Port:      8001

6. Demarrer les services

Utilisez les cellules ci-dessous pour demarrer les services souhaites.

# =============================================================================
# DEMARRER COMFYUI-QWEN
# =============================================================================
# Necessite: GPU avec 20GB+ VRAM
# Decommentez pour demarrer

# success, msg = start_service("comfyui-qwen")
# print(msg)

Demarrage individuel des services

Chaque service a des requis GPU différents. Decommentez uniquement les services que votre materiel peut supporter. Le statut des conteneurs s’affiche en temps reel dans la section précédente.

# =============================================================================
# DEMARRER FORGE-TURBO
# =============================================================================
# Necessite: GPU avec 8GB+ VRAM
# Decommentez pour demarrer

# success, msg = start_service("forge-turbo")
# print(msg)
# =============================================================================
# DEMARRER Z-IMAGE
# =============================================================================
# Necessite: GPU avec 15GB+ VRAM
# Decommentez pour demarrer

# success, msg = start_service("vllm-zimage")
# print(msg)

7. Test de connectivite

Verifier que les services repondent correctement.

# =============================================================================
# 7. TEST DE CONNECTIVITE
# =============================================================================

def test_comfyui_connection(url: str, token: str = None) -> Dict:
    """Test de connexion a ComfyUI."""
    headers = {}
    if token:
        headers["Authorization"] = f"Bearer {token}"
    
    try:
        resp = requests.get(f"{url}/system_stats", headers=headers, timeout=10)
        if resp.status_code == 200:
            return {"success": True, "data": resp.json()}
        elif resp.status_code == 401:
            return {"success": False, "error": "Authentication requise", "code": 401}
        else:
            return {"success": False, "error": f"HTTP {resp.status_code}", "code": resp.status_code}
    except requests.exceptions.ConnectionError:
        return {"success": False, "error": "Service non accessible"}
    except Exception as e:
        return {"success": False, "error": str(e)}

def test_forge_connection(url: str, user: str = None, password: str = None) -> Dict:
    """Test de connexion a Forge."""
    auth = None
    if user and password:
        auth = (user, password)
    
    try:
        resp = requests.get(f"{url}/sdapi/v1/options", auth=auth, timeout=10)
        if resp.status_code == 200:
            return {"success": True, "data": resp.json()}
        elif resp.status_code == 401:
            return {"success": False, "error": "Authentication requise", "code": 401}
        else:
            return {"success": False, "error": f"HTTP {resp.status_code}", "code": resp.status_code}
    except requests.exceptions.ConnectionError:
        return {"success": False, "error": "Service non accessible"}
    except Exception as e:
        return {"success": False, "error": str(e)}

def test_zimage_connection(url: str) -> Dict:
    """Test de connexion a Z-Image."""
    try:
        resp = requests.get(f"{url}/health", timeout=10)
        if resp.status_code == 200:
            return {"success": True, "data": resp.json() if resp.text else {}}
        else:
            return {"success": False, "error": f"HTTP {resp.status_code}", "code": resp.status_code}
    except requests.exceptions.ConnectionError:
        return {"success": False, "error": "Service non accessible"}
    except Exception as e:
        return {"success": False, "error": str(e)}

# Test de tous les services
print("\nTEST DE CONNECTIVITE")
print("=" * 60)

load_dotenv(ENV_FILE, override=True)

# ComfyUI
comfyui_url = os.getenv("COMFYUI_API_URL", "https://qwen-image-edit.myia.io")
comfyui_token = os.getenv("COMFYUI_API_TOKEN")
print(f"\nComfyUI: {comfyui_url}")
result = test_comfyui_connection(comfyui_url, comfyui_token)
if result["success"]:
    print(f"  Status: OK")
    if "data" in result:
        stats = result["data"]
        if "system" in stats:
            print(f"  OS: {stats['system'].get('os', 'N/A')}")
else:
    print(f"  Status: ERREUR - {result['error']}")

# Forge
forge_url = os.getenv("FORGE_API_URL", "https://turbo.stable-diffusion-webui-forge.myia.io")
forge_user = os.getenv("FORGE_USER")
forge_pass = os.getenv("FORGE_PASSWORD")
print(f"\nForge: {forge_url}")
result = test_forge_connection(forge_url, forge_user, forge_pass)
if result["success"]:
    print(f"  Status: OK")
else:
    print(f"  Status: ERREUR - {result['error']}")

# Z-Image
zimage_url = os.getenv("ZIMAGE_API_URL", "https://z-image.myia.io")
print(f"\nZ-Image: {zimage_url}")
result = test_zimage_connection(zimage_url)
if result["success"]:
    print(f"  Status: OK")
else:
    print(f"  Status: ERREUR - {result['error']}")

TEST DE CONNECTIVITE
============================================================

ComfyUI: http://127.0.0.1:8188
  Status: OK
  OS: posix

Forge: http://localhost:17861
  Status: OK

Z-Image: http://localhost:8001
  Status: OK

8. Arreter les services

Utilisez ces cellules pour arreter les services.

# =============================================================================
# ARRETER TOUS LES SERVICES
# =============================================================================
# Decommentez pour arreter tous les services

# for service_id in SERVICES:
#     success, msg = stop_service(service_id)
#     print(msg)

9. Resume et prochaines étapes

Ce que vous avez appris

  1. Prerequis pour le deploiement local (Docker, GPU, drivers)
  2. Mode LOCAL/REMOTE : basculer entre services locaux et myia.io
  3. Gestion Docker : demarrer/arreter les services
  4. Test de connectivite : verifier que tout fonctionne

Configuration rapide

# Pour utiliser les services locaux:
set_mode("local")
start_service("comfyui-qwen")

# Pour revenir aux services distants:
set_mode("remote")

Prochaines étapes

  1. Executez le notebook 00-1-GenAI-Environment-Intro.ipynb pour tester la configuration
  2. Passez aux notebooks 01-Foundation/ pour apprendre a utiliser les APIs
  3. Si vous avez un GPU puissant, essayez les notebooks 02-Advanced/ avec vos services locaux

Ressources

# =============================================================================
# FIN DU NOTEBOOK
# =============================================================================

print("\n" + "=" * 60)
print("   NOTEBOOK TERMINE")
print("=" * 60)
print(f"\nMode actuel: {get_current_mode().upper()}")
print(f"\nPour changer de mode:")
print(f"  set_mode('local')  - Utiliser les services locaux")
print(f"  set_mode('remote') - Utiliser les services myia.io")

============================================================
   NOTEBOOK TERMINE
============================================================

Mode actuel: LOCAL

Pour changer de mode:
  set_mode('local')  - Utiliser les services locaux
  set_mode('remote') - Utiliser les services myia.io
Retour au sommet