forked from 77media/video-flow
修复 视频片段重新生成 点击 Apply 没有传 video_id 给接口
This commit is contained in:
parent
540737210d
commit
ed79e49abe
@ -37,6 +37,10 @@ export class VideoSegmentEntityAdapter {
|
||||
task_status: string = "";
|
||||
/** 任务结果 */
|
||||
task_result: Array<{
|
||||
/** 任务ID */
|
||||
video_id: string;
|
||||
/** 任务状态 */
|
||||
video_status: number|null;
|
||||
/** 叙事目标 */
|
||||
narrative_goal: string;
|
||||
/** 镜头1描述 */
|
||||
@ -175,6 +179,8 @@ export class VideoSegmentEntityAdapter {
|
||||
*/
|
||||
static fromVideoSegmentEntity(entities: VideoSegmentEntity[]): VideoSegmentEntityAdapter {
|
||||
const taskResults: Array<{
|
||||
video_id: string;
|
||||
video_status: number|null;
|
||||
narrative_goal: string;
|
||||
shot_1: string;
|
||||
shot_2: string;
|
||||
@ -235,6 +241,8 @@ export class VideoSegmentEntityAdapter {
|
||||
|
||||
taskResults.push({
|
||||
narrative_goal: narrative_goal,
|
||||
video_id: entity.id,
|
||||
video_status: entity.status,
|
||||
shot_1: shots.shot_1 || "",
|
||||
shot_2: shots.shot_2 || "",
|
||||
shot_3: shots.shot_3 || "",
|
||||
|
||||
@ -60,7 +60,15 @@ export class TextToShotAdapter {
|
||||
let currentText = text;
|
||||
|
||||
// 按角色名称长度降序排序,避免短名称匹配到长名称的一部分
|
||||
const sortedRoles = [...roles].sort((a, b) => b.name.length - a.name.length);
|
||||
// 既要兼容 首字母大写 其余小写、还要兼容 全部大写
|
||||
const sortedRoles = [...roles].sort((a, b) => b.name.length - a.name.length).map(role => ({
|
||||
...role,
|
||||
name: role.name.charAt(0).toUpperCase() + role.name.slice(1).toLowerCase()
|
||||
})).concat([...roles].map(role => ({
|
||||
...role,
|
||||
name: role.name.toUpperCase()
|
||||
})));
|
||||
|
||||
|
||||
while (currentText.length > 0) {
|
||||
let matchFound = false;
|
||||
|
||||
@ -432,10 +432,9 @@ export const MediaViewer = React.memo(function MediaViewer({
|
||||
<div
|
||||
className="relative w-full h-full rounded-lg group"
|
||||
>
|
||||
{/* 只在生成过程中或没有视频时使用ProgressiveReveal */}
|
||||
<div className="relative w-full h-full">
|
||||
{/* 背景模糊的图片 */}
|
||||
<div className="absolute inset-0 overflow-hidden" style={{background: `url(${taskSketch[currentSketchIndex]?.url}) no-repeat center center`}}>
|
||||
{/* 背景模糊的图片 */}
|
||||
{taskObject.videos.data[currentSketchIndex].video_status !== 1 && (
|
||||
<div className="absolute inset-0 overflow-hidden z-20" style={{background: `url(${taskObject.shot_sketch.data[currentSketchIndex]?.url}) no-repeat center center`}}>
|
||||
{/* 生成中 */}
|
||||
{taskObject.videos.data[currentSketchIndex].video_status === 0 && (
|
||||
<div className="absolute inset-0 bg-black/10 flex items-center justify-center">
|
||||
@ -455,39 +454,39 @@ export const MediaViewer = React.memo(function MediaViewer({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{/* 视频 多个 取第一个 */}
|
||||
{ taskObject.videos.data[currentSketchIndex].urls && (
|
||||
<motion.div
|
||||
initial={{ clipPath: "inset(0 100% 0 0)" }}
|
||||
animate={{ clipPath: "inset(0 0% 0 0)" }}
|
||||
transition={{ duration: 0.8, ease: [0.43, 0.13, 0.23, 0.96] }}
|
||||
className="relative z-10 w-full h-full"
|
||||
>
|
||||
<video
|
||||
ref={mainVideoRef}
|
||||
key={taskObject.videos.data[currentSketchIndex].urls[0]}
|
||||
className="w-full h-full rounded-lg object-cover object-center relative z-10"
|
||||
src={taskObject.videos.data[currentSketchIndex].urls[0]}
|
||||
autoPlay={isVideoPlaying}
|
||||
loop={true}
|
||||
playsInline
|
||||
onLoadedData={() => applyVolumeSettings(mainVideoRef.current!)}
|
||||
onEnded={() => {
|
||||
if (isVideoPlaying) {
|
||||
// 自动切换到下一个视频的逻辑在父组件处理
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
{/* 视频 多个 取第一个 */}
|
||||
{ taskObject.videos.data[currentSketchIndex].urls && (
|
||||
<motion.div
|
||||
initial={{ clipPath: "inset(0 100% 0 0)" }}
|
||||
animate={{ clipPath: "inset(0 0% 0 0)" }}
|
||||
transition={{ duration: 0.8, ease: [0.43, 0.13, 0.23, 0.96] }}
|
||||
className="relative z-10 w-full h-full"
|
||||
>
|
||||
<video
|
||||
ref={mainVideoRef}
|
||||
key={taskObject.videos.data[currentSketchIndex].urls[0]}
|
||||
className="w-full h-full rounded-lg object-cover object-center relative z-10"
|
||||
src={taskObject.videos.data[currentSketchIndex].urls[0]}
|
||||
autoPlay={isVideoPlaying}
|
||||
loop={true}
|
||||
playsInline
|
||||
onLoadedData={() => applyVolumeSettings(mainVideoRef.current!)}
|
||||
onEnded={() => {
|
||||
if (isVideoPlaying) {
|
||||
// 自动切换到下一个视频的逻辑在父组件处理
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{/* 操作按钮组 */}
|
||||
<AnimatePresence>
|
||||
<motion.div
|
||||
className="absolute top-4 right-4 gap-2 z-[11] hidden group-hover:flex"
|
||||
className="absolute top-4 right-4 gap-2 z-[21] hidden group-hover:flex"
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
@ -501,10 +500,10 @@ export const MediaViewer = React.memo(function MediaViewer({
|
||||
</AnimatePresence>
|
||||
|
||||
{/* 底部控制区域 */}
|
||||
{ taskObject.videos.data[currentSketchIndex] && (
|
||||
{ taskObject.videos.data[currentSketchIndex].video_status === 1 && (
|
||||
<AnimatePresence>
|
||||
<motion.div
|
||||
className="absolute bottom-4 left-4 z-[11] flex items-center gap-3"
|
||||
className="absolute bottom-4 left-4 z-[21] flex items-center gap-3"
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.8 }}
|
||||
@ -534,8 +533,6 @@ export const MediaViewer = React.memo(function MediaViewer({
|
||||
|
||||
// 渲染分镜草图
|
||||
const renderSketchContent = (currentSketch: any) => {
|
||||
const defaultBgColors = ['RGB(45, 50, 70)', 'RGB(75, 80, 100)', 'RGB(105, 110, 130)'];
|
||||
const bgColors = defaultBgColors;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@ -307,7 +307,6 @@ export function useWorkflowData() {
|
||||
}
|
||||
taskCurrent.roles.data = characterList;
|
||||
if (task.task_status === 'COMPLETED') {
|
||||
console.log('----------角色生成完成,有几个分镜', sketchCount);
|
||||
// 角色生成完成
|
||||
}
|
||||
break;
|
||||
@ -337,7 +336,6 @@ export function useWorkflowData() {
|
||||
taskCurrent.shot_sketch.data = sketchList;
|
||||
if (task.task_status === 'COMPLETED') {
|
||||
// 草图生成完成
|
||||
console.log('----------草图生成完成', sketchCount);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ export function CharacterToken(props: ReactNodeViewProps) {
|
||||
>
|
||||
<div className="space-y-1">
|
||||
{roles.map((role) => {
|
||||
const isSelected = role.name === name;
|
||||
const isSelected = role.name.toLowerCase() === name.toLowerCase();
|
||||
return (
|
||||
<div
|
||||
key={role.name}
|
||||
|
||||
@ -226,14 +226,14 @@ export const ShotsEditor = forwardRef<any, ShotsEditorProps>(function ShotsEdito
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* <button
|
||||
<button
|
||||
data-alt="add-shot-button"
|
||||
onClick={handleAddShot}
|
||||
onClick={addShot}
|
||||
className="flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-white/60 hover:text-white hover:bg-white/5 rounded-md transition-colors"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
新增镜头
|
||||
</button> */}
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 分镜内容 */}
|
||||
|
||||
@ -18,10 +18,8 @@ interface ShotTabContentProps {
|
||||
roles?: any[];
|
||||
}
|
||||
|
||||
export function ShotTabContent({
|
||||
currentSketchIndex = 0,
|
||||
roles = []
|
||||
}: ShotTabContentProps) {
|
||||
export const ShotTabContent = (props: ShotTabContentProps) => {
|
||||
const { currentSketchIndex = 0, roles = [] } = props;
|
||||
const {
|
||||
loading,
|
||||
shotData,
|
||||
@ -48,7 +46,7 @@ export function ShotTabContent({
|
||||
const [selectedLibaryRole, setSelectedLibaryRole] = useState<any>(null);
|
||||
const [isLoadingShots, setIsLoadingShots] = useState(false);
|
||||
const shotsEditorRef = useRef<any>(null);
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
const [isRegenerate, setIsRegenerate] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('shotTabContent-----roles', roles);
|
||||
@ -163,15 +161,17 @@ export function ShotTabContent({
|
||||
};
|
||||
|
||||
// 点击按钮重新生成
|
||||
const handleRegenerate = () => {
|
||||
const handleRegenerate = async () => {
|
||||
console.log('regenerate');
|
||||
setIsRegenerate(true);
|
||||
const shotInfo = shotsEditorRef.current.getShotInfo();
|
||||
console.log('shotTabContent-----shotInfo', shotInfo);
|
||||
setSelectedSegment({
|
||||
...shotData[selectedIndex],
|
||||
lens: shotInfo
|
||||
});
|
||||
regenerateVideoSegment();
|
||||
await regenerateVideoSegment();
|
||||
setIsRegenerate(false);
|
||||
};
|
||||
|
||||
// 新增分镜
|
||||
@ -394,8 +394,8 @@ export function ShotTabContent({
|
||||
/>
|
||||
|
||||
{/* 重新生成按钮、新增分镜按钮 */}
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<motion.button
|
||||
<div className="grid grid-cols-1 gap-2">
|
||||
{/* <motion.button
|
||||
onClick={() => handleAddShot()}
|
||||
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"
|
||||
@ -404,16 +404,17 @@ export function ShotTabContent({
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
<span>Add Shot</span>
|
||||
</motion.button>
|
||||
</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
|
||||
text-blue-500 rounded-lg transition-colors"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
<RefreshCw className="w-4 h-4" />
|
||||
<span>Regenerate</span>
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
disabled={isRegenerate}
|
||||
>
|
||||
<RefreshCw className="w-4 h-4" />
|
||||
<span>{isRegenerate ? 'Regenerating...' : 'Regenerate'}</span>
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user