修复 视频片段重新生成 点击 Apply 没有传 video_id 给接口

This commit is contained in:
北枳 2025-08-16 20:56:47 +08:00
parent 540737210d
commit ed79e49abe
7 changed files with 71 additions and 59 deletions

View File

@ -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 || "",

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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}

View File

@ -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>
{/* 分镜内容 */}

View File

@ -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>