forked from 77media/video-flow
重构角色编辑相关接口,更新角色数据结构以支持新字段,优化角色列表和用户角色库的获取逻辑,增强角色选择功能。
This commit is contained in:
parent
03aa092a08
commit
3f1f2e34c8
@ -84,93 +84,21 @@ export enum Gender {
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色信息接口
|
||||
* 草图提示JSON结构接口
|
||||
*/
|
||||
export interface Character {
|
||||
/** 角色唯一标识符 */
|
||||
id: string;
|
||||
/** 角色名称 */
|
||||
name: string;
|
||||
/** 角色描述,包含外貌、性格等详细信息 */
|
||||
description: string;
|
||||
/** 角色类型 */
|
||||
role: RoleType;
|
||||
/** 角色年龄 */
|
||||
age: number;
|
||||
/** 角色性别 */
|
||||
gender: Gender;
|
||||
/** 角色种族 */
|
||||
race: Race;
|
||||
/** 角色简介 */
|
||||
brief?: string;
|
||||
/** 角色体型描述 */
|
||||
physique?: string;
|
||||
/** 角色发型描述 */
|
||||
hairstyle?: string;
|
||||
/** 角色默认举止描述 */
|
||||
default_demeanor?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 服装信息接口
|
||||
*/
|
||||
export interface Wardrobe {
|
||||
/** 服装所属角色ID */
|
||||
belongs_to: string;
|
||||
/** 服装详细描述 */
|
||||
description: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景信息接口
|
||||
*/
|
||||
export interface Scene {
|
||||
/** 场景名称 */
|
||||
name: string;
|
||||
/** 场景详细描述 */
|
||||
description: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目风格信息接口
|
||||
*/
|
||||
export interface ProjectStyle {
|
||||
/** 地理设置和种族信息 */
|
||||
geographic_setting_ethnicity: string;
|
||||
/** 格式要求 */
|
||||
format: string;
|
||||
/** 美学风格描述 */
|
||||
aesthetics: string;
|
||||
/** 技术蓝图 */
|
||||
technical_blueprint: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提示JSON结构接口
|
||||
*/
|
||||
export interface PromptJson {
|
||||
/** 导演指令 */
|
||||
directors_directive: string;
|
||||
/** 叙事提示 */
|
||||
narrative_prompt: string;
|
||||
/** 对话语言 */
|
||||
dialogue_language: string;
|
||||
/** 整体项目风格 */
|
||||
overall_project_style: string;
|
||||
/** 主要角色列表 */
|
||||
master_character_list: MasterCharacter[];
|
||||
/** 主要服装列表 */
|
||||
master_wardrobe_list: MasterWardrobe[];
|
||||
/** 主要场景列表 */
|
||||
master_scene_list: MasterScene[];
|
||||
export interface SketchPromptJson {
|
||||
/** 草图名称 */
|
||||
sketch_name: string;
|
||||
/** 草图描述 */
|
||||
sketch_description: string;
|
||||
/** 核心氛围 */
|
||||
core_atmosphere: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景草图项
|
||||
* 草图数据项
|
||||
*/
|
||||
export interface SketchItem {
|
||||
export interface SketchData {
|
||||
/** 草图名称 */
|
||||
sketch_name: string;
|
||||
/** 图片ID */
|
||||
@ -178,51 +106,97 @@ export enum Gender {
|
||||
/** 提示词 */
|
||||
prompt: string;
|
||||
/** 提示词JSON */
|
||||
prompt_json: PromptJson;
|
||||
/** 草图名称前缀 */
|
||||
sketch_name_prefix: string;
|
||||
/** 图片URL列表 */
|
||||
urls: string[];
|
||||
prompt_json: SketchPromptJson;
|
||||
/** 图片路径 */
|
||||
image_path: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 镜头草图项
|
||||
* 草图响应数据接口
|
||||
*/
|
||||
export interface ShotSketchItem {
|
||||
/** 镜头草图名称 */
|
||||
shot_sketch_name: string;
|
||||
export interface SketchResponse {
|
||||
/** 总数 */
|
||||
total_count: number;
|
||||
/** 草图数据列表 */
|
||||
data: SketchData[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色响应数据接口
|
||||
*/
|
||||
export interface CharacterResponse {
|
||||
/** 角色图片路径 */
|
||||
image_path: string;
|
||||
/** 角色名称 */
|
||||
character_name: string;
|
||||
/** 角色描述 */
|
||||
character_description: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色数据接口
|
||||
*/
|
||||
export interface CharacterData {
|
||||
/** 角色数据列表 */
|
||||
data: CharacterResponse[];
|
||||
/** 总数 */
|
||||
total_count: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 镜头草图提示JSON结构接口
|
||||
*/
|
||||
export interface ShotSketchPromptJson {
|
||||
/** 镜头类型 */
|
||||
shot_type: string;
|
||||
/** 帧描述 */
|
||||
frame_description: string;
|
||||
/** 关键动作 */
|
||||
key_action: string;
|
||||
/** 氛围 */
|
||||
atmosphere: string;
|
||||
/** 摄影蓝图构图 */
|
||||
cinematography_blueprint_composition: string;
|
||||
/** 摄影蓝图镜头运动 */
|
||||
cinematography_blueprint_camera_motion: string;
|
||||
/** 对话表演台词 */
|
||||
dialogue_performance_line?: any;
|
||||
/** 对话表演语言 */
|
||||
dialogue_performance_language?: any;
|
||||
/** 对话表演表达 */
|
||||
dialogue_performance_delivery?: any;
|
||||
/** 对话表演说话者 */
|
||||
dialogue_performance_speaker?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 镜头草图数据项
|
||||
*/
|
||||
export interface ShotSketchData {
|
||||
/** 图片ID */
|
||||
image_id: string;
|
||||
/** 提示词 */
|
||||
prompt: string;
|
||||
/** 提示词JSON */
|
||||
prompt_json: PromptJson;
|
||||
/** 镜头草图名称前缀 */
|
||||
shot_sketch_name_prefix: string;
|
||||
/** 图片URL列表 */
|
||||
urls: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频项
|
||||
*/
|
||||
export interface VideoItem {
|
||||
/** 视频ID */
|
||||
video_id: string;
|
||||
/** 描述 */
|
||||
description: string;
|
||||
/** 提示词JSON */
|
||||
prompt_json: PromptJson;
|
||||
/** 视频名称前缀 */
|
||||
video_name_prefix: string;
|
||||
/** 视频URL列表 */
|
||||
urls: string[];
|
||||
prompt_json: ShotSketchPromptJson;
|
||||
/** 图片URL */
|
||||
url: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 主要角色
|
||||
* 镜头草图响应数据接口
|
||||
*/
|
||||
export interface MasterCharacter {
|
||||
export interface ShotSketchResponse {
|
||||
/** 镜头草图数据列表 */
|
||||
data: ShotSketchData[];
|
||||
/** 总数 */
|
||||
total_count: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 主要角色列表项
|
||||
*/
|
||||
export interface MasterCharacterListItem {
|
||||
/** 角色ID */
|
||||
id: string;
|
||||
/** 角色名称 */
|
||||
@ -232,9 +206,9 @@ export enum Gender {
|
||||
}
|
||||
|
||||
/**
|
||||
* 主要服装
|
||||
* 主要服装列表项
|
||||
*/
|
||||
export interface MasterWardrobe {
|
||||
export interface MasterWardrobeListItem {
|
||||
/** 所属角色 */
|
||||
belongs_to: string;
|
||||
/** 服装描述 */
|
||||
@ -242,9 +216,9 @@ export enum Gender {
|
||||
}
|
||||
|
||||
/**
|
||||
* 主要场景
|
||||
* 主要场景列表项
|
||||
*/
|
||||
export interface MasterScene {
|
||||
export interface MasterSceneListItem {
|
||||
/** 场景名称 */
|
||||
name: string;
|
||||
/** 场景描述 */
|
||||
@ -252,11 +226,49 @@ export enum Gender {
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频数据
|
||||
* 视频提示JSON结构接口
|
||||
*/
|
||||
export interface VideoPromptJson {
|
||||
/** 导演指令 */
|
||||
directors_directive: string;
|
||||
/** 叙事提示 */
|
||||
narrative_prompt: string;
|
||||
/** 对话语言 */
|
||||
dialogue_language: string;
|
||||
/** 整体项目风格 */
|
||||
overall_project_style: string;
|
||||
/** 主要角色列表 */
|
||||
master_character_list: MasterCharacterListItem[];
|
||||
/** 主要服装列表 */
|
||||
master_wardrobe_list: MasterWardrobeListItem[];
|
||||
/** 主要场景列表 */
|
||||
master_scene_list: MasterSceneListItem[];
|
||||
/** 核心氛围 */
|
||||
core_atmosphere: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频数据项
|
||||
*/
|
||||
export interface VideoData {
|
||||
/** 视频列表 */
|
||||
data: VideoItem[];
|
||||
/** 视频ID */
|
||||
video_id: string;
|
||||
/** 描述 */
|
||||
description: string;
|
||||
/** 提示词JSON */
|
||||
prompt_json: VideoPromptJson;
|
||||
/** 视频名称前缀 */
|
||||
video_name_prefix: string;
|
||||
/** 视频URL列表 */
|
||||
urls: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频响应数据接口
|
||||
*/
|
||||
export interface VideoResponse {
|
||||
/** 视频数据列表 */
|
||||
data: VideoData[];
|
||||
/** 总数 */
|
||||
total_count: number;
|
||||
/** 全局ID */
|
||||
@ -266,37 +278,14 @@ export enum Gender {
|
||||
}
|
||||
|
||||
/**
|
||||
* 音乐数据
|
||||
* 音乐数据接口
|
||||
*/
|
||||
export interface MusicData {
|
||||
[key: string]: any;
|
||||
}
|
||||
/**
|
||||
* 视频信息接口
|
||||
*/
|
||||
export interface Video {
|
||||
/** 视频唯一标识符 */
|
||||
video_id: string;
|
||||
/** 视频描述 */
|
||||
description: string;
|
||||
/** 提示JSON数据 */
|
||||
prompt_json: PromptJson;
|
||||
/** 视频名称前缀 */
|
||||
video_name_prefix: string;
|
||||
/** 视频URL列表 */
|
||||
urls: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 音乐信息接口
|
||||
*/
|
||||
export interface Music {
|
||||
/** 音乐相关数据,当前为空对象 */
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 最终视频信息接口
|
||||
* 最终视频接口
|
||||
*/
|
||||
export interface FinalVideo {
|
||||
/** 最终视频URL */
|
||||
@ -304,126 +293,24 @@ export enum Gender {
|
||||
}
|
||||
|
||||
/**
|
||||
* 多语言视频信息接口
|
||||
* 多语言视频接口
|
||||
*/
|
||||
export interface MultilingualVideo {
|
||||
/** 多语言视频相关数据,当前为空对象 */
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目设置接口
|
||||
* 项目内容数据接口
|
||||
*/
|
||||
export interface ProjectSettings {
|
||||
/** 视频质量设置 */
|
||||
quality: string;
|
||||
/** 帧率设置 */
|
||||
frame_rate: string;
|
||||
/** 分辨率设置 */
|
||||
resolution: string;
|
||||
/** 音频设置 */
|
||||
audio: {
|
||||
/** 音频质量 */
|
||||
quality: string;
|
||||
/** 音频格式 */
|
||||
format: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目统计信息接口
|
||||
*/
|
||||
export interface ProjectStatistics {
|
||||
/** 总视频数 */
|
||||
total_videos: number;
|
||||
/** 总角色数 */
|
||||
total_characters: number;
|
||||
/** 总场景数 */
|
||||
total_scenes: number;
|
||||
/** 总服装数 */
|
||||
total_wardrobes: number;
|
||||
/** 总音乐数 */
|
||||
total_music: number;
|
||||
/** 总时长 */
|
||||
total_duration: number;
|
||||
/** 总大小 */
|
||||
total_size: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目元数据接口
|
||||
*/
|
||||
export interface ProjectMetadata {
|
||||
/** 项目版本 */
|
||||
version: string;
|
||||
/** 项目语言 */
|
||||
language: string;
|
||||
/** 项目分类 */
|
||||
category: string;
|
||||
/** 项目难度 */
|
||||
difficulty: string;
|
||||
/** 项目时长 */
|
||||
duration: string;
|
||||
/** 项目预算 */
|
||||
budget: string;
|
||||
/** 项目团队 */
|
||||
team: string[];
|
||||
/** 项目设备 */
|
||||
equipment: string[];
|
||||
/** 项目软件 */
|
||||
software: string[];
|
||||
/** 项目许可证 */
|
||||
license: string;
|
||||
/** 项目版权 */
|
||||
copyright: string;
|
||||
/** 项目评分 */
|
||||
rating: number;
|
||||
/** 项目评论数 */
|
||||
review_count: number;
|
||||
/** 项目下载数 */
|
||||
download_count: number;
|
||||
/** 项目分享数 */
|
||||
share_count: number;
|
||||
/** 项目收藏数 */
|
||||
favorite_count: number;
|
||||
/** 项目观看数 */
|
||||
view_count: number;
|
||||
/** 项目完成度 */
|
||||
completion_rate: number;
|
||||
/** 项目进度 */
|
||||
progress: number;
|
||||
/** 项目阶段 */
|
||||
stage: string;
|
||||
/** 项目里程碑 */
|
||||
milestones: string[];
|
||||
/** 项目任务 */
|
||||
tasks: string[];
|
||||
/** 项目文件 */
|
||||
files: string[];
|
||||
/** 项目链接 */
|
||||
links: string[];
|
||||
/** 项目备注 */
|
||||
notes: string;
|
||||
/** 项目历史 */
|
||||
history: string[];
|
||||
/** 项目日志 */
|
||||
logs: string[];
|
||||
/** 项目统计 */
|
||||
statistics: ProjectStatistics;
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目内容接口
|
||||
*/
|
||||
export interface ProjectContent {
|
||||
export interface ProjectContentData {
|
||||
/** 草图数据 */
|
||||
sketch: SketchItem[];
|
||||
sketch: SketchResponse;
|
||||
/** 角色数据 */
|
||||
character: Character[];
|
||||
character: CharacterData;
|
||||
/** 镜头草图数据 */
|
||||
shot_sketch: ShotSketchItem[];
|
||||
shot_sketch: ShotSketchResponse;
|
||||
/** 视频数据 */
|
||||
video: VideoData;
|
||||
video: VideoResponse;
|
||||
/** 音乐数据 */
|
||||
music: MusicData;
|
||||
/** 最终视频 */
|
||||
@ -432,40 +319,6 @@ export enum Gender {
|
||||
multilingual_video: MultilingualVideo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频流程项目接口
|
||||
*/
|
||||
export interface VideoFlowProject {
|
||||
/** 项目名称 */
|
||||
name: string;
|
||||
/** 项目描述 */
|
||||
description: string;
|
||||
/** 项目类型 */
|
||||
type: string;
|
||||
/** 项目状态 */
|
||||
status: string;
|
||||
/** 项目创建时间 */
|
||||
created_at: string;
|
||||
/** 项目更新时间 */
|
||||
updated_at: string;
|
||||
/** 项目所有者ID */
|
||||
owner_id: string;
|
||||
/** 项目标签列表 */
|
||||
tags: string[];
|
||||
/** 项目设置 */
|
||||
settings: ProjectSettings;
|
||||
/** 项目元数据 */
|
||||
metadata: ProjectMetadata;
|
||||
/** 项目内容 */
|
||||
content: ProjectContent;
|
||||
/** 音乐信息 */
|
||||
music: Music;
|
||||
/** 最终视频 */
|
||||
final_video: FinalVideo;
|
||||
/** 多语言视频 */
|
||||
multilingual_video: MultilingualVideo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频流程项目 - 完整的接口返回值类型
|
||||
*/
|
||||
@ -475,17 +328,17 @@ export enum Gender {
|
||||
/** 项目ID */
|
||||
project_id: string;
|
||||
/** 项目模式 */
|
||||
mode: ProjectMode;
|
||||
mode: string;
|
||||
/** 分辨率 */
|
||||
resolution: Resolution;
|
||||
resolution: string;
|
||||
/** 语言 */
|
||||
language: Language;
|
||||
language: string;
|
||||
/** 原始文本 */
|
||||
original_text: string;
|
||||
/** 生成的脚本 */
|
||||
generated_script: string;
|
||||
/** 项目状态 */
|
||||
status: ProjectStatus;
|
||||
status: string;
|
||||
/** 项目标题 */
|
||||
title: string;
|
||||
/** 项目类型 */
|
||||
@ -493,11 +346,21 @@ export enum Gender {
|
||||
/** 项目标签 */
|
||||
tags: string[];
|
||||
/** 项目步骤 */
|
||||
step: ProjectStep;
|
||||
step: string;
|
||||
/** 最后消息 */
|
||||
last_message: string;
|
||||
/** 项目内容 */
|
||||
data: ProjectContent;
|
||||
data: ProjectContentData;
|
||||
}
|
||||
|
||||
// 为了向后兼容,保留原有的接口名称
|
||||
export interface Character extends CharacterResponse {}
|
||||
export interface Sketch extends SketchResponse {}
|
||||
export interface Shot_sketch extends ShotSketchResponse {}
|
||||
export interface Video extends VideoResponse {}
|
||||
export interface Music extends MusicData {}
|
||||
export interface Final_video extends FinalVideo {}
|
||||
export interface Multilingual_video extends MultilingualVideo {}
|
||||
export interface RootObject extends VideoFlowProjectResponse {}
|
||||
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { useState, useCallback, useMemo } from 'react';
|
||||
import { RoleEntity, AITextEntity } from '../domain/Entities';
|
||||
import { RoleEditUseCase } from '../usecase/RoleEditUseCase';
|
||||
import { getRoleData, getRoleList, getUserRoleLibrary, replaceRole } from '@/api/video_flow';
|
||||
import { getUploadToken, uploadToQiniu } from '@/api/common';
|
||||
|
||||
/**
|
||||
@ -70,12 +69,12 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
*/
|
||||
const fetchRoleList = useCallback(async (projectId: string) => {
|
||||
try {
|
||||
const response = await getRoleList({ projectId });
|
||||
if (response.successful) {
|
||||
setRoleList(response.data);
|
||||
} else {
|
||||
throw new Error(`获取角色列表失败: ${response.message}`);
|
||||
}
|
||||
// 初始化角色编辑UseCase实例
|
||||
const newRoleEditUseCase = new RoleEditUseCase();
|
||||
const roleList = await newRoleEditUseCase.getRoleList(projectId);
|
||||
|
||||
setRoleList(roleList);
|
||||
setRoleEditUseCase(newRoleEditUseCase);
|
||||
} catch (error) {
|
||||
console.error('获取角色列表失败:', error);
|
||||
throw error;
|
||||
@ -90,18 +89,7 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
* @returns {Promise<void>} 初始化完成后的Promise
|
||||
*/
|
||||
const initializeRoleData = useCallback(async (roleId: string) => {
|
||||
try {
|
||||
const response = await getRoleData({ roleId });
|
||||
if (response.successful) {
|
||||
const { text } = response.data;
|
||||
setCurrentRoleText(text.content);
|
||||
} else {
|
||||
throw new Error(`获取角色数据失败: ${response.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('初始化角色数据失败:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
}, []);
|
||||
|
||||
/**
|
||||
@ -114,18 +102,22 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
if (role) {
|
||||
setSelectedRole(role);
|
||||
|
||||
// 初始化角色编辑UseCase实例
|
||||
const newRoleEditUseCase = new RoleEditUseCase();
|
||||
newRoleEditUseCase.roleList = roleList;
|
||||
await newRoleEditUseCase.selectRole(roleId);
|
||||
setRoleEditUseCase(newRoleEditUseCase);
|
||||
// 如果RoleEditUseCase已经初始化,直接使用;否则创建新的
|
||||
if (!roleEditUseCase) {
|
||||
const newRoleEditUseCase = new RoleEditUseCase();
|
||||
newRoleEditUseCase.roleList = roleList;
|
||||
setRoleEditUseCase(newRoleEditUseCase);
|
||||
}
|
||||
|
||||
// 调用selectRole方法
|
||||
await roleEditUseCase!.selectRole(roleId);
|
||||
|
||||
// 初始化角色数据
|
||||
await initializeRoleData(roleId);
|
||||
} else {
|
||||
throw new Error('未找到对应的角色');
|
||||
}
|
||||
}, [initializeRoleData, roleList]);
|
||||
}, [roleList, roleEditUseCase, initializeRoleData]);
|
||||
|
||||
/**
|
||||
* 优化AI文本
|
||||
@ -236,17 +228,19 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
*/
|
||||
const fetchUserRoleLibrary = useCallback(async () => {
|
||||
try {
|
||||
const response = await getUserRoleLibrary();
|
||||
if (response.successful) {
|
||||
setUserRoleLibrary(response.data);
|
||||
} else {
|
||||
throw new Error(`获取用户角色库失败: ${response.message}`);
|
||||
// 如果没有初始化RoleEditUseCase,创建一个新的实例
|
||||
if (!roleEditUseCase) {
|
||||
const newRoleEditUseCase = new RoleEditUseCase();
|
||||
setRoleEditUseCase(newRoleEditUseCase);
|
||||
}
|
||||
|
||||
const roleLibraryList = await roleEditUseCase!.getRoleLibraryList();
|
||||
setUserRoleLibrary(roleLibraryList);
|
||||
} catch (error) {
|
||||
console.error('获取用户角色库失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}, []);
|
||||
}, [roleEditUseCase]);
|
||||
|
||||
/**
|
||||
* 替换角色
|
||||
|
||||
@ -47,15 +47,15 @@ export class RoleEditUseCase {
|
||||
}
|
||||
|
||||
parseRoleList(detail: VideoFlowProjectResponse): RoleEntity[] {
|
||||
const characters = detail.data?.character || [];
|
||||
const characters = detail.data?.character.data || [];
|
||||
|
||||
return characters.map((char, index) => {
|
||||
const roleEntity: RoleEntity = {
|
||||
id: `role_${index + 1}`,
|
||||
name: char.name || '',
|
||||
generateText: char.description || '',
|
||||
name: char.character_name || '',
|
||||
generateText: char.character_description || '',
|
||||
tags: [], // 默认为空标签数组
|
||||
imageUrl: '', // 默认为空图片URL
|
||||
imageUrl: char.image_path || '', // 使用API返回的图片路径
|
||||
loadingProgress: 100, // 默认加载完成
|
||||
disableEdit: false, // 默认允许编辑
|
||||
updatedAt: Date.now()
|
||||
@ -265,7 +265,7 @@ export class RoleEditUseCase {
|
||||
id: `role_${Date.now()}`,
|
||||
name: '从图片识别的角色',
|
||||
generateText: '通过图片识别生成的角色描述',
|
||||
tagIds: [], // 空标签数组
|
||||
tags: [], // 空标签数组
|
||||
imageUrl: imageUrl, // 使用传入的图片地址
|
||||
loadingProgress: 100, // 加载完成
|
||||
disableEdit: false, // 允许编辑
|
||||
|
||||
@ -1,36 +1,40 @@
|
||||
import FloatingGlassPanel from './FloatingGlassPanel';
|
||||
import { ImageWave } from '@/components/ui/ImageWave';
|
||||
import { RoleEntity } from '@/app/service/domain/Entities';
|
||||
|
||||
const imageUrls = [
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-1.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-2.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-3.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-4.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-1.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-2.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-3.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-4.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-1.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-2.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-3.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-4.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-1.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-2.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-3.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-4.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-1.jpg',
|
||||
'https://d3phaj0sisr2ct.cloudfront.net/app/gen4/object-reference/welcome-ref-2.jpg',
|
||||
];
|
||||
interface CharacterLibrarySelectorProps {
|
||||
isReplaceLibraryOpen: boolean;
|
||||
setIsReplaceLibraryOpen: (open: boolean) => void;
|
||||
onSelect: (index: number) => void;
|
||||
/** 用户角色库数据 */
|
||||
userRoleLibrary: RoleEntity[];
|
||||
}
|
||||
|
||||
export function CharacterLibrarySelector({
|
||||
isReplaceLibraryOpen,
|
||||
setIsReplaceLibraryOpen,
|
||||
onSelect,
|
||||
}: {
|
||||
isReplaceLibraryOpen: boolean;
|
||||
setIsReplaceLibraryOpen: (open: boolean) => void;
|
||||
onSelect: (index: number) => void;
|
||||
}) {
|
||||
userRoleLibrary = []
|
||||
}: CharacterLibrarySelectorProps) {
|
||||
// 将 RoleEntity[] 转换为图片URL数组
|
||||
const imageUrls = userRoleLibrary.map(role => role.imageUrl);
|
||||
|
||||
// 如果没有数据,显示空状态
|
||||
if (userRoleLibrary.length === 0) {
|
||||
return (
|
||||
<FloatingGlassPanel
|
||||
open={isReplaceLibraryOpen}
|
||||
width='90vw'
|
||||
panel_style={{ background: 'unset', border: 'unset', backdropFilter: 'unset', boxShadow: 'none' }}
|
||||
onClose={() => setIsReplaceLibraryOpen(false)}
|
||||
>
|
||||
<div className="flex items-center justify-center h-64 text-white/50">
|
||||
<p>暂无角色库数据</p>
|
||||
</div>
|
||||
</FloatingGlassPanel>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<FloatingGlassPanel
|
||||
open={isReplaceLibraryOpen}
|
||||
@ -54,4 +58,4 @@ export function CharacterLibrarySelector({
|
||||
/>
|
||||
</FloatingGlassPanel>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { useState, useRef } from 'react';
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { ImageUp, Library, Play, Pause, RefreshCw, Wand2, Users, Check, ReplaceAll, X, TriangleAlert } from 'lucide-react';
|
||||
import { cn } from '@/public/lib/utils';
|
||||
@ -8,6 +8,7 @@ import FloatingGlassPanel from './FloatingGlassPanel';
|
||||
import { ReplaceCharacterPanel, mockShots, mockCharacter } from './replace-character-panel';
|
||||
import { CharacterLibrarySelector } from './character-library-selector';
|
||||
import HorizontalScroller from './HorizontalScroller';
|
||||
import { useRoleServiceHook } from '@/app/service/Interaction/RoleService';
|
||||
|
||||
interface Appearance {
|
||||
hairStyle: string;
|
||||
@ -56,7 +57,7 @@ interface CharacterTabContentProps {
|
||||
roles: Role[];
|
||||
}
|
||||
|
||||
export function CharacterTabContent({
|
||||
export function CharacterTabContent({
|
||||
taskSketch,
|
||||
currentRoleIndex,
|
||||
onSketchSelect,
|
||||
@ -73,7 +74,14 @@ export function CharacterTabContent({
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const [enableAnimation, setEnableAnimation] = useState(true);
|
||||
const [showAddToLibrary, setShowAddToLibrary] = useState(true);
|
||||
|
||||
const {fetchRoleList,roleList,fetchUserRoleLibrary,userRoleLibrary} = useRoleServiceHook()
|
||||
useEffect(() => {
|
||||
// 从url 获取 episodeId 作为projctId
|
||||
const projectId = new URLSearchParams(window.location.search).get('episodeId');
|
||||
if (projectId) {
|
||||
fetchRoleList(projectId);
|
||||
}
|
||||
}, [fetchRoleList]);
|
||||
const handleConfirmGotoReplace = () => {
|
||||
setIsRemindReplacePanelOpen(false);
|
||||
setIsReplacePanelOpen(true);
|
||||
@ -122,15 +130,23 @@ export function CharacterTabContent({
|
||||
|
||||
// 从角色库中选择角色
|
||||
const handleSelectCharacter = (index: number) => {
|
||||
console.log('index', index);
|
||||
console.log('选择的角色索引:', index);
|
||||
console.log('选择的角色数据:', userRoleLibrary[index]);
|
||||
|
||||
setIsReplaceLibraryOpen(false);
|
||||
setShowAddToLibrary(false);
|
||||
handleReplaceCharacter('https://c.huiying.video/images/5740cb7c-6e08-478f-9e7c-bca7f78a2bf6.jpg');
|
||||
|
||||
// 使用真实的角色数据
|
||||
const selectedRole = userRoleLibrary[index];
|
||||
if (selectedRole) {
|
||||
handleReplaceCharacter(selectedRole.imageUrl);
|
||||
}
|
||||
};
|
||||
|
||||
const handleOpenReplaceLibrary = () => {
|
||||
setIsReplaceLibraryOpen(true);
|
||||
setShowAddToLibrary(true);
|
||||
fetchUserRoleLibrary();
|
||||
};
|
||||
|
||||
const handleRegenerate = () => {
|
||||
@ -182,7 +198,7 @@ export function CharacterTabContent({
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
{/* 上部分:角色缩略图 */}
|
||||
<motion.div
|
||||
<motion.div
|
||||
className="space-y-6"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
@ -194,7 +210,7 @@ export function CharacterTabContent({
|
||||
selectedIndex={selectRoleIndex}
|
||||
onItemClick={(i: number) => handleChangeRole(i)}
|
||||
>
|
||||
{roles.map((role, index) => (
|
||||
{roleList.map((role, index) => (
|
||||
<motion.div
|
||||
key={`role-${index}`}
|
||||
className={cn(
|
||||
@ -205,8 +221,8 @@ export function CharacterTabContent({
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
<img
|
||||
src={role.url}
|
||||
<img
|
||||
src={role.imageUrl}
|
||||
alt={role.name}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
@ -241,7 +257,7 @@ export function CharacterTabContent({
|
||||
{/* 应用角色按钮 */}
|
||||
<div className='absolute top-3 right-3 flex gap-2'>
|
||||
<motion.button
|
||||
className="p-2 bg-black/50 hover:bg-black/70
|
||||
className="p-2 bg-black/50 hover:bg-black/70
|
||||
text-white rounded-full backdrop-blur-sm transition-colors z-10"
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
@ -250,7 +266,7 @@ export function CharacterTabContent({
|
||||
<ImageUp className="w-4 h-4" />
|
||||
</motion.button>
|
||||
<motion.button
|
||||
className="p-2 bg-black/50 hover:bg-black/70
|
||||
className="p-2 bg-black/50 hover:bg-black/70
|
||||
text-white rounded-full backdrop-blur-sm transition-colors z-10"
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
@ -271,7 +287,7 @@ export function CharacterTabContent({
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<motion.button
|
||||
onClick={() => handleReplaceCharacter('https://c.huiying.video/images/5740cb7c-6e08-478f-9e7c-bca7f78a2bf6.jpg')}
|
||||
className="flex items-center justify-center gap-2 px-4 py-3 bg-pink-500/10 hover:bg-pink-500/20
|
||||
className="flex items-center justify-center gap-2 px-4 py-3 bg-pink-500/10 hover:bg-pink-500/20
|
||||
text-pink-500 rounded-lg transition-colors"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
@ -281,7 +297,7 @@ export function CharacterTabContent({
|
||||
</motion.button>
|
||||
<motion.button
|
||||
onClick={() => handleRegenerate()}
|
||||
className="flex items-center justify-center gap-2 px-4 py-3 bg-blue-500/10 hover:bg-blue-500/20
|
||||
className="flex items-center justify-center gap-2 px-4 py-3 bg-blue-500/10 hover:bg-blue-500/20
|
||||
text-blue-500 rounded-lg transition-colors"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
@ -292,7 +308,7 @@ export function CharacterTabContent({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</motion.div>
|
||||
|
||||
@ -317,6 +333,7 @@ export function CharacterTabContent({
|
||||
isReplaceLibraryOpen={isReplaceLibraryOpen}
|
||||
setIsReplaceLibraryOpen={setIsReplaceLibraryOpen}
|
||||
onSelect={handleSelectCharacter}
|
||||
userRoleLibrary={userRoleLibrary}
|
||||
/>
|
||||
|
||||
{/* 提醒用户角色已修改 是否需要替换 */}
|
||||
@ -330,9 +347,9 @@ export function CharacterTabContent({
|
||||
<TriangleAlert className="w-6 h-6 text-yellow-400" />
|
||||
<p className="text-lg font-medium">角色已修改,是否需要替换?</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex gap-3 mt-2">
|
||||
<button
|
||||
<button
|
||||
onClick={() => handleConfirmGotoReplace()}
|
||||
data-alt="confirm-replace-button"
|
||||
className="px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-md transition-colors duration-200 flex items-center gap-2"
|
||||
@ -340,8 +357,8 @@ export function CharacterTabContent({
|
||||
<ReplaceAll className="w-4 h-4" />
|
||||
去替换
|
||||
</button>
|
||||
|
||||
<button
|
||||
|
||||
<button
|
||||
onClick={() => handleCloseRemindReplacePanel()}
|
||||
data-alt="ignore-button"
|
||||
className="px-4 py-2 bg-gray-600 hover:bg-gray-700 rounded-md transition-colors duration-200 flex items-center gap-2"
|
||||
@ -354,4 +371,4 @@ export function CharacterTabContent({
|
||||
</FloatingGlassPanel>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user