Metadata-Version: 2.4
Name: moha-hub
Version: 2.0.0
Summary: Python SDK for XiaoShi AI Hub - Upload, download, and manage AI models and datasets with xpai-enc encryption support
Author-email: XiaoShi AI <support@xiaoshiai.cn>
Maintainer-email: XiaoShi AI Team <support@xiaoshiai.cn>
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/poxiaoyun/moha-sdk
Project-URL: Repository, https://github.com/poxiaoyun/moha-sdk
Project-URL: Issues, https://github.com/poxiaoyun/moha-sdk/issues
Keywords: xiaoshi,ai-hub,machine-learning,deep-learning,model-hub,dataset,encryption,xpai-enc,sdk,api-client,model-encryption
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
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: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.20.0
Requires-Dist: tqdm>=4.62.0
Requires-Dist: cryptography>=46.0.3
Requires-Dist: websocket-client>=1.6.0
Provides-Extra: upload
Requires-Dist: gitpython>=3.1.0; extra == "upload"
Provides-Extra: encryption
Provides-Extra: dev
Requires-Dist: pytest>=6.0; extra == "dev"
Requires-Dist: pytest-cov>=2.0; extra == "dev"
Requires-Dist: pytest-mock>=3.6.0; extra == "dev"
Requires-Dist: black>=22.0; extra == "dev"
Requires-Dist: flake8>=4.0; extra == "dev"
Requires-Dist: mypy>=0.950; extra == "dev"
Requires-Dist: isort>=5.10.0; extra == "dev"
Requires-Dist: build>=0.8.0; extra == "dev"
Requires-Dist: twine>=4.0.0; extra == "dev"
Requires-Dist: gitpython>=3.1.0; extra == "dev"
Provides-Extra: test
Requires-Dist: pytest>=6.0; extra == "test"
Requires-Dist: pytest-cov>=2.0; extra == "test"
Requires-Dist: pytest-mock>=3.6.0; extra == "test"
Provides-Extra: all
Requires-Dist: gitpython>=3.1.0; extra == "all"
Dynamic: license-file

# Moha Hub Python SDK

[![PyPI version](https://badge.fury.io/py/moha-hub.svg)](https://badge.fury.io/py/moha-hub)
[![Python Support](https://img.shields.io/pypi/pyversions/moha-hub.svg)](https://pypi.org/project/moha-hub/)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

Moha Hub Python SDK provides Python APIs and the `moha` CLI for working with Moha Hub repositories. It supports model, dataset, and Space repository management, upload/download workflows, token or username/password authentication, organization selection, and optional envelope encryption for large model files.

## Features

- Python APIs similar to common Hub SDK patterns.
- `moha` CLI for authentication, repository management, branch management, upload, download, Space operations, and AI assistant workflows.
- Token authentication and username/password authentication.
- Current organization selection through `moha organization use` or `moha org use`.
- ASCII table output for structured CLI command results.
- Single-file and snapshot downloads with include/exclude filters.
- File and folder uploads with optional encryption for large model files.
- Space creation, deploy, redeploy, status, and log streaming APIs.
- OpenAI-compatible AI assistant with function calling.
- Type hints for IDE support.

## Installation

Moha SDK requires Python 3.10 or later.

```bash
pip install moha-hub
```

Install upload extras when you need upload support:

```bash
pip install "moha-hub[upload]"
```

Install a branch directly from GitHub:

```bash
pip install "git+https://github.com/poxiaoyun/moha-sdk.git@<branch-name>"
```

Install the local checkout for testing:

```bash
pip install -e ".[dev,upload]"
```

Verify the CLI entry point:

```bash
moha -h
```

## Quick Start

### CLI

```bash
# Show the compact default banner and usage.
moha

# Show full help.
moha -h

# Show basic or detailed debug information (place -v before the command).
moha -v
moha -v list model
moha -vvv download demo/my-model

# Log in with a token.
moha login https://rune.develop.xiaoshiai.cn --token your-token

# Log in interactively.
moha login https://rune.develop.xiaoshiai.cn

# Select an organization for unqualified repository IDs.
moha organization use demo

# List organizations. The current organization is marked with '*'.
moha org list

# Create and inspect repositories.
moha create model my-model --description "My model"
moha info model my-model

# Upload a folder or a single file.
moha upload my-model ./my_model
moha ul my-model ./my_model
moha upload my-model ./config.yaml configs/config.yaml

# Download a repository snapshot or selected files.
moha download my-model
moha dl my-model
moha download my-model config.yaml tokenizer.json

# Deploy and inspect a Space.
moha deploy demo/my-space
moha status demo/my-space
moha logs demo/my-space
moha logs demo/my-space -f -c web
```

The login endpoint must include a URL scheme:

```bash
moha login https://rune.develop.xiaoshiai.cn
```

Do not pass a bare host such as `rune.develop.xiaoshiai.cn`. After login succeeds,
the endpoint is saved in `~/.moha/config.json`; all later CLI commands use that
saved endpoint, so `--endpoint` is not needed or accepted.

### Debug output

Use counted `-v` flags before the command:

- `-v` prints basic diagnostics: command, configured endpoint, authentication
  source, HTTP request/response summaries, and upload/download progress messages.
- `-vv` adds SDK debug context such as the current organization.
- `-vvv` adds detailed, redacted request metadata, response headers, runtime
  versions, and configuration paths.

Passwords, tokens, authorization headers, file contents, AI messages, and signed
URL credentials are redacted. Raw third-party wire logging stays disabled.

### Python API

```python
from xiaoshiai_hub import moha_hub_download, snapshot_download

file_path = moha_hub_download(
    repo_id="demo/my-model",
    filename="config.yaml",
    repo_type="models",
    token="your-token",
)
print(f"Downloaded to: {file_path}")

repo_path = snapshot_download(
    repo_id="demo/my-model",
    repo_type="models",
    allow_patterns=["*.yaml", "*.md"],
    ignore_patterns=[".git*", "*.log"],
    token="your-token",
)
print(f"Snapshot downloaded to: {repo_path}")
```

```python
from xiaoshiai_hub import upload_file, upload_folder

upload_file(
    path_file="./config.yaml",
    path_in_repo="config.yaml",
    repo_id="demo/my-model",
    repo_type="models",
    commit_message="Upload config file",
    token="your-token",
)

upload_folder(
    folder_path="./my_model",
    repo_id="demo/my-model",
    repo_type="models",
    commit_message="Upload model files",
    ignore_patterns=["*.log", ".git*"],
    token="your-token",
)
```

### HubClient

```python
import sys

from xiaoshiai_hub import HubClient

client = HubClient(token="your-token")

repos = client.list_repositories(
    repo_type="models",
    scope="organization",
    organization="demo",
)
for repo in repos:
    print(f"{repo.organization}/{repo.name} - {repo.description}")

client.create_repository(
    organization="demo",
    repo_type="models",
    repo_name="my-model",
    description="My model",
    visibility="internal",
    metadata={
        "license": ["apache-2.0"],
        "frameworks": ["transformers"],
    },
    base_model=["demo/base-llama"],
    relationship="finetune",
)

repo_info = client.get_repository_info("demo", "models", "my-model")
print(f"Repository: {repo_info.organization}/{repo_info.name}")

client.update_repository(
    organization="demo",
    repo_type="models",
    repo_name="my-model",
    description="Updated description",
)

refs = client.get_repository_refs("demo", "models", "my-model")
for ref in refs:
    print(f"Branch: {ref.name} (commit: {ref.hash[:8]})")
```

## Authentication

The SDK supports token authentication and username/password authentication.

Authentication precedence:

1. CLI arguments
2. Environment variables
3. Locally saved token

Useful environment variables:

```bash
export MOHA_TOKEN="your-token"
export MOHA_USERNAME="your-username"
export MOHA_PASSWORD="your-password"
export MOHA_ORGANIZATION="demo"
```

After `moha login <endpoint>`, the token is stored in `~/.moha/token.json` and the
endpoint is stored in `~/.moha/config.json`, both with user-only permissions. The
`MOHA_ENDPOINT` environment variable remains available as the default for direct
Python SDK calls, but the CLI uses the endpoint saved by login.

## Organizations

Use `organization` or the `org` alias:

```bash
moha organization list
moha organization list --mine
moha organization use demo

moha org list
moha org use demo
```

`organization list` fetches all accessible organizations and renders them in a table. The current organization is marked with `*`.

Current organization precedence:

1. `--organization`
2. `MOHA_ORGANIZATION`
3. Local config saved by `moha organization use`

Once selected, repository commands can omit the organization prefix:

```bash
moha organization use demo
moha create model my-model --description "My model"
moha upload my-model ./my_model
moha download my-model
```

## CLI Commands

Top-level commands are grouped by function in `moha -h`.

| Group | Command | Description |
| --- | --- | --- |
| Auth | `login` | Log in and save token |
| Auth | `logout` | Log out and delete saved token |
| Auth | `whoami` | Show current login status |
| Organization | `organization list` / `org l` | List organizations |
| Organization | `organization use` / `org u` | Select current organization |
| Repository | `list` / `l` | List repositories and images |
| Repository | `create` / `c` | Create repositories and images |
| Repository | `info` / `i` | Show repository and image information |
| Repository | `update` / `u` | Update repositories and images |
| Repository | `delete` / `del` | Delete repositories and images |
| Branch | `refs` | List repository refs |
| Branch | `branch-create` / `bc` | Create branch |
| Branch | `branch-delete` / `bd` | Delete branch |
| Branch | `branch-list` / `bl` | List branches |
| Transfer | `upload` / `ul` | Upload a file or folder |
| Transfer | `upload-file` | Upload one file |
| Transfer | `download` / `dl` | Download a snapshot or selected files |
| Transfer | `download-file` | Download one file |
| Space | `deploy` | Deploy Space |
| Space | `redeploy` | Redeploy Space |
| Space | `status` | Show Space status |
| Space | `logs` | Show Space logs |
| AI | `ai` | Start the AI assistant |
| AI | `ai-config` | Configure the AI assistant |
| Legacy | `repo-list` | List repositories |
| Legacy | `repo-create` | Create repository |
| Legacy | `repo-info` | Show repository information |
| Legacy | `repo-update` | Update repository |
| Legacy | `repo-delete` | Delete repository |
| Legacy | `space-deploy` | Deploy Space |
| Legacy | `space-redeploy` | Redeploy Space |
| Legacy | `space-status` | Show Space status |

Legacy command names remain available and are listed after the primary commands.

Structured CLI results use ASCII tables. Interactive prompts, errors, progress bars, and AI assistant natural-language responses remain plain terminal text.

## Repository Commands

`moha list` shows resource-specific help. The list scope defaults to `all`.
`moha create` and `moha info` also use resource-specific subcommands.
`moha update` and `moha delete` use the same resource-specific structure.
Destructive commands prompt for `--yes-i-really-mean-that`; pass `--force` to skip the prompt.
Image list output includes the full repository path and tag count. Image info output includes supported architectures when tag metadata is available.
Model list output includes encryption type. Encrypted models show a lock emoji plus the encryption algorithm; unencrypted models show `-`.
Space list output includes emoji runtime status after the repository type column.
Space logs use the Space pod log WebSocket proxy. If a pod has multiple containers, pass `--container` / `-c` with the container name. Use `--follow` / `-f` to stream logs in real time.
Short resource aliases are also available: `model` / `m`, `dataset` / `ds`, `image` / `img`, and `space` / `s`.

```bash
moha list model
moha l m
moha list models --scope all
moha list dataset --scope create
moha list image --scope favorite
moha list space --scope organization --organization demo
moha list model --mine --organization demo

moha create model demo/my-model --description "My model" --visibility internal
moha c m demo/my-model --description "My model"
moha create dataset demo/my-dataset --description "My dataset"
moha create image demo/runtime --repo registry.example/demo/runtime --visibility internal
moha create space demo/my-space --description "My Space"
moha info model demo/my-model
moha i img demo/runtime
moha info image demo/runtime
moha update model demo/my-model --description "Updated description"
moha update image demo/runtime --description "Updated image"
moha delete model demo/my-model
moha del img demo/runtime --force
```

## Branch Commands

```bash
moha refs demo/my-model
moha branch-list demo/my-model
moha bl demo/my-model
moha branch-create demo/my-model dev --from main
moha bc demo/my-model dev --from main
moha branch-delete demo/my-model dev
moha bd demo/my-model dev --force
```

## Upload and Download

```bash
moha upload demo/my-model ./my_model
moha ul demo/my-model ./my_model
moha upload demo/my-model ./my_model artifacts
moha upload demo/my-model ./config.yaml configs/config.yaml

moha upload demo/my-model ./my_model \
  --revision main \
  --message "Upload model files" \
  --ignore "*.log" \
  --exclude ".git*"

moha upload demo/my-model ./model.safetensors \
  --encrypt \
  --encryption-password "your-secure-password"

moha download demo/my-model
moha dl demo/my-model
moha download demo/my-model config.yaml tokenizer.json
moha download demo/my-model --include "*.json" --exclude "*.log" --local-dir ./downloads
```

The legacy upload order is still accepted:

```bash
moha upload ./my_model demo/my-model
```

## Encryption

Large model files can be encrypted during upload.

Supported algorithms:

| Algorithm | Description |
| --- | --- |
| `AES` | AES-256-CTR, default |
| `SM4` | SM4-CTR |

Automatic encryption applies only when:

1. File size is at least 5 MB.
2. File extension is one of the supported model file extensions, such as `.safetensors`, `.bin`, `.pt`, `.pth`, or `.ckpt`.

Small files and non-model files remain readable.

```python
from xiaoshiai_hub import upload_file

upload_file(
    path_file="./model.safetensors",
    path_in_repo="model.safetensors",
    repo_id="demo/my-model",
    repo_type="models",
    encryption_password="your-secure-password",
    algorithm="AES",
    token="your-token",
)
```

## Spaces

```python
from xiaoshiai_hub import HubClient

client = HubClient(token="your-token")

clusters = client.list_clusters("demo")
workspaces = client.list_cluster_workspaces("demo", clusters[0].id)
flavors = client.list_workspace_flavors("demo", clusters[0].id, workspaces[0].id)
products = client.list_products("demo")

client.create_space_repository(
    organization="demo",
    repo_name="my-gradio-app",
    cluster=clusters[0].id,
    namespace=workspaces[0].id,
    product_id="gradio",
    product_version="latest",
    visibility="internal",
    flavor=flavors[0].id if flavors else None,
    env=[{"name": "MODEL_NAME", "value": "llama-7b"}],
    description="My Gradio app",
)

client.deploy_space("demo", "my-gradio-app")
status = client.get_space_status("demo", "my-gradio-app")
print(f"Status: {status.phase}, healthy: {status.healthy}")

pods = client.list_space_pods("demo", "my-gradio-app")
pod_name = pods[0]["metadata"]["name"]
client.stream_space_logs(
    "demo",
    "my-gradio-app",
    pod=pod_name,
    container="web",
    follow=True,
    on_message=sys.stdout.write,
)
```

## AI Assistant

Configure an OpenAI-compatible Chat Completion API:

```bash
moha ai-config
moha ai-config --api-base https://api.deepseek.com --api-key your-api-key --model deepseek-chat
moha ai-config --show
```

Or use environment variables:

```bash
export MOHA_AI_API_BASE="https://api.deepseek.com"
export MOHA_AI_API_KEY="your-api-key"
export MOHA_AI_MODEL="deepseek-chat"
```

Start interactive mode or run a one-shot prompt:

```bash
moha ai
moha ai --model deepseek-chat
moha ai --no-stream
moha ai --prompt "List model repositories I created."
```

The assistant can list and inspect repositories, create and update repositories, manage branches, inspect files, create or update text files, upload/download content, and inspect Space status. Destructive operations such as deleting repositories, branches, or files are not executed by the assistant; use the corresponding CLI command and confirm in the terminal.

## Development

```bash
git clone https://github.com/poxiaoyun/moha-sdk.git
cd moha-sdk
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev,upload]"
```

Run available checks:

```bash
python -m compileall xiaoshiai_hub tests
python -m pytest tests/test_regressions.py
```

## API Reference

Top-level functions:

| Function | Description |
| --- | --- |
| `moha_hub_download()` | Download one file from a repository |
| `snapshot_download()` | Download a full repository snapshot |
| `upload_file()` | Upload one file to a repository |
| `upload_folder()` | Upload a folder to a repository |
| `login()` | Log in and save token |
| `save_token()` / `load_token()` / `delete_token()` | Token management |
| `save_endpoint()` / `load_endpoint()` | CLI endpoint config |
| `save_current_organization()` / `load_current_organization()` | Current organization config |
| `envelope_enc_file()` | Encrypt a file with envelope encryption |

`HubClient` methods:

| Method | Description |
| --- | --- |
| `list_organizations()` | List organizations |
| `get_organization()` | Get organization information |
| `list_repositories()` | List repositories |
| `list_images()` | List container images |
| `create_repository()` | Create repository |
| `create_image()` | Create container image |
| `get_repository_info()` | Get repository information |
| `update_repository()` | Update repository information |
| `get_image()` | Get container image information |
| `update_image()` | Update container image information |
| `delete_repository()` | Delete repository |
| `delete_image()` | Delete container image |
| `get_repository_refs()` | List repository refs |
| `get_default_branch()` | Get the default branch name |
| `create_branch()` | Create branch |
| `delete_branch()` | Delete branch |
| `get_repository_content()` | Browse repository content |
| `create_file()` | Create or update a repository file |
| `delete_file()` | Delete a repository file |
| `download_file()` | Download one file |
| `create_space_repository()` | Create Space repository |
| `deploy_space()` | Deploy Space |
| `redeploy_space()` | Redeploy Space |
| `get_space_status()` | Get Space status |
| `list_space_pods()` | List Space pods |
| `stream_space_logs()` | Stream Space logs |
| `list_clusters()` | List available clusters |
| `list_cluster_workspaces()` | List workspaces under a cluster |
| `list_workspace_flavors()` | List workspace flavors |
| `list_products()` | List product templates |
| `get_product()` | Get product details |
| `set_repository_encrypted()` | Set repository encryption flag |
| `cancel_repository_encrypted()` | Cancel repository encryption flag |
| `generate_data_key()` | Generate a data key through KMS |

Exception types:

| Exception | Description |
| --- | --- |
| `HubException` | Base exception for Hub errors |
| `RepositoryNotFoundError` | Repository was not found |
| `FileNotFoundError` | File was not found in a repository |
| `AuthenticationError` | Authentication failed |
| `HTTPError` | HTTP request failed |
| `UploadError` | Upload failed |

## License

Apache License 2.0. See [LICENSE](LICENSE).
