Metadata-Version: 2.2
Name: large-file-upload-sdk
Version: 3.1.1
Summary: Large File Upload SDK - Support chunked upload, resumable transfer, and Token authentication
Home-page: https://github.com/your-username/file-upload-server
Author: SAIS Development Team
Author-email: SAIS Development Team <dev@sais.com.cn>
License: MIT
Project-URL: Homepage, https://github.com/your-username/file-upload-server
Project-URL: Documentation, https://github.com/your-username/file-upload-server#readme
Project-URL: Repository, https://github.com/your-username/file-upload-server
Project-URL: Bug Reports, https://github.com/your-username/file-upload-server/issues
Keywords: file upload,large file,chunked upload,resumable upload,file transfer,token authentication
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Archiving
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
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
Requires-Python: >=3.7
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.25.0
Requires-Dist: urllib3>=1.26.0
Requires-Dist: oss2>=2.18.0
Provides-Extra: dev
Requires-Dist: pytest>=6.0; extra == "dev"
Requires-Dist: pytest-cov>=2.0; extra == "dev"
Requires-Dist: black>=21.0; extra == "dev"
Requires-Dist: flake8>=3.8; extra == "dev"
Dynamic: author
Dynamic: home-page
Dynamic: requires-python

# File Upload Server

星河启智二期用于上传大文件的服务器 - 基于 FastAPI 构建，支持分片上传和断点续传

## 功能特性

- ✅ **分片上传**: 支持大文件分片上传，提高上传成功率
- ✅ **断点续传**: 网络中断后可继续上传，无需重新开始
- ✅ **MD5校验**: 可选的文件和分片MD5校验，确保数据完整性
- ✅ **并发控制**: 支持多文件并发上传
- ✅ **自动清理**: 自动清理过期的临时文件
- ✅ **Token认证**: 类似HuggingFace的Token认证机制，安全便捷
- ✅ **权限控制**: 支持用户角色和数据集访问权限管理
- ✅ **使用限制**: 支持文件大小和每日上传次数限制
- ✅ **上传记录**: 自动保存上传记录到数据库，支持查询和统计
- ✅ **RESTful API**: 提供完整的REST API接口
- ✅ **在线文档**: 自动生成的API文档
- ✅ **Docker支持**: 支持容器化部署

## 技术栈

- **后端框架**: FastAPI 0.104+
- **异步处理**: asyncio + aiofiles
- **数据验证**: Pydantic
- **ASGI服务器**: Uvicorn
- **容器化**: Docker

## 快速开始

### 环境要求

- Python 3.11+
- 或者 Docker

### 本地开发

1. **克隆项目**
```bash
git clone <repository-url>
cd file-upload-server
```

2. **安装依赖**
```bash
pip install -r requirements.txt
```

3. **配置环境变量**
```bash
cp env.example .env
# 编辑 .env 文件，根据环境修改 UPLOAD_BASE_DIR
```

4. **启动服务**
```bash
python main.py
```

服务将在 `http://localhost:8000` 启动

### Docker部署

1. **构建镜像**
```bash
docker build -t file-upload-server .
```

2. **运行容器**
```bash
# Staging环境（使用默认配置）
docker run -d \
  --name file-upload-server \
  -p 8000:8000 \
  -v /cpfs-nfs/sais/data-plaza-svc:/cpfs-nfs/sais/data-plaza-svc \
  file-upload-server

# Production环境（只需覆盖UPLOAD_BASE_DIR）
docker run -d \
  --name file-upload-server \
  -p 8000:8000 \
  -v /normal-cpfs-datasets:/normal-cpfs-datasets \
  -v /normal-cpfs-datasets-temp:/normal-cpfs-datasets-temp \
  -e UPLOAD_BASE_DIR=/normal-cpfs-datasets \
  -e TEMP_DIR=/normal-cpfs-datasets-temp \
  file-upload-server
```

## API 接口

服务启动后访问 `http://localhost:8000/docs` 查看完整的API文档

### 主要接口

| 接口 | 方法 | 说明 |
|------|------|------|
| `/` | GET | 服务信息 |
| `/health` | GET | 健康检查 |
| `/api/token/generate` | POST | 生成访问令牌 |
| `/api/token/verify` | POST | 验证令牌有效性 |
| `/api/token/revoke` | DELETE | 撤销访问令牌 |
| `/api/upload/check` | POST | 检查文件状态，支持断点续传 |
| `/api/upload/chunk` | POST | 上传文件分片 |
| `/api/upload/merge` | POST | 合并分片完成上传 |
| `/api/upload/status/{file_id}` | GET | 获取上传状态 |
| `/api/upload/{file_id}` | DELETE | 取消上传 |
| `/api/upload/records` | GET | 查询上传记录（支持分页和筛选） |
| `/api/upload/records/stats` | GET | 获取上传统计信息 |
| `/api/download/{filename}` | GET | 下载文件 |

## 使用示例

### Python SDK

#### 安装SDK
```bash
pip install large-file-upload-sdk
```

#### 用法（Token认证 - 推荐）
```python
import file_upload_sdk as api  # 注意：包名是large-file-upload-sdk，但导入时使用file_upload_sdk

# 方式1：使用用户信息自动获取Token
api.init_sdk(
    base_url="https://file-upload-server.ai4s.com.cn/",
    user_id=12345,
    user_name="张三"
)

# 方式2：直接使用已有的Token
api.init_sdk(
    base_url="https://file-upload-server.ai4s.com.cn/",
    access_token="hf_AbCdEfGhIjKlMnOpQrStUvWxYz1234567890"
)

# 上传文件
result = api.upload_file(
    file_path="/path/to/local/your_file.suffix",
    dataset_id="my-dataset",  
    file_name="your_file.suffix"
)

if result['success']:
    print(f"上传成功！文件URL: {result['file_url']}")
else:
    print(f"上传失败: {result['error']}")
```

#### 兼容旧版本（API Key认证）
```python
import file_upload_sdk as api

# 使用API Key（兼容旧版本）
api.init_sdk(
    base_url="http://localhost:8000",
    api_key="ak_12345_xxx_yyy"
)

# 或者通过user_id自动申请API Key
api.init_sdk(
    base_url="http://localhost:8000",
    user_id=12345
)
```

#### 带进度显示的用法
```python
import file_upload_sdk as api

api.init_sdk("http://localhost:8000")

def show_progress(progress):
    print(f"\r上传进度: {progress:.1f}%", end="", flush=True)

result = api.upload_file(
    file_path="/path/to/large_file.zip",
    file_name="uploaded_file.zip",
    progress_callback=show_progress
)
```

#### 面向对象的用法
```python
from file_upload_sdk import FileUploadSDK

# Token认证方式
sdk = FileUploadSDK(
    base_url="http://localhost:8000",
    user_id=12345,
    user_name="张三",
    chunk_size=5 * 1024 * 1024,  # 5MB分片
    retry_times=5
)

# 或者直接使用Token
sdk = FileUploadSDK(
    base_url="http://localhost:8000",
    access_token="hf_AbCdEfGhIjKlMnOpQrStUvWxYz1234567890",
    chunk_size=5 * 1024 * 1024,
    retry_times=5
)

result = sdk.upload_file(
    file_path="/path/to/your_file.suffix",
    dataset_id="my-dataset",
    file_name="your_file.suffix",
    enable_md5_check=True
)
```

#### 断点续传示例
```python
import file_upload_sdk as api

# 使用Token认证
api.init_sdk(
    base_url="http://localhost:8000",
    user_id=12345,
    user_name="张三"
)

# 使用自定义文件ID进行断点续传
file_id = "my_unique_file_id"

result = api.upload_file(
    file_path="/path/to/large_file.zip",
    dataset_id="my-dataset",
    file_name="large_file.zip",
    custom_file_id=file_id
)

# 如果上传中断，再次调用相同的代码即可继续上传
```

### cURL 使用示例

#### 0. 获取访问令牌（首次使用）

```bash
curl -X POST "http://localhost:8000/api/token/generate" \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "12345",
    "user_name": "张三",
    "role": "user",
    "max_file_size": 10737418240,
    "daily_upload_limit": 100
  }'
```

**响应示例：**
```json
{
  "access_token": "hf_AbCdEfGhIjKlMnOpQrStUvWxYz1234567890",
  "token_type": "Bearer",
  "user_info": {
    "user_id": "12345",
    "user_name": "张三",
    "role": "user",
    "max_file_size": 10737418240,
    "daily_upload_limit": 100
  }
}
```

#### 1. 检查文件状态

```bash
curl -X POST "http://localhost:8000/api/upload/check" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer hf_AbCdEfGhIjKlMnOpQrStUvWxYz1234567890" \
  -d '{
    "file_id": "unique-file-id",
    "file_name": "large-file.zip",
    "file_size": 1073741824,
    "total_chunks": 100,
    "dataset_id": "my-dataset",
    "file_md5": "d41d8cd98f00b204e9800998ecf8427e"
  }'
```

#### 2. 上传分片

```bash
curl -X POST "http://localhost:8000/api/upload/chunk" \
  -H "Authorization: Bearer hf_AbCdEfGhIjKlMnOpQrStUvWxYz1234567890" \
  -F "file_id=unique-file-id" \
  -F "file_name=large-file.zip" \
  -F "file_size=1073741824" \
  -F "chunk_index=0" \
  -F "total_chunks=100" \
  -F "chunk_size=10485760" \
  -F "dataset_id=my-dataset" \
  -F "chunk_file=@chunk_0.bin"
```

#### 3. 合并文件

```bash
curl -X POST "http://localhost:8000/api/upload/merge" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer hf_AbCdEfGhIjKlMnOpQrStUvWxYz1234567890" \
  -d '{
    "file_id": "unique-file-id",
    "file_name": "large-file.zip",
    "total_chunks": 100,
    "dataset_id": "my-dataset",
    "file_md5": "d41d8cd98f00b204e9800998ecf8427e"
  }'
```

## 上传记录查询

系统会自动将所有成功的上传记录保存到数据库，方便用户查询历史上传记录和统计信息。

### 查询上传记录

**接口**: `GET /api/upload/records`

**功能**: 
- 分页查询上传记录
- 支持按数据集ID筛选
- 支持按文件名模糊搜索
- 普通用户只能查询自己的记录，管理员可查询所有用户

**示例**:
```bash
# 基本查询（第一页）
curl -H "Authorization: Bearer your_token" \
  "https://file-upload-server.ai4s.com.cn/api/upload/records?page=1&page_size=10"

# 按数据集筛选
curl -H "Authorization: Bearer your_token" \
  "https://file-upload-server.ai4s.com.cn/api/upload/records?dataset_id=my-dataset"

# 搜索文件名
curl -H "Authorization: Bearer your_token" \
  "https://file-upload-server.ai4s.com.cn/api/upload/records?file_name=report"
```

**响应示例**:
```json
{
  "code": 200,
  "message": "查询成功，共 25 条记录",
  "total": 25,
  "page": 1,
  "page_size": 10,
  "records": [
    {
      "id": 1,
      "user_id": "user_123",
      "user_name": "张三",
      "file_id": "abc123",
      "file_name": "example.pdf",
      "file_size": 10485760,
      "file_md5": "d41d8cd98f00b204e9800998ecf8427e",
      "file_path": "/uploads/dataset_001/example.pdf",
      "dataset_id": "dataset_001",
      "total_chunks": 10,
      "upload_status": "completed",
      "upload_started_at": "2024-01-01T10:00:00",
      "upload_completed_at": "2024-01-01T10:05:00",
      "created_at": "2024-01-01T10:05:00"
    }
  ]
}
```

### 获取上传统计

**接口**: `GET /api/upload/records/stats`

**功能**: 获取当前用户的上传统计信息

**示例**:
```bash
curl -H "Authorization: Bearer your_token" \
  "https://file-upload-server.ai4s.com.cn/api/upload/records/stats"
```

**响应示例**:
```json
{
  "code": 200,
  "message": "统计信息获取成功",
  "data": {
    "total_files": 125,
    "total_size": 5368709120,
    "total_size_gb": 5.0,
    "today_files": 10,
    "today_size": 419430400,
    "today_size_gb": 0.39
  }
}
```

### Python 调用示例

```python
import requests

# 查询上传记录
def get_upload_records(token, page=1, page_size=10):
    url = f"https://file-upload-server.ai4s.com.cn/api/upload/records"
    headers = {"Authorization": f"Bearer {token}"}
    params = {"page": page, "page_size": page_size}
    response = requests.get(url, headers=headers, params=params)
    return response.json()

# 获取统计信息
def get_upload_stats(token):
    url = "https://file-upload-server.ai4s.com.cn/api/upload/records/stats"
    headers = {"Authorization": f"Bearer {token}"}
    response = requests.get(url, headers=headers)
    return response.json()

# 使用示例
token = "hf_your_token_here"
records = get_upload_records(token, page=1, page_size=20)
print(f"共有 {records['total']} 条记录")
for record in records['records']:
    print(f"文件: {record['file_name']}, 大小: {record['file_size']} 字节")

stats = get_upload_stats(token)
print(f"总上传: {stats['data']['total_files']} 个文件, {stats['data']['total_size_gb']} GB")
```

### 前端集成

详细的前端集成示例（React、Vue）请参考：[API_UPLOAD_RECORDS.md](./API_UPLOAD_RECORDS.md)

## 配置说明

主要配置项 (在 `config.py` 或环境变量中设置):

| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `HOST` | 0.0.0.0 | 服务器地址 |
| `PORT` | 8000 | 服务器端口 |
| `UPLOAD_BASE_DIR` | /cpfs-nfs/sais/data-plaza-svc/datasets | 数据集基础路径 |
| `TEMP_DIR` | /data/uploads/temp | 临时文件目录 |
| `CHUNK_SIZE` | 10MB | 分片大小 |
| `CHUNK_EXPIRE_HOURS` | 24 | 分片过期时间(小时) |
| `ENABLE_MD5_CHECK` | true | 是否启用MD5校验 |
| `DATABASE_URL` | sqlite:///./tokens.db | 数据库连接URL（Token存储） |

### 环境配置

根据部署环境，只需要修改 `UPLOAD_BASE_DIR` 环境变量：

- **Staging环境**: `UPLOAD_BASE_DIR=/cpfs-nfs/sais/data-plaza-svc/datasets`
- **Production环境**: `UPLOAD_BASE_DIR=/normal-cpfs-datasets`

文件最终会保存在: `{UPLOAD_BASE_DIR}/{datasetName}/full/download/`

### Token认证配置

Token认证系统支持以下配置：

- **数据库存储**: Token信息存储在MySQL/SQLite数据库中
- **永不过期**: Token一旦生成，永久有效（除非手动撤销）
- **安全存储**: Token使用SHA256哈希存储，不保存明文
- **权限控制**: 支持用户角色、数据集访问权限和使用限制

#### Token格式
```
hf_<32位随机字符串>
```

#### 用户角色
- **admin**: 管理员，可访问所有数据集和功能
- **user**: 普通用户，按配置的权限访问
- **guest**: 访客用户，受限的访问权限

## 项目结构

```
file-upload-server/
├── main.py                  # 主应用入口
├── config.py                # 配置管理
├── models.py                # 数据模型
├── services.py              # 业务逻辑
├── routers.py               # 路由定义
├── file_upload_sdk.py       # Python SDK
├── sdk_usage_example.py     # SDK使用示例
├── test_client.py           # 测试客户端
├── setup.py                 # SDK打包配置
├── requirements.txt         # 依赖包
├── Dockerfile               # Docker镜像
├── .dockerignore            # Docker忽略文件
├── env.example              # 环境变量示例
└── README.md                # 项目说明
```

## 开发指南

### 构建SDK包

```bash
# 构建wheel和tar.gz包
python setup.py sdist bdist_wheel

# 或者使用build工具
pip install build
python -m build
```

### 发布到PyPI（可选）

```bash
# 安装发布工具
pip install twine

# 上传到测试PyPI
twine upload --repository testpypi dist/*

# 上传到正式PyPI
twine upload dist/*
```

### 运行测试

```bash
pytest
```

### 代码检查

```bash
flake8 .
black .
```

## 部署建议

### 生产环境

1. **使用反向代理**: 建议使用 Nginx 作为反向代理
2. **文件存储**: 使用网络存储(如NFS)或对象存储
3. **监控**: 配置日志和监控系统
4. **安全**: 配置HTTPS和访问控制

### 性能优化

1. **增加worker数量**: `uvicorn main:app --workers 4`
2. **调整分片大小**: 根据网络条件调整 `CHUNK_SIZE`
3. **使用SSD**: 临时文件目录使用SSD存储

## 安全注意事项

### Token安全

1. **安全存储**: 不要在代码中硬编码Token，使用环境变量或配置文件
2. **定期轮换**: 建议定期更新Token，虽然Token永不过期
3. **最小权限**: 只授予必要的权限，避免使用admin角色
4. **及时撤销**: 不再使用的Token应及时撤销

### 网络安全

1. **HTTPS**: 生产环境必须使用HTTPS
2. **防火墙**: 配置适当的防火墙规则
3. **访问控制**: 限制允许访问的IP范围

## 许可证

此项目为内部使用项目

## 支持

如有问题请联系开发团队或提交 Issue

## 相关文档

- [Token认证使用指南](TOKEN_USAGE_EXAMPLE.md) - 详细的Token认证使用说明
- [上传记录功能指南](UPLOAD_RECORDS_GUIDE.md) - 上传记录数据库存储和查询说明
- [上传记录API文档](API_UPLOAD_RECORDS.md) - 上传记录查询接口使用文档（包含前端集成示例）
- [API文档](http://localhost:8000/docs) - 在线交互式API文档
