Metadata-Version: 2.4
Name: huace-aigc-oss-proxy-client
Version: 0.1.20
Summary: 华策 AIGC OSS Proxy Client - 统一 RustFS / 阿里云 OSS / 七牛云上传，支持内网/公网默认上传网络
Author-email: Huace <support@huace.com>
License: MIT
Project-URL: Homepage, https://github.com/huace/huace-aigc-oss-proxy-client
Project-URL: Repository, https://github.com/huace/huace-aigc-oss-proxy-client
Keywords: aigc,oss,huace,sdk,rustfs,aliyun,s3
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Provides-Extra: aliyun
Requires-Dist: oss2>=2.18.0; extra == "aliyun"
Provides-Extra: rustfs
Requires-Dist: boto3>=1.34.0; extra == "rustfs"
Provides-Extra: qiniu
Requires-Dist: qiniu>=7.12.0; extra == "qiniu"
Requires-Dist: requests>=2.20.0; extra == "qiniu"
Provides-Extra: all
Requires-Dist: oss2>=2.18.0; extra == "all"
Requires-Dist: boto3>=1.34.0; extra == "all"
Requires-Dist: qiniu>=7.12.0; extra == "all"
Requires-Dist: requests>=2.20.0; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-env>=1.0.0; extra == "dev"
Requires-Dist: moto[s3]>=5.0.0; extra == "dev"
Requires-Dist: build>=1.0.0; extra == "dev"
Requires-Dist: twine>=5.0.0; extra == "dev"

# AIGC OSS Proxy Python SDK

[![Python Version](https://img.shields.io/pypi/pyversions/huace-aigc-oss-proxy-client.svg)](https://pypi.org/project/huace-aigc-oss-proxy-client/)

华策 AIGC 插件对象存储上传 SDK，支持内网 RustFS 与公网（阿里云 OSS / 七牛云）。

**Python 版本**：`>= 3.10`

## 安装

```bash
# 全量（RustFS + 阿里云 + 七牛）
pip install huace-aigc-oss-proxy-client[all]

# 按需安装
pip install huace-aigc-oss-proxy-client[aliyun]   # 仅阿里云
pip install huace-aigc-oss-proxy-client[rustfs]   # 仅 RustFS
pip install huace-aigc-oss-proxy-client[qiniu]    # 仅七牛
```

## 快速开始

### 1. 配置环境变量

复制 [env.example](./env.example) 为 `.env`，填入 AK/SK、Bucket 等。变量名统一前缀 `HUACE_AIGC_`。

```bash
cp env.example .env
```

### 2. 上传文件

```python
from huace_aigc_oss import OssProxy

proxy = OssProxy.from_env()

# 上传到内网
result = proxy.upload("/tmp/output.wav", "output.wav", route="local")
print(result.url)   # 内网访问地址
print(result.key)   # 对象 key

# 上传到公网
result = proxy.upload("/tmp/output.wav", "output.wav", route="public")
print(result.url)   # 公网访问地址

# 不指定 route，走环境变量 HUACE_AIGC_OSS_DEFAULT_UPLOAD_ROUTE
result = proxy.upload("/tmp/output.wav", "output.wav")
print(result.url)
```

**参数说明**

| 参数 | 说明 |
|------|------|
| 第 1 个参数 | 本地文件路径 |
| `download_name` | 下载时显示的文件名（必填） |
| `route` | `local`（内网）或 `public`（公网）；可省略，见下方环境变量 |

省略 `route` 时，使用环境变量 `HUACE_AIGC_OSS_DEFAULT_UPLOAD_ROUTE` 的值。

## 内网转公网

将内网 RustFS 链接转为阿里云公网链接；若传入的已是公网链接，则原样返回。

```python
from huace_aigc_oss import OssProxy

proxy = OssProxy.from_env()

public_url = proxy.local_to_public_url(
    "http://oss.aigc-transdubbing.huacemedia.com/huace-shortmovie/tmp/abc.mp4"
)
print(public_url)
```

**前提**：`HUACE_AIGC_OSS_ALIYUN_ENABLED=true`，且阿里云凭证已配置。

## 环境变量

`OssProxy.from_env()` / `OssClient.from_env()` 从进程环境读取配置。变量名统一前缀 **`HUACE_AIGC_`**。完整模板见 [env.example](./env.example)。

### 上传网络

| 变量 | 字段含义 | 是否必填 | 默认值 |
|------|----------|----------|--------|
| `HUACE_AIGC_OSS_DEFAULT_UPLOAD_ROUTE` | `upload()` 未传 `route` 时的默认上传网络；代码里传了 `route=` 则以代码为准 | 与代码 `route` 至少填一处 | 无 |
| `HUACE_AIGC_OSS_ALIYUN_ENABLED` | 是否启用阿里云 OSS 作为公网后端 | 否 | `true` |
| `HUACE_AIGC_OSS_QINIU_ENABLED` | 是否启用七牛云作为公网后端 | 否 | `false` |

**`HUACE_AIGC_OSS_DEFAULT_UPLOAD_ROUTE` 取值**

- `local` — 上传到内网 RustFS
- `public` — 上传到公网；具体厂商由上方 `ALIYUN_ENABLED` / `QINIU_ENABLED` 决定，二者均启用时优先阿里云

**公网后端选择规则**（`route=public` 时生效，无需单独配置 provider 变量）

- 仅 `ALIYUN_ENABLED=true` → 阿里云 OSS
- 仅 `QINIU_ENABLED=true` → 七牛云
- 二者均为 `true` → 优先阿里云
- 二者均为 `false` → 公网上传报错

### RustFS（内网）

| 变量 | 字段含义 | 是否必填 | 默认值 |
|------|----------|----------|--------|
| `HUACE_AIGC_OSS_RUSTFS_ENDPOINT` | RustFS 服务端点（含协议，不含端口则走默认 80） | 否 | `http://oss.aigc-transdubbing.huacemedia.com` |
| `HUACE_AIGC_OSS_RUSTFS_ACCESS_KEY` | RustFS 访问 Access Key | 是 | 无 |
| `HUACE_AIGC_OSS_RUSTFS_SECRET_KEY` | RustFS 访问 Secret Key | 是 | 无 |
| `HUACE_AIGC_OSS_RUSTFS_BUCKET` | RustFS 桶名 | 是 | 无 |
| `HUACE_AIGC_OSS_RUSTFS_KEY_PREFIX` | 上传对象 key 前缀，最终 key 为 `{prefix}/{sha256}{ext}` | 否 | `tmp` |

### 阿里云 OSS（公网）

| 变量 | 字段含义 | 是否必填 | 默认值 |
|------|----------|----------|--------|
| `HUACE_AIGC_OSS_ALIYUN_ENABLED` | 是否启用阿里云后端（见上方公网选择规则） | 否 | `true` |
| `HUACE_AIGC_OSS_ALIYUN_ACCESS_KEY_ID` | 阿里云 AccessKey ID | 启用时必填 | 无 |
| `HUACE_AIGC_OSS_ALIYUN_ACCESS_KEY_SECRET` | 阿里云 AccessKey Secret | 启用时必填 | 无 |
| `HUACE_AIGC_OSS_ALIYUN_BUCKET` | 阿里云 Bucket 名称 | 启用时必填 | 无 |
| `HUACE_AIGC_OSS_ALIYUN_KEY_PREFIX` | 上传对象 key 前缀 | 否 | `tmp` |

### 七牛云（公网，可选）

| 变量 | 字段含义 | 是否必填 | 默认值 |
|------|----------|----------|--------|
| `HUACE_AIGC_OSS_QINIU_ENABLED` | 是否启用七牛后端（见上方公网选择规则） | 否 | `false` |
| `HUACE_AIGC_OSS_QINIU_ACCESS_KEY` | 七牛 Access Key | 启用时必填 | 无 |
| `HUACE_AIGC_OSS_QINIU_SECRET_KEY` | 七牛 Secret Key | 启用时必填 | 无 |
| `HUACE_AIGC_OSS_QINIU_BUCKET` | 七牛存储空间名 | 启用时必填 | 无 |
| `HUACE_AIGC_OSS_QINIU_DOMAIN` | 七牛绑定的访问域名（用于生成公网 URL） | 启用时必填 | 无 |
| `HUACE_AIGC_OSS_QINIU_KEY_PREFIX` | 上传对象 key 前缀 | 否 | `tmp` |

## Docker 部署

容器内需能解析内网 OSS 域名，添加 `extra_hosts`：

```yaml
extra_hosts:
  - "oss.aigc-transdubbing.huacemedia.com:192.168.1.18"
```

## 示例项目

更多命令行示例见 [example/](./example/) 目录：

```bash
cd example
cp .env.example .env   # 填入凭证
pip install -r requirements.txt
python upload_file.py "assert/2.mp4" "2.mp4" --route public
```

## 迁移阿里云 OSS → 华策 OSS 代理 SDK

> SDK 发布地址：https://pypi.org/project/huace-aigc-oss-proxy-client/
> 
> **执行迁移前必须先访问该页面阅读 SDK README，了解 `OssProxy.from_env()` 和 `proxy.upload()` 的接口细节。**

## 目标

将项目从直接调用阿里云 OSS (`oss2`) 切换为华策 OSS 代理 SDK
(`huace-aigc-oss-proxy-client`)，实现内网 RustFS + 公网阿里云双路由上传。

上传默认走内网 RustFS（`HUACE_AIGC_OSS_DEFAULT_UPLOAD_ROUTE=local`），
公网阿里云作为备选和 URL 转换通道。

容器需解析内网 OSS 域名：`oss.aigc-transdubbing.huacemedia.com` → `192.168.1.18`。

## 改动范围和目标

### 1. requirements.txt

- **目标**：删除所有 `oss2` 依赖，替换为 `huace-aigc-oss-proxy-client[all]>=0.1.11`
- **涉及文件**：项目中所有 `requirements*.txt`

### 2. 环境变量文件

- **目标**：删除旧的阿里云 OSS 凭据变量，替换为 `HUACE_AIGC_*` 前缀的新变量
- **涉及文件**：`.env`、`.env.prod`、`.env.test`、`.env.local`（含 `docker/` 目录下的）

需要删除的旧变量：
- `OSS_ACCESS_KEY_ID`、`OSS_ACCESS_KEY_SECRET`
- `OSS_ENDPOINT`、`OSS_BUCKET_NAME`
- `OSS_REGION`、`OSS_URL_EXPIRE`、`OSS_SIGN_URL`、`OSS_CUSTOM_DOMAIN`
- `OSS_KEY_PREFIX`、`OSS_NAME_PREFIX`、`OSS_PREFIX`

需要新增的新变量：
| 变量 | 值 |
|------|-----|
| `HUACE_AIGC_OSS_DEFAULT_UPLOAD_ROUTE` | `local` |
| `HUACE_AIGC_OSS_RUSTFS_ACCESS_KEY` | `<RustFS AK>` |
| `HUACE_AIGC_OSS_RUSTFS_SECRET_KEY` | `<RustFS SK>` |
| `HUACE_AIGC_OSS_RUSTFS_BUCKET` | `<bucket>` |
| `HUACE_AIGC_OSS_RUSTFS_KEY_PREFIX` | `tmp/<项目名>` |
| `HUACE_AIGC_OSS_RUSTFS_ENDPOINT` | `http://oss.aigc-transdubbing.huacemedia.com` |
| `HUACE_AIGC_OSS_ALIYUN_ENABLED` | `true` |
| `HUACE_AIGC_OSS_ALIYUN_ACCESS_KEY_ID` | `<Aliyun AK>` |
| `HUACE_AIGC_OSS_ALIYUN_ACCESS_KEY_SECRET` | `<Aliyun SK>` |
| `HUACE_AIGC_OSS_ALIYUN_BUCKET` | `<bucket>` |
| `HUACE_AIGC_OSS_ALIYUN_KEY_PREFIX` | `tmp/<项目名>` |

每个项目使用独立的前缀，格式 `tmp/<项目名>`，如 `tmp/voiceprint`、`tmp/tts-indextts`。

需要保留的变量（不是 SDK 凭据，是业务逻辑变量，不要删除）：
- `OSS_OUTPUT_PREFIX`、`OSS_DELETE_LOCAL_AFTER_UPLOAD`、`OSS_UPLOAD_RETRIES`
- 仅用于构造文件路径/healthcheck key 的 `OSS_NAME_PREFIX`

### 3. Python OSS 服务代码

- **目标**：所有直接使用 `oss2` 的 Python 文件，内部实现替换为 `OssProxy.from_env()`
- **约束**：保持原有函数名、类名、参数签名不变（调用方无需修改）
- **涉及模式**：
  - 模块级函数（惰性初始化全局实例）
  - 类封装（构造时初始化，方法中调用）
  - 带 task_id 的上传（文件路径或 bytes 输入，返回 `{"url": ..., "oss_key": ...}`）

新 SDK 与旧 SDK 的关键差异：
- 不需要 `oss2.Auth` / `oss2.Bucket`，用 `OssProxy.from_env()` 从环境变量读取
- Key 由 SHA256 自动生成，无法手动指定；`object_key` 参数降级为 `download_name`
- URL 由 `result.url` 直接返回，不需要手动拼接
- 不支持签名 URL（代理统一管理），`sign_url` 参数保留但忽略
- 不需要 `HAS_OSS2` 标志位（新 SDK 始终可用）
- `download_file` 改为 HTTP 下载（新 SDK 不暴露 `bucket.get_object_to_file`）
- `generate_url` / `generate_signed_url` / `public_url` 等不再需要，可标记为废弃

### 4. config.py

- **目标**：删除 `OSS_ACCESS_KEY_*`、`OSS_ENDPOINT`、`OSS_BUCKET_NAME`、`OSS_REGION`、`OSS_URL_EXPIRE`、`OSS_SIGN_URL`、`OSS_CUSTOM_DOMAIN` 的 `os.environ.get` 读取
- **目标**：删除未被调用的辅助函数（如 `oss_endpoint_host()`）
- **保留**：业务逻辑变量（`OSS_OUTPUT_PREFIX` 等）

### 5. 调用方代码

- **目标**：清理已删除 config 变量的 import；清理 `app_celery.py` 中对 `OSS_ENDPOINT`/`OSS_BUCKET_NAME` 的读取
- **目标**：如有日志消息引用旧变量名，更新为 `HUACE_AIGC_*`
- **目标**：返回值中 `bucket`/`endpoint` 字段无法再提供，设为空字符串

### 6. Docker Compose

- **目标**：所有 `docker-compose*.yml` 文件的每个 service 添加 `extra_hosts`
- **内容**：`- "oss.aigc-transdubbing.huacemedia.com:192.168.1.18"`
- **插入位置**：`restart:` 行之后，与 `restart:` 同级缩进
- **缩进要求**：必须根据每个文件现有的 service key 缩进风格来设置，不能硬编码（2 空格/4 空格/8 空格项目均存在）
- **network_mode: host** 的 service 也照加（保持一致性）
- **已存在**该域名的文件跳过

## 验证标准

全部改动完成后，以下 grep 应无输出（或仅剩项目特有变量）：

```bash
# import oss2 全部清除
grep -rn "import oss2\|from oss2" --include="*.py" . | grep -v .venv | grep -v __pycache__

# .env 旧凭据全部替换
grep -rn "OSS_ACCESS_KEY_ID\|OSS_ACCESS_KEY_SECRET\|OSS_ENDPOINT\|OSS_BUCKET_NAME=" --include=".env*" . | grep -v .venv

# requirements 无 oss2
grep -rn "oss2" --include="requirements*.txt" . | grep -v .venv

# config.py 旧 OSS 变量全部删除
grep -rn "OSS_ACCESS_KEY_ID\|OSS_ENDPOINT\|OSS_BUCKET_NAME\|OSS_REGION\|OSS_URL_EXPIRE\|OSS_SIGN_URL\|OSS_CUSTOM_DOMAIN" --include="config.py" . | grep -v .venv

# docker-compose 每个 service 都有 extra_hosts
grep -A1 "extra_hosts:" **/docker-compose*.yml | grep "oss.aigc-transdubbing"
```

## 常见遗漏

1. `docker/` 子目录下的 `.env.prod` / `.env.test` 文件
2. `app_celery.py` 等非 OSS 服务文件中的环境变量读取
3. 多 service 的 docker-compose 文件漏加某些 service
4. 不同缩进风格的 docker-compose 硬编码导致结构损坏
5. 项目特有业务变量被误删（`OSS_OUTPUT_PREFIX` 等）
6. 调用方残留已删除变量的 import
