mirror of
https://github.com/vegu-ai/talemate.git
synced 2026-09-01 19:48:52 +02:00
Port Docker CUDA support to 0.39 (#350)
* fix: port Docker CUDA support to 0.39 * docs: show manual Docker GPU opt-in
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
- "OpenRouter Client: The default model for newly created OpenRouter clients is now google/gemini-3.6-flash."
|
||||
- "OpenRouter Client: New OpenRouter clients now have reasoning enabled by default, with a budget of 2048 reasoning tokens, so the default model works out of the box. With reasoning off Talemate pre-fills the start of the response to steer it, and some providers — Google and Anthropic among them — reject requests that do that."
|
||||
fixes:
|
||||
- "Docker: `docker compose up` now requires an NVIDIA GPU and the NVIDIA Container Toolkit and exposes all host NVIDIA GPUs to Talemate, restoring CUDA detection for PyTorch. Hosts without an NVIDIA GPU must use `docker compose -f docker-compose.cpu.yml up`; the standalone manual-build command remains a complete CPU configuration."
|
||||
- "Scene Forking: Forking from a message now refuses a save name that is not a valid filename or that an existing save already uses, instead of writing over that save or outside the scene directory. The timeline fork already refused both."
|
||||
- "Prompt Finalization: The fuzzy match threshold slider's always-visible value bubble no longer overlaps the note above it."
|
||||
- "Frontend: A backend websocket URL configured with the host 0.0.0.0 now connects — the URL was used literally, which most browsers refuse, so the app stayed on 'backend not connected'. The host is resolved to the hostname the UI itself was loaded from."
|
||||
|
||||
20
docker-compose.cpu.yml
Normal file
20
docker-compose.cpu.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
services:
|
||||
talemate:
|
||||
image: ghcr.io/vegu-ai/talemate:latest
|
||||
ports:
|
||||
- "${TALEMATE_FRONTEND_PORT:-8082}:${TALEMATE_FRONTEND_PORT:-8082}"
|
||||
- "${TALEMATE_BACKEND_PORT:-5050}:${TALEMATE_BACKEND_PORT:-5050}"
|
||||
volumes:
|
||||
- ./config.yaml:/app/config.yaml
|
||||
- ./secrets:/app/secrets
|
||||
- ./pi:/app/pi
|
||||
- ./scenes:/app/scenes
|
||||
- ./templates:/app/templates
|
||||
- ./chroma:/app/chroma
|
||||
- ./tts:/app/tts
|
||||
environment:
|
||||
- PYTHONUNBUFFERED=1
|
||||
- PYTHONPATH=/app/src:$PYTHONPATH
|
||||
- VITE_TALEMATE_BACKEND_WEBSOCKET_URL=${VITE_TALEMATE_BACKEND_WEBSOCKET_URL:-}
|
||||
- TALEMATE_FRONTEND_PORT=${TALEMATE_FRONTEND_PORT:-8082}
|
||||
- TALEMATE_BACKEND_PORT=${TALEMATE_BACKEND_PORT:-5050}
|
||||
@@ -1,24 +1,18 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
talemate:
|
||||
extends:
|
||||
file: docker-compose.cpu.yml
|
||||
service: talemate
|
||||
# Uncomment this block to enable NVIDIA GPU access for standalone manual builds.
|
||||
# deploy:
|
||||
# resources:
|
||||
# reservations:
|
||||
# devices:
|
||||
# - driver: nvidia
|
||||
# count: all
|
||||
# capabilities: [gpu]
|
||||
image: talemate:local
|
||||
pull_policy: build
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "${TALEMATE_FRONTEND_PORT:-8082}:${TALEMATE_FRONTEND_PORT:-8082}"
|
||||
- "${TALEMATE_BACKEND_PORT:-5050}:${TALEMATE_BACKEND_PORT:-5050}"
|
||||
volumes:
|
||||
- ./config.yaml:/app/config.yaml
|
||||
- ./secrets:/app/secrets
|
||||
- ./pi:/app/pi
|
||||
- ./scenes:/app/scenes
|
||||
- ./templates:/app/templates
|
||||
- ./chroma:/app/chroma
|
||||
- ./tts:/app/tts
|
||||
environment:
|
||||
- PYTHONUNBUFFERED=1
|
||||
- PYTHONPATH=/app/src:$PYTHONPATH
|
||||
- VITE_TALEMATE_BACKEND_WEBSOCKET_URL=${VITE_TALEMATE_BACKEND_WEBSOCKET_URL:-}
|
||||
- TALEMATE_FRONTEND_PORT=${TALEMATE_FRONTEND_PORT:-8082}
|
||||
- TALEMATE_BACKEND_PORT=${TALEMATE_BACKEND_PORT:-5050}
|
||||
|
||||
@@ -1,22 +1,12 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
talemate:
|
||||
image: ghcr.io/vegu-ai/talemate:latest
|
||||
ports:
|
||||
- "${TALEMATE_FRONTEND_PORT:-8082}:${TALEMATE_FRONTEND_PORT:-8082}"
|
||||
- "${TALEMATE_BACKEND_PORT:-5050}:${TALEMATE_BACKEND_PORT:-5050}"
|
||||
volumes:
|
||||
- ./config.yaml:/app/config.yaml
|
||||
- ./secrets:/app/secrets
|
||||
- ./pi:/app/pi
|
||||
- ./scenes:/app/scenes
|
||||
- ./templates:/app/templates
|
||||
- ./chroma:/app/chroma
|
||||
- ./tts:/app/tts
|
||||
environment:
|
||||
- PYTHONUNBUFFERED=1
|
||||
- PYTHONPATH=/app/src:$PYTHONPATH
|
||||
- VITE_TALEMATE_BACKEND_WEBSOCKET_URL=${VITE_TALEMATE_BACKEND_WEBSOCKET_URL:-}
|
||||
- TALEMATE_FRONTEND_PORT=${TALEMATE_FRONTEND_PORT:-8082}
|
||||
- TALEMATE_BACKEND_PORT=${TALEMATE_BACKEND_PORT:-5050}
|
||||
extends:
|
||||
file: docker-compose.cpu.yml
|
||||
service: talemate
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [gpu]
|
||||
|
||||
@@ -177,6 +177,8 @@ start_custom.bat
|
||||
|
||||
For Docker deployments, you can configure the frontend port, backend port, and the WebSocket URL at container startup without rebuilding the image.
|
||||
|
||||
The commands below use the default CUDA configuration and require an NVIDIA GPU and the NVIDIA Container Toolkit. On a host without an NVIDIA GPU, add `-f docker-compose.cpu.yml` to every command; for example, `TALEMATE_FRONTEND_PORT=9090 docker compose -f docker-compose.cpu.yml up`.
|
||||
|
||||
### Changing the frontend port
|
||||
|
||||
Set `TALEMATE_FRONTEND_PORT` before running `docker compose up`:
|
||||
@@ -226,4 +228,4 @@ The WebSocket URL is determined in this order:
|
||||
This means you can use a single Docker image across different environments (staging, production) by simply changing the environment variable.
|
||||
|
||||
!!! info "`0.0.0.0` in the WebSocket URL"
|
||||
`0.0.0.0` is a bind address, not an address a browser can connect to. If the environment variable's host is `0.0.0.0`, the frontend replaces it with the hostname the page was loaded from — the configured port and path are kept. So `ws://0.0.0.0:6060/ws` behaves like auto-detection for the host, but on port `6060`.
|
||||
`0.0.0.0` is a bind address, not an address a browser can connect to. If the environment variable's host is `0.0.0.0`, the frontend replaces it with the hostname the page was loaded from — the configured port and path are kept. So `ws://0.0.0.0:6060/ws` behaves like auto-detection for the host, but on port `6060`.
|
||||
|
||||
@@ -48,7 +48,7 @@ See [API key encryption](../../user-guide/api-key-encryption.md) for the full ke
|
||||
|
||||
## Docker Compose passthroughs
|
||||
|
||||
The values below are not consumed by Talemate's Python code directly — they're consumed by `docker-compose.yml` so that the same variable controls both the published host port and the value passed into the container as `TALEMATE_BACKEND_PORT` / `TALEMATE_FRONTEND_PORT`:
|
||||
The values below are not consumed by Talemate's Python code directly — they're consumed by the default and CPU-only Compose configurations so that the same variable controls both the published host port and the value passed into the container as `TALEMATE_BACKEND_PORT` / `TALEMATE_FRONTEND_PORT`:
|
||||
|
||||
- `TALEMATE_BACKEND_PORT`
|
||||
- `TALEMATE_FRONTEND_PORT`
|
||||
|
||||
@@ -5,11 +5,32 @@
|
||||
1. copy config file
|
||||
1. linux: `cp config.example.yaml config.yaml`
|
||||
1. windows: `copy config.example.yaml config.yaml` (or just copy the file and rename it via the file explorer)
|
||||
1. `docker compose up`
|
||||
1. Start Talemate:
|
||||
1. NVIDIA GPU host with the NVIDIA Container Toolkit installed: `docker compose up`
|
||||
1. Host without an NVIDIA GPU: `docker compose -f docker-compose.cpu.yml up`
|
||||
1. Navigate your browser to http://localhost:8082
|
||||
|
||||
The default Compose configuration requires an NVIDIA GPU and the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). It reserves all NVIDIA GPUs and does not fall back to CPU execution.
|
||||
|
||||
On a host without an NVIDIA GPU, you must use:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.cpu.yml up
|
||||
```
|
||||
|
||||
!!! info "Pre-built Images"
|
||||
The default setup uses pre-built images from GitHub Container Registry that include CUDA support by default. To manually build the container instead, use `docker compose -f docker-compose.manual.yml up --build`.
|
||||
The default setup uses a pre-built image from GitHub Container Registry. To build it locally with CUDA enabled, use `docker compose -f docker-compose.yml -f docker-compose.manual.yml up --build`. For a local CPU-only build, use the standalone command `docker compose -f docker-compose.manual.yml up --build`; combining `docker-compose.cpu.yml` and `docker-compose.manual.yml` is also supported.
|
||||
|
||||
## Verify CUDA access
|
||||
|
||||
With the container running, verify that Docker exposed the GPU and that PyTorch can use it:
|
||||
|
||||
```bash
|
||||
docker compose exec talemate nvidia-smi
|
||||
docker compose exec talemate /app/.venv/bin/python -B -c "import torch; print(torch.__version__, torch.version.cuda, torch.cuda.is_available())"
|
||||
```
|
||||
|
||||
The final value from the Python command should be `True`. See [Common issues](troubleshoot.md#cuda-is-not-available-in-a-running-container) if either command fails.
|
||||
|
||||
!!! note
|
||||
When connecting local APIs running on the hostmachine (e.g. text-generation-webui), you need to use `host.docker.internal` as the hostname.
|
||||
|
||||
@@ -8,6 +8,43 @@
|
||||
|
||||
## Docker
|
||||
|
||||
### Docker cannot start with the NVIDIA device request
|
||||
|
||||
The default configuration requires both an NVIDIA GPU and a working NVIDIA Container Toolkit. If either is missing, Docker reports an error similar to:
|
||||
|
||||
```text
|
||||
could not select device driver "nvidia" with capabilities: [[gpu]]
|
||||
```
|
||||
|
||||
On a host without an NVIDIA GPU, start the CPU-only configuration instead:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.cpu.yml up
|
||||
```
|
||||
|
||||
If the host has an NVIDIA GPU, confirm `nvidia-smi` works on the host, then install or repair the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Verify the Toolkit before retrying Talemate:
|
||||
|
||||
```bash
|
||||
docker run --rm --gpus all ubuntu nvidia-smi
|
||||
```
|
||||
|
||||
### CUDA is not available in a running container
|
||||
|
||||
If the Toolkit probe succeeds and Talemate starts, check the running container:
|
||||
|
||||
```bash
|
||||
docker compose exec talemate nvidia-smi
|
||||
docker compose exec talemate /app/.venv/bin/python -B -c "import torch; print(torch.__version__, torch.version.cuda, torch.cuda.is_available())"
|
||||
```
|
||||
|
||||
If `nvidia-smi` works inside Talemate but the Python command reports `False`, update the host NVIDIA driver to one compatible with the image's locked CUDA 12.8 build, then recreate the container.
|
||||
|
||||
To run without CUDA instead, use:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.cpu.yml up
|
||||
```
|
||||
|
||||
### Docker has created `config.yaml` directory
|
||||
|
||||
If you do not copy the example config to `config.yaml` before running `docker compose up` docker will create a `config` directory in the root of the project. This will cause the backend to fail to start.
|
||||
@@ -66,4 +103,4 @@ location /ws {
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
Google AI, Groq, KoboldCpp, LMStudio, Mistral, OpenAI, TabbyAPI, and Text-Generation-WebUI.'
|
||||
- path: getting-started/advanced/change-host-and-port.md
|
||||
title: Changing host and port
|
||||
summary: How to change the backend (default localhost:5050) and frontend (default localhost:8082) host/port via TALEMATE_BACKEND_/FRONTEND_HOST/PORT
|
||||
env vars or --host/--port CLI flags, point the frontend at a new backend with VITE_TALEMATE_BACKEND_WEBSOCKET_URL, plus
|
||||
Docker runtime configuration and 0.36.x-to-0.37.0 upgrade notes (frontend port 8080-to-8082, renamed compose variables).
|
||||
summary: Changing the backend (localhost:5050) and frontend (localhost:8082) bind addresses via TALEMATE_BACKEND_HOST/PORT
|
||||
and TALEMATE_FRONTEND_HOST/PORT or the --host/--port CLI flags, rebuilding the frontend with VITE_TALEMATE_BACKEND_WEBSOCKET_URL,
|
||||
Docker Compose runtime overrides with CUDA/CPU file selection, and the 0.37.0 rename notes.
|
||||
- path: getting-started/advanced/debug-logging.md
|
||||
title: Debug Logging
|
||||
summary: Enable verbose DEBUG-level logging with TALEMATE_DEBUG=1 on Linux and Windows; errors then also go to a rotating
|
||||
@@ -45,8 +45,9 @@
|
||||
Text-Generation-WebUI, LMStudio, TabbyAPI), and assigning the client to all agents.'
|
||||
- path: getting-started/installation/docker.md
|
||||
title: Docker
|
||||
summary: 'Docker install: clone the repo, copy config.example.yaml to config.yaml, run docker compose up, and open http://localhost:8082.
|
||||
Notes on pre-built CUDA images vs manual build and using host.docker.internal to reach local APIs on the host machine.'
|
||||
summary: 'Docker installation and GPU/CPU launch paths: clone and copy config.yaml, then use docker compose up for NVIDIA
|
||||
CUDA or docker compose -f docker-compose.cpu.yml up on CPU-only hosts. Covers local builds with docker-compose.manual.yml,
|
||||
CUDA verification with nvidia-smi/PyTorch, host.docker.internal, and Pi Bridge config.'
|
||||
- path: getting-started/installation/linux.md
|
||||
title: Linux
|
||||
summary: 'Linux install: python and uv prerequisites, running install.sh (which downloads portable Node.js 22 and offers
|
||||
@@ -54,9 +55,9 @@
|
||||
frontend (corepack pnpm serve).'
|
||||
- path: getting-started/installation/troubleshoot.md
|
||||
title: Common issues
|
||||
summary: 'Installation troubleshooting: Windows frontend failures caused by special characters in the path, Docker creating
|
||||
a config.yaml directory when the example config was not copied, configuring VITE_TALEMATE_BACKEND_WEBSOCKET_URL at container
|
||||
runtime, and running behind a reverse proxy with SSL/nginx WebSocket upgrades.'
|
||||
summary: Troubleshooting Windows install paths, Docker CUDA startup failures, and reverse-proxy WebSockets. Shows the CPU
|
||||
opt-out command, NVIDIA Container Toolkit smoke test, in-container nvidia-smi/PyTorch checks, the config.yaml mount pitfall,
|
||||
VITE WebSocket URL, and nginx upgrade headers.
|
||||
- path: getting-started/installation/windows.md
|
||||
title: Windows
|
||||
summary: 'Windows install: download the release ZIP and double-click start.bat, which auto-downloads portable Python 3 and
|
||||
|
||||
181
tests/test_docker_compose.py
Normal file
181
tests/test_docker_compose.py
Normal file
@@ -0,0 +1,181 @@
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from packaging.markers import Marker, default_environment
|
||||
|
||||
|
||||
ROOT = Path(__file__).parent.parent
|
||||
COMPOSE_AVAILABLE = (
|
||||
shutil.which("docker") is not None
|
||||
and subprocess.run(
|
||||
["docker", "compose", "version"],
|
||||
capture_output=True,
|
||||
check=False,
|
||||
).returncode
|
||||
== 0
|
||||
)
|
||||
PORTS = {5050: 5050, 8082: 8082}
|
||||
CPU_COMMAND = "docker compose -f docker-compose.cpu.yml up"
|
||||
COMPOSE_DEFAULTS = {
|
||||
"PYTHONPATH": "",
|
||||
"TALEMATE_BACKEND_PORT": "5050",
|
||||
"TALEMATE_FRONTEND_PORT": "8082",
|
||||
"VITE_TALEMATE_BACKEND_WEBSOCKET_URL": "",
|
||||
}
|
||||
ENVIRONMENT_KEYS = {
|
||||
"PYTHONPATH",
|
||||
"PYTHONUNBUFFERED",
|
||||
"TALEMATE_BACKEND_PORT",
|
||||
"TALEMATE_FRONTEND_PORT",
|
||||
"VITE_TALEMATE_BACKEND_WEBSOCKET_URL",
|
||||
}
|
||||
VOLUME_TARGETS = {
|
||||
"/app/chroma",
|
||||
"/app/config.yaml",
|
||||
"/app/pi",
|
||||
"/app/scenes",
|
||||
"/app/secrets",
|
||||
"/app/templates",
|
||||
"/app/tts",
|
||||
}
|
||||
|
||||
|
||||
def render_compose(*files: str) -> dict:
|
||||
command = ["docker", "compose"]
|
||||
for compose_file in files:
|
||||
command.extend(["-f", compose_file])
|
||||
command.extend(["config", "--format", "json"])
|
||||
result = subprocess.run(
|
||||
command,
|
||||
cwd=ROOT,
|
||||
capture_output=True,
|
||||
check=True,
|
||||
env={**os.environ, **COMPOSE_DEFAULTS},
|
||||
text=True,
|
||||
)
|
||||
return json.loads(result.stdout)
|
||||
|
||||
|
||||
def assert_runtime_contract(service: dict, *, gpu: bool, local_build: bool) -> None:
|
||||
ports = {int(port["target"]): int(port["published"]) for port in service["ports"]}
|
||||
assert ports == PORTS
|
||||
assert {volume["target"] for volume in service["volumes"]} == VOLUME_TARGETS
|
||||
assert set(service["environment"]) == ENVIRONMENT_KEYS
|
||||
|
||||
devices = (
|
||||
service.get("deploy", {})
|
||||
.get("resources", {})
|
||||
.get("reservations", {})
|
||||
.get("devices", [])
|
||||
)
|
||||
if gpu:
|
||||
assert devices == [{"driver": "nvidia", "count": -1, "capabilities": ["gpu"]}]
|
||||
else:
|
||||
assert devices == []
|
||||
|
||||
if local_build:
|
||||
assert service["image"] == "talemate:local"
|
||||
assert service["pull_policy"] == "build"
|
||||
assert service["build"]["dockerfile"] == "Dockerfile"
|
||||
else:
|
||||
assert service["image"] == "ghcr.io/vegu-ai/talemate:latest"
|
||||
assert "build" not in service
|
||||
|
||||
|
||||
@pytest.mark.skipif(not COMPOSE_AVAILABLE, reason="Docker Compose CLI is unavailable")
|
||||
@pytest.mark.parametrize(
|
||||
("files", "gpu", "local_build"),
|
||||
[
|
||||
pytest.param((), True, False, id="default-cuda-image"),
|
||||
pytest.param(("docker-compose.cpu.yml",), False, False, id="cpu-image"),
|
||||
pytest.param(
|
||||
("docker-compose.manual.yml",), False, True, id="standalone-cpu-build"
|
||||
),
|
||||
pytest.param(
|
||||
("docker-compose.yml", "docker-compose.manual.yml"),
|
||||
True,
|
||||
True,
|
||||
id="cuda-build",
|
||||
),
|
||||
pytest.param(
|
||||
("docker-compose.cpu.yml", "docker-compose.manual.yml"),
|
||||
False,
|
||||
True,
|
||||
id="cpu-build",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_documented_compose_invocations_render_complete_service(
|
||||
files: tuple[str, ...], gpu: bool, local_build: bool
|
||||
):
|
||||
service = render_compose(*files)["services"]["talemate"]
|
||||
|
||||
assert_runtime_contract(service, gpu=gpu, local_build=local_build)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not COMPOSE_AVAILABLE, reason="Docker Compose CLI is unavailable")
|
||||
def test_render_compose_ignores_ambient_port_overrides(monkeypatch):
|
||||
monkeypatch.setenv("TALEMATE_FRONTEND_PORT", "9090")
|
||||
monkeypatch.setenv("TALEMATE_BACKEND_PORT", "6060")
|
||||
|
||||
service = render_compose("docker-compose.cpu.yml")["services"]["talemate"]
|
||||
ports = {int(port["target"]): int(port["published"]) for port in service["ports"]}
|
||||
|
||||
assert ports == PORTS
|
||||
|
||||
|
||||
def applies_to_docker(package: dict) -> bool:
|
||||
markers = package.get("resolution-markers")
|
||||
if not markers:
|
||||
return True
|
||||
|
||||
environment = default_environment()
|
||||
environment.update(
|
||||
platform_machine="x86_64",
|
||||
platform_system="Linux",
|
||||
python_full_version="3.11.0",
|
||||
python_version="3.11",
|
||||
sys_platform="linux",
|
||||
)
|
||||
return any(Marker(marker).evaluate(environment) for marker in markers)
|
||||
|
||||
|
||||
def test_locked_torch_build_includes_cuda():
|
||||
with (ROOT / "uv.lock").open("rb") as lock_file:
|
||||
packages = tomllib.load(lock_file)["package"]
|
||||
|
||||
docker_torch_packages = [
|
||||
package
|
||||
for package in packages
|
||||
if package["name"] == "torch" and applies_to_docker(package)
|
||||
]
|
||||
|
||||
assert len(docker_torch_packages) == 1
|
||||
torch = docker_torch_packages[0]
|
||||
assert "+cu" in torch["version"]
|
||||
assert torch["source"]["registry"].startswith("https://download.pytorch.org/whl/cu")
|
||||
|
||||
|
||||
def test_cpu_opt_out_is_shown_on_install_and_startup_failure_paths():
|
||||
install = (ROOT / "docs/getting-started/installation/docker.md").read_text()
|
||||
advanced = (
|
||||
ROOT / "docs/getting-started/advanced/change-host-and-port.md"
|
||||
).read_text()
|
||||
environment_variables = (
|
||||
ROOT / "docs/getting-started/advanced/environment-variables.md"
|
||||
).read_text()
|
||||
troubleshooting = (
|
||||
ROOT / "docs/getting-started/installation/troubleshoot.md"
|
||||
).read_text()
|
||||
|
||||
assert CPU_COMMAND in install
|
||||
assert CPU_COMMAND in advanced
|
||||
assert CPU_COMMAND in troubleshooting
|
||||
assert "default and CPU-only Compose configurations" in environment_variables
|
||||
assert "working NVIDIA Container Toolkit" in troubleshooting
|
||||
assert 'could not select device driver "nvidia"' in troubleshooting
|
||||
@@ -51,6 +51,7 @@ def test_docs_index_loads_and_paths_exist():
|
||||
for entry in index:
|
||||
assert entry.keys() >= {"path", "title", "summary"}
|
||||
assert (docs.DOCS_DIR / entry["path"]).is_file(), entry["path"]
|
||||
assert not entry["title"].startswith(":material-"), entry["path"]
|
||||
|
||||
|
||||
def test_search_docs_returns_matches():
|
||||
|
||||
Reference in New Issue
Block a user