视频生成模型
当前视频生成模型,包括输入提示词生成视频,以及输入首帧图片生成视频。通过这篇教程,您可以了解如何调用视频生成模型。
1.模型系列
MiniMax系列
MiniMax系列 | 文生视频 | 图生视频 | RPM | 分辨率&时长 | 计费 |
---|---|---|---|---|---|
MiniMax-Hailuo-02 | √ | √ | 5 | 6s,768p 6s,1080p 10s,768p | 768P 6s,2.29元/视频; 768P 10s,4.57元/视频; 1080P 6s,4元/视频 |
MiniMax-T2V-01 | √ | 5 | 6s,720p | 3.4元/视频 | |
MiniMax-T2V-01-Director | √ | 5 | 6s,720p | 3.4元/视频 | |
MiniMax-I2V-01 | √ | 5 | 6s,720p | 3.4元/视频 | |
MiniMax-I2V-01-Live | √ | 5 | 6s,720p | 3.4元/视频 | |
MiniMax-I2V-01-Director | √ | 5 | 6s,720p | 3.4元/视频 |
Doubao-Seedance-1.0系列
Doubao-Seedance-1.0系列 | 文生视频 | 图生视频 | 支持分辨率&时长 | RPM | 并发数 | 计费 |
---|---|---|---|---|---|---|
Doubao-Seedance-1.0-Pro | √ | √ | 5s,10s 480p,720p,1080p | 600 | 10 | 15元/M Tokens |
2.使用前提
您已创建大模型平台API_Key,用于模型调用。
- 若您还未申请,请前往 AI 智算云平台-大模型平台-模型广场
3.API接入方式
视频生成模型,当前仅支持代码接入,暂不支持客户端直接调用。
3.1 代码接入
名之梦系列(I2V/T2V/Hailuo-02)
共3个接口可用:
- 1)生成:https://$BASE_URL/v1/p004/video_generation
- 2)查询:https://$BASE_URL/v1/p004/query/video_generation
- 3)获取:https://$BASE_URL/v1/p004/files/retrieve
BASE_URL:llmapi.blsc.cn
支持 curl、python、golang、java、nodejs
图生视频将prompt换成first_frame_image即可,即传图片,而非文字即可
# 生成请求
curl --location 'https://$BASE_URL/v1/p004/video_generation' \
--header 'Authorization: Bearer [申请到的key]' \
--header 'Content-Type: application/json' \
--data '{
"model": "[模型ID]",
"prompt": "曹冲称象"
}'
# 查询处理状态
curl --location 'https://$BASE_URL/v1/p004/query/video_generation?task_id=[生成请求返回的task_id]' \
--header 'Authorization: Bearer [申请到的key]'
# 获取视频, 返回中有download_url
curl --location 'https://$BASE_URL/v1/p004/files/retrieve?file_id=[查询状态请求返回的file_id]' \
--header 'Authorization: Bearer [申请到的key]'
import os
import time
import requests
import json
api_key = "请在此输入API Key"
output_file_name = "output_video.mp4" # 输出文件名
prompt = "请在此输入生成视频的提示词文本内容"
model = "Model ID"
def invoke_video_generation()->str:
print("-----------------提交视频生成任务-----------------")
url = "https://$BASE_URL/v1/p004/video_generation"
payload = json.dumps({
"prompt": prompt,
"model": model
})
headers = {
'authorization': 'Bearer ' + api_key,
'content-type': 'application/json',
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
task_id = response.json()['task_id']
print("视频生成任务提交成功,任务ID:"+task_id)
return task_id
def query_video_generation(task_id: str):
url = "https://$BASE_URL/v1/p004/query/video_generation?task_id="+task_id
headers = {
'authorization': 'Bearer ' + api_key
}
response = requests.request("GET", url, headers=headers)
status = response.json()['status']
if status == 'Preparing':
print("...准备中...")
return "", 'Preparing'
elif status == 'Queueing':
print("...队列中...")
return "", 'Queueing'
elif status == 'Processing':
print("...生成中...")
return "", 'Processing'
elif status == 'Success':
return response.json()['file_id'], "Finished"
elif status == 'Fail':
return "", "Fail"
else:
return "", "Unknown"
def fetch_video_result(file_id: str):
print("---------------视频生成成功,下载中---------------")
url = "https://$BASE_URL/v1/p004/files/retrieve?file_id="+file_id
headers = {
'authorization': 'Bearer '+api_key,
}
response = requests.request("GET", url, headers=headers)
print(response.text)
download_url = response.json()['file']['download_url']
print("视频下载链接:" + download_url)
with open(output_file_name, 'wb') as f:
f.write(requests.get(download_url).content)
print("已下载在:"+os.getcwd()+'/'+output_file_name)
if __name__ == '__main__':
task_id = invoke_video_generation()
count = 0
print("-----------------已提交视频生成任务-----------------")
while True:
time.sleep(10)
count += 1
if count > 60:
print("---------------超时,生成失败---------------")
break
file_id, status = query_video_generation(task_id)
if file_id != "":
fetch_video_result(file_id)
print("---------------生成成功---------------")
break
elif status == "Fail" or status == "Unknown":
print("---------------生成失败---------------")
break
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
)
const (
apiKey = "请在此输入API Key"
prompt = "请在此输入生成视频的提示词文本内容"
model = "Model ID"
baseURL = "https://$BASE_URL" // 替换为实际BASE_URL
outputFileName = "output_video.mp4"
maxRetryCount = 60
retryInterval = 10 * time.Second
)
type VideoTaskResponse struct {
TaskID string `json:"task_id"`
}
type QueryResponse struct {
Status string `json:"status"`
FileID string `json:"file_id,omitempty"`
File struct {
DownloadURL string `json:"download_url"`
} `json:"file,omitempty"`
}
func invokeVideoGeneration() (string, error) {
fmt.Println("-----------------提交视频生成任务-----------------")
url := baseURL + "/v1/p004/video_generation"
payload := map[string]string{
"prompt": prompt,
"model": model,
}
jsonData, err := json.Marshal(payload)
if err != nil {
return "", fmt.Errorf("JSON编码失败: %v", err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return "", fmt.Errorf("创建请求失败: %v", err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("请求失败: %v", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("读取响应失败: %v", err)
}
var taskResp VideoTaskResponse
if err := json.Unmarshal(body, &taskResp); err != nil {
return "", fmt.Errorf("JSON解析失败: %v", err)
}
fmt.Printf("视频生成任务提交成功,任务ID:%s\n", taskResp.TaskID)
return taskResp.TaskID, nil
}
func queryVideoGeneration(taskID string) (string, string, error) {
url := baseURL + "/v1/p004/query/video_generation?task_id=" + taskID
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", "", fmt.Errorf("创建请求失败: %v", err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", "", fmt.Errorf("请求失败: %v", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", "", fmt.Errorf("读取响应失败: %v", err)
}
var queryResp QueryResponse
if err := json.Unmarshal(body, &queryResp); err != nil {
return "", "", fmt.Errorf("JSON解析失败: %v", err)
}
switch queryResp.Status {
case "Preparing":
fmt.Println("...准备中...")
return "", "Preparing", nil
case "Queueing":
fmt.Println("...队列中...")
return "", "Queueing", nil
case "Processing":
fmt.Println("...生成中...")
return "", "Processing", nil
case "Success":
return queryResp.FileID, "Finished", nil
case "Fail":
return "", "Fail", nil
default:
return "", "Unknown", nil
}
}
func fetchVideoResult(fileID string) error {
fmt.Println("---------------视频生成成功,下载中---------------")
url := baseURL + "/v1/p004/files/retrieve?file_id=" + fileID
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return fmt.Errorf("创建请求失败: %v", err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("请求失败: %v", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("读取响应失败: %v", err)
}
var queryResp QueryResponse
if err := json.Unmarshal(body, &queryResp); err != nil {
return fmt.Errorf("JSON解析失败: %v", err)
}
downloadURL := queryResp.File.DownloadURL
fmt.Println("视频下载链接:" + downloadURL)
// 下载视频文件
resp, err = http.Get(downloadURL)
if err != nil {
return fmt.Errorf("下载失败: %v", err)
}
defer resp.Body.Close()
out, err := os.Create(outputFileName)
if err != nil {
return fmt.Errorf("创建文件失败: %v", err)
}
defer out.Close()
_, err = io.Copy(out, resp.Body)
if err != nil {
return fmt.Errorf("保存文件失败: %v", err)
}
wd, _ := os.Getwd()
fmt.Printf("已下载在:%s/%s\n", wd, outputFileName)
return nil
}
func main() {
taskID, err := invokeVideoGeneration()
if err != nil {
fmt.Printf("提交任务失败: %v\n", err)
return
}
fmt.Println("-----------------已提交视频生成任务-----------------")
for count := 0; count < maxRetryCount; count++ {
time.Sleep(retryInterval)
fileID, status, err := queryVideoGeneration(taskID)
if err != nil {
fmt.Printf("查询任务状态失败: %v\n", err)
continue
}
if fileID != "" {
if err := fetchVideoResult(fileID); err != nil {
fmt.Printf("下载视频失败: %v\n", err)
} else {
fmt.Println("---------------生成成功---------------")
}
break
}
if status == "Fail" || status == "Unknown" {
fmt.Println("---------------生成失败---------------")
break
}
if count >= maxRetryCount {
fmt.Println("---------------超时,生成失败---------------")
}
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest.BodyPublishers;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class VideoGenerationClient {
private static final String API_KEY = "请在此输入API Key";
private static final String PROMPT = "请在此输入生成视频的提示词文本内容";
private static final String MODEL = "Model ID";
private static final String BASE_URL = "https://$BASE_URL"; // 替换为实际BASE_URL
private static final String OUTPUT_FILE = "output_video.mp4";
private static final int MAX_RETRIES = 60;
private static final int RETRY_INTERVAL_SECONDS = 10;
private static final ObjectMapper objectMapper = new ObjectMapper();
private static final HttpClient httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30))
.build();
public static void main(String[] args) {
try {
String taskId = invokeVideoGeneration();
System.out.println("-----------------已提交视频生成任务-----------------");
boolean completed = false;
for (int i = 0; i < MAX_RETRIES && !completed; i++) {
TimeUnit.SECONDS.sleep(RETRY_INTERVAL_SECONDS);
var result = queryVideoGeneration(taskId);
String status = result.get("status");
String fileId = result.get("fileId");
if (fileId != null && !fileId.isEmpty()) {
fetchVideoResult(fileId);
System.out.println("---------------生成成功---------------");
completed = true;
} else if ("Fail".equals(status) || "Unknown".equals(status)) {
System.out.println("---------------生成失败---------------");
completed = true;
}
}
if (!completed) {
System.out.println("---------------超时,生成失败---------------");
}
} catch (Exception e) {
System.err.println("程序执行出错: " + e.getMessage());
e.printStackTrace();
}
}
private static String invokeVideoGeneration() throws Exception {
System.out.println("-----------------提交视频生成任务-----------------");
String url = BASE_URL + "/v1/p004/video_generation";
String requestBody = objectMapper.writeValueAsString(Map.of(
"prompt", PROMPT,
"model", MODEL
));
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer " + API_KEY)
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Map<String, String> responseMap = objectMapper.readValue(response.body(), Map.class);
String taskId = responseMap.get("task_id");
System.out.println("视频生成任务提交成功,任务ID:" + taskId);
return taskId;
}
private static Map<String, String> queryVideoGeneration(String taskId) throws Exception {
String url = BASE_URL + "/v1/p004/query/video_generation?task_id=" + taskId;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer " + API_KEY)
.GET()
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
Map<String, Object> responseMap = objectMapper.readValue(response.body(), Map.class);
String status = (String) responseMap.get("status");
switch (status) {
case "Preparing":
System.out.println("...准备中...");
break;
case "Queueing":
System.out.println("...队列中...");
break;
case "Processing":
System.out.println("...生成中...");
break;
}
String fileId = responseMap.containsKey("file_id") ?
(String) responseMap.get("file_id") : null;
return Map.of(
"status", status,
"fileId", fileId != null ? fileId : ""
);
}
private static void fetchVideoResult(String fileId) throws Exception {
System.out.println("---------------视频生成成功,下载中---------------");
String url = BASE_URL + "/v1/p004/files/retrieve?file_id=" + fileId;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer " + API_KEY)
.GET()
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
Map<String, Object> responseMap = objectMapper.readValue(response.body(), Map.class);
@SuppressWarnings("unchecked")
Map<String, String> fileInfo = (Map<String, String>) responseMap.get("file");
String downloadUrl = fileInfo.get("download_url");
System.out.println("视频下载链接:" + downloadUrl);
// 下载视频文件
HttpRequest downloadRequest = HttpRequest.newBuilder()
.uri(URI.create(downloadUrl))
.GET()
.build();
HttpResponse<byte[]> downloadResponse = httpClient.send(
downloadRequest,
HttpResponse.BodyHandlers.ofByteArray()
);
Files.write(
Path.of(OUTPUT_FILE),
downloadResponse.body(),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING
);
System.out.println("已下载在:" + Path.of("").toAbsolutePath() + "/" + OUTPUT_FILE);
const axios = require('axios');
const fs = require('fs');
const path = require('path');
// 配置参数
const config = {
apiKey: '请在此输入API Key',
prompt: '请在此输入生成视频的提示词文本内容',
model: 'Model ID',
baseUrl: 'https://$BASE_URL', // 替换为实际BASE_URL
outputFile: 'output_video.mp4',
maxRetries: 60,
retryInterval: 10000 // 10秒
};
// 提交视频生成任务
async function invokeVideoGeneration() {
console.log('-----------------提交视频生成任务-----------------');
try {
const response = await axios.post(
`${config.baseUrl}/v1/p004/video_generation`,
{
prompt: config.prompt,
model: config.model
},
{
headers: {
'Authorization': `Bearer ${config.apiKey}`,
'Content-Type': 'application/json'
}
}
);
console.log(response.data);
const taskId = response.data.task_id;
console.log(`视频生成任务提交成功,任务ID:${taskId}`);
return taskId;
} catch (error) {
console.error('提交任务失败:', error.response?.data || error.message);
throw error;
}
}
// 查询任务状态
async function queryVideoGeneration(taskId) {
try {
const response = await axios.get(
`${config.baseUrl}/v1/p004/query/video_generation?task_id=${taskId}`,
{
headers: {
'Authorization': `Bearer ${config.apiKey}`
}
}
);
const status = response.data.status;
switch (status) {
case 'Preparing':
console.log('...准备中...');
return { fileId: null, status };
case 'Queueing':
console.log('...队列中...');
return { fileId: null, status };
case 'Processing':
console.log('...生成中...');
return { fileId: null, status };
case 'Success':
return { fileId: response.data.file_id, status: 'Finished' };
case 'Fail':
return { fileId: null, status: 'Fail' };
default:
return { fileId: null, status: 'Unknown' };
}
} catch (error) {
console.error('查询任务状态失败:', error.response?.data || error.message);
throw error;
}
}
// 下载视频结果
async function fetchVideoResult(fileId) {
console.log('---------------视频生成成功,下载中---------------');
try {
// 获取下载URL
const response = await axios.get(
`${config.baseUrl}/v1/p004/files/retrieve?file_id=${fileId}`,
{
headers: {
'Authorization': `Bearer ${config.apiKey}`
}
}
);
console.log(response.data);
const downloadUrl = response.data.file.download_url;
console.log(`视频下载链接:${downloadUrl}`);
// 下载视频文件
const writer = fs.createWriteStream(config.outputFile);
const downloadResponse = await axios({
method: 'get',
url: downloadUrl,
responseType: 'stream'
});
downloadResponse.data.pipe(writer);
await new Promise((resolve, reject) => {
writer.on('finish', resolve);
writer.on('error', reject);
});
console.log(`已下载在:${path.join(process.cwd(), config.outputFile)}`);
} catch (error) {
console.error('下载视频失败:', error.response?.data || error.message);
throw error;
}
}
// 主流程
async function main() {
try {
const taskId = await invokeVideoGeneration();
console.log('-----------------已提交视频生成任务-----------------');
let retryCount = 0;
let completed = false;
while (retryCount < config.maxRetries && !completed) {
await new Promise(resolve => setTimeout(resolve, config.retryInterval));
retryCount++;
const { fileId, status } = await queryVideoGeneration(taskId);
if (fileId) {
await fetchVideoResult(fileId);
console.log('---------------生成成功---------------');
completed = true;
} else if (status === 'Fail' || status === 'Unknown') {
console.log('---------------生成失败---------------');
completed = true;
}
}
if (!completed) {
console.log('---------------超时,生成失败---------------');
}
} catch (error) {
console.error('程序执行出错:', error);
}
}
// 启动程序
main();
豆包(Doubao-Seedance-1.0-Pro)
共两个接口:
- 1)生成:https://$BASE_URL/v1/p001/contents/generations/tasks
- 2)查询:https://$BASE_URL/v1/p001/contents/generations/tasks?filter.task_ids=task_id
BASE_URL:llmapi.blsc.cn
curl、python、golang、java、nodejs
# 文本生成视频
curl --location 'https://$BASE_URL/v1/p001/contents/generations/tasks' \
--header 'Authorization: Bearer [申请的key]' \
--data '{
"model": "Doubao-Seedance-1.0-Pro",
"content": [
{
"type": "text",
"text": "多个镜头。汤姆猫正在追老鼠杰瑞,在花园的草地上。 --ratio 16:9"
}
]
}'
# 图片生成视频
curl --location 'https://$BASE_URL/v1/p001/contents/generations/tasks' \
--header 'Authorization: Bearer [申请的key]' \
--data '{
"model": "Doubao-Seedance-1.0-Pro",
"content": [
{
"type": "text",
"text": "一只大熊猫正安静的坐着 --ratio adaptive --dur 5"
},
{
"type": "image_url",
"image_url": {
"url": "https://seopic.699pic.com/photo/50032/8264.jpg_wh1200.jpg"
}
}
]
}'
# 查询视频
curl --location --request GET 'https://$BASE_URL/v1/p001/contents/generations/tasks?filter.task_ids=[生成接口返回的id]' \
--header 'Authorization: Bearer [申请的key]'
视频生成成功后,查询返回的示例,在usage里有消耗的token和视频连接
import requests
BASE_URL = "your_base_url" # 替换为实际的BASE_URL
API_KEY = "your_api_key" # 替换为申请的key
def generate_video_from_text(prompt, ratio="16:9"):
"""
通过文本生成视频
:param prompt: 文本提示词
:param ratio: 视频比例,默认为16:9
:return: 响应结果
"""
url = f"https://{BASE_URL}/v1/p001/contents/generations/tasks"
headers = {
"Authorization": f"Bearer {API_KEY}"
}
payload = {
"model": "Doubao-Seedance-1.0-Pro",
"content": [
{
"type": "text",
"text": f"{prompt} --ratio {ratio}"
}
]
}
response = requests.post(url, headers=headers, json=payload)
return response.json()
def generate_video_from_image(prompt, image_url, ratio="adaptive", duration=5):
"""
通过图片生成视频
:param prompt: 文本提示词
:param image_url: 图片URL
:param ratio: 视频比例,默认为adaptive
:param duration: 视频时长(秒),默认为5
:return: 响应结果
"""
url = f"https://{BASE_URL}/v1/p001/contents/generations/tasks"
headers = {
"Authorization": f"Bearer {API_KEY}"
}
payload = {
"model": "Doubao-Seedance-1.0-Pro",
"content": [
{
"type": "text",
"text": f"{prompt} --ratio {ratio} --dur {duration}"
},
{
"type": "image_url",
"image_url": {
"url": image_url
}
}
]
}
response = requests.post(url, headers=headers, json=payload)
return response.json()
def get_video_status(task_id):
"""
查询视频生成状态
:param task_id: 任务ID
:return: 响应结果
"""
url = f"https://{BASE_URL}/v1/p001/contents/generations/tasks"
headers = {
"Authorization": f"Bearer {API_KEY}"
}
params = {
"filter.task_ids": task_id
}
response = requests.get(url, headers=headers, params=params)
return response.json()
# 使用示例
if __name__ == "__main__":
# 示例1: 文本生成视频
text_response = generate_video_from_text(
"多个镜头。汤姆猫正在追老鼠杰瑞,在花园的草地上"
)
print("文本生成视频响应:", text_response)
# 示例2: 图片生成视频
image_response = generate_video_from_image(
prompt="一只大熊猫正安静的坐着",
image_url="https://seopic.699pic.com/photo/50032/8264.jpg_wh1200.jpg"
)
print("图片生成视频响应:", image_response)
# 示例3: 查询视频状态(假设task_id是上面返回的)
if "id" in text_response: # 假设响应中包含task_id字段
status_response = get_video_status(text_response["id"])
print("视频生成状态:", status_response)
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
)
const (
baseURL = "your_base_url" // 替换为实际的 BASE_URL
apiKey = "your_api_key" // 替换为申请的 key
)
// 文本生成视频请求结构体
type TextToVideoRequest struct {
Model string `json:"model"`
Content []Content `json:"content"`
}
// 图片生成视频请求结构体
type ImageToVideoRequest struct {
Model string `json:"model"`
Content []Content `json:"content"`
}
// 内容结构体
type Content struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
ImageURL *ImageURL `json:"image_url,omitempty"`
}
// 图片URL结构体
type ImageURL struct {
URL string `json:"url"`
}
// 生成视频响应结构体
type GenerationResponse struct {
TaskID string `json:"id"`
// 根据实际API响应添加更多字段
}
// 查询状态响应结构体
type StatusResponse struct {
// 根据实际API响应定义字段
}
// GenerateVideoFromText 通过文本生成视频
func GenerateVideoFromText(prompt, ratio string) (*GenerationResponse, error) {
url := fmt.Sprintf("https://%s/v1/p001/contents/generations/tasks", baseURL)
requestBody := TextToVideoRequest{
Model: "Doubao-Seedance-1.0-Pro",
Content: []Content{
{
Type: "text",
Text: fmt.Sprintf("%s --ratio %s", prompt, ratio),
},
},
}
return sendGenerationRequest(url, requestBody)
}
// GenerateVideoFromImage 通过图片生成视频
func GenerateVideoFromImage(prompt, imageURL, ratio string, duration int) (*GenerationResponse, error) {
url := fmt.Sprintf("https://%s/v1/p001/contents/generations/tasks", baseURL)
requestBody := ImageToVideoRequest{
Model: "Doubao-Seedance-1.0-Pro",
Content: []Content{
{
Type: "text",
Text: fmt.Sprintf("%s --ratio %s --dur %d", prompt, ratio, duration),
},
{
Type: "image_url",
ImageURL: &ImageURL{URL: imageURL},
},
},
}
return sendGenerationRequest(url, requestBody)
}
// GetVideoStatus 查询视频生成状态
func GetVideoStatus(taskID string) (*StatusResponse, error) {
base := fmt.Sprintf("https://%s/v1/p001/contents/generations/tasks", baseURL)
params := url.Values{}
params.Add("filter.task_ids", taskID)
fullURL := fmt.Sprintf("%s?%s", base, params.Encode())
req, err := http.NewRequest("GET", fullURL, nil)
if err != nil {
return nil, fmt.Errorf("创建请求失败: %v", err)
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("请求失败: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API返回错误状态码: %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应体失败: %v", err)
}
var statusResp StatusResponse
if err := json.Unmarshal(body, &statusResp); err != nil {
return nil, fmt.Errorf("解析响应JSON失败: %v", err)
}
return &statusResp, nil
}
// sendGenerationRequest 发送生成请求的公共方法
func sendGenerationRequest(url string, requestBody interface{}) (*GenerationResponse, error) {
jsonBody, err := json.Marshal(requestBody)
if err != nil {
return nil, fmt.Errorf("JSON编码失败: %v", err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
if err != nil {
return nil, fmt.Errorf("创建请求失败: %v", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("请求失败: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API返回错误状态码: %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应体失败: %v", err)
}
var genResp GenerationResponse
if err := json.Unmarshal(body, &genResp); err != nil {
return nil, fmt.Errorf("解析响应JSON失败: %v", err)
}
return &genResp, nil
}
func main() {
// 示例1: 文本生成视频
textResp, err := GenerateVideoFromText(
"多个镜头。汤姆猫正在追老鼠杰瑞,在花园的草地上",
"16:9",
)
if err != nil {
fmt.Printf("文本生成视频失败: %v\n", err)
} else {
fmt.Printf("文本生成视频响应: %+v\n", textResp)
}
// 示例2: 图片生成视频
imageResp, err := GenerateVideoFromImage(
"一只大熊猫正安静的坐着",
"https://seopic.699pic.com/photo/50032/8264.jpg_wh1200.jpg",
"adaptive",
5,
)
if err != nil {
fmt.Printf("图片生成视频失败: %v\n", err)
} else {
fmt.Printf("图片生成视频响应: %+v\n", imageResp)
}
// 示例3: 查询视频状态(假设taskID是上面返回的)
if textResp != nil {
statusResp, err := GetVideoStatus(textResp.TaskID)
if err != nil {
fmt.Printf("查询视频状态失败: %v\n", err)
} else {
fmt.Printf("视频生成状态: %+v\n", statusResp)
}
}
}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.List;
public class VideoGenerationClient {
private static final String BASE_URL = "your_base_url"; // 替换为实际的 BASE_URL
private static final String API_KEY = "your_api_key"; // 替换为申请的 key
private static final ObjectMapper objectMapper = new ObjectMapper();
// 文本生成视频请求
public static class TextToVideoRequest {
public String model = "Doubao-Seedance-1.0-Pro";
public List<Content> content;
public TextToVideoRequest(String prompt, String ratio) {
this.content = List.of(
new Content("text", prompt + " --ratio " + ratio, null)
);
}
}
// 图片生成视频请求
public static class ImageToVideoRequest {
public String model = "Doubao-Seedance-1.0-Pro";
public List<Content> content;
public ImageToVideoRequest(String prompt, String imageUrl, String ratio, int duration) {
this.content = List.of(
new Content("text", prompt + " --ratio " + ratio + " --dur " + duration, null),
new Content("image_url", null, new ImageUrl(imageUrl))
);
}
}
// 内容结构
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class Content {
public String type;
public String text;
public ImageUrl image_url;
public Content(String type, String text, ImageUrl imageUrl) {
this.type = type;
this.text = text;
this.image_url = imageUrl;
}
}
// 图片URL结构
public static class ImageUrl {
public String url;
public ImageUrl(String url) {
this.url = url;
}
}
// 生成视频响应
public static class GenerationResponse {
@JsonProperty("id")
public String task_id;
// 根据实际API响应添加更多字段
}
// 查询状态响应
public static class StatusResponse {
// 根据实际API响应定义字段
}
// 通过文本生成视频
public static GenerationResponse generateVideoFromText(String prompt, String ratio) throws Exception {
String url = "https://" + BASE_URL + "/v1/p001/contents/generations/tasks";
TextToVideoRequest request = new TextToVideoRequest(prompt, ratio);
return sendGenerationRequest(url, request);
}
// 通过图片生成视频
public static GenerationResponse generateVideoFromImage(
String prompt, String imageUrl, String ratio, int duration) throws Exception {
String url = "https://" + BASE_URL + "/v1/p001/contents/generations/tasks";
ImageToVideoRequest request = new ImageToVideoRequest(prompt, imageUrl, ratio, duration);
return sendGenerationRequest(url, request);
}
// 查询视频生成状态
public static StatusResponse getVideoStatus(String taskId) throws Exception {
String url = "https://" + BASE_URL + "/v1/p001/contents/generations/tasks" +
"?filter.task_ids=" + URLEncoder.encode(taskId, StandardCharsets.UTF_8);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer " + API_KEY)
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException("API返回错误状态码: " + response.statusCode());
}
return objectMapper.readValue(response.body(), StatusResponse.class);
}
// 发送生成请求的公共方法
private static GenerationResponse sendGenerationRequest(String url, Object requestBody) throws Exception {
String requestBodyJson;
try {
requestBodyJson = objectMapper.writeValueAsString(requestBody);
} catch (JsonProcessingException e) {
throw new RuntimeException("JSON序列化失败", e);
}
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + API_KEY)
.POST(HttpRequest.BodyPublishers.ofString(requestBodyJson))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException("API返回错误状态码: " + response.statusCode());
}
return objectMapper.readValue(response.body(), GenerationResponse.class);
}
public static void main(String[] args) {
try {
// 示例1: 文本生成视频
System.out.println("正在通过文本生成视频...");
GenerationResponse textResponse = generateVideoFromText(
"多个镜头。汤姆猫正在追老鼠杰瑞,在花园的草地上",
"16:9"
);
System.out.println("文本生成视频成功,任务ID: " + textResponse.task_id);
// 示例2: 图片生成视频
System.out.println("\n正在通过图片生成视频...");
GenerationResponse imageResponse = generateVideoFromImage(
"一只大熊猫正安静的坐着",
"https://seopic.699pic.com/photo/50032/8264.jpg_wh1200.jpg",
"adaptive",
5
);
System.out.println("图片生成视频成功,任务ID: " + imageResponse.task_id);
// 示例3: 查询视频状态(使用第一个任务的ID)
System.out.println("\n正在查询视频生成状态...");
StatusResponse statusResponse = getVideoStatus(textResponse.task_id);
System.out.println("视频生成状态: " + objectMapper.writeValueAsString(statusResponse));
} catch (Exception e) {
System.err.println("发生错误: " + e.getMessage());
e.printStackTrace();
}
}
}
const axios = require('axios');
const BASE_URL = 'your_base_url'; // 替换为实际的 BASE_URL
const API_KEY = 'your_api_key'; // 替换为申请的 key
class VideoGenerationClient {
// 文本生成视频
static async generateVideoFromText(prompt, ratio = '16:9') {
const url = `https://${BASE_URL}/v1/p001/contents/generations/tasks`;
const data = {
model: "Doubao-Seedance-1.0-Pro",
content: [
{
type: "text",
text: `${prompt} --ratio ${ratio}`
}
]
};
try {
const response = await axios.post(url, data, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
}
});
return response.data;
} catch (error) {
throw new Error(`文本生成视频失败: ${error.response?.data?.message || error.message}`);
}
}
// 图片生成视频
static async generateVideoFromImage(prompt, imageUrl, ratio = 'adaptive', duration = 5) {
const url = `https://${BASE_URL}/v1/p001/contents/generations/tasks`;
const data = {
model: "Doubao-Seedance-1.0-Pro",
content: [
{
type: "text",
text: `${prompt} --ratio ${ratio} --dur ${duration}`
},
{
type: "image_url",
image_url: {
url: imageUrl
}
}
]
};
try {
const response = await axios.post(url, data, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
}
});
return response.data;
} catch (error) {
throw new Error(`图片生成视频失败: ${error.response?.data?.message || error.message}`);
}
}
// 查询视频状态
static async getVideoStatus(taskId) {
const url = `https://${BASE_URL}/v1/p001/contents/generations/tasks?filter.task_ids=${encodeURIComponent(taskId)}`;
try {
const response = await axios.get(url, {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
});
return response.data;
} catch (error) {
throw new Error(`查询视频状态失败: ${error.response?.data?.message || error.message}`);
}
}
}
// 使用示例
(async () => {
try {
// 示例1: 文本生成视频
console.log('正在通过文本生成视频...');
const textResponse = await VideoGenerationClient.generateVideoFromText(
'多个镜头。汤姆猫正在追老鼠杰瑞,在花园的草地上'
);
console.log('文本生成视频成功:', textResponse);
// 示例2: 图片生成视频
console.log('\n正在通过图片生成视频...');
const imageResponse = await VideoGenerationClient.generateVideoFromImage(
'一只大熊猫正安静的坐着',
'https://seopic.699pic.com/photo/50032/8264.jpg_wh1200.jpg'
);
console.log('图片生成视频成功:', imageResponse);
// 示例3: 查询视频状态(使用第一个任务的ID)
if (textResponse.id) {
console.log('\n正在查询视频生成状态...');
const statusResponse = await VideoGenerationClient.getVideoStatus(textResponse.id);
console.log('视频生成状态:', statusResponse);
}
} catch (error) {
console.error('发生错误:', error.message);
}
})();