spark-pulse 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spark_pulse-1.0.0/LICENSE +28 -0
- spark_pulse-1.0.0/PKG-INFO +288 -0
- spark_pulse-1.0.0/README.md +261 -0
- spark_pulse-1.0.0/pyproject.toml +63 -0
- spark_pulse-1.0.0/setup.cfg +4 -0
- spark_pulse-1.0.0/spark_pulse/__init__.py +3 -0
- spark_pulse-1.0.0/spark_pulse/app.py +125 -0
- spark_pulse-1.0.0/spark_pulse/auth.py +203 -0
- spark_pulse-1.0.0/spark_pulse/cli.py +128 -0
- spark_pulse-1.0.0/spark_pulse/config.py +97 -0
- spark_pulse-1.0.0/spark_pulse/mcp_http.py +190 -0
- spark_pulse-1.0.0/spark_pulse/mcp_server.py +181 -0
- spark_pulse-1.0.0/spark_pulse/mock/__init__.py +1 -0
- spark_pulse-1.0.0/spark_pulse/mock/cache.py +35 -0
- spark_pulse-1.0.0/spark_pulse/mock/deployments.py +89 -0
- spark_pulse-1.0.0/spark_pulse/mock/recipes.py +127 -0
- spark_pulse-1.0.0/spark_pulse/mock/system.py +61 -0
- spark_pulse-1.0.0/spark_pulse/routers/__init__.py +1 -0
- spark_pulse-1.0.0/spark_pulse/routers/cache.py +21 -0
- spark_pulse-1.0.0/spark_pulse/routers/deployments.py +49 -0
- spark_pulse-1.0.0/spark_pulse/routers/memory.py +27 -0
- spark_pulse-1.0.0/spark_pulse/routers/recipes.py +23 -0
- spark_pulse-1.0.0/spark_pulse/routers/settings.py +32 -0
- spark_pulse-1.0.0/spark_pulse/service.py +139 -0
- spark_pulse-1.0.0/spark_pulse/sse.py +38 -0
- spark_pulse-1.0.0/spark_pulse/tools/__init__.py +32 -0
- spark_pulse-1.0.0/spark_pulse/tools/cache.py +89 -0
- spark_pulse-1.0.0/spark_pulse/tools/recipes.py +87 -0
- spark_pulse-1.0.0/spark_pulse/tools/system.py +81 -0
- spark_pulse-1.0.0/spark_pulse/ui/assets/index-Bfz9_KnT.css +1 -0
- spark_pulse-1.0.0/spark_pulse/ui/assets/index-CGo1yVbQ.js +291 -0
- spark_pulse-1.0.0/spark_pulse/ui/index.html +27 -0
- spark_pulse-1.0.0/spark_pulse/version.py +10 -0
- spark_pulse-1.0.0/spark_pulse.egg-info/PKG-INFO +288 -0
- spark_pulse-1.0.0/spark_pulse.egg-info/SOURCES.txt +42 -0
- spark_pulse-1.0.0/spark_pulse.egg-info/dependency_links.txt +1 -0
- spark_pulse-1.0.0/spark_pulse.egg-info/entry_points.txt +2 -0
- spark_pulse-1.0.0/spark_pulse.egg-info/requires.txt +16 -0
- spark_pulse-1.0.0/spark_pulse.egg-info/top_level.txt +1 -0
- spark_pulse-1.0.0/tests/test_auth.py +48 -0
- spark_pulse-1.0.0/tests/test_config.py +70 -0
- spark_pulse-1.0.0/tests/test_tools_cache.py +34 -0
- spark_pulse-1.0.0/tests/test_tools_recipes.py +71 -0
- spark_pulse-1.0.0/tests/test_tools_system.py +62 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright © 2026 Kharkevich Engineering Lab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
───
|
|
24
|
+
|
|
25
|
+
Disclaimer: This project is not sponsored by, endorsed by, or affiliated with
|
|
26
|
+
NVIDIA Corporation or any of their subsidiaries. NVIDIA, DGX, and the NVIDIA
|
|
27
|
+
logo are trademarks of NVIDIA Corporation. This product is independent and not
|
|
28
|
+
officially associated with NVIDIA in any way.
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spark-pulse
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Web UI for spark-vllm-docker — recipe management, deployment, and monitoring for DGX Spark
|
|
5
|
+
Maintainer-email: Alexander Kharkevich <alex@kharkevich.org>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: homepage, https://github.com/kharkevich-engineering-lab/spark-pulse
|
|
8
|
+
Project-URL: repository, https://github.com/kharkevich-engineering-lab/spark-pulse
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: fastapi>=0.115.0
|
|
13
|
+
Requires-Dist: uvicorn[standard]>=0.34.0
|
|
14
|
+
Requires-Dist: sse-starlette>=2.2.0
|
|
15
|
+
Requires-Dist: pyyaml>=6.0
|
|
16
|
+
Requires-Dist: pydantic>=2.0
|
|
17
|
+
Requires-Dist: click>=8.0
|
|
18
|
+
Requires-Dist: authlib>=1.3.0
|
|
19
|
+
Requires-Dist: httpx>=0.28.0
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: black>=24.8.0; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
23
|
+
Requires-Dist: httpx>=0.28; extra == "dev"
|
|
24
|
+
Provides-Extra: mcp
|
|
25
|
+
Requires-Dist: mcp>=1.0.0; extra == "mcp"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# Spark Pulse
|
|
29
|
+
|
|
30
|
+
Web UI for [spark-vllm-docker](https://github.com/eugr/spark-vllm-docker) — recipe management, deployment, and monitoring for NVIDIA DGX Spark hardware.
|
|
31
|
+
|
|
32
|
+
**License:** [MIT](LICENSE) — Copyright © 2026 Kharkevich Engineering Lab
|
|
33
|
+
|
|
34
|
+
> **Disclaimer:** This project is not sponsored by, endorsed by, or affiliated
|
|
35
|
+
> with NVIDIA Corporation or any of its subsidiaries. NVIDIA, DGX, and NVIDIA
|
|
36
|
+
> trademarks are property of their respective owners.
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- **Recipe Browser** — Browse available vLLM deployment recipes, view model details, configs, and mods
|
|
41
|
+
- **Job Management** — Launch deployments with custom parameters, monitor status, view live logs via SSE, stop jobs
|
|
42
|
+
- **Memory Monitor** — Real-time GPU memory, CPU RAM, and disk usage via SSE streaming
|
|
43
|
+
- **Cache Manager** — Browse and clean HF model cache, wheels, ccache, Triton cache, and more
|
|
44
|
+
- **Settings** — Configure spark-vllm-docker path, default container, GPU memory utilization
|
|
45
|
+
- **OIDC Authentication** — Configurable authentication (Keycloak, Auth0, Google, Azure AD, etc.)
|
|
46
|
+
- **Dark/Light Theme** — Switch between dark, light, or system theme (persisted in localStorage)
|
|
47
|
+
- **Custom Modals** — Beautiful confirmation dialogs and error alerts
|
|
48
|
+
- **MCP Server** — Expose spark-vllm-docker operations as Model Context Protocol tools for AI assistants
|
|
49
|
+
|
|
50
|
+
## Architecture
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
┌─────────────┐ HTTP / SSE ┌──────────────────────┐
|
|
54
|
+
│ Browser │ ◄───────────────► │ FastAPI + Uvicorn │
|
|
55
|
+
│ React SPA │ │ Port 8100 │
|
|
56
|
+
└─────────────┘ │ │
|
|
57
|
+
│ spark-vllm-docker/ │
|
|
58
|
+
│ Docker, nvidia-smi │
|
|
59
|
+
└──────────────────────┘
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Project Structure
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
spark-pulse/
|
|
66
|
+
├── pyproject.toml # Python package config (setuptools)
|
|
67
|
+
├── README.md
|
|
68
|
+
├── LICENSE
|
|
69
|
+
│
|
|
70
|
+
├── spark_pulse/ # Python package
|
|
71
|
+
│ ├── __init__.py # Package init + version
|
|
72
|
+
│ ├── app.py # FastAPI app factory (creates app, mounts SPA)
|
|
73
|
+
│ ├── cli.py # CLI: spark-pulse start|install|mcp|...
|
|
74
|
+
│ ├── config.py # Config loader (YAML + env vars)
|
|
75
|
+
│ ├── service.py # Systemd service management
|
|
76
|
+
│ ├── auth.py # OIDC authentication middleware + routes
|
|
77
|
+
│ ├── mcp_server.py # MCP (Model Context Protocol) server
|
|
78
|
+
│ ├── config.yaml # Default configuration
|
|
79
|
+
│ ├── routers/ # API route modules
|
|
80
|
+
│ │ ├── recipes.py # Recipe listing + detail
|
|
81
|
+
│ │ ├── deployments.py # Deployment CRUD + launch/stop
|
|
82
|
+
│ │ ├── memory.py # GPU/CPU/disk stats
|
|
83
|
+
│ │ ├── cache.py # Cache scanning + cleanup
|
|
84
|
+
│ │ └── settings.py # Settings CRUD
|
|
85
|
+
│ ├── tools/ # Tool abstractions (real/mock swap)
|
|
86
|
+
│ │ ├── __init__.py # Factory: real vs mock
|
|
87
|
+
│ │ ├── system.py # nvidia-smi, free, df
|
|
88
|
+
│ │ ├── cache.py # cache dir scanning
|
|
89
|
+
│ │ └── recipes.py # YAML recipe parsing
|
|
90
|
+
│ ├── mock/ # Simulation mode implementations
|
|
91
|
+
│ │ ├── system.py # DGX Spark 128GB mock
|
|
92
|
+
│ │ ├── cache.py # Plausible cache sizes
|
|
93
|
+
│ │ ├── recipes.py # 6 realistic recipes
|
|
94
|
+
│ │ └── deployments.py # In-memory tracker
|
|
95
|
+
│ ├── ui/ # Built frontend (generated by `npm run build`)
|
|
96
|
+
│ │ └── index.html # Vite build output
|
|
97
|
+
│ └── data/ # Persistent state (deployments.json)
|
|
98
|
+
│
|
|
99
|
+
├── web/ # Frontend (separate npm project)
|
|
100
|
+
│ ├── package.json # Vite + React + TypeScript + Tailwind
|
|
101
|
+
│ ├── vite.config.ts # Builds to ../spark_pulse/ui/
|
|
102
|
+
│ ├── tsconfig.json
|
|
103
|
+
│ └── src/
|
|
104
|
+
│ ├── main.tsx # Entry point
|
|
105
|
+
│ ├── App.tsx # Router + AuthProvider
|
|
106
|
+
│ ├── lib/
|
|
107
|
+
│ │ ├── types.ts # TypeScript types
|
|
108
|
+
│ │ ├── api.ts # API client + SSE hooks
|
|
109
|
+
│ │ ├── utils.ts # Formatting helpers
|
|
110
|
+
│ │ ├── theme.ts # Theme state manager
|
|
111
|
+
│ │ └── auth.ts # Auth context
|
|
112
|
+
│ ├── hooks/
|
|
113
|
+
│ │ └── useQuery.ts # Data fetching hook
|
|
114
|
+
│ ├── components/
|
|
115
|
+
│ │ ├── Layout.tsx # Sidebar nav + theme toggle
|
|
116
|
+
│ │ ├── StatusBadge.tsx # Status indicators
|
|
117
|
+
│ │ └── Modal.tsx # Confirm + Alert modals
|
|
118
|
+
│ └── pages/
|
|
119
|
+
│ ├── RecipesPage.tsx
|
|
120
|
+
│ ├── JobsPage.tsx
|
|
121
|
+
│ ├── MemoryPage.tsx
|
|
122
|
+
│ ├── CachePage.tsx
|
|
123
|
+
│ └── SettingsPage.tsx
|
|
124
|
+
│
|
|
125
|
+
└── scripts/
|
|
126
|
+
├── run-dev-server.sh # Full dev (venv + frontend + backend)
|
|
127
|
+
├── run-backend.sh # Backend only (simulation)
|
|
128
|
+
├── run-production.sh # Production mode
|
|
129
|
+
└── build-ui.sh # Build frontend only
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Installation
|
|
133
|
+
|
|
134
|
+
### As a Python package
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Install from local repo
|
|
138
|
+
pip install -e .
|
|
139
|
+
|
|
140
|
+
# Or with MCP support
|
|
141
|
+
pip install -e ".[mcp]"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
This provides the `spark-pulse` CLI command.
|
|
145
|
+
|
|
146
|
+
### First-time setup
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Install Python dependencies (from repo root)
|
|
150
|
+
pip install -e ".[dev]"
|
|
151
|
+
|
|
152
|
+
# Build frontend
|
|
153
|
+
cd web && npm install && npm run build && cd ..
|
|
154
|
+
|
|
155
|
+
# Configure (edit spark_pulse/config.yaml or use Settings page)
|
|
156
|
+
# Default spark_vllm_path: /tmp/spark-vllm-docker
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Usage
|
|
160
|
+
|
|
161
|
+
### Quick start (development)
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# One command — venv + frontend deps + backend (sim) + frontend dev server
|
|
165
|
+
./scripts/run-dev-server.sh
|
|
166
|
+
# → Frontend: http://localhost:3000
|
|
167
|
+
# → Backend: http://localhost:8100 (+ /docs Swagger UI)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Simulation mode (local dev without DGX)
|
|
171
|
+
|
|
172
|
+
Set `SIMULATION_MODE=1` to get mock data for all APIs — useful for frontend
|
|
173
|
+
development on macOS or any machine without a DGX Spark:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Full dev (includes frontend dev server)
|
|
177
|
+
./scripts/run-dev-server.sh
|
|
178
|
+
|
|
179
|
+
# Backend only (simulation)
|
|
180
|
+
./scripts/run-backend.sh
|
|
181
|
+
# → http://localhost:8100
|
|
182
|
+
|
|
183
|
+
# Production mode (real tools, needs spark-vllm-docker + nvidia-smi)
|
|
184
|
+
./scripts/run-production.sh
|
|
185
|
+
|
|
186
|
+
# Just build frontend into spark_pulse/ui/
|
|
187
|
+
./scripts/build-ui.sh
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Systemd service (production)
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Install systemd unit
|
|
194
|
+
sudo spark-pulse install
|
|
195
|
+
|
|
196
|
+
# Uninstall
|
|
197
|
+
sudo spark-pulse uninstall
|
|
198
|
+
|
|
199
|
+
# Check status
|
|
200
|
+
spark-pulse status
|
|
201
|
+
|
|
202
|
+
# Stop service
|
|
203
|
+
spark-pulse stop-service
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### MCP Server (AI Assistants)
|
|
207
|
+
|
|
208
|
+
Expose spark-vllm-docker operations as MCP tools:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
# Start MCP server (stdio mode for AI assistants)
|
|
212
|
+
spark-pulse mcp
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Exposed tools:
|
|
216
|
+
- `list_recipes` — list available deployment recipes
|
|
217
|
+
- `get_recipe` — get recipe details by name
|
|
218
|
+
- `create_deployment` — launch a recipe deployment
|
|
219
|
+
- `stop_deployment` — stop a running deployment
|
|
220
|
+
- `list_deployments` — list all deployments with status
|
|
221
|
+
- `get_memory` — get GPU/CPU/disk stats
|
|
222
|
+
- `list_cache` — list cache directories with sizes
|
|
223
|
+
- `clean_cache` — clean specified cache directories
|
|
224
|
+
- `get_logs` — get deployment logs
|
|
225
|
+
|
|
226
|
+
### OIDC Authentication
|
|
227
|
+
|
|
228
|
+
Configure authentication in `spark_pulse/config.yaml`:
|
|
229
|
+
|
|
230
|
+
```yaml
|
|
231
|
+
auth_enabled: true
|
|
232
|
+
oidc_provider_url: https://keycloak.example.com/realms/myrealm
|
|
233
|
+
oidc_client_id: spark-manager
|
|
234
|
+
oidc_client_secret: your-secret-here
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Or via environment variables:
|
|
238
|
+
```bash
|
|
239
|
+
export SPARK_PULSE_AUTH_ENABLED=true
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
When enabled:
|
|
243
|
+
- All routes are protected except `/health`, `/auth/*`
|
|
244
|
+
- Users are redirected to the OIDC provider on `/auth/login`
|
|
245
|
+
- After successful auth, users see their name and a logout button in the header
|
|
246
|
+
|
|
247
|
+
### Environment variables
|
|
248
|
+
|
|
249
|
+
Override config via environment:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
export SPARK_VLLM_PATH=/path/to/spark-vllm-docker
|
|
253
|
+
export WEBUI_PORT=8100
|
|
254
|
+
export SPARK_PULSE_AUTH_ENABLED=true
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## API Reference
|
|
258
|
+
|
|
259
|
+
| Method | Path | Description |
|
|
260
|
+
|--------|------|-------------|
|
|
261
|
+
| `GET` | `/api/recipes` | List all recipes |
|
|
262
|
+
| `GET` | `/api/recipes/{id}` | Recipe details |
|
|
263
|
+
| `GET` | `/api/deployments` | List deployments |
|
|
264
|
+
| `POST` | `/api/deployments` | Create + launch |
|
|
265
|
+
| `DELETE` | `/api/deployments/{id}` | Stop deployment |
|
|
266
|
+
| `GET` | `/api/deployments/{id}/logs` | Recent logs |
|
|
267
|
+
| `GET` | `/api/memory` | All memory stats |
|
|
268
|
+
| `GET` | `/api/memory/gpu` | GPU stats |
|
|
269
|
+
| `GET` | `/api/cache` | Cache dirs + sizes |
|
|
270
|
+
| `POST` | `/api/cache/clean` | Clean caches |
|
|
271
|
+
| `GET` | `/api/settings` | Current settings |
|
|
272
|
+
| `PUT` | `/api/settings` | Update settings |
|
|
273
|
+
| `GET` | `/auth/login` | Redirect to OIDC login |
|
|
274
|
+
| `GET` | `/auth/callback` | OIDC callback |
|
|
275
|
+
| `GET` | `/auth/me` | Current user info |
|
|
276
|
+
| `GET` | `/` | SPA entry point |
|
|
277
|
+
|
|
278
|
+
## Building for distribution
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# Build frontend
|
|
282
|
+
cd web && npm run build && cd ..
|
|
283
|
+
|
|
284
|
+
# Build Python package
|
|
285
|
+
python -m build
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
The built frontend is bundled into the wheel via `package-data: ui/**/*`.
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# Spark Pulse
|
|
2
|
+
|
|
3
|
+
Web UI for [spark-vllm-docker](https://github.com/eugr/spark-vllm-docker) — recipe management, deployment, and monitoring for NVIDIA DGX Spark hardware.
|
|
4
|
+
|
|
5
|
+
**License:** [MIT](LICENSE) — Copyright © 2026 Kharkevich Engineering Lab
|
|
6
|
+
|
|
7
|
+
> **Disclaimer:** This project is not sponsored by, endorsed by, or affiliated
|
|
8
|
+
> with NVIDIA Corporation or any of its subsidiaries. NVIDIA, DGX, and NVIDIA
|
|
9
|
+
> trademarks are property of their respective owners.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Recipe Browser** — Browse available vLLM deployment recipes, view model details, configs, and mods
|
|
14
|
+
- **Job Management** — Launch deployments with custom parameters, monitor status, view live logs via SSE, stop jobs
|
|
15
|
+
- **Memory Monitor** — Real-time GPU memory, CPU RAM, and disk usage via SSE streaming
|
|
16
|
+
- **Cache Manager** — Browse and clean HF model cache, wheels, ccache, Triton cache, and more
|
|
17
|
+
- **Settings** — Configure spark-vllm-docker path, default container, GPU memory utilization
|
|
18
|
+
- **OIDC Authentication** — Configurable authentication (Keycloak, Auth0, Google, Azure AD, etc.)
|
|
19
|
+
- **Dark/Light Theme** — Switch between dark, light, or system theme (persisted in localStorage)
|
|
20
|
+
- **Custom Modals** — Beautiful confirmation dialogs and error alerts
|
|
21
|
+
- **MCP Server** — Expose spark-vllm-docker operations as Model Context Protocol tools for AI assistants
|
|
22
|
+
|
|
23
|
+
## Architecture
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
┌─────────────┐ HTTP / SSE ┌──────────────────────┐
|
|
27
|
+
│ Browser │ ◄───────────────► │ FastAPI + Uvicorn │
|
|
28
|
+
│ React SPA │ │ Port 8100 │
|
|
29
|
+
└─────────────┘ │ │
|
|
30
|
+
│ spark-vllm-docker/ │
|
|
31
|
+
│ Docker, nvidia-smi │
|
|
32
|
+
└──────────────────────┘
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Project Structure
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
spark-pulse/
|
|
39
|
+
├── pyproject.toml # Python package config (setuptools)
|
|
40
|
+
├── README.md
|
|
41
|
+
├── LICENSE
|
|
42
|
+
│
|
|
43
|
+
├── spark_pulse/ # Python package
|
|
44
|
+
│ ├── __init__.py # Package init + version
|
|
45
|
+
│ ├── app.py # FastAPI app factory (creates app, mounts SPA)
|
|
46
|
+
│ ├── cli.py # CLI: spark-pulse start|install|mcp|...
|
|
47
|
+
│ ├── config.py # Config loader (YAML + env vars)
|
|
48
|
+
│ ├── service.py # Systemd service management
|
|
49
|
+
│ ├── auth.py # OIDC authentication middleware + routes
|
|
50
|
+
│ ├── mcp_server.py # MCP (Model Context Protocol) server
|
|
51
|
+
│ ├── config.yaml # Default configuration
|
|
52
|
+
│ ├── routers/ # API route modules
|
|
53
|
+
│ │ ├── recipes.py # Recipe listing + detail
|
|
54
|
+
│ │ ├── deployments.py # Deployment CRUD + launch/stop
|
|
55
|
+
│ │ ├── memory.py # GPU/CPU/disk stats
|
|
56
|
+
│ │ ├── cache.py # Cache scanning + cleanup
|
|
57
|
+
│ │ └── settings.py # Settings CRUD
|
|
58
|
+
│ ├── tools/ # Tool abstractions (real/mock swap)
|
|
59
|
+
│ │ ├── __init__.py # Factory: real vs mock
|
|
60
|
+
│ │ ├── system.py # nvidia-smi, free, df
|
|
61
|
+
│ │ ├── cache.py # cache dir scanning
|
|
62
|
+
│ │ └── recipes.py # YAML recipe parsing
|
|
63
|
+
│ ├── mock/ # Simulation mode implementations
|
|
64
|
+
│ │ ├── system.py # DGX Spark 128GB mock
|
|
65
|
+
│ │ ├── cache.py # Plausible cache sizes
|
|
66
|
+
│ │ ├── recipes.py # 6 realistic recipes
|
|
67
|
+
│ │ └── deployments.py # In-memory tracker
|
|
68
|
+
│ ├── ui/ # Built frontend (generated by `npm run build`)
|
|
69
|
+
│ │ └── index.html # Vite build output
|
|
70
|
+
│ └── data/ # Persistent state (deployments.json)
|
|
71
|
+
│
|
|
72
|
+
├── web/ # Frontend (separate npm project)
|
|
73
|
+
│ ├── package.json # Vite + React + TypeScript + Tailwind
|
|
74
|
+
│ ├── vite.config.ts # Builds to ../spark_pulse/ui/
|
|
75
|
+
│ ├── tsconfig.json
|
|
76
|
+
│ └── src/
|
|
77
|
+
│ ├── main.tsx # Entry point
|
|
78
|
+
│ ├── App.tsx # Router + AuthProvider
|
|
79
|
+
│ ├── lib/
|
|
80
|
+
│ │ ├── types.ts # TypeScript types
|
|
81
|
+
│ │ ├── api.ts # API client + SSE hooks
|
|
82
|
+
│ │ ├── utils.ts # Formatting helpers
|
|
83
|
+
│ │ ├── theme.ts # Theme state manager
|
|
84
|
+
│ │ └── auth.ts # Auth context
|
|
85
|
+
│ ├── hooks/
|
|
86
|
+
│ │ └── useQuery.ts # Data fetching hook
|
|
87
|
+
│ ├── components/
|
|
88
|
+
│ │ ├── Layout.tsx # Sidebar nav + theme toggle
|
|
89
|
+
│ │ ├── StatusBadge.tsx # Status indicators
|
|
90
|
+
│ │ └── Modal.tsx # Confirm + Alert modals
|
|
91
|
+
│ └── pages/
|
|
92
|
+
│ ├── RecipesPage.tsx
|
|
93
|
+
│ ├── JobsPage.tsx
|
|
94
|
+
│ ├── MemoryPage.tsx
|
|
95
|
+
│ ├── CachePage.tsx
|
|
96
|
+
│ └── SettingsPage.tsx
|
|
97
|
+
│
|
|
98
|
+
└── scripts/
|
|
99
|
+
├── run-dev-server.sh # Full dev (venv + frontend + backend)
|
|
100
|
+
├── run-backend.sh # Backend only (simulation)
|
|
101
|
+
├── run-production.sh # Production mode
|
|
102
|
+
└── build-ui.sh # Build frontend only
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Installation
|
|
106
|
+
|
|
107
|
+
### As a Python package
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Install from local repo
|
|
111
|
+
pip install -e .
|
|
112
|
+
|
|
113
|
+
# Or with MCP support
|
|
114
|
+
pip install -e ".[mcp]"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This provides the `spark-pulse` CLI command.
|
|
118
|
+
|
|
119
|
+
### First-time setup
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# Install Python dependencies (from repo root)
|
|
123
|
+
pip install -e ".[dev]"
|
|
124
|
+
|
|
125
|
+
# Build frontend
|
|
126
|
+
cd web && npm install && npm run build && cd ..
|
|
127
|
+
|
|
128
|
+
# Configure (edit spark_pulse/config.yaml or use Settings page)
|
|
129
|
+
# Default spark_vllm_path: /tmp/spark-vllm-docker
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Usage
|
|
133
|
+
|
|
134
|
+
### Quick start (development)
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# One command — venv + frontend deps + backend (sim) + frontend dev server
|
|
138
|
+
./scripts/run-dev-server.sh
|
|
139
|
+
# → Frontend: http://localhost:3000
|
|
140
|
+
# → Backend: http://localhost:8100 (+ /docs Swagger UI)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Simulation mode (local dev without DGX)
|
|
144
|
+
|
|
145
|
+
Set `SIMULATION_MODE=1` to get mock data for all APIs — useful for frontend
|
|
146
|
+
development on macOS or any machine without a DGX Spark:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Full dev (includes frontend dev server)
|
|
150
|
+
./scripts/run-dev-server.sh
|
|
151
|
+
|
|
152
|
+
# Backend only (simulation)
|
|
153
|
+
./scripts/run-backend.sh
|
|
154
|
+
# → http://localhost:8100
|
|
155
|
+
|
|
156
|
+
# Production mode (real tools, needs spark-vllm-docker + nvidia-smi)
|
|
157
|
+
./scripts/run-production.sh
|
|
158
|
+
|
|
159
|
+
# Just build frontend into spark_pulse/ui/
|
|
160
|
+
./scripts/build-ui.sh
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Systemd service (production)
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
# Install systemd unit
|
|
167
|
+
sudo spark-pulse install
|
|
168
|
+
|
|
169
|
+
# Uninstall
|
|
170
|
+
sudo spark-pulse uninstall
|
|
171
|
+
|
|
172
|
+
# Check status
|
|
173
|
+
spark-pulse status
|
|
174
|
+
|
|
175
|
+
# Stop service
|
|
176
|
+
spark-pulse stop-service
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### MCP Server (AI Assistants)
|
|
180
|
+
|
|
181
|
+
Expose spark-vllm-docker operations as MCP tools:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Start MCP server (stdio mode for AI assistants)
|
|
185
|
+
spark-pulse mcp
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Exposed tools:
|
|
189
|
+
- `list_recipes` — list available deployment recipes
|
|
190
|
+
- `get_recipe` — get recipe details by name
|
|
191
|
+
- `create_deployment` — launch a recipe deployment
|
|
192
|
+
- `stop_deployment` — stop a running deployment
|
|
193
|
+
- `list_deployments` — list all deployments with status
|
|
194
|
+
- `get_memory` — get GPU/CPU/disk stats
|
|
195
|
+
- `list_cache` — list cache directories with sizes
|
|
196
|
+
- `clean_cache` — clean specified cache directories
|
|
197
|
+
- `get_logs` — get deployment logs
|
|
198
|
+
|
|
199
|
+
### OIDC Authentication
|
|
200
|
+
|
|
201
|
+
Configure authentication in `spark_pulse/config.yaml`:
|
|
202
|
+
|
|
203
|
+
```yaml
|
|
204
|
+
auth_enabled: true
|
|
205
|
+
oidc_provider_url: https://keycloak.example.com/realms/myrealm
|
|
206
|
+
oidc_client_id: spark-manager
|
|
207
|
+
oidc_client_secret: your-secret-here
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Or via environment variables:
|
|
211
|
+
```bash
|
|
212
|
+
export SPARK_PULSE_AUTH_ENABLED=true
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
When enabled:
|
|
216
|
+
- All routes are protected except `/health`, `/auth/*`
|
|
217
|
+
- Users are redirected to the OIDC provider on `/auth/login`
|
|
218
|
+
- After successful auth, users see their name and a logout button in the header
|
|
219
|
+
|
|
220
|
+
### Environment variables
|
|
221
|
+
|
|
222
|
+
Override config via environment:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
export SPARK_VLLM_PATH=/path/to/spark-vllm-docker
|
|
226
|
+
export WEBUI_PORT=8100
|
|
227
|
+
export SPARK_PULSE_AUTH_ENABLED=true
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## API Reference
|
|
231
|
+
|
|
232
|
+
| Method | Path | Description |
|
|
233
|
+
|--------|------|-------------|
|
|
234
|
+
| `GET` | `/api/recipes` | List all recipes |
|
|
235
|
+
| `GET` | `/api/recipes/{id}` | Recipe details |
|
|
236
|
+
| `GET` | `/api/deployments` | List deployments |
|
|
237
|
+
| `POST` | `/api/deployments` | Create + launch |
|
|
238
|
+
| `DELETE` | `/api/deployments/{id}` | Stop deployment |
|
|
239
|
+
| `GET` | `/api/deployments/{id}/logs` | Recent logs |
|
|
240
|
+
| `GET` | `/api/memory` | All memory stats |
|
|
241
|
+
| `GET` | `/api/memory/gpu` | GPU stats |
|
|
242
|
+
| `GET` | `/api/cache` | Cache dirs + sizes |
|
|
243
|
+
| `POST` | `/api/cache/clean` | Clean caches |
|
|
244
|
+
| `GET` | `/api/settings` | Current settings |
|
|
245
|
+
| `PUT` | `/api/settings` | Update settings |
|
|
246
|
+
| `GET` | `/auth/login` | Redirect to OIDC login |
|
|
247
|
+
| `GET` | `/auth/callback` | OIDC callback |
|
|
248
|
+
| `GET` | `/auth/me` | Current user info |
|
|
249
|
+
| `GET` | `/` | SPA entry point |
|
|
250
|
+
|
|
251
|
+
## Building for distribution
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# Build frontend
|
|
255
|
+
cd web && npm run build && cd ..
|
|
256
|
+
|
|
257
|
+
# Build Python package
|
|
258
|
+
python -m build
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The built frontend is bundled into the wheel via `package-data: ui/**/*`.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
# ── Project metadata ────────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
[project]
|
|
8
|
+
name = "spark-pulse"
|
|
9
|
+
version = "1.0.0"
|
|
10
|
+
description = "Web UI for spark-vllm-docker — recipe management, deployment, and monitoring for DGX Spark"
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
license = "MIT"
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
dependencies = [
|
|
15
|
+
"fastapi>=0.115.0",
|
|
16
|
+
"uvicorn[standard]>=0.34.0",
|
|
17
|
+
"sse-starlette>=2.2.0",
|
|
18
|
+
"pyyaml>=6.0",
|
|
19
|
+
"pydantic>=2.0",
|
|
20
|
+
"click>=8.0",
|
|
21
|
+
"authlib>=1.3.0",
|
|
22
|
+
"httpx>=0.28.0",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.optional-dependencies]
|
|
26
|
+
dev = [
|
|
27
|
+
"black>=24.8.0",
|
|
28
|
+
"pytest>=8.0",
|
|
29
|
+
"httpx>=0.28",
|
|
30
|
+
]
|
|
31
|
+
mcp = [
|
|
32
|
+
"mcp>=1.0.0",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[[project.maintainers]]
|
|
36
|
+
name = "Alexander Kharkevich"
|
|
37
|
+
email = "alex@kharkevich.org"
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
homepage = "https://github.com/kharkevich-engineering-lab/spark-pulse"
|
|
41
|
+
repository = "https://github.com/kharkevich-engineering-lab/spark-pulse"
|
|
42
|
+
|
|
43
|
+
# ── Console script ──────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
[project.scripts]
|
|
46
|
+
spark-pulse = "spark_pulse.cli:main"
|
|
47
|
+
|
|
48
|
+
[tool.pytest.ini_options]
|
|
49
|
+
testpaths = ["tests"]
|
|
50
|
+
python_files = ["test_*.py"]
|
|
51
|
+
addopts = "--tb=short -v"
|
|
52
|
+
|
|
53
|
+
# ── Packaging ───────────────────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.packages.find]
|
|
56
|
+
where = ["."]
|
|
57
|
+
include = ["spark_pulse*", "spark_pulse.*"]
|
|
58
|
+
|
|
59
|
+
[tool.setuptools.package-data]
|
|
60
|
+
spark_pulse = [
|
|
61
|
+
"ui/**/*",
|
|
62
|
+
"service/templates/**/*",
|
|
63
|
+
]
|