|
3 | 3 | import json |
4 | 4 | import sys |
5 | 5 | from functools import wraps |
6 | | -from typing import Any, Callable, Dict, List, Literal, TypeVar, Union |
| 6 | +from typing import Any, Callable, Dict, List, Literal, Sequence, TypeVar, Union |
7 | 7 |
|
8 | 8 | import click |
9 | 9 |
|
10 | 10 | from together import Together |
11 | 11 | from together.error import InvalidRequestError |
12 | 12 | from together.types import DedicatedEndpoint, ListEndpoint |
| 13 | +from together.types.endpoints import HardwareWithStatus |
13 | 14 |
|
14 | 15 |
|
15 | 16 | def print_endpoint( |
@@ -258,28 +259,84 @@ def hardware(client: Together, model: str | None, json: bool, available: bool) - |
258 | 259 | fetch_and_print_hardware_options(client, model, json, available) |
259 | 260 |
|
260 | 261 |
|
| 262 | +def format_hardware_table( |
| 263 | + hardware_options: Sequence[HardwareWithStatus], |
| 264 | + show_availability: bool = True, |
| 265 | +) -> None: |
| 266 | + """Print hardware options in a formatted table.""" |
| 267 | + if not hardware_options: |
| 268 | + click.echo(" No hardware options found.", err=True) |
| 269 | + return |
| 270 | + |
| 271 | + # Calculate column widths |
| 272 | + id_width = max(len(h.id) for h in hardware_options) |
| 273 | + id_width = max(id_width, len("HARDWARE ID")) |
| 274 | + |
| 275 | + # Print header |
| 276 | + if show_availability: |
| 277 | + header = f" {'HARDWARE ID':<{id_width}} {'GPU':<12} {'COUNT':<5} {'MEMORY':<8} {'STATUS':<12} {'PRICE':<12}" |
| 278 | + separator = f" {'-' * id_width} {'-' * 12} {'-' * 5} {'-' * 8} {'-' * 12} {'-' * 12}" |
| 279 | + else: |
| 280 | + header = f" {'HARDWARE ID':<{id_width}} {'GPU':<12} {'COUNT':<5} {'MEMORY':<8} {'PRICE':<12}" |
| 281 | + separator = f" {'-' * id_width} {'-' * 12} {'-' * 5} {'-' * 8} {'-' * 12}" |
| 282 | + |
| 283 | + click.echo(header, err=True) |
| 284 | + click.echo(separator, err=True) |
| 285 | + |
| 286 | + # Print each hardware option |
| 287 | + for hw in hardware_options: |
| 288 | + gpu_type = hw.specs.gpu_type if hw.specs else "N/A" |
| 289 | + gpu_count = str(hw.specs.gpu_count) if hw.specs else "N/A" |
| 290 | + gpu_memory = f"{int(hw.specs.gpu_memory)}GB" if hw.specs else "N/A" |
| 291 | + price = f"${hw.pricing.cents_per_minute / 100:.2f}/min" if hw.pricing else "N/A" |
| 292 | + |
| 293 | + if show_availability: |
| 294 | + if hw.availability: |
| 295 | + status = hw.availability.status |
| 296 | + # Add visual indicators for status |
| 297 | + if status == "available": |
| 298 | + status_display = click.style("✓ available", fg="green") |
| 299 | + elif status == "unavailable": |
| 300 | + status_display = click.style("✗ unavailable", fg="red") |
| 301 | + else: # insufficient |
| 302 | + status_display = click.style("⚠ insufficient", fg="yellow") |
| 303 | + else: |
| 304 | + status_display = "—" |
| 305 | + |
| 306 | + row = f" {hw.id:<{id_width}} {gpu_type:<12} {gpu_count:<5} {gpu_memory:<8} {status_display:<23} {price:<12}" |
| 307 | + else: |
| 308 | + row = f" {hw.id:<{id_width}} {gpu_type:<12} {gpu_count:<5} {gpu_memory:<8} {price:<12}" |
| 309 | + |
| 310 | + click.echo(row, err=True) |
| 311 | + |
| 312 | + |
261 | 313 | def fetch_and_print_hardware_options( |
262 | 314 | client: Together, model: str | None, print_json: bool, available: bool |
263 | 315 | ) -> None: |
264 | 316 | """Print hardware options for a model.""" |
265 | | - |
266 | | - message = "Available hardware options:" if available else "All hardware options:" |
267 | | - click.echo(message, err=True) |
268 | 317 | hardware_options = client.endpoints.list_hardware(model) |
| 318 | + |
269 | 319 | if available: |
270 | 320 | hardware_options = [ |
271 | 321 | hardware |
272 | 322 | for hardware in hardware_options |
273 | 323 | if hardware.availability is not None |
274 | 324 | and hardware.availability.status == "available" |
275 | 325 | ] |
| 326 | + message = f"Available hardware options for model '{model}':" if model else "Available hardware options:" |
| 327 | + else: |
| 328 | + message = f"Hardware options for model '{model}':" if model else "All hardware options:" |
| 329 | + |
| 330 | + click.echo(message, err=True) |
| 331 | + click.echo("", err=True) |
276 | 332 |
|
277 | 333 | if print_json: |
278 | 334 | json_output = [hardware.model_dump() for hardware in hardware_options] |
279 | 335 | click.echo(json.dumps(json_output, indent=2)) |
280 | 336 | else: |
281 | | - for hardware in hardware_options: |
282 | | - click.echo(f" {hardware.id}", err=True) |
| 337 | + # Show availability column only when model is specified (availability info is only returned with model filter) |
| 338 | + show_availability = model is not None |
| 339 | + format_hardware_table(hardware_options, show_availability=show_availability) |
283 | 340 |
|
284 | 341 |
|
285 | 342 | @endpoints.command() |
|
0 commit comments