forked from 77media/video-flow
修复构建报错
This commit is contained in:
parent
01509ad3d5
commit
310ea1c49f
@ -158,6 +158,7 @@ export const useRoleServiceHook = (): UseRoleService => {
|
|||||||
content: keyword,
|
content: keyword,
|
||||||
loadingProgress: 100,
|
loadingProgress: 100,
|
||||||
disableEdit: false,
|
disableEdit: false,
|
||||||
|
updatedAt: Date.now(),
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
: role
|
: role
|
||||||
@ -177,6 +178,7 @@ export const useRoleServiceHook = (): UseRoleService => {
|
|||||||
content: keyword,
|
content: keyword,
|
||||||
loadingProgress: 100,
|
loadingProgress: 100,
|
||||||
disableEdit: false,
|
disableEdit: false,
|
||||||
|
updatedAt: Date.now(),
|
||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -383,6 +385,7 @@ export const useRoleServiceHook = (): UseRoleService => {
|
|||||||
content: highlight,
|
content: highlight,
|
||||||
loadingProgress: 100,
|
loadingProgress: 100,
|
||||||
disableEdit: false,
|
disableEdit: false,
|
||||||
|
updatedAt: Date.now(),
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -83,3 +83,17 @@ export class SceneItem extends EditItem<SceneEntity> {
|
|||||||
super(entity, metadata);
|
super(entity, metadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签可编辑项
|
||||||
|
*/
|
||||||
|
export class TagItem extends EditItem<TagValueObject> {
|
||||||
|
type: ItemType.TEXT = ItemType.TEXT;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
entity: TagValueObject,
|
||||||
|
metadata: Record<string, any> = {}
|
||||||
|
) {
|
||||||
|
super(entity, metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -95,6 +95,8 @@ export interface TagValueObject {
|
|||||||
disableEdit: boolean;
|
disableEdit: boolean;
|
||||||
/** 颜色 */
|
/** 颜色 */
|
||||||
color?: string;
|
color?: string;
|
||||||
|
/** 更新时间 */
|
||||||
|
readonly updatedAt: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,90 +0,0 @@
|
|||||||
import { SceneEntity, AITextEntity } from '../domain/Entities';
|
|
||||||
import { SceneItem, TagItem, TextItem } from '../domain/Item';
|
|
||||||
import { regenerateScene, applySceneToShots, getSceneData } from '@/api/video_flow';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 场景编辑用例
|
|
||||||
* 负责场景内容的初始化、修改和优化
|
|
||||||
*/
|
|
||||||
export class SceneEditUseCase {
|
|
||||||
constructor(private sceneItem: SceneItem) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description: 重新生成场景
|
|
||||||
* @param {TextItem} prompt
|
|
||||||
* @param {TagItem[]} tags
|
|
||||||
* @return {*}
|
|
||||||
*/
|
|
||||||
async AIgenerateScene(prompt: TextItem, tags: TagItem[]): Promise<SceneEntity> {
|
|
||||||
const promptText = prompt.entity.content;
|
|
||||||
const tagList = tags.map((tag) => tag.entity.content);
|
|
||||||
|
|
||||||
// 调用重新生成场景接口
|
|
||||||
const response = await regenerateScene({
|
|
||||||
sceneId: this.sceneItem.entity.id || '',
|
|
||||||
prompt: promptText,
|
|
||||||
tagTypes: tagList,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.successful) {
|
|
||||||
const sceneEntity = response.data;
|
|
||||||
this.sceneItem.setEntity(sceneEntity);
|
|
||||||
return sceneEntity;
|
|
||||||
} else {
|
|
||||||
throw new Error(`重新生成场景失败: ${response.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 应用此场景到指定分镜
|
|
||||||
* @param shotIds 分镜ID列表
|
|
||||||
* @returns 应用结果
|
|
||||||
*/
|
|
||||||
async applyScene(shotIds: string[]) {
|
|
||||||
const sceneId = this.sceneItem.entity.id;
|
|
||||||
|
|
||||||
return await applySceneToShots({
|
|
||||||
sceneId,
|
|
||||||
shotIds
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重新获取当前场景的数据
|
|
||||||
* @description 从服务器重新获取当前场景的AI文本和标签数据,并更新当前实体
|
|
||||||
* @returns Promise<{ text: AITextEntity; tags: TagValueObject[] }> 场景相关的AI文本和标签数据
|
|
||||||
* @throws {Error} 当API调用失败时抛出错误
|
|
||||||
*/
|
|
||||||
async refreshSceneData(): Promise<{ text: AITextEntity; tags: TagValueObject[] }> {
|
|
||||||
const sceneId = this.sceneItem.entity.id;
|
|
||||||
|
|
||||||
if (!sceneId) {
|
|
||||||
throw new Error('场景ID不存在,无法获取场景数据');
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await getSceneData({
|
|
||||||
sceneId: sceneId
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.successful) {
|
|
||||||
// 更新当前场景的实体数据
|
|
||||||
const { text, tags } = response.data;
|
|
||||||
|
|
||||||
// 更新场景实体中的相关字段
|
|
||||||
const updatedSceneEntity = {
|
|
||||||
...this.sceneItem.entity,
|
|
||||||
generateTextId: text.id, // 更新AI文本ID
|
|
||||||
tagIds: tags.map(tag => tag.id), // 更新标签ID列表
|
|
||||||
updatedAt: Date.now(), // 更新时间戳
|
|
||||||
};
|
|
||||||
|
|
||||||
// 更新当前UseCase中的实体
|
|
||||||
this.sceneItem.setEntity(updatedSceneEntity);
|
|
||||||
|
|
||||||
return response.data;
|
|
||||||
} else {
|
|
||||||
throw new Error(`获取场景数据失败: ${response.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
69
compile_test.sh
Executable file
69
compile_test.sh
Executable file
@ -0,0 +1,69 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
BRANCH_NAME="dev"
|
||||||
|
|
||||||
|
# 修改项目名称
|
||||||
|
PROJECT_NAME="video-flow-frontend-test"
|
||||||
|
|
||||||
|
# 设置日志文件路径
|
||||||
|
LOGFILE="build_and_copy.log"
|
||||||
|
|
||||||
|
# 记录开始时间
|
||||||
|
echo "Build process started at $(date)" | tee $LOGFILE
|
||||||
|
|
||||||
|
# 获取当前分支名
|
||||||
|
current_branch=$(git rev-parse --abbrev-ref HEAD)
|
||||||
|
|
||||||
|
# 打包之前,需要检查是否在 dev 分支,工作区是否干净,是否和远程分支一致
|
||||||
|
if [ "$(git branch --show-current)" != "$BRANCH_NAME" ]; then
|
||||||
|
echo "当前分支不是 dev 分支"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查工作区是否干净
|
||||||
|
if [ -n "$(git status --porcelain)" ]; then
|
||||||
|
echo "工作区不干净"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查远程分支是否和本地分支一致
|
||||||
|
if [ "$(git rev-parse HEAD)" != "$(git rev-parse origin/$BRANCH_NAME)" ]; then
|
||||||
|
echo "本地分支和远程分支不一致"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# 检查当前分支并运行相应的 npm 命令
|
||||||
|
if [ "$current_branch" = "$BRANCH_NAME" ]; then
|
||||||
|
echo "On dev branch, building project..." | tee -a $LOGFILE
|
||||||
|
PROFILE_ENV=$BRANCH_NAME
|
||||||
|
|
||||||
|
# 安装依赖并构建
|
||||||
|
yarn install
|
||||||
|
yarn build
|
||||||
|
|
||||||
|
# 准备dist目录
|
||||||
|
mkdir -p dist
|
||||||
|
cp -r .next dist/
|
||||||
|
cp -r public dist/
|
||||||
|
cp package.json dist/
|
||||||
|
cp package-lock.json dist/
|
||||||
|
|
||||||
|
else
|
||||||
|
echo "On non-dev branch ($current_branch), exiting"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 创建tar包
|
||||||
|
tar -czvf $PROJECT_NAME-$PROFILE_ENV.tar.gz dist
|
||||||
|
|
||||||
|
# 记录结束时间
|
||||||
|
echo "Build process completed at $(date)" | tee -a $LOGFILE
|
||||||
|
|
||||||
|
# 上传到 nexus
|
||||||
|
echo "upload to nexus at $(date)" | tee -a $LOGFILE
|
||||||
|
curl -u 'admin':'YZ9Gq6=8\*G|?:,' --upload-file $PROJECT_NAME-$PROFILE_ENV.tar.gz https://repo.qikongjian.com/repository/frontend-tar-files/
|
||||||
|
|
||||||
|
# 清理构建文件
|
||||||
|
rm -rf dist
|
||||||
|
rm $PROJECT_NAME-$PROFILE_ENV.tar.gz
|
||||||
@ -2,6 +2,7 @@ import { useState, useEffect, useCallback } from 'react';
|
|||||||
import { detailScriptEpisodeNew, getScriptTitle, getRunningStreamData, StreamData } from '@/api/video_flow';
|
import { detailScriptEpisodeNew, getScriptTitle, getRunningStreamData, StreamData } from '@/api/video_flow';
|
||||||
import { useSearchParams } from 'next/navigation';
|
import { useSearchParams } from 'next/navigation';
|
||||||
import { ApiResponse } from '@/api/common';
|
import { ApiResponse } from '@/api/common';
|
||||||
|
import { SketchData, CharacterResponse, VideoData } from '@/api/DTO/movieEdit';
|
||||||
|
|
||||||
// 步骤映射
|
// 步骤映射
|
||||||
const STEP_MAP = {
|
const STEP_MAP = {
|
||||||
@ -15,34 +16,35 @@ const STEP_MAP = {
|
|||||||
type ApiStep = keyof typeof STEP_MAP;
|
type ApiStep = keyof typeof STEP_MAP;
|
||||||
|
|
||||||
interface TaskData {
|
interface TaskData {
|
||||||
sketch?: Array<{
|
sketch?: {
|
||||||
url: string;
|
url: string;
|
||||||
script: string;
|
script: string;
|
||||||
bg_rgb: string[];
|
bg_rgb: string[];
|
||||||
}>;
|
}[];
|
||||||
roles?: Array<{
|
roles?: {
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
sound: string;
|
sound: string;
|
||||||
soundDescription: string;
|
soundDescription: string;
|
||||||
roleDescription: string;
|
roleDescription: string;
|
||||||
}>;
|
}[];
|
||||||
videos?: Array<{
|
videos?: {
|
||||||
url: string;
|
url: string;
|
||||||
script: string;
|
script: string;
|
||||||
audio: string;
|
audio: string;
|
||||||
}>;
|
}[];
|
||||||
music?: Array<{
|
music?: {
|
||||||
url: string;
|
url: string;
|
||||||
script: string;
|
script: string;
|
||||||
name: string;
|
name: string;
|
||||||
duration: string;
|
duration: string;
|
||||||
totalDuration: string;
|
totalDuration: string;
|
||||||
isLooped: boolean;
|
isLooped: boolean;
|
||||||
}>;
|
}[];
|
||||||
final?: {
|
final?: {
|
||||||
url: string;
|
url: string;
|
||||||
};
|
};
|
||||||
|
[key: string]: any; // 允许其他可能的字段
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useApiData = () => {
|
export const useApiData = () => {
|
||||||
@ -192,7 +194,38 @@ export const useApiData = () => {
|
|||||||
|
|
||||||
// 设置任务数据
|
// 设置任务数据
|
||||||
if (data) {
|
if (data) {
|
||||||
setTaskData(data);
|
// 将 ProjectContentData 转换为 TaskData
|
||||||
|
const convertedData: TaskData = {
|
||||||
|
sketch: data.sketch?.data?.map((item: SketchData) => ({
|
||||||
|
url: item.image_path,
|
||||||
|
script: item.prompt,
|
||||||
|
bg_rgb: ['255', '255', '255'] // 默认白色背景
|
||||||
|
})) || [],
|
||||||
|
roles: data.character?.data?.map((item: CharacterResponse) => ({
|
||||||
|
name: item.character_name,
|
||||||
|
url: item.image_path,
|
||||||
|
sound: '',
|
||||||
|
soundDescription: '',
|
||||||
|
roleDescription: item.character_description
|
||||||
|
})) || [],
|
||||||
|
videos: data.video?.data?.map((item: VideoData) => ({
|
||||||
|
url: item.urls?.[0] || '',
|
||||||
|
script: item.description || '',
|
||||||
|
audio: '' // 音频URL可能需要从其他地方获取
|
||||||
|
})) || [],
|
||||||
|
music: data.music?.data?.map((item: any) => ({
|
||||||
|
url: item.url || '',
|
||||||
|
script: item.description || '',
|
||||||
|
name: item.name || '',
|
||||||
|
duration: item.duration || '',
|
||||||
|
totalDuration: item.total_duration || '',
|
||||||
|
isLooped: item.is_looped || false
|
||||||
|
})) || [],
|
||||||
|
final: data.final_video ? {
|
||||||
|
url: data.final_video.video || ''
|
||||||
|
} : undefined
|
||||||
|
};
|
||||||
|
setTaskData(convertedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -424,7 +424,7 @@ export function useWorkflowData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { name, status, data, tags, mode, original_text } = response.data;
|
const { name, status, data, tags, mode, original_text } = response.data;
|
||||||
setMode(mode);
|
setMode(mode as 'automatic' | 'manual' | 'auto');
|
||||||
setOriginalText(original_text);
|
setOriginalText(original_text);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
|
||||||
@ -569,9 +569,9 @@ export function useWorkflowData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 粗剪
|
// 粗剪
|
||||||
if (data.final_simple_video && data.final_simple_video.video) {
|
if ((data as any).final_simple_video && (data as any).final_simple_video.video) {
|
||||||
setFinal({
|
setFinal({
|
||||||
url: data.final_simple_video.video
|
url: (data as any).final_simple_video.video
|
||||||
});
|
});
|
||||||
taskData.status = '5.5';
|
taskData.status = '5.5';
|
||||||
loadingText = LOADING_TEXT_MAP.postProduction('generating fine-grained video clips...');
|
loadingText = LOADING_TEXT_MAP.postProduction('generating fine-grained video clips...');
|
||||||
|
|||||||
@ -14,7 +14,7 @@ interface ScriptRendererProps {
|
|||||||
isPauseWorkFlow: boolean;
|
isPauseWorkFlow: boolean;
|
||||||
applyScript: any;
|
applyScript: any;
|
||||||
mode: string;
|
mode: string;
|
||||||
from: string;
|
from?: string;
|
||||||
setIsUpdate?: (isUpdate: boolean) => void;
|
setIsUpdate?: (isUpdate: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ export const ScriptRenderer: React.FC<ScriptRendererProps> = ({ data, setIsPause
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const themeBlock = data.find(block => block.id === 'categories');
|
const themeBlock = data.find(block => block.id === 'categories');
|
||||||
if (themeBlock && themeBlock.content.length > 0) {
|
if (themeBlock && themeBlock.content.length > 0) {
|
||||||
const themeTag = themeBlock.content[0].text.split(',').map(item => item.trim());
|
const themeTag = themeBlock.content[0].text.split(',').map((item: string) => item.trim());
|
||||||
console.log('themeTag', themeTag);
|
console.log('themeTag', themeTag);
|
||||||
setAddThemeTag(themeTag);
|
setAddThemeTag(themeTag);
|
||||||
}
|
}
|
||||||
@ -110,13 +110,13 @@ export const ScriptRenderer: React.FC<ScriptRendererProps> = ({ data, setIsPause
|
|||||||
// console.log(e.target.value);
|
// console.log(e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBlockTextBlur = (block: ScriptBlock) => (e: ContentEditableEvent) => {
|
const handleBlockTextBlur = (block: ScriptBlock) => () => {
|
||||||
setEditBlockId(null);
|
setEditBlockId(null);
|
||||||
if (contentEditableRef.current) {
|
if (contentEditableRef.current) {
|
||||||
const text = contentEditableRef.current.innerText;
|
const text = contentEditableRef.current.innerText;
|
||||||
console.log('contentEditableRef---text', text);
|
console.log('contentEditableRef---text', text);
|
||||||
console.log('contentEditableRef---block', block.id, block);
|
console.log('contentEditableRef---block', block.id, block);
|
||||||
if (block.content[0].text !== text) {
|
if (block.content[0].text !== text && setIsUpdate) {
|
||||||
setIsUpdate(true);
|
setIsUpdate(true);
|
||||||
}
|
}
|
||||||
setAnyAttribute(block.id, text,from !== 'tab',(old: string)=>{
|
setAnyAttribute(block.id, text,from !== 'tab',(old: string)=>{
|
||||||
@ -140,7 +140,9 @@ export const ScriptRenderer: React.FC<ScriptRendererProps> = ({ data, setIsPause
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setAddThemeTag(value);
|
setAddThemeTag(value);
|
||||||
setIsUpdate(true);
|
if (setIsUpdate) {
|
||||||
|
setIsUpdate(true);
|
||||||
|
}
|
||||||
from !== 'tab' && setIsPauseWorkFlow(true);
|
from !== 'tab' && setIsPauseWorkFlow(true);
|
||||||
setAnyAttribute('categories', value.join(','),from !== 'tab',(old: string)=>{
|
setAnyAttribute('categories', value.join(','),from !== 'tab',(old: string)=>{
|
||||||
if(old!==value.join(',')){
|
if(old!==value.join(',')){
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Node, mergeAttributes } from '@tiptap/core'
|
import { Node, mergeAttributes } from '@tiptap/core'
|
||||||
import { ReactNodeViewRenderer, NodeViewWrapper } from '@tiptap/react'
|
import { ReactNodeViewRenderer, NodeViewWrapper, ReactNodeViewProps } from '@tiptap/react'
|
||||||
import { motion, AnimatePresence } from 'framer-motion'
|
import { motion, AnimatePresence } from 'framer-motion'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
@ -33,7 +33,8 @@ export const CharacterToken = Node.create({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
function CharacterView({ node }) {
|
function CharacterView(props: ReactNodeViewProps) {
|
||||||
|
const { node } = props;
|
||||||
const [showCard, setShowCard] = useState(false)
|
const [showCard, setShowCard] = useState(false)
|
||||||
const { name, avatar, gender, age } = node.attrs
|
const { name, avatar, gender, age } = node.attrs
|
||||||
|
|
||||||
|
|||||||
@ -71,6 +71,7 @@ export function ReplaceScenePanel({
|
|||||||
showAddToLibrary={false}
|
showAddToLibrary={false}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
onConfirm={onConfirm}
|
onConfirm={onConfirm}
|
||||||
|
isLoading={false}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user