添加角色简介生成功能,移除生成剧本逻辑,优化模板故事模式样式

This commit is contained in:
海龙 2025-08-19 23:43:42 +08:00
parent 84b6662a51
commit d7d41e91ac
4 changed files with 43 additions and 42 deletions

View File

@ -1105,6 +1105,37 @@ export const analyzeImageDescription = async (request: {
}>>("/character/analyze_image_description", request); }>>("/character/analyze_image_description", request);
}; };
/**
*
* @description URLAI服务分析图片并生成角色简介
* @param request -
* @returns Promise<ApiResponse<角色简介结果>>
*/
export const generateCharacterBrief = async (request: {
/** 图片的URL地址必须是有效的HTTP/HTTPS链接 */
image_url: string;
}) => {
return post<ApiResponse<{
success: boolean;
/** 原始图片URL */
original_url: string;
/** 裁剪后图片URL */
cutout_url: string;
/** 头像框选区域 */
bounding_box: {
/** 左侧坐标 */
left: number;
/** 顶部坐标 */
top: number;
/** 宽度 */
width: number;
/** 高度 */
height: number;
};
character_brief:Record<string, any>
}>>("/movie_story/generate_character_brief", request);
};
/** /**
* *
* @description * @description

View File

@ -37,8 +37,6 @@ interface UseImageStoryService {
uploadAndAnalyzeImage: () => Promise<void>; uploadAndAnalyzeImage: () => Promise<void>;
/** 触发文件选择 */ /** 触发文件选择 */
triggerFileSelection: () => Promise<void>; triggerFileSelection: () => Promise<void>;
/** 触发生成剧本函数 */
generateScript: () => Promise<string>;
/** 更新故事类型 */ /** 更新故事类型 */
updateStoryType: (storyType: string) => void; updateStoryType: (storyType: string) => void;
/** 更新故事内容 */ /** 更新故事内容 */
@ -278,39 +276,6 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
} }
}, [imageStoryUseCase, activeImageUrl, storyContent]); }, [imageStoryUseCase, activeImageUrl, storyContent]);
/**
*
* @returns {Promise<string>} ID或内容
*/
const generateScript = useCallback(async (): Promise<string> => {
if (!activeImageUrl) {
throw new Error("请先上传图片");
}
const finalStoryContent = storyContent;
if (!finalStoryContent.trim()) {
throw new Error("请先输入或生成故事内容");
}
try {
setIsLoading(true);
// 这里可以调用后端API生成剧本
// 暂时返回一个模拟的剧本ID
const scriptId = `script_${Date.now()}`;
// TODO: 实现实际的剧本生成逻辑
// const response = await generateScriptFromImage(imageStory);
// return response.scriptId;
return scriptId;
} catch (error) {
console.error("生成剧本失败:", error);
throw error;
} finally {
setIsLoading(false);
}
}, [activeImageUrl, storyContent]);
/** /**
* *
@ -531,7 +496,6 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
setCharactersAnalysis, setCharactersAnalysis,
uploadAndAnalyzeImage, uploadAndAnalyzeImage,
triggerFileSelection, triggerFileSelection,
generateScript,
updateStoryType, updateStoryType,
updateStoryContent, updateStoryContent,
updateCharacterName, updateCharacterName,

View File

@ -1,7 +1,7 @@
import { ImageStoryEntity } from "../domain/Entities"; import { ImageStoryEntity } from "../domain/Entities";
import { AIGenerateImageStory } from "@/api/movie_start"; import { AIGenerateImageStory } from "@/api/movie_start";
import { MovieStartDTO, CharacterAnalysis } from "@/api/DTO/movie_start_dto"; import { MovieStartDTO, CharacterAnalysis } from "@/api/DTO/movie_start_dto";
import { analyzeImageDescription } from "@/api/video_flow"; import { generateCharacterBrief } from "@/api/video_flow";
/** /**
* *
@ -101,6 +101,12 @@ export class ImageStoryUseCase {
}); });
if (response.successful && response.data) { if (response.successful && response.data) {
// ! 后端实际返回的是对象 但是由于前端只是做字符串数据的转交,所以这里就处理成字符串
// ! 至于为什么这里是前端来处理因为后端这个数据很多时候都说要以对象方式使用唯独给AI时是字符串
// ! 然后后端就不处理这个东西了,就给前端来处理了,真 懒
response.data.characters_analysis.forEach((character) => {
character.whisk_caption = JSON.stringify(character.whisk_caption);
});
// 解析并存储新的数据结构 // 解析并存储新的数据结构
this.parseAndStoreAnalysisData(response.data); this.parseAndStoreAnalysisData(response.data);
@ -254,7 +260,7 @@ export class ImageStoryUseCase {
const imageUrl = await uploadFile(file); const imageUrl = await uploadFile(file);
// 2. 调用AI分析接口获取人物特征描述 // 2. 调用AI分析接口获取人物特征描述
const analysisResult = await analyzeImageDescription({ const analysisResult = await generateCharacterBrief({
image_url: imageUrl, image_url: imageUrl,
}); });
@ -265,7 +271,7 @@ export class ImageStoryUseCase {
// 3. 返回新的头像URL和特征描述用于替换旧数据 // 3. 返回新的头像URL和特征描述用于替换旧数据
const result = { const result = {
crop_url: imageUrl, crop_url: imageUrl,
whisk_caption: analysisResult.data.description, whisk_caption: JSON.stringify(analysisResult.data.character_brief),
}; };
// 清理临时元素 // 清理临时元素

View File

@ -142,7 +142,7 @@ const RenderTemplateStoryMode = ({
) : selectedTemplate ? ( ) : selectedTemplate ? (
<div className="relative h-full"> <div className="relative h-full">
{/* 模板信息头部 - 增加顶部空间 */} {/* 模板信息头部 - 增加顶部空间 */}
<div className="flex gap-3 py-4 border-b border-white/[0.1] min-h-[300px]"> <div className="flex gap-3 py-4 border-b border-white/[0.1] h-[300px]">
{/* 左侧图片 */} {/* 左侧图片 */}
<div className="w-1/3"> <div className="w-1/3">
<div <div
@ -191,7 +191,7 @@ const RenderTemplateStoryMode = ({
{/* 左侧:当前选中角色的音频与照片更改 - 精简版本 */} {/* 左侧:当前选中角色的音频与照片更改 - 精简版本 */}
<div className="flex-1 space-y-4"> <div className="flex-1 space-y-4">
{/* 图片上传部分 - 精简 */} {/* 图片上传部分 - 精简 */}
<div className="space-y-2 mb-8"> <div className="space-y-2 mb-8 mt-4">
<div className="flex justify-center"> <div className="flex justify-center">
<Tooltip <Tooltip
title="Upload a portrait photo to replace this character's appearance in the movie." title="Upload a portrait photo to replace this character's appearance in the movie."
@ -350,7 +350,7 @@ const RenderTemplateStoryMode = ({
}} }}
footer={null} footer={null}
width="60%" width="60%"
style={{ maxWidth: "800px", marginTop: "10vh" }} style={{ maxWidth: "800px", marginTop: "0vh" }}
className="template-modal" className="template-modal"
closeIcon={ closeIcon={
<div className="w-6 h-6 bg-white/10 rounded-full flex items-center justify-center hover:bg-white/20 transition-colors"> <div className="w-6 h-6 bg-white/10 rounded-full flex items-center justify-center hover:bg-white/20 transition-colors">