Metadata-Version: 2.4
Name: usfbios
Version: 1.0.1
Summary: Official Python SDK for the USF BIOS fine-tuning platform API
Project-URL: Homepage, https://bios.us.com
Project-URL: Documentation, https://bios.us.com/docs
Author-email: USF Inc <bios@us.inc>
License-Expression: MIT
License-File: LICENSE
Keywords: fine-tuning,llm,machine-learning,sdk,usfbios
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.8
Requires-Dist: requests>=2.28.0
Description-Content-Type: text/markdown

# usfbios

Official Python SDK for the [USF BIOS](https://bios.us.com) fine-tuning platform API.

## Installation

```bash
pip install usfbios
```

## Quick Start

```python
from usfbios import USFBios

client = USFBios(api_key="sk_live_...")

# Search for models
result = client.models.search(query="llama", type="llm", limit=5)
for model in result["models"]:
    print(f"{model['id']} -- {model['totalParams']}B params")

# Create a training job
job = client.training.create(
    model="meta-llama/Llama-3.1-8B-Instruct",
    dataset_id="ds_abc123",
    method="sft",
    adapter="lora",
    epochs=3,
    learning_rate=2e-4,
    lora_rank=16,
)
print(f"Job {job['id']} created -- status: {job['status']}")
```

## Authentication

The SDK supports two authentication methods:

**API Key** (recommended):
```python
client = USFBios(api_key="sk_live_...")
```

**JWT Access Token**:
```python
client = USFBios(
    access_token="eyJhbG...",
    org_id="org_abc123",
)
```

## Configuration

| Parameter | Type | Default | Description |
|---|---|---|---|
| `api_key` | `str` | `None` | API key for authentication (prefix: `sk_live_`) |
| `access_token` | `str` | `None` | JWT access token (alternative to API key) |
| `org_id` | `str` | `None` | Organization ID (required for JWT auth) |
| `workspace_id` | `str` | `None` | Workspace ID (optional, overrides key default) |
| `base_url` | `str` | `https://api-bios.us.inc` | API base URL |
| `timeout` | `float` | `30.0` | Request timeout in seconds |

## Resources

### Models

Search the HuggingFace model catalog, fetch training configs, and check adapter compatibility.

```python
# Search models
result = client.models.search(query="llama", type="llm", limit=10)

# Get model config
config = client.models.get_config("meta-llama/Llama-3.1-8B")
print(f"{config['totalParams']}B params, MoE: {config['isMoE']}")

# Check adapter compatibility
compat = client.models.get_adapter_compatibility(
    model_type="llama",
    training_method="rlhf",
    rlhf_algorithm="dpo",
)
usable = [a for a in compat["adapters"] if a["compatible"]]
print(f"{len(usable)} compatible adapters")
```

### Datasets

Upload, import, preview, and manage training datasets.

```python
# List datasets
datasets = client.datasets.list()

# Upload a dataset
uploaded = client.datasets.upload(
    file_path="./training_data.jsonl",
    name="My SFT Dataset",
)
print(f"Uploaded: {uploaded['id']}")

# Import from HuggingFace
imported = client.datasets.import_from_huggingface(
    repo_id="databricks/dolly-15k",
    integration_id="int_abc123",
    name="Dolly 15k",
)

# Preview dataset rows
preview = client.datasets.preview("ds_abc123", page=1, page_size=5)
print(preview["columns"])

# Validate before uploading
result = client.datasets.validate("./data.jsonl")
if result["valid"]:
    print(f"Valid {result['format']} with {result['row_count']} rows")
else:
    print("Errors:", result["errors"])

# Search HuggingFace Hub
hub_results = client.datasets.search_hub(query="code instruct")

# Preview a Hub dataset
hub_preview = client.datasets.preview_hub(
    dataset_id="databricks/dolly-15k",
    split="train",
    limit=5,
)

# Get format specs
specs = client.datasets.get_format_specs()

# Get storage usage
usage = client.datasets.get_storage_usage()

# Delete a dataset
client.datasets.delete("ds_abc123")
```

### Training

Create, monitor, stop, and resume fine-tuning jobs.

```python
# Create a training job
job = client.training.create(
    model="meta-llama/Llama-3.1-8B-Instruct",
    dataset_id="ds_abc123",
    method="sft",
    adapter="lora",
    epochs=3,
    learning_rate=2e-4,
    lora_rank=16,
    lora_alpha=32,
    gpu_type="A100_80GB",
    gpu_count=1,
)

# List jobs
jobs = client.training.list(status="running")

# Get job details
job = client.training.get("job_abc123")
print(f"Status: {job['status']}, Progress: {job.get('progress', 0)}%")

# Get metrics
metrics = client.training.get_metrics("job_abc123")
print(f"Current loss: {metrics.get('current_loss')}")

# Get checkpoints
checkpoints = client.training.get_checkpoints("job_abc123")
for cp in checkpoints:
    print(f"Step {cp['step']}: loss {cp.get('loss')}")

# Get logs
logs = client.training.get_logs("job_abc123")
for line in logs["logs"]:
    print(line)

# Stop a job
client.training.stop("job_abc123", keep_data=True)

# Resume a stopped job
client.training.resume("job_abc123")

# Delete a checkpoint
client.training.delete_checkpoint("job_abc123", "cp_xyz789")
```

### Wallet

View wallet balance and transaction history.

```python
# Get balance
balance = client.wallet.get_balance()
print(f"Balance: ${balance['balance_cents'] / 100:.2f}")
print(f"Available: ${balance['available_cents'] / 100:.2f}")

# List transactions
txns = client.wallet.get_transactions(limit=20)
for t in txns:
    print(f"{t['type']}: ${t['amount_cents'] / 100:.2f} -- {t.get('description')}")

# Get pricing
pricing = client.wallet.get_pricing()
```

### GPU

View GPU pricing and get hardware recommendations.

```python
# Get all GPU pricing
pricing = client.gpu.get_pricing()
for gpu in pricing["gpus"]:
    print(f"{gpu['display_name']}: {gpu['price_display']} -- {gpu['vram_gb']}GB VRAM")

# Get recommended GPU for a model
rec = client.gpu.get_recommended("meta-llama/Llama-3.1-8B-Instruct")
if rec:
    print(f"Recommended: {rec['display_name']} x{rec['recommended_count']}")
    print(f"Total VRAM: {rec['total_vram_gb']}GB")
    print(f"Cost: ${rec['estimated_cost_per_hour_cents'] / 100:.2f}/hr")
    print(f"Reason: {rec['reason']}")
```

### Introspect

Discover the permissions and scope of your API key.

```python
info = client.introspect()
print(f"Org: {info['org']['name']}")
print(f"Scopes: {', '.join(info['scopes'])}")
print(f"Allowed tools: {len(info['allowed_mcp_tools'])}")
```

## Error Handling

All API errors raise `ApiError` with `status`, `code`, `request_id`, and `message` attributes.

```python
from usfbios import USFBios, ApiError

client = USFBios(api_key="sk_live_...")

try:
    job = client.training.get("bad_id")
except ApiError as e:
    if e.status == 404:
        print("Job not found")
    elif e.status == 401:
        print("Invalid API key")
    elif e.status == 403:
        print("Insufficient permissions")
    else:
        print(f"API error {e.status}: {e.message}")
        if e.request_id:
            print(f"Request ID: {e.request_id}")
```

## Python Version Support

- Python 3.8+

## License

MIT
