mirror of
https://github.com/KohakuBlueleaf/KohakuHub.git
synced 2026-07-16 02:33:10 -05:00
725 lines
16 KiB
Markdown
725 lines
16 KiB
Markdown
---
|
|
title: Settings API
|
|
description: Manage user, organization, and repository settings
|
|
icon: settings
|
|
---
|
|
|
|
# Settings API
|
|
|
|
Manage settings for users, organizations, and repositories including profiles, avatars, and LFS configuration.
|
|
|
|
## User Settings
|
|
|
|
### Get Current User Info
|
|
|
|
Get authenticated user information in HuggingFace-compatible format.
|
|
|
|
**Endpoint:** `GET /api/whoami-v2`
|
|
|
|
**Authentication:** Required
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"type": "user",
|
|
"id": "123",
|
|
"name": "alice",
|
|
"fullname": "alice",
|
|
"email": "alice@example.com",
|
|
"emailVerified": true,
|
|
"canPay": false,
|
|
"isPro": false,
|
|
"orgs": [
|
|
{
|
|
"name": "myorg",
|
|
"fullname": "myorg",
|
|
"roleInOrg": "admin"
|
|
}
|
|
],
|
|
"auth": {
|
|
"type": "access_token",
|
|
"accessToken": {
|
|
"displayName": "Auto-generated token",
|
|
"role": "write"
|
|
}
|
|
},
|
|
"site": {
|
|
"name": "KohakuHub",
|
|
"api": "kohakuhub",
|
|
"version": "0.0.1"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Example:**
|
|
|
|
```python
|
|
import requests
|
|
|
|
response = requests.get(
|
|
"http://localhost:28080/api/whoami-v2",
|
|
headers={"Authorization": "Bearer YOUR_TOKEN"}
|
|
)
|
|
user_info = response.json()
|
|
print(f"Logged in as: {user_info['name']}")
|
|
```
|
|
|
|
---
|
|
|
|
### Get Namespace Type
|
|
|
|
Determine if a namespace is a user or organization.
|
|
|
|
**Endpoint:** `GET /api/users/{username}/type`
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Location | Required | Description |
|
|
|-----------|------|----------|----------|-------------|
|
|
| `username` | string | path | Yes | Username or organization name |
|
|
| `fallback` | boolean | query | No | Enable fallback to external sources (default: `true`) |
|
|
|
|
**Authentication:** Optional
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"type": "user",
|
|
"_source": "local"
|
|
}
|
|
```
|
|
|
|
Or:
|
|
|
|
```json
|
|
{
|
|
"type": "org",
|
|
"_source": "local"
|
|
}
|
|
```
|
|
|
|
**Example:**
|
|
|
|
```python
|
|
response = requests.get("http://localhost:28080/api/users/myorg/type")
|
|
data = response.json()
|
|
if data["type"] == "org":
|
|
print("This is an organization")
|
|
```
|
|
|
|
---
|
|
|
|
### Get User Profile
|
|
|
|
Get public user profile information.
|
|
|
|
**Endpoint:** `GET /api/users/{username}/profile`
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Location | Required | Description |
|
|
|-----------|------|----------|----------|-------------|
|
|
| `username` | string | path | Yes | Username to query |
|
|
| `fallback` | boolean | query | No | Enable fallback to external sources (default: `true`) |
|
|
|
|
**Authentication:** Optional
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"username": "alice",
|
|
"full_name": "Alice Smith",
|
|
"bio": "ML Engineer",
|
|
"website": "https://example.com",
|
|
"social_media": {
|
|
"twitter_x": "alice_ml",
|
|
"github": "alice",
|
|
"huggingface": "alice"
|
|
},
|
|
"created_at": "2025-01-01T00:00:00Z",
|
|
"_source": "local"
|
|
}
|
|
```
|
|
|
|
**Example:**
|
|
|
|
```python
|
|
response = requests.get("http://localhost:28080/api/users/alice/profile")
|
|
profile = response.json()
|
|
```
|
|
|
|
---
|
|
|
|
### Update User Settings
|
|
|
|
Update authenticated user's settings.
|
|
|
|
**Endpoint:** `PUT /api/users/{username}/settings`
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Location | Required | Description |
|
|
|-----------|------|----------|----------|-------------|
|
|
| `username` | string | path | Yes | Username (must match authenticated user) |
|
|
|
|
**Request Body:**
|
|
|
|
```json
|
|
{
|
|
"email": "newemail@example.com",
|
|
"full_name": "Alice Smith",
|
|
"bio": "ML Engineer and researcher",
|
|
"website": "https://example.com",
|
|
"social_media": {
|
|
"twitter_x": "alice_ml",
|
|
"threads": "alice",
|
|
"github": "alice",
|
|
"huggingface": "alice"
|
|
}
|
|
}
|
|
```
|
|
|
|
**All fields are optional:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `email` | string | Email address (triggers re-verification) |
|
|
| `full_name` | string | Full display name |
|
|
| `bio` | string | User biography |
|
|
| `website` | string | Personal website URL |
|
|
| `social_media` | object | Social media handles |
|
|
|
|
**Authentication:** Required (can only update own settings)
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "User settings updated successfully"
|
|
}
|
|
```
|
|
|
|
**Example:**
|
|
|
|
```python
|
|
response = requests.put(
|
|
"http://localhost:28080/api/users/alice/settings",
|
|
headers={"Authorization": "Bearer YOUR_TOKEN"},
|
|
json={
|
|
"bio": "ML Engineer and researcher",
|
|
"website": "https://alice.example.com"
|
|
}
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
### Manage User Avatar
|
|
|
|
#### Upload Avatar
|
|
|
|
**Endpoint:** `POST /api/users/{username}/avatar`
|
|
|
|
**Authentication:** Required (can only upload own avatar)
|
|
|
|
**Request:** Multipart form data with image file
|
|
|
|
Supported formats: JPEG, PNG, WebP, GIF
|
|
Maximum size: 10 MB
|
|
|
|
**Processing:**
|
|
- Images are resized to max 1024x1024 (maintains aspect ratio)
|
|
- Center-cropped to square
|
|
- Converted to JPEG (quality: 95)
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Avatar uploaded successfully",
|
|
"size_bytes": 245678
|
|
}
|
|
```
|
|
|
|
#### Get Avatar
|
|
|
|
**Endpoint:** `GET /api/users/{username}/avatar`
|
|
|
|
**Authentication:** Optional
|
|
|
|
**Response:** JPEG image with cache headers
|
|
|
|
**Cache-Control:** `public, max-age=86400` (24 hours)
|
|
|
|
#### Delete Avatar
|
|
|
|
**Endpoint:** `DELETE /api/users/{username}/avatar`
|
|
|
|
**Authentication:** Required (can only delete own avatar)
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Avatar deleted successfully"
|
|
}
|
|
```
|
|
|
|
**Example:**
|
|
|
|
```python
|
|
# Upload avatar
|
|
with open("avatar.png", "rb") as f:
|
|
response = requests.post(
|
|
"http://localhost:28080/api/users/alice/avatar",
|
|
headers={"Authorization": "Bearer YOUR_TOKEN"},
|
|
files={"file": f}
|
|
)
|
|
|
|
# Get avatar URL
|
|
avatar_url = "http://localhost:28080/api/users/alice/avatar"
|
|
|
|
# Delete avatar
|
|
response = requests.delete(
|
|
"http://localhost:28080/api/users/alice/avatar",
|
|
headers={"Authorization": "Bearer YOUR_TOKEN"}
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Organization Settings
|
|
|
|
### Get Organization Profile
|
|
|
|
Get public organization profile information.
|
|
|
|
**Endpoint:** `GET /api/organizations/{org_name}/profile`
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Location | Required | Description |
|
|
|-----------|------|----------|----------|-------------|
|
|
| `org_name` | string | path | Yes | Organization name |
|
|
|
|
**Authentication:** Optional
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"name": "myorg",
|
|
"description": "Machine Learning Research",
|
|
"bio": "We build open-source ML models",
|
|
"website": "https://myorg.example.com",
|
|
"social_media": {
|
|
"twitter_x": "myorg_ml",
|
|
"github": "myorg"
|
|
},
|
|
"member_count": 5,
|
|
"created_at": "2025-01-01T00:00:00Z"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Update Organization Settings
|
|
|
|
Update organization settings (admin only).
|
|
|
|
**Endpoint:** `PUT /api/organizations/{org_name}/settings`
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Location | Required | Description |
|
|
|-----------|------|----------|----------|-------------|
|
|
| `org_name` | string | path | Yes | Organization name |
|
|
|
|
**Request Body:**
|
|
|
|
```json
|
|
{
|
|
"description": "Machine Learning Research",
|
|
"bio": "We build open-source ML models",
|
|
"website": "https://myorg.example.com",
|
|
"social_media": {
|
|
"twitter_x": "myorg_ml",
|
|
"threads": "myorg",
|
|
"github": "myorg",
|
|
"huggingface": "myorg"
|
|
}
|
|
}
|
|
```
|
|
|
|
**All fields are optional:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `description` | string | Organization description |
|
|
| `bio` | string | Organization biography |
|
|
| `website` | string | Organization website URL |
|
|
| `social_media` | object | Social media handles |
|
|
|
|
**Authentication:** Required (admin or super-admin role)
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Organization settings updated successfully"
|
|
}
|
|
```
|
|
|
|
**Example:**
|
|
|
|
```python
|
|
response = requests.put(
|
|
"http://localhost:28080/api/organizations/myorg/settings",
|
|
headers={"Authorization": "Bearer YOUR_TOKEN"},
|
|
json={
|
|
"description": "Machine Learning Research",
|
|
"website": "https://myorg.example.com"
|
|
}
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
### Manage Organization Avatar
|
|
|
|
#### Upload Avatar
|
|
|
|
**Endpoint:** `POST /api/organizations/{org_name}/avatar`
|
|
|
|
**Authentication:** Required (admin or super-admin)
|
|
|
|
**Request:** Multipart form data with image file
|
|
|
|
Same processing as user avatars (1024x1024, center-cropped, JPEG).
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Avatar uploaded successfully",
|
|
"size_bytes": 245678
|
|
}
|
|
```
|
|
|
|
#### Get Avatar
|
|
|
|
**Endpoint:** `GET /api/organizations/{org_name}/avatar`
|
|
|
|
**Authentication:** Optional
|
|
|
|
**Response:** JPEG image with cache headers
|
|
|
|
#### Delete Avatar
|
|
|
|
**Endpoint:** `DELETE /api/organizations/{org_name}/avatar`
|
|
|
|
**Authentication:** Required (admin or super-admin)
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Avatar deleted successfully"
|
|
}
|
|
```
|
|
|
|
**Example:**
|
|
|
|
```python
|
|
# Upload organization avatar
|
|
with open("org-logo.png", "rb") as f:
|
|
response = requests.post(
|
|
"http://localhost:28080/api/organizations/myorg/avatar",
|
|
headers={"Authorization": "Bearer YOUR_TOKEN"},
|
|
files={"file": f}
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Repository Settings
|
|
|
|
### Update Repository Settings
|
|
|
|
Update repository configuration including visibility and LFS settings.
|
|
|
|
**Endpoint:** `PUT /api/{repo_type}s/{namespace}/{name}/settings`
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Location | Required | Description |
|
|
|-----------|------|----------|----------|-------------|
|
|
| `repo_type` | string | path | Yes | Repository type: `model`, `dataset`, or `space` |
|
|
| `namespace` | string | path | Yes | Repository namespace |
|
|
| `name` | string | path | Yes | Repository name |
|
|
|
|
**Request Body:**
|
|
|
|
```json
|
|
{
|
|
"private": false,
|
|
"lfs_threshold_bytes": 10000000,
|
|
"lfs_keep_versions": 10,
|
|
"lfs_suffix_rules": [".safetensors", ".bin", ".gguf"]
|
|
}
|
|
```
|
|
|
|
**All fields are optional:**
|
|
|
|
| Field | Type | Description | Constraints |
|
|
|-------|------|-------------|-------------|
|
|
| `private` | boolean | Repository visibility | Checks quota before changing |
|
|
| `lfs_threshold_bytes` | integer | Size threshold for LFS (bytes) | Min: 1,000,000 (1 MB), null = server default |
|
|
| `lfs_keep_versions` | integer | Number of LFS versions to keep | Min: 2, null = server default |
|
|
| `lfs_suffix_rules` | array[string] | File extensions to always use LFS | Must start with '.', null = no custom rules |
|
|
|
|
**Note:** All size values use **decimal units** (1 MB = 1,000,000 bytes, not 1,048,576).
|
|
|
|
**Authentication:** Required (write permission)
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Repository settings updated successfully"
|
|
}
|
|
```
|
|
|
|
**Error Responses:**
|
|
|
|
| Status | Description |
|
|
|--------|-------------|
|
|
| 400 | Invalid settings or quota exceeded |
|
|
| 403 | Not authorized |
|
|
| 404 | Repository not found |
|
|
|
|
**Example:**
|
|
|
|
```python
|
|
# Update repository visibility and LFS settings
|
|
response = requests.put(
|
|
"http://localhost:28080/api/models/myorg/mymodel/settings",
|
|
headers={"Authorization": "Bearer YOUR_TOKEN"},
|
|
json={
|
|
"private": False,
|
|
"lfs_threshold_bytes": 10000000, # 10 MB
|
|
"lfs_keep_versions": 10,
|
|
"lfs_suffix_rules": [".safetensors", ".bin", ".gguf"]
|
|
}
|
|
)
|
|
|
|
# Make repository private
|
|
response = requests.put(
|
|
"http://localhost:28080/api/models/myorg/mymodel/settings",
|
|
headers={"Authorization": "Bearer YOUR_TOKEN"},
|
|
json={"private": True}
|
|
)
|
|
|
|
# Reset LFS threshold to server default
|
|
response = requests.put(
|
|
"http://localhost:28080/api/models/myorg/mymodel/settings",
|
|
headers={"Authorization": "Bearer YOUR_TOKEN"},
|
|
json={"lfs_threshold_bytes": None}
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
### Get Repository LFS Settings
|
|
|
|
Get repository LFS configuration with both configured and effective values.
|
|
|
|
**Endpoint:** `GET /api/{repo_type}s/{namespace}/{name}/settings/lfs`
|
|
|
|
**Parameters:**
|
|
|
|
| Parameter | Type | Location | Required | Description |
|
|
|-----------|------|----------|----------|-------------|
|
|
| `repo_type` | string | path | Yes | Repository type: `model`, `dataset`, or `space` |
|
|
| `namespace` | string | path | Yes | Repository namespace |
|
|
| `name` | string | path | Yes | Repository name |
|
|
|
|
**Authentication:** Required (write permission)
|
|
|
|
**Response:**
|
|
|
|
```json
|
|
{
|
|
"lfs_threshold_bytes": 10000000,
|
|
"lfs_keep_versions": 10,
|
|
"lfs_suffix_rules": [".safetensors", ".bin"],
|
|
"lfs_threshold_bytes_effective": 10000000,
|
|
"lfs_threshold_bytes_source": "repository",
|
|
"lfs_keep_versions_effective": 10,
|
|
"lfs_keep_versions_source": "repository",
|
|
"lfs_suffix_rules_effective": [
|
|
".safetensors", ".bin", ".pt", ".pth", ".ckpt",
|
|
".onnx", ".pb", ".h5", ".tflite", ".gguf", ".ggml",
|
|
".msgpack", ".zip", ".tar", ".gz", ".bz2", ".xz",
|
|
".7z", ".rar", ".npy", ".npz", ".arrow", ".parquet",
|
|
".mp4", ".avi", ".mkv", ".mov", ".wav", ".mp3",
|
|
".flac", ".tiff", ".tif"
|
|
],
|
|
"lfs_suffix_rules_source": "merged",
|
|
"server_defaults": {
|
|
"lfs_threshold_bytes": 5000000,
|
|
"lfs_keep_versions": 5,
|
|
"lfs_suffix_rules_default": [
|
|
".safetensors", ".bin", ".pt", ".pth", ".ckpt",
|
|
".onnx", ".pb", ".h5", ".tflite", ".gguf", ".ggml",
|
|
".msgpack", ".zip", ".tar", ".gz", ".bz2", ".xz",
|
|
".7z", ".rar", ".npy", ".npz", ".arrow", ".parquet",
|
|
".mp4", ".avi", ".mkv", ".mov", ".wav", ".mp3",
|
|
".flac", ".tiff", ".tif"
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
**Field Descriptions:**
|
|
|
|
- **Configured values** (null = using server default):
|
|
- `lfs_threshold_bytes`: Repository-specific threshold
|
|
- `lfs_keep_versions`: Repository-specific keep versions
|
|
- `lfs_suffix_rules`: Repository-specific custom suffix rules
|
|
|
|
- **Effective values** (resolved with server defaults):
|
|
- `*_effective`: Actual values being used
|
|
- `*_source`: Where the value comes from (`repository` or `server_default` or `merged`)
|
|
|
|
- **Server defaults** (for reference):
|
|
- Global default values from configuration
|
|
- 32 built-in suffix rules for ML models, archives, and media files
|
|
|
|
**Important Notes:**
|
|
|
|
1. **Suffix rule merging**: Repository suffix rules are **ADDED TO** (not replacing) server defaults
|
|
2. **Server default suffixes**: Files with these extensions ALWAYS use LFS, even if size < threshold
|
|
3. **Size units**: All sizes use decimal units (1 MB = 1,000,000 bytes)
|
|
|
|
**Example:**
|
|
|
|
```python
|
|
response = requests.get(
|
|
"http://localhost:28080/api/models/myorg/mymodel/settings/lfs",
|
|
headers={"Authorization": "Bearer YOUR_TOKEN"}
|
|
)
|
|
lfs_settings = response.json()
|
|
|
|
print(f"Threshold: {lfs_settings['lfs_threshold_bytes_effective']} bytes")
|
|
print(f"Keep versions: {lfs_settings['lfs_keep_versions_effective']}")
|
|
print(f"Custom suffixes: {lfs_settings['lfs_suffix_rules']}")
|
|
print(f"Total suffixes (with defaults): {len(lfs_settings['lfs_suffix_rules_effective'])}")
|
|
```
|
|
|
|
---
|
|
|
|
## Server Default LFS Suffix Rules
|
|
|
|
KohakuHub includes **32 server-wide default suffix rules** that always use LFS:
|
|
|
|
**ML Model Formats (12):**
|
|
`.safetensors`, `.bin`, `.pt`, `.pth`, `.ckpt`, `.onnx`, `.pb`, `.h5`, `.tflite`, `.gguf`, `.ggml`, `.msgpack`
|
|
|
|
**Compressed Archives (9):**
|
|
`.zip`, `.tar`, `.gz`, `.bz2`, `.xz`, `.7z`, `.rar`
|
|
|
|
**Data Files (4):**
|
|
`.npy`, `.npz`, `.arrow`, `.parquet`
|
|
|
|
**Media Files (5):**
|
|
`.mp4`, `.avi`, `.mkv`, `.mov`, `.wav`, `.mp3`, `.flac`
|
|
|
|
**Large Images (2):**
|
|
`.tiff`, `.tif`
|
|
|
|
These rules apply to ALL repositories automatically. Repository-specific suffix rules ADD to these defaults.
|
|
|
|
---
|
|
|
|
## Usage Examples
|
|
|
|
### Complete User Profile Update
|
|
|
|
```python
|
|
import requests
|
|
|
|
BASE_URL = "http://localhost:28080"
|
|
TOKEN = "YOUR_TOKEN"
|
|
|
|
headers = {"Authorization": f"Bearer {TOKEN}"}
|
|
|
|
# Update profile
|
|
requests.put(
|
|
f"{BASE_URL}/api/users/alice/settings",
|
|
headers=headers,
|
|
json={
|
|
"full_name": "Alice Smith",
|
|
"bio": "ML Engineer specializing in NLP",
|
|
"website": "https://alice.example.com",
|
|
"social_media": {
|
|
"twitter_x": "alice_ml",
|
|
"github": "alice",
|
|
"huggingface": "alice"
|
|
}
|
|
}
|
|
)
|
|
|
|
# Upload avatar
|
|
with open("avatar.jpg", "rb") as f:
|
|
requests.post(
|
|
f"{BASE_URL}/api/users/alice/avatar",
|
|
headers=headers,
|
|
files={"file": f}
|
|
)
|
|
```
|
|
|
|
### Repository LFS Configuration
|
|
|
|
```python
|
|
# Configure repository to always use LFS for GGUF files
|
|
requests.put(
|
|
f"{BASE_URL}/api/models/myorg/mymodel/settings",
|
|
headers=headers,
|
|
json={
|
|
"lfs_threshold_bytes": 10000000, # 10 MB
|
|
"lfs_suffix_rules": [".gguf", ".ggml"] # Added to 32 server defaults
|
|
}
|
|
)
|
|
|
|
# Check effective settings
|
|
response = requests.get(
|
|
f"{BASE_URL}/api/models/myorg/mymodel/settings/lfs",
|
|
headers=headers
|
|
)
|
|
settings = response.json()
|
|
|
|
# All .safetensors files will use LFS (server default)
|
|
# All .gguf files will use LFS (custom rule)
|
|
# Files > 10 MB will use LFS (threshold)
|
|
```
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
- [Organization Management API](./organizations.md) - Create and manage organizations
|
|
- [Quota Management API](./quota.md) - Manage storage quotas
|
|
- [Repository API](../API.md#repositories) - Create and manage repositories
|
|
- [CLI Settings Commands](../CLI.md#settings) - Manage settings via CLI
|