Guide de l'utilisateur d'Open WebUI pour les modèles à pondération ouverte sur GDC sous air gap

Ce document fournit des instructions détaillées pour déployer Open WebUI, une interface de chat auto-hébergée basée sur un navigateur, dans des environnements Google Distributed Cloud (GDC) air-gapped. Open WebUI se connecte aux backends d'inférence déployés avec les guides de l'utilisateur Ollama et vLLM via leurs API compatibles avec Ollama et OpenAI. Les développeurs et les utilisateurs finaux peuvent ainsi interagir avec les modèles de pondérations ouverts sans écrire d'appels d'API.

Architecture

Open WebUI s'exécute en tant que Deployment à instance répliquée unique dans son propre espace de noms du cluster standard. Son état (comptes utilisateur, discussions, paramètres) est stocké sur un ReadWriteOnce PersistentVolumeClaim. Un ConfigMap contient les paramètres de connexion des backends d'inférence, qui sont accessibles via leurs noms Service dans le cluster, et un Secret contient la clé de signature de session. Un Service Kubernetes de type LoadBalancer expose l'interface Web, et les objets NetworkPolicy/ProjectNetworkPolicy sécurisent l'accès à celle-ci.

Avant de commencer

Assurez-vous qu'au moins un backend d'inférence a été déployé avec le guide de l'utilisateur des modèles Gemma avec Ollama, le guide de l'utilisateur des modèles Gemma avec vLLM ou le guide de l'utilisateur des modèles Mistral avec vLLM, et que vous avez accès au répertoire ${HOME}/gdcag-solutions de l'implémentation de référence correspondante sur le poste de travail.

Identity and Access Management

Assurez-vous que les comptes, rôles et autorisations IAM nécessaires sont correctement configurés.

Rôles Utilisateur GDC sur l'organisation :

  • Facultatif : Administrateur de cluster standard (afficher les clusters depuis la console)

Utilisateur GDC sur le projet :

  • Administrateur de cluster standard (standard-cluster-admin)

Utilisateur GDC sur le cluster standard :

  • StandardClusterRoleBinding au StandardClusterRole cluster-admin (créé par un administrateur IAM du projet, consultez la section Identity and Access Management de l'implémentation de référence)

Station de travail

Sauf indication contraire, exécutez toutes les commandes de ce guide à partir d'un poste de travail disposant des outils requis et d'une connectivité à l'environnement et à Internet.

  1. Créez la structure de répertoires du guide de l'utilisateur :

    mkdir -p ${HOME}/gdcag-solutions/open-weight-models/open-webui/env.d
    mkdir -p ${HOME}/gdcag-solutions/open-weight-models/open-webui/secrets
    
    chmod u=rwx,go= ${HOME}/gdcag-solutions/open-weight-models/open-webui/secrets
    
  2. Créez la clé de signature de session :

    openssl rand -hex 32 > ${HOME}/gdcag-solutions/open-weight-models/open-webui/secrets/open_webui_secret_key
    
    chmod u=rw,go= ${HOME}/gdcag-solutions/open-weight-models/open-webui/secrets/open_webui_secret_key
    
  3. Créez le fichier de configuration de l'environnement du guide de l'utilisateur :

    cat << 'EOF' > ${HOME}/gdcag-solutions/open-weight-models/open-webui/env.d/open-webui.sh && echo "Successfully created." || echo "Failed to create!"
    # Open WebUI
    export GDCS_OPEN_WEBUI_IMAGE_TAG="v0.11.3"
    export GDCS_OPEN_WEBUI_NAME="open-webui"
    export GDCS_OPEN_WEBUI_PVC_SIZE="20Gi"
    export GDCS_OPEN_WEBUI_SECRET_KEY="$(cat ${GDCS_USER_GUIDE_HOME}/secrets/open_webui_secret_key)"
    
    # Inference backends (in-cluster Service addresses, several backends separated by ';').
    # The user guides name the Service after the model: Ollama uses GDCS_OLLAMA_MODEL_KUBERNETES
    # (gemma4:e4b -> gemma4-e4b) and vLLM uses GDCS_HF_MODEL_KUBERNETES (such as vllm-gemma or vllm-mistral)
    # (mistralai/Mistral-7B-Instruct-v0.2 -> mistralai-mistral-7b-instruct-v0-2); kubectl get service
    # in the workload namespace (ollama-gemma, vllm-gemma or vllm-mistral) lists them.
    export GDCS_OPEN_WEBUI_ENABLE_OLLAMA_API="OPEN_WEBUI_ENABLE_OLLAMA_API"
    export GDCS_OPEN_WEBUI_OLLAMA_BASE_URLS="OPEN_WEBUI_OLLAMA_BASE_URLS"
    export GDCS_OPEN_WEBUI_ENABLE_OPENAI_API="OPEN_WEBUI_ENABLE_OPENAI_API"
    export GDCS_OPEN_WEBUI_OPENAI_API_BASE_URLS="OPEN_WEBUI_OPENAI_API_BASE_URLS"
    export GDCS_OPEN_WEBUI_OPENAI_API_KEYS="none"         # vLLM does not check API keys unless started with --api-key
    
    # Workload
    export GDCS_WORKLOAD_NAMESPACE="open-webui"
    
    # CPU resources
    export GDCS_WORKLOAD_CPU_LIMIT="2"
    export GDCS_WORKLOAD_CPU_REQUEST="1"
    
    # Memory resources
    export GDCS_WORKLOAD_MEMORY_LIMIT="4Gi"
    export GDCS_WORKLOAD_MEMORY_REQUEST="2Gi"
    
    EOF
    

    Remplacez les éléments suivants :

    • OPEN_WEBUI_ENABLE_OLLAMA_API : true si vous avez déployé un backend Ollama, sinon false.
    • OPEN_WEBUI_OLLAMA_BASE_URLS : URL des services Ollama dans le cluster, séparées par ;, par exemple http://gemma4-e4b.ollama-gemma.svc.cluster.local. Laissez ce champ vide si vous n'avez pas déployé de backend Ollama.
    • OPEN_WEBUI_ENABLE_OPENAI_API : true si vous avez déployé un backend vLLM, sinon false.
    • OPEN_WEBUI_OPENAI_API_BASE_URLS : URL dans le cluster des services vLLM avec le chemin d'accès /v1, séparées par ;, par exemple http://mistralai-mistral-7b-instruct-v0-2.vllm-mistral.svc.cluster.local/v1 ou http://google-gemma-4-e2b-it.vllm-gemma.svc.cluster.local/v1. Laissez ce champ vide si vous n'avez pas déployé de backend vLLM.
  4. Créez le fichier de chargement de l'environnement du guide de l'utilisateur :

    cat << 'EOF' > ${HOME}/gdcag-solutions/open-weight-models/open-webui/env.sh && echo "Successfully created." || echo "Failed to create!"
    source "${HOME}/gdcag-solutions/open-weight-models/IMPLEMENTATION/env.sh"
    
    export GDCS_USER_GUIDE_HOME="${HOME}/gdcag-solutions/open-weight-models/open-webui"
    echo "GDCS_USER_GUIDE_HOME=${GDCS_USER_GUIDE_HOME}"
    
    # Sourced in dependency order
    source "${GDCS_USER_GUIDE_HOME}/env.d/open-webui.sh"
    EOF
    

    Remplacez les éléments suivants :

    • IMPLEMENTATION : ollama ou vllm, l'implémentation de référence que vous avez effectuée sur ce poste de travail.
  5. Modifiez et examinez le fichier d'environnement avec l'éditeur de votre choix :

    ${EDITOR:-vi} ${HOME}/gdcag-solutions/open-weight-models/open-webui/env.d/open-webui.sh
    
  6. Sourcez le fichier d'environnement :

    source ${HOME}/gdcag-solutions/open-weight-models/open-webui/env.sh
    

    Le résultat ressemble à ce qui suit :

    GDCS_ROOT_HOME=HOME_DIRECTORY_PATH/gdcag-solutions
    GDCS_IMPLEMENTATION_HOME=HOME_DIRECTORY_PATH/gdcag-solutions/open-weight-models/IMPLEMENTATION
    GDCS_USER_GUIDE_HOME=HOME_DIRECTORY_PATH/gdcag-solutions/open-weight-models/open-webui
    

Cluster

  1. Configurez gdcloud :

    gdcloud config set core/account "default-user"
    gdcloud config set core/organization_console_url "${GDC_ZONAL_CONSOLE_URL}"
    gdcloud config set core/project "${GDC_PROJECT}"
    gdcloud config set core/zone "${GDC_ZONE}"
    
  2. Authentifiez-vous auprès de l'environnement GDC :

    gdcloud auth login
    
  3. Récupérez les identifiants du cluster :

    gdcloud clusters get-credentials "${GDC_STANDARD_CLUSTER_NAME}" \
    --project="${GDC_PROJECT}" \
    --standard \
    --zone="${GDC_ZONE}"
    
  4. Vérifiez que les backends d'inférence Service référencés dans le fichier d'environnement existent :

    for url in $(echo "${GDCS_OPEN_WEBUI_OLLAMA_BASE_URLS};${GDCS_OPEN_WEBUI_OPENAI_API_BASE_URLS}" | tr ';' ' '); do
      host=$(echo "${url}" | sed -E 's#https?://([^/:]+).*#\1#')
      kubectl get service "${host%%.*}" --namespace="$(echo "${host}" | cut -d. -f2)" --output=wide
    done
    

Implémentation

Migration d'artefacts

  1. Définissez la liste des images de conteneurs requises pour la solution :

    declare -a GDCS_REGISTRY_IMAGES=(
      "ghcr.io/open-webui/open-webui:${GDCS_OPEN_WEBUI_IMAGE_TAG}"
    )
    export SERIALIZED_IMAGES=$(declare -p GDCS_REGISTRY_IMAGES)
    
  2. Amorcez les images de conteneurs requises dans Artifact Registry à l'aide du script de l'implémentation de référence :

    ${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh
    

Espace de noms

  1. Créez l'espace de noms :

    kubectl create namespace "${GDCS_WORKLOAD_NAMESPACE}"
    
  2. Ajoutez le imagePullSecret :

    kubectl create secret docker-registry "${GDCS_HARBOR_K8S_PULL_SECRET}" \
    --dry-run=client \
    --from-file=.dockerconfigjson=${GDCS_HARBOR_K8S_DOCKER_CONFIG}/config.json \
    --namespace="${GDCS_WORKLOAD_NAMESPACE}" \
    --output=yaml | kubectl apply -f -
    
  3. Créez le Secret avec la clé de signature de session :

    kubectl create secret generic "${GDCS_OPEN_WEBUI_NAME}" \
    --dry-run=client \
    --from-literal=WEBUI_SECRET_KEY="${GDCS_OPEN_WEBUI_SECRET_KEY}" \
    --namespace="${GDCS_WORKLOAD_NAMESPACE}" \
    --output=yaml | kubectl apply -f -
    

Stockage

  1. Créez le fichier manifeste pour le PersistentVolumeClaim pour les données Open WebUI :

    cat <<EOF > "${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-rwo-pvc.yaml" && echo "Successfully created." || echo "Failed to create!"
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: ${GDCS_OPEN_WEBUI_NAME}-rwo
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: ${GDCS_OPEN_WEBUI_PVC_SIZE}
      storageClassName: standard-rwo
      volumeMode: Filesystem
    EOF
    
  2. Appliquez le fichier manifeste pour PersistentVolumeClaim :

    kubectl apply \
    --filename="${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-rwo-pvc.yaml" \
    --namespace="${GDCS_WORKLOAD_NAMESPACE}"
    

Interface Web

  1. Créez le fichier manifeste pour les éléments ConfigMap, Deployment et Service d'Open WebUI. Open WebUI s'exécute en mode hors connexion (OFFLINE_MODE), conserve ce ConfigMap comme source de vérité (ENABLE_PERSISTENT_CONFIG=false) et désactive les fonctionnalités qui nécessitent un accès à Internet :

    cat <<EOF > "${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-deployment.yaml" && echo "Successfully created." || echo "Failed to create!"
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ${GDCS_OPEN_WEBUI_NAME}
    data:
      DATA_DIR: "/app/backend/data"
      ENABLE_COMMUNITY_SHARING: "false"
      ENABLE_IMAGE_GENERATION: "false"
      ENABLE_OLLAMA_API: "${GDCS_OPEN_WEBUI_ENABLE_OLLAMA_API}"
      ENABLE_OPENAI_API: "${GDCS_OPEN_WEBUI_ENABLE_OPENAI_API}"
      ENABLE_PERSISTENT_CONFIG: "false"
      ENABLE_SIGNUP: "true"
      ENABLE_VERSION_UPDATE_CHECK: "false"
      ENABLE_WEB_SEARCH: "false"
      OFFLINE_MODE: "true"
      OLLAMA_BASE_URLS: "${GDCS_OPEN_WEBUI_OLLAMA_BASE_URLS}"
      OPENAI_API_BASE_URLS: "${GDCS_OPEN_WEBUI_OPENAI_API_BASE_URLS}"
      OPENAI_API_KEYS: "${GDCS_OPEN_WEBUI_OPENAI_API_KEYS}"
      PORT: "8080"
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: ${GDCS_OPEN_WEBUI_NAME}
      name: ${GDCS_OPEN_WEBUI_NAME}
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: ${GDCS_OPEN_WEBUI_NAME}
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            app: ${GDCS_OPEN_WEBUI_NAME}
        spec:
          containers:
            - envFrom:
                - configMapRef:
                    name: ${GDCS_OPEN_WEBUI_NAME}
                - secretRef:
                    name: ${GDCS_OPEN_WEBUI_NAME}
              image: ${GDCS_HARBOR_PROJECT_URI}/open-webui/open-webui:${GDCS_OPEN_WEBUI_IMAGE_TAG}
              imagePullPolicy: IfNotPresent
              livenessProbe:
                failureThreshold: 3
                httpGet:
                  path: /health
                  port: 8080
                periodSeconds: 30
                timeoutSeconds: 10
              name: open-webui
              ports:
                - containerPort: 8080
                  name: http
              readinessProbe:
                failureThreshold: 3
                httpGet:
                  path: /health
                  port: 8080
                periodSeconds: 10
                successThreshold: 1
                timeoutSeconds: 5
              resources:
                limits:
                  cpu: "${GDCS_WORKLOAD_CPU_LIMIT}"
                  memory: "${GDCS_WORKLOAD_MEMORY_LIMIT}"
                requests:
                  cpu: "${GDCS_WORKLOAD_CPU_REQUEST}"
                  memory: "${GDCS_WORKLOAD_MEMORY_REQUEST}"
              securityContext:
                allowPrivilegeEscalation: false
              startupProbe:
                failureThreshold: 60
                httpGet:
                  path: /health
                  port: 8080
                periodSeconds: 10
                timeoutSeconds: 5
              volumeMounts:
                - mountPath: /app/backend/data
                  name: data
          imagePullSecrets:
            - name: ${GDCS_HARBOR_K8S_PULL_SECRET}
          volumes:
            - name: data
              persistentVolumeClaim:
                claimName: ${GDCS_OPEN_WEBUI_NAME}-rwo
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: ${GDCS_OPEN_WEBUI_NAME}
    spec:
      ports:
        - name: http
          port: 80
          protocol: TCP
          targetPort: 8080
      selector:
        app: ${GDCS_OPEN_WEBUI_NAME}
      type: LoadBalancer
    EOF
    
  2. Appliquez le fichier manifeste pour les éléments ConfigMap, Deployment et Service d'Open WebUI :

    kubectl apply \
    --filename="${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-deployment.yaml" \
    --namespace="${GDCS_WORKLOAD_NAMESPACE}"
    
  3. Créez le fichier manifeste pour l'NetworkPolicy Open WebUI :

    cat <<EOF > "${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-netpol.yaml" && echo "Successfully created." || echo "Failed to create!"
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: allow-${GDCS_OPEN_WEBUI_NAME}-ingress
      namespace: ${GDCS_WORKLOAD_NAMESPACE}
    spec:
      ingress:
        - from:
            - ipBlock:
                cidr: 0.0.0.0/0
            - namespaceSelector: {}
          ports:
            - port: 8080
              protocol: TCP
      podSelector: {}
      policyTypes:
        - Ingress
    EOF
    
  4. Appliquez le fichier manifeste pour l'NetworkPolicy Open WebUI :

    kubectl apply \
    --filename="${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-netpol.yaml"
    
  1. Attendez que l'état de Pod passe à "En cours d'exécution" :

    watch --color --interval 5 --no-title \
    "kubectl get pods --selector=app=${GDCS_OPEN_WEBUI_NAME} \
    --namespace=${GDCS_WORKLOAD_NAMESPACE} | GREP_COLORS='mt=01;92' grep -E --color=always -e '^' -e 'Running'"
    
  2. Attendez que le Deployment soit prêt :

    watch --color --interval 5 --no-title \
    "kubectl get deployment/${GDCS_OPEN_WEBUI_NAME} \
    --namespace=${GDCS_WORKLOAD_NAMESPACE} | GREP_COLORS='mt=01;92' grep -E --color=always -e '^' -e '1/1     1            1'"
    
  3. Facultatif : Diffusez les journaux du conteneur pour surveiller la progression du démarrage :

    kubectl logs deployment/${GDCS_OPEN_WEBUI_NAME} \
    --follow \
    --namespace="${GDCS_WORKLOAD_NAMESPACE}"
    

Validation

  1. Récupérez l'adresse IP de l'équilibreur de charge pour Open WebUI :

    export OPEN_WEBUI_LB_IP=$(kubectl get service/${GDCS_OPEN_WEBUI_NAME} --namespace="${GDCS_WORKLOAD_NAMESPACE}" --output=jsonpath='{.status.loadBalancer.ingress[*].ip}')
    echo "OPEN_WEBUI_LB_IP=${OPEN_WEBUI_LB_IP}"
    
  2. Vérifiez les points de terminaison d'état et de version à l'aide de l'équilibreur de charge :

    curl --show-error --silent http://${OPEN_WEBUI_LB_IP}/health && echo
    
    curl --show-error --silent http://${OPEN_WEBUI_LB_IP}/api/version && echo
    

    Le résultat ressemble à ce qui suit :

    {"status":true}
    {"version":"0.11.3"}
    
  3. Vérifiez les points de terminaison d'état et de version à l'aide du transfert de port :

    kubectl port-forward service/${GDCS_OPEN_WEBUI_NAME} \
    --namespace="${GDCS_WORKLOAD_NAMESPACE}" 8080:80 &
    PF_PID=$!
    
    sleep 2
    
    curl --show-error --silent http://127.0.0.1:8080/health && echo
    curl --show-error --silent http://127.0.0.1:8080/api/version && echo
    
    kill ${PF_PID}
    
  4. Vérifiez qu'Open WebUI peut atteindre les backends d'inférence :

    kubectl exec deployment/${GDCS_OPEN_WEBUI_NAME} \
    --namespace="${GDCS_WORKLOAD_NAMESPACE}" \
    -- sh -c 'for url in $(echo "${OLLAMA_BASE_URLS};${OPENAI_API_BASE_URLS}" | tr ";" " "); do case "${url}" in *"/v1") echo "${url}/models"; curl --max-time 10 --show-error --silent "${url}/models" | head -c 300; echo;; *) echo "${url}/api/tags"; curl --max-time 10 --show-error --silent "${url}/api/tags" | head -c 300; echo;; esac; done'
    
  5. Ouvrez http://${OPEN_WEBUI_LB_IP} dans un navigateur et créez le premier compte. Le premier compte créé devient l'administrateur. Sélectionnez un modèle dans la vue de chat et envoyez une requête.

Opérations

Ajouter ou modifier des backends d'inférence

  1. Mettez à jour GDCS_OPEN_WEBUI_OLLAMA_BASE_URLS ou GDCS_OPEN_WEBUI_OPENAI_API_BASE_URLS dans env.d/open-webui.sh, sourcez le fichier d'environnement, puis exécutez à nouveau l'étape du fichier manifeste dans l'interface Web. Appliquez ensuite le fichier manifeste et redémarrez Open WebUI, qui lit le ConfigMap à chaque démarrage, car la configuration persistante est désactivée :

    kubectl apply \
    --filename="${GDCS_USER_GUIDE_HOME}/${GDCS_OPEN_WEBUI_NAME}-deployment.yaml" \
    --namespace="${GDCS_WORKLOAD_NAMESPACE}"
    
    kubectl rollout restart deployment/${GDCS_OPEN_WEBUI_NAME} \
    --namespace="${GDCS_WORKLOAD_NAMESPACE}"
    

Mettre à niveau

  1. Définissez la nouvelle valeur GDCS_OPEN_WEBUI_IMAGE_TAG dans le fichier d'environnement, sourcez-la, amorcez la nouvelle image et effectuez un déploiement progressif de Deployment :

    source ${HOME}/gdcag-solutions/open-weight-models/open-webui/env.sh
    
    declare -a GDCS_REGISTRY_IMAGES=(
      "ghcr.io/open-webui/open-webui:${GDCS_OPEN_WEBUI_IMAGE_TAG}"
    )
    export SERIALIZED_IMAGES=$(declare -p GDCS_REGISTRY_IMAGES)
    ${GDCS_IMPLEMENTATION_HOME}/seed_registry.sh
    
    kubectl set image deployment/${GDCS_OPEN_WEBUI_NAME} \
    open-webui="${GDCS_HARBOR_PROJECT_URI}/open-webui/open-webui:${GDCS_OPEN_WEBUI_IMAGE_TAG}" \
    --namespace="${GDCS_WORKLOAD_NAMESPACE}"
    

Sauvegarde

  1. Créez un VolumeSnapshot du volume de données (le standard VolumeSnapshotClass est disponible sur les clusters GDC standards) :

    cat <<EOF | kubectl apply --namespace="${GDCS_WORKLOAD_NAMESPACE}" -f -
    apiVersion: snapshot.storage.k8s.io/v1
    kind: VolumeSnapshot
    metadata:
      name: ${GDCS_OPEN_WEBUI_NAME}-$(date +%Y%m%d-%H%M)
    spec:
      source:
        persistentVolumeClaimName: ${GDCS_OPEN_WEBUI_NAME}-rwo
      volumeSnapshotClassName: standard
    EOF
    

Dépannage

Problème constaté Cause probable Action
Aucun modèle n'est proposé dans la vue de chat L'adresse du backend Service est incorrecte, le backend n'est pas prêt ou le backend NetworkPolicy n'accepte pas l'espace de noms Open WebUI. Exécutez l'étape de vérification du backend dans Validation ; vérifiez le backend Deployment et son NetworkPolicy.
Pod redémarrages au démarrage Démarrage lent sur le PersistentVolume Vérifiez kubectl describe pod ; startupProbe autorise 10 minutes
Échec de l'importation de documents (RAG) Le mode hors connexion bloque le téléchargement du modèle d'embedding par défaut Configurez RAG_EMBEDDING_ENGINE=ollama avec un modèle d'embedding diffusé par Ollama, ou laissez le RAG désactivé
L'adresse IP de l'équilibreur de charge reste <pending> ou n'est pas accessible Équilibreur de charge non disponible dans l'environnement ou ProjectNetworkPolicy manquant Utilisez l'étape de validation du transfert de port. Demandez un ProjectNetworkPolicy à l'administrateur NetworkPolicy du projet.
Session non valide après un redémarrage de Pod WEBUI_SECRET_KEY modifié Maintenir la stabilité de Secret ; le restaurer à partir de secrets/open_webui_secret_key

Effectuer un nettoyage

  1. Supprimez les ressources Open WebUI :

    kubectl delete namespace "${GDCS_WORKLOAD_NAMESPACE}"
    
  2. Supprimez les fichiers locaux :

    rm -rf ${HOME}/gdcag-solutions/open-weight-models/open-webui
    

Autres ressources