Metadata-Version: 2.5
Name: modelwharf
Version: 0.1.0
Summary: Store local and ModelScope models in MinIO
Project-URL: Homepage, https://github.com/linwenqi1/modelwharf
Project-URL: Repository, https://github.com/linwenqi1/modelwharf
Project-URL: Issues, https://github.com/linwenqi1/modelwharf/issues
Author-email: Wenqi Lin <linwenqi05@outlook.com>
License: MIT
License-File: LICENSE
Keywords: minio,model,modelscope,storage
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.10
Requires-Dist: minio<8,>=7.2
Requires-Dist: typer<1,>=0.12
Provides-Extra: build
Requires-Dist: modelscope>=1.18; extra == 'build'
Requires-Dist: pyinstaller<7,>=6; extra == 'build'
Provides-Extra: dev
Requires-Dist: pytest<9,>=8; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: modelscope
Requires-Dist: modelscope>=1.18; extra == 'modelscope'
Description-Content-Type: text/markdown

# ModelWharf

ModelWharf 是一个独立的模型存储管理工具，将本地模型目录或 ModelScope 模型快照上传到 MinIO，并用 manifest 描述每个不可混淆的模型版本。

## 功能

- `modelwharf upload`：上传本地模型目录
- `modelwharf pull`：下载 ModelScope 快照并上传
- `modelwharf list`：列出已完整上传的模型版本
- `modelwharf info`：读取并展示 manifest
- `modelwharf delete`：删除 MinIO 模型版本，不操作本地缓存
- `modelwharf clean-temp`：清理遗留临时下载，不操作持久缓存
- 为每个文件记录相对路径、大小和 SHA-256
- 业务逻辑、模型来源和对象存储相互解耦

对象路径固定为：

```text
models/<name>/<version>/.modelwharf/manifest.json
models/<name>/<version>/<model files...>
```

`.modelwharf/` 是 ModelWharf 的保留命名空间。模型根目录中原有的
`manifest.json` 会作为普通模型文件原样保存，不会与 ModelWharf 元数据冲突；为避免覆盖，待上传模型自身不能包含 `.modelwharf/` 下的文件。

## 安装

Python 3.10 或更新版本：

```bash
pip install .
```

需要从 ModelScope 拉取模型时：

```bash
pip install '.[modelscope]'
```

## 配置

```bash
export MINIO_ENDPOINT=localhost:9000
export MINIO_ACCESS_KEY=minioadmin
export MINIO_SECRET_KEY=minioadmin
export MINIO_SECURE=false
export MODELWHARF_BUCKET=models
export MODELWHARF_CACHE=~/.cache/modelwharf
```

除密钥外均有上述默认值。生产环境应显式设置凭据，不要把密钥提交到仓库。

ModelScope 下载缓存按来源模型和 revision 使用其原生目录结构管理，不使用 MinIO
中的 `name/version` 作为缓存键。因此，同一个来源发布成不同的 ModelWharf 名称时可以
复用下载缓存，不同来源也不会因为目标名称相同而混用缓存。

## 使用

### 命令行

```bash
modelwharf upload ./Qwen3-0.6B --name qwen3-0.6b --version v1

modelwharf pull Qwen/Qwen3-0.6B \
  --name qwen3-0.6b \
  --version v1 \
  --revision master

# 完全绕过持久缓存，上传结束后删除临时下载
modelwharf pull Qwen/Qwen3-0.6B \
  --name qwen3-0.6b \
  --version v2 \
  --no-cache

modelwharf list
modelwharf info qwen3-0.6b:v1

# 删除 MinIO 模型版本，需要确认；自动化脚本可使用 --yes
modelwharf delete qwen3-0.6b:v1

# 删除超过 24 小时且没有活动进程的临时目录
modelwharf clean-temp

# 包含最近产生但已无活动进程的临时目录，并跳过确认
modelwharf clean-temp --all --yes
```

### Python SDK

CLI 和 SDK 共用同一套业务逻辑。可以直接使用显式配置创建客户端：

```python
from modelwharf import ModelWharf

client = ModelWharf(
    endpoint="localhost:9000",
    access_key="minioadmin",
    secret_key="minioadmin",
    bucket="models",
)

manifest = client.upload(
    "./Qwen3-0.6B",
    name="qwen3-0.6b",
    version="v1",
)

manifest = client.pull(
    "Qwen/Qwen3-0.6B",
    version="v2",
    revision="master",
)

references = client.list()
manifest = client.info("qwen3-0.6b:v1")
deleted_objects = client.delete("qwen3-0.6b:v1")
```

也可以读取与 CLI 相同的环境变量：

```python
from modelwharf import ModelWharf

client = ModelWharf.from_env()
```

SDK 不打印消息、不请求删除确认，也不会将错误转换成进程退出码。调用方可以捕获
`ModelWharfError` 或更具体的 `ModelNotFoundError`、`ModelAlreadyExistsError`。
如需注入自定义对象存储或模型来源实现，可使用 `ModelWharf.from_components(...)`。

如果 `pull` 省略 `--name`，ModelWharf 会使用 model ID 最后一段的小写形式。

模型版本默认不可变。若 `<name>:<version>` 的 `.modelwharf/manifest.json` 已存在，
`upload` 和 `pull` 会在写入任何对象前报错：

```text
Error: model already exists: qwen3-0.6b:v1
```

需要发布修改后的模型时，请使用新的 version。

`delete` 只操作配置的 MinIO bucket，不删除或修改本地 ModelScope 缓存。删除范围
严格限定为 `<name>/<version>/`，模型文件先删除，`.modelwharf/manifest.json`
最后删除，以便中途失败后可以重试。启用 MinIO bucket versioning 时，该命令创建
删除标记，历史 object version 仍由 MinIO 的版本和生命周期策略管理。

`pull` 默认使用 ModelScope 的正常缓存和完整性检查。`--no-cache` 表示既不读取
持久缓存，也不写入持久缓存；模型会下载到系统临时目录，并在上传成功、失败或中断后
自动删除。大型模型需要确保系统临时目录有足够空间；可通过操作系统的 `TMPDIR`
环境变量选择临时磁盘。

`clean-temp` 只检查系统临时目录下直接以 `modelwharf-` 开头的目录，跳过带有活动
进程标记的下载。默认仅清理超过 24 小时的残留；`--all` 会包含最近的非活动目录。
该命令不会连接 MinIO，也不会访问 `MODELWHARF_CACHE`。

## 开发与测试

```bash
pip install -e '.[dev,modelscope]'
pytest
ruff check .
```

## 构建单文件程序

在每个目标操作系统和 CPU 架构上分别构建：

```bash
pip install '.[build]'
pyinstaller --onefile --name modelwharf \
  --collect-all modelscope \
  modelwharf/__main__.py
```

产物位于 `dist/modelwharf`。PyInstaller 不是跨平台编译器，因此 Linux amd64、Linux arm64、Windows amd64 和 macOS arm64 需要各自在对应环境构建。ModelScope 的依赖和模型格式可能随版本变化，发布前应在干净机器上验证 `upload`、`pull`、`list` 和 `info`。

## 架构

```text
CLI ─┐
     ├──> ModelWharf SDK ──> ModelWharfService ──> MinioStorage ──> MinIO
代码 ─┘                              ^
                                     |
                            ModelScopeProvider
```

CLI 只解析输入和展示结果，并与 Python 代码共用公开 SDK；下载、manifest 生成和上传编排均位于核心服务中。以后可以在不改写业务逻辑的情况下增加 FastAPI、Web UI、Hugging Face provider 或其他 S3 存储实现。
