forked from 77media/video-flow
统一创建入口:V4接口
This commit is contained in:
parent
bb56a0bdaf
commit
680ddd7cc6
@ -334,3 +334,43 @@ export interface TextToImageResponse {
|
||||
/** 是否成功 */
|
||||
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 {
|
||||
CreateMovieProjectV2Request,
|
||||
CreateMovieProjectV3Request,
|
||||
CreateMovieProjectV4Request
|
||||
} from "./DTO/movie_start_dto";
|
||||
import { post } from "./request";
|
||||
import { getClientUserData } from './common';
|
||||
@ -41,3 +42,17 @@ export const createMovieProjectV3 = async (
|
||||
const user_data = getClientUserData();
|
||||
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 } from "@/api/create_movie";
|
||||
import { createMovieProject, createMovieProjectV2, createMovieProjectV3, createMovieProjectV4 } from "@/api/create_movie";
|
||||
import { QueueResponse, withQueuePolling, QueueResponseData } from "@/api/movie_queue";
|
||||
|
||||
/**
|
||||
@ -11,7 +10,9 @@ export enum MovieProjectMode {
|
||||
/** 照片生成模式 */
|
||||
IMAGE = "image",
|
||||
/** 模板生成模式 */
|
||||
TEMPLATE = "template"
|
||||
TEMPLATE = "template",
|
||||
/** V4增强模式(支持角色、场景、道具等) */
|
||||
V4 = "v4"
|
||||
}
|
||||
|
||||
/** 创建项目响应数据 */
|
||||
@ -43,6 +44,9 @@ export class MovieProjectService {
|
||||
case MovieProjectMode.TEMPLATE:
|
||||
apiCall = createMovieProjectV3 as (p: T) => Promise<QueueResponse>;
|
||||
break;
|
||||
case MovieProjectMode.V4:
|
||||
apiCall = createMovieProjectV4 as (p: T) => Promise<QueueResponse>;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`不支持的创建模式: ${mode}`);
|
||||
}
|
||||
|
||||
@ -18,6 +18,9 @@ import { AddItemModal } from './AddItemModal';
|
||||
import { defaultConfig } from './config-options';
|
||||
import type { ConfigOptions } from './config-options';
|
||||
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() {
|
||||
const [photos, setPhotos] = useState<PhotoItem[]>([]);
|
||||
@ -28,6 +31,7 @@ export default function VideoCreationForm() {
|
||||
const [currentItemType, setCurrentItemType] = useState<PhotoType | null>(null);
|
||||
const [editingIndex, setEditingIndex] = useState<number | null>(null);
|
||||
const [replacingIndex, setReplacingIndex] = useState<number | null>(null);
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
|
||||
const { isMobile, isDesktop } = useDeviceType();
|
||||
|
||||
@ -74,13 +78,6 @@ export default function VideoCreationForm() {
|
||||
setConfigOptions(prev => ({ ...prev, [key]: value }));
|
||||
};
|
||||
|
||||
/** Handle opening add item modal */
|
||||
const handleOpenAddItemModal = (type: PhotoType) => {
|
||||
setCurrentItemType(type);
|
||||
setEditingIndex(null);
|
||||
setAddItemModalVisible(true);
|
||||
};
|
||||
|
||||
/** Handle editing a photo */
|
||||
const handleEditPhoto = (index: number) => {
|
||||
const photo = photos[index];
|
||||
@ -165,13 +162,89 @@ export default function VideoCreationForm() {
|
||||
};
|
||||
|
||||
/** Handle video creation */
|
||||
const handleCreate = () => {
|
||||
console.log({
|
||||
text: inputText,
|
||||
photos,
|
||||
config: configOptions,
|
||||
});
|
||||
// TODO: Implement video creation logic
|
||||
const handleCreate = async () => {
|
||||
if (isCreating) return;
|
||||
|
||||
if (!inputText.trim()) {
|
||||
window.msg?.warning('Please enter your story description');
|
||||
return;
|
||||
}
|
||||
|
||||
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 (
|
||||
@ -298,10 +371,15 @@ export default function VideoCreationForm() {
|
||||
{/* Right Side - Create Button */}
|
||||
<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}
|
||||
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" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user