优化文本解析适配器,增强对话内容处理逻辑,确保角色名称的正确记录。更新分镜编辑器以支持内容变化的回调,改进分镜描述和对话内容的动态加载。修复视频段生成逻辑,确保视频编辑数据的准确性。

This commit is contained in:
北枳 2025-08-10 18:39:58 +08:00
parent 9bdc45812c
commit 5e6ead0f00
4 changed files with 67 additions and 43 deletions

View File

@ -190,18 +190,25 @@ export class TextToShotAdapter {
shotData.shotDialogsContent.forEach(paragraph => { shotData.shotDialogsContent.forEach(paragraph => {
let dialogRoleName = ''; let dialogRoleName = '';
let dialogContent = ''; let dialogContent = '';
let firstFindRole = false;
// 遍历段落内容 // 遍历段落内容
paragraph.content.forEach((node, index) => { if (paragraph.content) {
if (node.type === 'characterToken') { paragraph.content.forEach((node, index) => {
// 记录说话角色的名称 if (node.type === 'characterToken') {
index === 0 && (dialogRoleName = node.attrs.name); // 记录说话角色的名称
index !== 0 && (dialogContent += node.attrs.name); if (!firstFindRole) {
} else if (node.type === 'text') { dialogRoleName = node.attrs.name;
// 累积对话内容 firstFindRole = true;
dialogContent += node.text; } else {
} dialogContent += node.attrs.name;
}); }
} else if (node.type === 'text') {
// 累积对话内容
dialogContent += node.text;
}
});
}
// 如果有角色名和对话内容,添加到结果中 // 如果有角色名和对话内容,添加到结果中
if (dialogRoleName && dialogContent) { if (dialogRoleName && dialogContent) {

View File

@ -1,4 +1,5 @@
import React, { useState, useCallback, useEffect } from 'react'; import React, { useState, useCallback, useEffect } from 'react';
import { flushSync } from 'react-dom';
import { EditorContent, useEditor } from '@tiptap/react'; import { EditorContent, useEditor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit'; import StarterKit from '@tiptap/starter-kit';
import Placeholder from '@tiptap/extension-placeholder' import Placeholder from '@tiptap/extension-placeholder'
@ -12,6 +13,7 @@ interface ShotEditorProps {
roles?: any[]; roles?: any[];
onCharacterClick?: (attrs: any) => void; onCharacterClick?: (attrs: any) => void;
placeholder?: string; placeholder?: string;
onChangeContent?: (content: any) => void;
} }
declare module '@tiptap/core' { declare module '@tiptap/core' {
@ -36,14 +38,17 @@ interface EditorRef {
editor: any; editor: any;
insertCharacter: (character: CharacterToken) => void; insertCharacter: (character: CharacterToken) => void;
insertContent: (content: any) => void; insertContent: (content: any) => void;
getContent: () => any;
} }
const ShotEditor = React.forwardRef<EditorRef, ShotEditorProps>( const ShotEditor = React.forwardRef<EditorRef, ShotEditorProps>(
function ShotEditor({ content, onCharacterClick, roles, placeholder }, ref) { function ShotEditor({ content, onCharacterClick, roles, placeholder, onChangeContent }, ref) {
const [segments, setSegments] = useState(content); const [segments, setSegments] = useState(content);
const [isOptimizing, setIsOptimizing] = useState(false); const [isOptimizing, setIsOptimizing] = useState(false);
useEffect(() => {
onChangeContent?.(segments);
}, [segments]);
const handleSmartPolish = () => { const handleSmartPolish = () => {
setIsOptimizing(true); setIsOptimizing(true);
setTimeout(() => { setTimeout(() => {
@ -60,9 +65,11 @@ const ShotEditor = React.forwardRef<EditorRef, ShotEditorProps>(
ShotTitle, ShotTitle,
ReadonlyText, ReadonlyText,
Placeholder.configure({ Placeholder.configure({
placeholder: placeholder || 'Add shot description here...', placeholder: ({ node }) => {
showOnlyWhenEditable: true, console.log('-==========placeholder node===========-', segments);
showOnlyCurrent: false,
return placeholder || 'Add shot description here...';
},
}), }),
], ],
content: { type: 'doc', content: segments }, content: { type: 'doc', content: segments },
@ -76,9 +83,10 @@ const ShotEditor = React.forwardRef<EditorRef, ShotEditorProps>(
editor.setOptions({ editable: true }) editor.setOptions({ editable: true })
}, },
onUpdate: ({ editor }) => { onUpdate: ({ editor }) => {
const json = editor.getJSON() const json = editor.getJSON();
console.log('-==========json===========-', json); flushSync(() => {
setSegments(json.content); setSegments(json.content);
});
}, },
}) })
@ -94,9 +102,6 @@ const ShotEditor = React.forwardRef<EditorRef, ShotEditorProps>(
}, },
insertContent: (content: any) => { insertContent: (content: any) => {
editor?.commands.insertContent(content); editor?.commands.insertContent(content);
},
getContent: () => {
return segments;
} }
}), [editor]) // 依赖 editor确保更新 }), [editor]) // 依赖 editor确保更新

View File

@ -23,8 +23,20 @@ interface CharacterToken {
const createEmptyShot = (): Shot => ({ const createEmptyShot = (): Shot => ({
name: `shot${Date.now()}`, name: `shot${Date.now()}`,
shotDescContent: [], shotDescContent: [{
shotDialogsContent: [] type: 'paragraph',
content: [{
type: 'text',
text: 'Add shot description here...'
}]
}],
shotDialogsContent: [{
type: 'paragraph',
content: [{
type: 'text',
text: 'Add shot dialogue here...'
}]
}]
}); });
interface ShotsEditorProps { interface ShotsEditorProps {
@ -50,32 +62,31 @@ export const ShotsEditor = forwardRef<any, ShotsEditorProps>(({ roles, shotInfo,
} }
}, [shotInfo]); }, [shotInfo]);
// 更新当前分镜内容 const handleDescContentChange = (content: any) => {
const updateShot = () => {
const shot = shots[currentShotIndex]; const shot = shots[currentShotIndex];
if (descEditorRef.current) { shot.shotDescContent = content;
const content = descEditorRef.current.getContent(); setShots(prevShots =>
console.log('-==========descEditorcontent===========-', content); prevShots.map((item, index) =>
shot.shotDescContent = content; index === currentShotIndex ? shot : item
} )
if (dialogEditorRef.current) { );
const content = dialogEditorRef.current.getContent(); }
console.log('-==========dialogEditorcontent===========-', content); const handleDialogContentChange = (content: any) => {
shot.shotDialogsContent = content; const shot = shots[currentShotIndex];
} shot.shotDialogsContent = content;
setShots([...shots]); setShots(prevShots =>
prevShots.map((item, index) =>
index === currentShotIndex ? shot : item
)
);
} }
const handleShotTabClick = (index: number) => { const handleShotTabClick = (index: number) => {
// 切换前更新当前分镜内容
updateShot();
setCurrentShotIndex(index); setCurrentShotIndex(index);
} }
const getShotInfo = () => { const getShotInfo = () => {
// 生成前 更新当前分镜内容 console.log('-==========getShotInfo shots===========-', shots);
updateShot();
console.log('-==========shots===========-', shots);
const shotInfo = shots.map((shot) => { const shotInfo = shots.map((shot) => {
return TextToShotAdapter.toLensType(shot); return TextToShotAdapter.toLensType(shot);
}); });
@ -93,7 +104,6 @@ export const ShotsEditor = forwardRef<any, ShotsEditorProps>(({ roles, shotInfo,
} }
const newShot = createEmptyShot(); const newShot = createEmptyShot();
setShots([...shots, newShot]); setShots([...shots, newShot]);
// onShotsChange([...shots, newShot]);
// 自动切换到新创建的分镜 // 自动切换到新创建的分镜
setCurrentShotIndex(shots.length); setCurrentShotIndex(shots.length);
}; };
@ -250,6 +260,7 @@ export const ShotsEditor = forwardRef<any, ShotsEditorProps>(({ roles, shotInfo,
onCharacterClick={() => {}} onCharacterClick={() => {}}
roles={roles} roles={roles}
placeholder="Add shot description here..." placeholder="Add shot description here..."
onChangeContent={(content) => {handleDescContentChange(content)}}
/> />
</div> </div>
@ -281,6 +292,7 @@ export const ShotsEditor = forwardRef<any, ShotsEditorProps>(({ roles, shotInfo,
onCharacterClick={() => {}} onCharacterClick={() => {}}
roles={roles} roles={roles}
placeholder="Add shot dialogue here..." placeholder="Add shot dialogue here..."
onChangeContent={(content) => {handleDialogContentChange(content)}}
/> />
</div> </div>
</div> </div>

View File

@ -113,7 +113,7 @@ export function ShotTabContent({
...shotData[selectedIndex], ...shotData[selectedIndex],
lens: shotInfo lens: shotInfo
}); });
// regenerateVideoSegment(); regenerateVideoSegment();
}; };
// 新增分镜 // 新增分镜