拆镜复刻片段重试切片API | 真人/虚拟素材库上传API
This commit is contained in:
@@ -165,6 +165,43 @@ export async function uploadVideo(file: File, durationSeconds?: number): Promise
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
function privatePortraitUploadEndpoint(path: string, durationSeconds?: number): string {
|
||||
const base = `${import.meta.env.VITE_API_BASE || 'http://localhost:8000'}/api${path}`;
|
||||
const query = typeof durationSeconds === 'number' && durationSeconds > 0
|
||||
? `?duration_seconds=${encodeURIComponent(String(durationSeconds))}`
|
||||
: '';
|
||||
return `${base}${query}`;
|
||||
}
|
||||
|
||||
async function uploadPrivatePortraitFile(path: string, file: File, durationSeconds?: number, errorMessage = '素材上传失败'): Promise<UploadResourceResult> {
|
||||
const form = new FormData();
|
||||
form.append('file', file);
|
||||
const token = localStorage.getItem('auth_token');
|
||||
const res = await fetch(privatePortraitUploadEndpoint(path, durationSeconds), {
|
||||
method: 'POST',
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||
body: form,
|
||||
});
|
||||
if (!res.ok) throw new Error(errorMessage);
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
export async function uploadPrivatePortraitImage(file: File): Promise<UploadResourceResult> {
|
||||
return uploadPrivatePortraitFile('/private-portrait/uploads/image', file, undefined, '真人图片素材上传失败');
|
||||
}
|
||||
|
||||
export async function uploadPrivatePortraitVideo(file: File, durationSeconds?: number): Promise<UploadResourceResult> {
|
||||
return uploadPrivatePortraitFile('/private-portrait/uploads/video', file, durationSeconds, '真人视频素材上传失败');
|
||||
}
|
||||
|
||||
export async function uploadPrivatePortraitVirtualImage(file: File): Promise<UploadResourceResult> {
|
||||
return uploadPrivatePortraitFile('/private-portrait/virtual/uploads/image', file, undefined, '虚拟图片素材上传失败');
|
||||
}
|
||||
|
||||
export async function uploadPrivatePortraitVirtualVideo(file: File, durationSeconds?: number): Promise<UploadResourceResult> {
|
||||
return uploadPrivatePortraitFile('/private-portrait/virtual/uploads/video', file, durationSeconds, '虚拟视频素材上传失败');
|
||||
}
|
||||
|
||||
export async function uploadHotOpeningImage(file: File): Promise<UploadResourceResult> {
|
||||
const form = new FormData();
|
||||
form.append('file', file);
|
||||
@@ -957,7 +994,7 @@ export async function getPrivatePortraitValidateSession(sessionId: string): Prom
|
||||
return api.get<PrivatePortraitValidateSession>(`/private-portrait/validate-sessions/${sessionId}`);
|
||||
}
|
||||
|
||||
export async function createPrivatePortraitAsset(projectId: string, payload: { url: string; assetType?: string; name?: string | null; videoDuration?: number | null; videoCoverUrl?: string | null; fileSize?: number | null; mimeType?: string | null }): Promise<PrivatePortraitAsset> {
|
||||
export async function createPrivatePortraitAsset(projectId: string, payload: { url: string; assetType?: string; name?: string | null; videoDuration?: number | null; videoCoverUrl?: string | null; fileSize?: number | null; mimeType?: string | null; uploadResourceId?: string | null }): Promise<PrivatePortraitAsset> {
|
||||
return api.post<PrivatePortraitAsset>(`/private-portrait/projects/${projectId}/assets`, {
|
||||
url: payload.url,
|
||||
asset_type: payload.assetType || 'Image',
|
||||
@@ -966,6 +1003,7 @@ export async function createPrivatePortraitAsset(projectId: string, payload: { u
|
||||
video_cover_url: payload.videoCoverUrl || null,
|
||||
file_size: payload.fileSize ?? null,
|
||||
mime_type: payload.mimeType || null,
|
||||
upload_resource_id: payload.uploadResourceId || null,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1027,7 +1065,7 @@ export async function deletePrivatePortraitVirtualProject(projectId: string): Pr
|
||||
await api.delete(`/private-portrait/virtual-projects/${projectId}`);
|
||||
}
|
||||
|
||||
export async function createPrivatePortraitVirtualAsset(projectId: string, payload: { url: string; assetType?: string; name?: string | null; videoDuration?: number | null; videoCoverUrl?: string | null; fileSize?: number | null; mimeType?: string | null }): Promise<PrivatePortraitAsset> {
|
||||
export async function createPrivatePortraitVirtualAsset(projectId: string, payload: { url: string; assetType?: string; name?: string | null; videoDuration?: number | null; videoCoverUrl?: string | null; fileSize?: number | null; mimeType?: string | null; uploadResourceId?: string | null }): Promise<PrivatePortraitAsset> {
|
||||
return api.post<PrivatePortraitAsset>(`/private-portrait/virtual-projects/${projectId}/assets`, {
|
||||
url: payload.url,
|
||||
asset_type: payload.assetType || 'Image',
|
||||
@@ -1036,6 +1074,7 @@ export async function createPrivatePortraitVirtualAsset(projectId: string, paylo
|
||||
video_cover_url: payload.videoCoverUrl || null,
|
||||
file_size: payload.fileSize ?? null,
|
||||
mime_type: payload.mimeType || null,
|
||||
upload_resource_id: payload.uploadResourceId || null,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
|
||||
import { Button, Input, Modal, Space, Upload, message } from 'antd';
|
||||
import { UploadOutlined } from '@ant-design/icons';
|
||||
import type { UploadFile } from 'antd/es/upload/interface';
|
||||
import { createPrivatePortraitAsset, uploadImage, uploadVideo } from '../../../api';
|
||||
import { createPrivatePortraitAsset, uploadPrivatePortraitImage, uploadPrivatePortraitVideo } from '../../../api';
|
||||
|
||||
const MIN_PRIVATE_VIDEO_DURATION = 2;
|
||||
const MAX_PRIVATE_VIDEO_DURATION = 15;
|
||||
@@ -89,14 +89,15 @@ const PrivatePortraitAssetUpload: React.FC<Props> = ({ projectId, open, onClose,
|
||||
return;
|
||||
}
|
||||
|
||||
const uploaded = assetType === 'Video' ? await uploadVideo(file) : await uploadImage(file);
|
||||
const uploaded = assetType === 'Video' ? await uploadPrivatePortraitVideo(file, videoDuration || undefined) : await uploadPrivatePortraitImage(file);
|
||||
await createPrivatePortraitAsset(projectId, {
|
||||
url: uploaded.url,
|
||||
assetType,
|
||||
name: name.trim() || file.name,
|
||||
videoDuration,
|
||||
fileSize: file.size,
|
||||
videoDuration: uploaded.duration_seconds ?? videoDuration,
|
||||
fileSize: uploaded.file_size_bytes ?? file.size,
|
||||
mimeType: file.type || null,
|
||||
uploadResourceId: uploaded.resource_id || null,
|
||||
});
|
||||
message.success(assetType === 'Video' ? '视频素材已提交入库,处理中' : '图片素材已提交入库,处理中');
|
||||
reset();
|
||||
|
||||
@@ -35,8 +35,8 @@ import {
|
||||
deletePrivatePortraitVirtualProject,
|
||||
getPrivatePortraitVirtualAssets,
|
||||
getPrivatePortraitVirtualProjects,
|
||||
uploadImage,
|
||||
uploadVideo,
|
||||
uploadPrivatePortraitVirtualImage,
|
||||
uploadPrivatePortraitVirtualVideo,
|
||||
} from '../../../api';
|
||||
import type { PrivatePortraitAsset, PrivatePortraitProject } from '../../../types';
|
||||
|
||||
@@ -276,14 +276,15 @@ const VirtualMaterialPanel: React.FC = () => {
|
||||
if (currentType === 'Video' && !validatePrivateVideoDuration(duration, message.error)) {
|
||||
return;
|
||||
}
|
||||
const uploaded = currentType === 'Video' ? await uploadVideo(file) : await uploadImage(file);
|
||||
const uploaded = currentType === 'Video' ? await uploadPrivatePortraitVirtualVideo(file, duration || undefined) : await uploadPrivatePortraitVirtualImage(file);
|
||||
await createPrivatePortraitVirtualAsset(selectedProjectId, {
|
||||
url: uploaded.url,
|
||||
assetType: currentType,
|
||||
name: assetName.trim() || file.name,
|
||||
videoDuration: duration,
|
||||
fileSize: file.size,
|
||||
videoDuration: uploaded.duration_seconds ?? duration,
|
||||
fileSize: uploaded.file_size_bytes ?? file.size,
|
||||
mimeType: file.type || null,
|
||||
uploadResourceId: uploaded.resource_id || null,
|
||||
});
|
||||
message.success(currentType === 'Video' ? '视频素材已提交入库,处理中' : '图片素材已提交入库,处理中');
|
||||
setUploadOpen(false);
|
||||
|
||||
Reference in New Issue
Block a user