forked from 77media/video-flow
优化角色识别逻辑,调整视频帧处理和角色识别结果的返回,更新角色识别响应的导出方式,增强用户体验。同时,修复扫描失败时的状态管理,确保扫描过程的流畅性。
This commit is contained in:
parent
ebb9a951bd
commit
1f723d39f8
@ -309,7 +309,7 @@ export const useShotService = (): UseShotService => {
|
|||||||
*/
|
*/
|
||||||
const filterRole = useCallback(async (
|
const filterRole = useCallback(async (
|
||||||
video: HTMLVideoElement,
|
video: HTMLVideoElement,
|
||||||
): Promise<string> => {
|
) => {
|
||||||
try {
|
try {
|
||||||
// 创建canvas元素来截取视频帧
|
// 创建canvas元素来截取视频帧
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
@ -356,12 +356,11 @@ export const useShotService = (): UseShotService => {
|
|||||||
imageUrl
|
imageUrl
|
||||||
);
|
);
|
||||||
console.log('角色识别结果:', recognitionResult);
|
console.log('角色识别结果:', recognitionResult);
|
||||||
|
return recognitionResult;
|
||||||
} catch (recognitionError) {
|
} catch (recognitionError) {
|
||||||
console.warn('角色识别失败,但图片上传成功:', recognitionError);
|
console.warn('角色识别失败,但图片上传成功:', recognitionError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return imageUrl;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取视频帧失败:', error);
|
console.error('获取视频帧失败:', error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
@ -439,7 +439,7 @@ export interface RoleRecognitionResponse {
|
|||||||
characters_used: CharacterUsed[];
|
characters_used: CharacterUsed[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const roleRecognitionResponse:RoleRecognitionResponse = {
|
export const roleRecognitionResponse:RoleRecognitionResponse = {
|
||||||
"project_id": "d0df7120-e27b-4f84-875c-e532f1bd318c",
|
"project_id": "d0df7120-e27b-4f84-875c-e532f1bd318c",
|
||||||
"video_id": "984f3347-c81c-4af8-9145-49ead82becde",
|
"video_id": "984f3347-c81c-4af8-9145-49ead82becde",
|
||||||
"target_image_url": "https://cdn.qikongjian.com/videos/1754970412744_kqxplx.png",
|
"target_image_url": "https://cdn.qikongjian.com/videos/1754970412744_kqxplx.png",
|
||||||
|
|||||||
@ -228,8 +228,6 @@ export function CharacterTabContent({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建本地预览URL
|
|
||||||
const imageUrl = URL.createObjectURL(file);
|
|
||||||
uploadImageToQiniu(file).then((data) => {
|
uploadImageToQiniu(file).then((data) => {
|
||||||
console.log('上传图片成功', data);
|
console.log('上传图片成功', data);
|
||||||
// 清空input的值,这样同一个文件可以重复选择
|
// 清空input的值,这样同一个文件可以重复选择
|
||||||
@ -333,8 +331,9 @@ export function CharacterTabContent({
|
|||||||
whileHover={{ scale: 1.05 }}
|
whileHover={{ scale: 1.05 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
onClick={handleUploadClick}
|
onClick={handleUploadClick}
|
||||||
|
disabled={isUploading}
|
||||||
>
|
>
|
||||||
<ImageUp className="w-4 h-4" />
|
{isUploading ? <Loader2 className="w-4 h-4 animate-spin" /> : <ImageUp className="w-4 h-4" />}
|
||||||
</motion.button>
|
</motion.button>
|
||||||
<motion.button
|
<motion.button
|
||||||
className="p-2 bg-black/50 hover:bg-black/70
|
className="p-2 bg-black/50 hover:bg-black/70
|
||||||
@ -342,9 +341,8 @@ export function CharacterTabContent({
|
|||||||
whileHover={{ scale: 1.05 }}
|
whileHover={{ scale: 1.05 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
onClick={() => handleOpenReplaceLibrary()}
|
onClick={() => handleOpenReplaceLibrary()}
|
||||||
disabled={isUploading}
|
|
||||||
>
|
>
|
||||||
{isUploading ? <Loader2 className="w-4 h-4 animate-spin" /> : <Library className="w-4 h-4" />}
|
<Library className="w-4 h-4" />
|
||||||
</motion.button>
|
</motion.button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -78,7 +78,7 @@ export function EditModal({
|
|||||||
const isTabDisabled = (tabId: string) => {
|
const isTabDisabled = (tabId: string) => {
|
||||||
if (tabId === 'settings') return false;
|
if (tabId === 'settings') return false;
|
||||||
// 换成 如果对应标签下 数据存在 就不禁用
|
// 换成 如果对应标签下 数据存在 就不禁用
|
||||||
if (tabId === '1') return roles.length === 0;
|
// if (tabId === '1') return roles.length === 0;
|
||||||
if (tabId === '2') return taskScenes.length === 0;
|
if (tabId === '2') return taskScenes.length === 0;
|
||||||
if (tabId === '3') return sketchVideo.length === 0;
|
if (tabId === '3') return sketchVideo.length === 0;
|
||||||
if (tabId === '4') return false;
|
if (tabId === '4') return false;
|
||||||
|
|||||||
@ -62,7 +62,7 @@ export const PersonDetectionScene: React.FC<Props> = ({
|
|||||||
onScanStart,
|
onScanStart,
|
||||||
onScanTimeout,
|
onScanTimeout,
|
||||||
onScanExit,
|
onScanExit,
|
||||||
scanTimeout = 10000,
|
scanTimeout = 100000,
|
||||||
isScanFailed = false,
|
isScanFailed = false,
|
||||||
onDetectionsChange,
|
onDetectionsChange,
|
||||||
onPersonClick
|
onPersonClick
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import FloatingGlassPanel from './FloatingGlassPanel';
|
|||||||
import { ReplaceCharacterPanel, mockShots, mockCharacter } from './replace-character-panel';
|
import { ReplaceCharacterPanel, mockShots, mockCharacter } from './replace-character-panel';
|
||||||
import HorizontalScroller from './HorizontalScroller';
|
import HorizontalScroller from './HorizontalScroller';
|
||||||
import { useEditData } from '@/components/pages/work-flow/use-edit-data';
|
import { useEditData } from '@/components/pages/work-flow/use-edit-data';
|
||||||
|
import { roleRecognitionResponse } from '@/app/service/usecase/ShotEditUsecase';
|
||||||
|
|
||||||
interface ShotTabContentProps {
|
interface ShotTabContentProps {
|
||||||
currentSketchIndex: number;
|
currentSketchIndex: number;
|
||||||
@ -32,6 +33,7 @@ export function ShotTabContent({
|
|||||||
|
|
||||||
const [detections, setDetections] = useState<PersonDetection[]>([]);
|
const [detections, setDetections] = useState<PersonDetection[]>([]);
|
||||||
const [scanState, setScanState] = useState<'idle' | 'scanning' | 'detected'>('idle');
|
const [scanState, setScanState] = useState<'idle' | 'scanning' | 'detected'>('idle');
|
||||||
|
const [isScanFailed, setIsScanFailed] = useState(false);
|
||||||
|
|
||||||
const [isReplaceLibraryOpen, setIsReplaceLibraryOpen] = useState(false);
|
const [isReplaceLibraryOpen, setIsReplaceLibraryOpen] = useState(false);
|
||||||
const [isReplacePanelOpen, setIsReplacePanelOpen] = useState(false);
|
const [isReplacePanelOpen, setIsReplacePanelOpen] = useState(false);
|
||||||
@ -48,26 +50,25 @@ export function ShotTabContent({
|
|||||||
}, [selectedIndex, shotData]);
|
}, [selectedIndex, shotData]);
|
||||||
|
|
||||||
// 处理扫描开始
|
// 处理扫描开始
|
||||||
const handleScan = () => {
|
const handleScan = async () => {
|
||||||
if (scanState === 'detected') {
|
if (scanState === 'detected') {
|
||||||
// 如果已经有检测结果,点击按钮退出检测状态
|
// 如果已经有检测结果,点击按钮退出检测状态
|
||||||
setScanState('idle');
|
setScanState('idle');
|
||||||
setDetections([]); // 清除检测结果
|
setDetections([]); // 清除检测结果
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
filterRole(document.getElementById('person-detection-video') as HTMLVideoElement);
|
|
||||||
setScanState('scanning');
|
setScanState('scanning');
|
||||||
// 模拟检测过程
|
await filterRole(document.getElementById('person-detection-video') as HTMLVideoElement);
|
||||||
setTimeout(() => {
|
|
||||||
const mockDetections: PersonDetection[] = [
|
if (roleRecognitionResponse.recognition_result.code === 200) {
|
||||||
{
|
setDetections(roleRecognitionResponse.recognition_result.data.matched_persons.map((person) => ({
|
||||||
id: '1',
|
id: person.person_id,
|
||||||
name: '人物1',
|
name: person.person_id,
|
||||||
position: { top: 0, left: 100, width: 100, height: 200 }
|
position: { top: person.bbox.y, left: person.bbox.x, width: person.bbox.width, height: person.bbox.height }
|
||||||
}
|
})));
|
||||||
];
|
} else {
|
||||||
setDetections(mockDetections);
|
setIsScanFailed(true);
|
||||||
}, 5000);
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理扫描超时/失败
|
// 处理扫描超时/失败
|
||||||
@ -76,6 +77,12 @@ export function ShotTabContent({
|
|||||||
setDetections([]);
|
setDetections([]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理退出扫描
|
||||||
|
const handleScanExit = () => {
|
||||||
|
setScanState('idle');
|
||||||
|
setDetections([]);
|
||||||
|
};
|
||||||
|
|
||||||
// 处理检测到结果
|
// 处理检测到结果
|
||||||
const handleDetectionsChange = (newDetections: PersonDetection[]) => {
|
const handleDetectionsChange = (newDetections: PersonDetection[]) => {
|
||||||
if (newDetections.length > 0 && scanState === 'scanning') {
|
if (newDetections.length > 0 && scanState === 'scanning') {
|
||||||
@ -287,7 +294,7 @@ export function ShotTabContent({
|
|||||||
detections={detections}
|
detections={detections}
|
||||||
triggerScan={scanState === 'scanning'}
|
triggerScan={scanState === 'scanning'}
|
||||||
onScanTimeout={handleScanTimeout}
|
onScanTimeout={handleScanTimeout}
|
||||||
onScanExit={handleScanTimeout}
|
onScanExit={handleScanExit}
|
||||||
onDetectionsChange={handleDetectionsChange}
|
onDetectionsChange={handleDetectionsChange}
|
||||||
onPersonClick={handlePersonClick}
|
onPersonClick={handlePersonClick}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user