forked from 77media/video-flow
统一创建入口:V4接口
This commit is contained in:
parent
bb56a0bdaf
commit
680ddd7cc6
@ -334,3 +334,43 @@ export interface TextToImageResponse {
|
|||||||
/** 是否成功 */
|
/** 是否成功 */
|
||||||
successful: boolean;
|
successful: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建电影V4接口请求数据
|
||||||
|
*/
|
||||||
|
export interface CreateMovieProjectV4Request {
|
||||||
|
/** 剧本内容 */
|
||||||
|
script: string;
|
||||||
|
/** 模式 */
|
||||||
|
mode: "auto" | "manual";
|
||||||
|
/** 分辨率 */
|
||||||
|
resolution: "720p" | "1080p" | "4k";
|
||||||
|
/** 语言 */
|
||||||
|
language: string;
|
||||||
|
/** 画面比例(横/竖屏) */
|
||||||
|
aspect_ratio: AspectRatioValue;
|
||||||
|
/** 是否是图生 */
|
||||||
|
is_image_to_video: boolean;
|
||||||
|
/** pcode编码 */
|
||||||
|
pcode: string;
|
||||||
|
/** 角色简介数组 */
|
||||||
|
character_briefs?: {
|
||||||
|
character_name:string;
|
||||||
|
character_description:string;
|
||||||
|
image_url:string;
|
||||||
|
}[];
|
||||||
|
/** 场景简介数组 */
|
||||||
|
scene_briefs?: {
|
||||||
|
scene_name:string;
|
||||||
|
scene_description:string;
|
||||||
|
image_url:string;
|
||||||
|
scene_type:string;
|
||||||
|
}[];
|
||||||
|
/** 道具简介数组 */
|
||||||
|
prop_briefs?: {
|
||||||
|
prop_name:string;
|
||||||
|
prop_description:string;
|
||||||
|
image_url:string;
|
||||||
|
prop_type:string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
CreateMovieProjectV2Request,
|
CreateMovieProjectV2Request,
|
||||||
CreateMovieProjectV3Request,
|
CreateMovieProjectV3Request,
|
||||||
|
CreateMovieProjectV4Request
|
||||||
} from "./DTO/movie_start_dto";
|
} from "./DTO/movie_start_dto";
|
||||||
import { post } from "./request";
|
import { post } from "./request";
|
||||||
import { getClientUserData } from './common';
|
import { getClientUserData } from './common';
|
||||||
@ -41,3 +42,17 @@ export const createMovieProjectV3 = async (
|
|||||||
const user_data = getClientUserData();
|
const user_data = getClientUserData();
|
||||||
return withQueuePolling(apiCall, { ...(request as any), user_data } as any);
|
return withQueuePolling(apiCall, { ...(request as any), user_data } as any);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建电影项目V4
|
||||||
|
* @param request - 创建项目请求参数
|
||||||
|
* @returns Promise<QueueResponse>
|
||||||
|
*/
|
||||||
|
export const createMovieProjectV4 = async (
|
||||||
|
request: CreateMovieProjectV4Request
|
||||||
|
): Promise<QueueResponse> => {
|
||||||
|
const apiCall = (params: CreateMovieProjectV4Request) =>
|
||||||
|
post<QueueResponse>("/movie/create_movie_project_v4", params);
|
||||||
|
const user_data = getClientUserData();
|
||||||
|
return withQueuePolling(apiCall, { ...(request as any), user_data } as any);
|
||||||
|
};
|
||||||
@ -1,5 +1,4 @@
|
|||||||
|
import { createMovieProject, createMovieProjectV2, createMovieProjectV3, createMovieProjectV4 } from "@/api/create_movie";
|
||||||
import { createMovieProject, createMovieProjectV2, createMovieProjectV3 } from "@/api/create_movie";
|
|
||||||
import { QueueResponse, withQueuePolling, QueueResponseData } from "@/api/movie_queue";
|
import { QueueResponse, withQueuePolling, QueueResponseData } from "@/api/movie_queue";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -11,7 +10,9 @@ export enum MovieProjectMode {
|
|||||||
/** 照片生成模式 */
|
/** 照片生成模式 */
|
||||||
IMAGE = "image",
|
IMAGE = "image",
|
||||||
/** 模板生成模式 */
|
/** 模板生成模式 */
|
||||||
TEMPLATE = "template"
|
TEMPLATE = "template",
|
||||||
|
/** V4增强模式(支持角色、场景、道具等) */
|
||||||
|
V4 = "v4"
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 创建项目响应数据 */
|
/** 创建项目响应数据 */
|
||||||
@ -43,6 +44,9 @@ export class MovieProjectService {
|
|||||||
case MovieProjectMode.TEMPLATE:
|
case MovieProjectMode.TEMPLATE:
|
||||||
apiCall = createMovieProjectV3 as (p: T) => Promise<QueueResponse>;
|
apiCall = createMovieProjectV3 as (p: T) => Promise<QueueResponse>;
|
||||||
break;
|
break;
|
||||||
|
case MovieProjectMode.V4:
|
||||||
|
apiCall = createMovieProjectV4 as (p: T) => Promise<QueueResponse>;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`不支持的创建模式: ${mode}`);
|
throw new Error(`不支持的创建模式: ${mode}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,9 @@ import { AddItemModal } from './AddItemModal';
|
|||||||
import { defaultConfig } from './config-options';
|
import { defaultConfig } from './config-options';
|
||||||
import type { ConfigOptions } from './config-options';
|
import type { ConfigOptions } from './config-options';
|
||||||
import { useDeviceType } from '@/hooks/useDeviceType';
|
import { useDeviceType } from '@/hooks/useDeviceType';
|
||||||
|
import { MovieProjectService, MovieProjectMode } from '@/app/service/Interaction/MovieProjectService';
|
||||||
|
import type { CreateMovieProjectV4Request } from '@/api/DTO/movie_start_dto';
|
||||||
|
import { getCurrentUser } from '@/lib/auth';
|
||||||
|
|
||||||
export default function VideoCreationForm() {
|
export default function VideoCreationForm() {
|
||||||
const [photos, setPhotos] = useState<PhotoItem[]>([]);
|
const [photos, setPhotos] = useState<PhotoItem[]>([]);
|
||||||
@ -28,6 +31,7 @@ export default function VideoCreationForm() {
|
|||||||
const [currentItemType, setCurrentItemType] = useState<PhotoType | null>(null);
|
const [currentItemType, setCurrentItemType] = useState<PhotoType | null>(null);
|
||||||
const [editingIndex, setEditingIndex] = useState<number | null>(null);
|
const [editingIndex, setEditingIndex] = useState<number | null>(null);
|
||||||
const [replacingIndex, setReplacingIndex] = useState<number | null>(null);
|
const [replacingIndex, setReplacingIndex] = useState<number | null>(null);
|
||||||
|
const [isCreating, setIsCreating] = useState(false);
|
||||||
|
|
||||||
const { isMobile, isDesktop } = useDeviceType();
|
const { isMobile, isDesktop } = useDeviceType();
|
||||||
|
|
||||||
@ -74,13 +78,6 @@ export default function VideoCreationForm() {
|
|||||||
setConfigOptions(prev => ({ ...prev, [key]: value }));
|
setConfigOptions(prev => ({ ...prev, [key]: value }));
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Handle opening add item modal */
|
|
||||||
const handleOpenAddItemModal = (type: PhotoType) => {
|
|
||||||
setCurrentItemType(type);
|
|
||||||
setEditingIndex(null);
|
|
||||||
setAddItemModalVisible(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Handle editing a photo */
|
/** Handle editing a photo */
|
||||||
const handleEditPhoto = (index: number) => {
|
const handleEditPhoto = (index: number) => {
|
||||||
const photo = photos[index];
|
const photo = photos[index];
|
||||||
@ -165,13 +162,89 @@ export default function VideoCreationForm() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** Handle video creation */
|
/** Handle video creation */
|
||||||
const handleCreate = () => {
|
const handleCreate = async () => {
|
||||||
console.log({
|
if (isCreating) return;
|
||||||
text: inputText,
|
|
||||||
photos,
|
if (!inputText.trim()) {
|
||||||
config: configOptions,
|
window.msg?.warning('Please enter your story description');
|
||||||
});
|
return;
|
||||||
// TODO: Implement video creation logic
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
setIsCreating(true);
|
||||||
|
|
||||||
|
const user = getCurrentUser();
|
||||||
|
if (!user?.id) {
|
||||||
|
window.msg?.error('Please login first');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Separate photos by type */
|
||||||
|
const characterPhotos = photos.filter(p => p.type === 'character');
|
||||||
|
const scenePhotos = photos.filter(p => p.type === 'scene');
|
||||||
|
const propPhotos = photos.filter(p => p.type === 'prop');
|
||||||
|
|
||||||
|
/** Build request parameters */
|
||||||
|
const requestParams: CreateMovieProjectV4Request = {
|
||||||
|
script: inputText,
|
||||||
|
mode: configOptions.expansion_mode ? 'auto' : 'manual',
|
||||||
|
resolution: '720p',
|
||||||
|
language: configOptions.language,
|
||||||
|
aspect_ratio: configOptions.aspect_ratio,
|
||||||
|
is_image_to_video: photos.length > 0,
|
||||||
|
pcode: configOptions.pcode,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Add character briefs if exists */
|
||||||
|
if (characterPhotos.length > 0) {
|
||||||
|
requestParams.character_briefs = characterPhotos.map(photo => ({
|
||||||
|
character_name: photo.name || 'Character',
|
||||||
|
character_description: photo.description || '',
|
||||||
|
image_url: photo.url,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add scene briefs if exists */
|
||||||
|
if (scenePhotos.length > 0) {
|
||||||
|
requestParams.scene_briefs = scenePhotos.map(photo => ({
|
||||||
|
scene_name: photo.name || 'Scene',
|
||||||
|
scene_description: photo.description || '',
|
||||||
|
image_url: photo.url,
|
||||||
|
scene_type: 'custom',
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add prop briefs if exists */
|
||||||
|
if (propPhotos.length > 0) {
|
||||||
|
requestParams.prop_briefs = propPhotos.map(photo => ({
|
||||||
|
prop_name: photo.name || 'Prop',
|
||||||
|
prop_description: photo.description || '',
|
||||||
|
image_url: photo.url,
|
||||||
|
prop_type: 'custom',
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Creating video with params:', requestParams);
|
||||||
|
|
||||||
|
/** Call MovieProjectService V4 API */
|
||||||
|
const result = await MovieProjectService.createProject<CreateMovieProjectV4Request>(
|
||||||
|
MovieProjectMode.V4,
|
||||||
|
requestParams
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('Video creation successful, project_id:', result.project_id);
|
||||||
|
window.msg?.success(`Video created successfully! Project ID: ${result.project_id}`);
|
||||||
|
|
||||||
|
/** TODO: Navigate to project detail page or next step */
|
||||||
|
// window.location.href = `/movies/${result.project_id}`;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to create video:', error);
|
||||||
|
if (error instanceof Error && error.message !== '操作已取消') {
|
||||||
|
window.msg?.error(error.message || 'Failed to create video');
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
setIsCreating(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -298,10 +371,15 @@ export default function VideoCreationForm() {
|
|||||||
{/* Right Side - Create Button */}
|
{/* Right Side - Create Button */}
|
||||||
<button
|
<button
|
||||||
data-alt="create-button"
|
data-alt="create-button"
|
||||||
className="w-8 h-8 rounded-full bg-black hover:bg-gray-900 border border-white/20 hover:border-cyan-400/60 transition-all duration-200 flex items-center justify-center text-white shadow-lg hover:shadow-cyan-400/20"
|
className="w-8 h-8 rounded-full bg-black hover:bg-gray-900 border border-white/20 hover:border-cyan-400/60 transition-all duration-200 flex items-center justify-center text-white shadow-lg hover:shadow-cyan-400/20 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
onClick={handleCreate}
|
onClick={handleCreate}
|
||||||
|
disabled={isCreating}
|
||||||
>
|
>
|
||||||
|
{isCreating ? (
|
||||||
|
<span className="animate-spin inline-block w-4 h-4 border-2 border-white border-t-transparent rounded-full" />
|
||||||
|
) : (
|
||||||
<ArrowRightOutlined className="text-base font-bold" />
|
<ArrowRightOutlined className="text-base font-bold" />
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user