- 🎨 文生图 - 根据文本描述生成图片
- 🖼️ 图生图 - 基于上传的图片进行创意变换
- 🎬 文生视频 - 根据文本描述生成视频
- 🎥 图生视频 - 基于图片生成相关视频
- 📊 多尺寸支持 - 横屏、竖屏等多种规格
- 🎭 视频角色功能 - 创建角色,生成角色视频
- 🎬 Remix 功能 - 基于已有视频继续创作
- 🎥 分镜功能 - 支持生成分镜视频
- 🔐 Token 管理 - 支持多 Token 管理和轮询负载均衡
- 🌐 代理支持 - 支持 HTTP 和 SOCKS5 代理
- 📝 详细日志 - 完整的请求/响应日志记录
- 🔄 异步处理 - 高效的异步任务处理
- 💾 数据持久化 - SQLite 数据库存储
- 🎯 OpenAI 兼容 - 完全兼容 OpenAI API 格式
- 🛡️ 安全认证 - API Key 验证和权限管理
- 📱 Web 管理界面 - 直观的管理后台
- Docker 和 Docker Compose(推荐)
- 或 Python 3.8+
# 直接使用自动构建的 Docker 镜像
docker run -d \
--name sora2api \
-p 8090:8090 \
-v $(pwd)/data:/app/data \
-v $(pwd)/config/setting.toml:/app/config/setting.toml \
ghcr.io/raomaiping/sora2api:latest
# 查看日志
docker logs -f sora2api# 克隆项目
git clone https://github.com/raomaiping/sora2api.git
cd sora2api
# 启动服务
docker-compose up -d
# 查看日志
docker-compose logs -f# 使用 WARP 代理启动
docker-compose -f docker-compose.warp.yml up -d
# 查看日志
docker-compose -f docker-compose.warp.yml logs -f项目已配置 GitHub Actions,每次推送到 main 分支或创建版本标签时,会自动构建并推送 Docker 镜像到 GitHub Container Registry:
- 镜像地址:
ghcr.io/raomaiping/sora2api:latest - 查看构建状态: 访问 GitHub Actions
- 查看镜像: 访问 GitHub Packages
# 克隆项目
git clone https://github.com/raomaiping/sora2api.git
cd sora2api
# 创建虚拟环境
python -m venv venv
# 激活虚拟环境
# Windows
venv\Scripts\activate
# Linux/Mac
source venv/bin/activate
# 安装依赖
pip install -r requirements.txt
# 启动服务
python main.py服务启动后,访问管理后台进行初始化配置:
- 地址: http://localhost:8090
- 用户名:
admin - 密码:
admin
| 功能 | 模型 | 说明 |
|---|---|---|
| 文生图 | sora-image* |
使用 content 为字符串 |
| 图生图 | sora-image* |
使用 content 数组 + image_url |
| 文生视频 | sora-video* |
使用 content 为字符串 |
| 图生视频 | sora-video* |
使用 content 数组 + image_url |
| 创建角色 | sora-video* |
使用 content 数组 + video_url |
| 角色生成视频 | sora-video* |
使用 content 数组 + video_url + 文本 |
| Remix | sora-video* |
在 content 中包含 Remix ID |
| 视频分镜 | sora-video* |
在 content 中使用[时长s]提示词格式触发 |
| 异步任务创建 | 所有模型 | 使用 /v1/tasks 端点创建任务,返回任务ID |
| 查询任务状态 | - | 使用 /v1/tasks/{task_id} 端点查询任务状态 |
- 端点:
http://localhost:8090/v1/chat/completions - 认证: 在请求头中添加
Authorization: Bearer YOUR_API_KEY - 默认 API Key:
han1234(建议修改)
图片模型
| 模型 | 说明 | 尺寸 |
|---|---|---|
sora-image |
文生图(默认) | 360×360 |
sora-image-landscape |
文生图(横屏) | 540×360 |
sora-image-portrait |
文生图(竖屏) | 360×540 |
视频模型
| 模型 | 时长 | 方向 | 说明 |
|---|---|---|---|
sora-video-10s |
10秒 | 横屏 | 文生视频/图生视频 |
sora-video-15s |
15秒 | 横屏 | 文生视频/图生视频 |
sora-video-landscape-10s |
10秒 | 横屏 | 文生视频/图生视频 |
sora-video-landscape-15s |
15秒 | 横屏 | 文生视频/图生视频 |
sora-video-portrait-10s |
10秒 | 竖屏 | 文生视频/图生视频 |
sora-video-portrait-15s |
15秒 | 竖屏 | 文生视频/图生视频 |
文生图
curl -X POST "http://localhost:8090/v1/chat/completions" \
-H "Authorization: Bearer han1234" \
-H "Content-Type: application/json" \
-d '{
"model": "sora-image",
"messages": [
{
"role": "user",
"content": "一只可爱的小猫咪"
}
]
}'图生图
curl -X POST "http://localhost:8090/v1/chat/completions" \
-H "Authorization: Bearer han1234" \
-H "Content-Type: application/json" \
-d '{
"model": "sora-image",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "将这张图片变成油画风格"
},
{
"type": "image_url",
"image_url": {
"url": "data:image/png;base64,<base64_encoded_image_data>"
}
}
]
}
],
"stream": true
}'文生视频
curl -X POST "http://localhost:8090/v1/chat/completions" \
-H "Authorization: Bearer han1234" \
-H "Content-Type: application/json" \
-d '{
"model": "sora-video-landscape-10s",
"messages": [
{
"role": "user",
"content": "一只小猫在草地上奔跑"
}
],
"stream": true
}'图生视频
curl -X POST "http://localhost:8090/v1/chat/completions" \
-H "Authorization: Bearer han1234" \
-H "Content-Type: application/json" \
-d '{
"model": "sora-video-landscape-10s",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "这只猫在跳舞"
},
{
"type": "image_url",
"image_url": {
"url": "data:image/png;base64,<base64_encoded_image_data>"
}
}
]
}
],
"stream": true
}'视频Remix(基于已有视频继续创作)
- 提示词内包含remix分享链接或id即可
curl -X POST "http://localhost:8090/v1/chat/completions" \
-H "Authorization: Bearer han1234" \
-H "Content-Type: application/json" \
-d '{
"model": "sora-video-landscape-10s",
"messages": [
{
"role": "user",
"content": "https://sora.chatgpt.com/p/s_68e3a06dcd888191b150971da152c1f5改成水墨画风格"
}
]
}'视频分镜
- 示例触发提示词:
[5.0s]猫猫从飞机上跳伞 [5.0s]猫猫降落 [10.0s]猫猫在田野奔跑 - 或
[5.0s]猫猫从飞机上跳伞 [5.0s]猫猫降落 [10.0s]猫猫在田野奔跑
curl -X POST "http://localhost:8090/v1/chat/completions" \
-H "Authorization: Bearer han1234" \
-H "Content-Type: application/json" \
-d '{
"model": "sora-video-landscape-10s",
"messages": [
{
"role": "user",
"content": "[5.0s]猫猫从飞机上跳伞 [5.0s]猫猫降落 [10.0s]猫猫在田野奔跑"
}
]
}'Sora2API 支持视频角色生成功能。
- 角色创建: 如果只有视频,无prompt,则生成角色自动提取角色信息,输出角色名
- 角色生成: 有视频、prompt,则上传视频创建角色,使用角色和prompt进行生成,输出视频
场景 1: 仅创建角色(不生成视频)
上传视频提取角色信息,获取角色名称和头像。
curl -X POST "http://localhost:8090/v1/chat/completions" \
-H "Authorization: Bearer han1234" \
-H "Content-Type: application/json" \
-d '{
"model": "sora-video-landscape-10s",
"messages": [
{
"role": "user",
"content": [
{
"type": "video_url",
"video_url": {
"url": "data:video/mp4;base64,<base64_encoded_video_data>"
}
}
]
}
],
"stream": true
}'场景 2: 创建角色并生成视频
上传视频创建角色,然后使用该角色生成新视频。
curl -X POST "http://localhost:8090/v1/chat/completions" \
-H "Authorization: Bearer han1234" \
-H "Content-Type: application/json" \
-d '{
"model": "sora-video-landscape-10s",
"messages": [
{
"role": "user",
"content": [
{
"type": "video_url",
"video_url": {
"url": "data:video/mp4;base64,<base64_encoded_video_data>"
}
},
{
"type": "text",
"text": "角色做一个跳舞的动作"
}
]
}
],
"stream": true
}'import requests
import base64
# 读取视频文件并编码为 Base64
with open("video.mp4", "rb") as f:
video_data = base64.b64encode(f.read()).decode("utf-8")
# 仅创建角色
response = requests.post(
"http://localhost:8090/v1/chat/completions",
headers={
"Authorization": "Bearer han1234",
"Content-Type": "application/json"
},
json={
"model": "sora-video-landscape-10s",
"messages": [
{
"role": "user",
"content": [
{
"type": "video_url",
"video_url": {
"url": f"data:video/mp4;base64,{video_data}"
}
}
]
}
],
"stream": True
},
stream=True
)
# 处理流式响应
for line in response.iter_lines():
if line:
print(line.decode("utf-8"))Sora2API 支持异步任务创建和查询,允许您提交任务后立即获得任务ID,然后通过轮询查询任务状态。
工作流程:
-
创建任务 (
POST /v1/tasks)- 调用内部方法
create_task_async()创建任务 - 内部会调用 Sora API 创建生成任务,获取 Sora 的任务ID
- 生成内部任务ID(格式:
task_xxxxx)并保存到数据库 - 立即返回内部任务ID给用户,不等待任务完成
- 后台自动启动轮询任务,使用创建任务时的 Token 查询 Sora API 状态
- 调用内部方法
-
查询任务 (
GET /v1/tasks/{task_id})- 直接从本地数据库查询任务状态
- 不调用 Sora API,响应速度快
- 返回任务状态、进度、结果URL等信息
-
后台轮询(自动运行)
- 使用创建任务时的 Token 和 Sora 任务ID查询 Sora API
- 自动更新数据库中的任务状态、进度和结果URL
- 支持无水印模式:如果启用了无水印,会自动处理并保存无水印URL
优势:
- ✅ 查询快速:不依赖 Sora API 响应速度
- ✅ 减少 API 调用:查询任务不调用 Sora API
- ✅ 状态统一:由后台轮询统一更新数据库状态
- ✅ 支持无水印:自动处理无水印视频URL
curl -X POST "http://localhost:8090/v1/tasks" \
-H "Authorization: Bearer han1234" \
-H "Content-Type: application/json" \
-d '{
"model": "sora-video-landscape-10s",
"prompt": "一只小猫在草地上奔跑",
"image": "data:image/png;base64,<base64_encoded_image_data>"
}'响应示例:
{
"task_id": "task_abc123xyz",
"status": "processing",
"message": "Task created successfully"
}curl -X GET "http://localhost:8090/v1/tasks/task_abc123xyz" \
-H "Authorization: Bearer han1234"响应示例(处理中):
{
"task_id": "task_abc123xyz",
"status": "processing",
"progress": 45.0,
"model": "sora-video-landscape-10s",
"prompt": "一只小猫在草地上奔跑",
"result_urls": null,
"error_message": null,
"created_at": "2024-01-01T12:00:00",
"completed_at": null
}响应示例(已完成):
{
"task_id": "task_abc123xyz",
"status": "completed",
"progress": 100.0,
"model": "sora-video-landscape-10s",
"prompt": "一只小猫在草地上奔跑",
"result_urls": [
"http://localhost:8090/tmp/video_abc123.mp4"
],
"error_message": null,
"created_at": "2024-01-01T12:00:00",
"completed_at": "2024-01-01T12:05:30"
}响应示例(失败):
{
"task_id": "task_abc123xyz",
"status": "failed",
"progress": 0.0,
"model": "sora-video-landscape-10s",
"prompt": "一只小猫在草地上奔跑",
"result_urls": null,
"error_message": "Content policy violation: Content violates guardrails",
"created_at": "2024-01-01T12:00:00",
"completed_at": "2024-01-01T12:01:00"
}import requests
import time
# 创建任务
response = requests.post(
"http://localhost:8090/v1/tasks",
headers={
"Authorization": "Bearer han1234",
"Content-Type": "application/json"
},
json={
"model": "sora-video-landscape-10s",
"prompt": "一只小猫在草地上奔跑"
}
)
task_data = response.json()
task_id = task_data["task_id"]
print(f"任务已创建,任务ID: {task_id}")
# 轮询任务状态
while True:
response = requests.get(
f"http://localhost:8090/v1/tasks/{task_id}",
headers={"Authorization": "Bearer han1234"}
)
task_status = response.json()
print(f"任务状态: {task_status['status']}, 进度: {task_status['progress']}%")
if task_status["status"] == "completed":
print(f"任务完成!结果URL: {task_status['result_urls']}")
break
elif task_status["status"] == "failed":
print(f"任务失败: {task_status['error_message']}")
break
time.sleep(5) # 每5秒查询一次本项目采用 MIT 许可证。详见 LICENSE 文件。
感谢所有贡献者和使用者的支持!
- 提交 Issue:GitHub Issues
- 讨论:GitHub Discussions
⭐ 如果这个项目对你有帮助,请给个 Star!