This commit is contained in:
海龙 2025-08-12 18:45:35 +08:00
commit b59d32d79d
7 changed files with 41 additions and 30 deletions

View File

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

View File

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

View File

@ -44,7 +44,8 @@ export const useEditData = (tabType: string) => {
fetchUserRoleLibrary, fetchUserRoleLibrary,
optimizeRoleText, optimizeRoleText,
updateRoleText, updateRoleText,
regenerateRole regenerateRole,
uploadImageToQiniu
} = useRoleServiceHook(); } = useRoleServiceHook();
const { const {
@ -105,6 +106,7 @@ export const useEditData = (tabType: string) => {
updateRoleText, updateRoleText,
regenerateRole, regenerateRole,
fetchUserRoleLibrary, fetchUserRoleLibrary,
uploadImageToQiniu,
// role shot // role shot
shotSelectionList, shotSelectionList,
selectedRoleId, selectedRoleId,

View File

@ -1,6 +1,6 @@
import React, { useState, useRef, useEffect } from 'react'; import React, { useState, useRef, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion'; import { motion, AnimatePresence } from 'framer-motion';
import { ImageUp, Library, Play, Pause, RefreshCw, Wand2, Users, Check, ReplaceAll, X, TriangleAlert } from 'lucide-react'; import { ImageUp, Library, Play, Pause, RefreshCw, Wand2, Users, Check, ReplaceAll, X, TriangleAlert, Loader2 } from 'lucide-react';
import { cn } from '@/public/lib/utils'; import { cn } from '@/public/lib/utils';
import { CharacterEditor } from './character-editor'; import { CharacterEditor } from './character-editor';
import ImageBlurTransition from './ImageBlurTransition'; import ImageBlurTransition from './ImageBlurTransition';
@ -78,6 +78,7 @@ export function CharacterTabContent({
const [isRegenerate, setIsRegenerate] = useState(false); const [isRegenerate, setIsRegenerate] = useState(false);
const [isLoadingShots, setIsLoadingShots] = useState(false); const [isLoadingShots, setIsLoadingShots] = useState(false);
const [isLoadingLibrary, setIsLoadingLibrary] = useState(false); const [isLoadingLibrary, setIsLoadingLibrary] = useState(false);
const [isUploading, setIsUploading] = useState(false);
const { const {
loading, loading,
@ -89,6 +90,7 @@ export function CharacterTabContent({
updateRoleText, updateRoleText,
regenerateRole, regenerateRole,
fetchUserRoleLibrary, fetchUserRoleLibrary,
uploadImageToQiniu,
// role shot // role shot
shotSelectionList, shotSelectionList,
fetchRoleShots, fetchRoleShots,
@ -212,6 +214,7 @@ export function CharacterTabContent({
}; };
const handleUploadClick = () => { const handleUploadClick = () => {
setIsUploading(true);
fileInputRef.current?.click(); fileInputRef.current?.click();
}; };
@ -225,13 +228,12 @@ export function CharacterTabContent({
return; return;
} }
// 创建本地预览URL uploadImageToQiniu(file).then((data) => {
const imageUrl = URL.createObjectURL(file); console.log('上传图片成功', data);
setShowAddToLibrary(false); // 清空input的值这样同一个文件可以重复选择
handleReplaceCharacter(imageUrl); event.target.value = '';
setIsUploading(false);
// 清空input的值这样同一个文件可以重复选择 });
event.target.value = '';
}; };
// 如果loading 显示loading状态 // 如果loading 显示loading状态
@ -329,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

View File

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

View File

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

View File

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