重构视频流和交互服务,使用 TagValueObject 替代 TagEntity。更新相关方法和接口以保持一致性。移除未使用的 TextEditUseCase。增强角色和场景编辑功能。

This commit is contained in:
海龙 2025-08-08 20:21:23 +08:00
parent 067295a2bc
commit 46bda04605
14 changed files with 340 additions and 221 deletions

View File

@ -7,8 +7,8 @@ import {
RoleEntity,
SceneEntity,
VideoSegmentEntity,
TagEntity,
} from "@/app/service/domain/Entities";
import { TagValueObject } from "@/app/service/domain/valueObject";
import {
ContentItem,
LensType,
@ -252,8 +252,8 @@ export const getVideoJson = async (data: {
export const regenerateRole = async (request: {
/** 角色提示词 */
prompt: string;
/** 标签类型列表 */
tagTypes: (number | string)[];
/** 标签列表 */
tagTypes: TagValueObject[];
/** 角色ID可选如果重新生成现有角色 */
roleId?: string;
}): Promise<ApiResponse<RoleEntity>> => {
@ -318,7 +318,7 @@ export const getRoleData = async (request: {
/** AI文本数据 */
text: AITextEntity;
/** 标签列表 */
tags: TagEntity[];
tags: TagValueObject[];
}>
> => {
return post<ApiResponse<any>>("/movie/get_role_data", request);
@ -358,7 +358,7 @@ export const updateTag = async (request: {
tagId: string;
/** 新的标签内容 */
content: string | number;
}): Promise<ApiResponse<TagEntity>> => {
}): Promise<ApiResponse<TagValueObject>> => {
return post<ApiResponse<any>>("/movie/update_tag", request);
};
@ -384,8 +384,8 @@ export const updateText = async (request: {
export const regenerateScene = async (request: {
/** 场景提示词 */
prompt: string;
/** 标签类型列表 */
tagTypes: (number | string)[];
/** 标签列表 */
tagTypes: TagValueObject[];
/** 场景ID可选如果重新生成现有场景 */
sceneId?: string;
}): Promise<ApiResponse<SceneEntity>> => {
@ -419,7 +419,7 @@ export const getSceneData = async (request: {
/** AI文本数据 */
text: AITextEntity;
/** 标签列表 */
tags: TagEntity[];
tags: TagValueObject[];
}>
> => {
return post<ApiResponse<any>>("/movie/get_scene_data", request);
@ -493,7 +493,7 @@ export const getShotData = async (request: {
/** AI文本数据 */
text: AITextEntity;
/** 标签列表 */
tags: TagEntity[];
tags: TagValueObject[];
}>
> => {
return post<ApiResponse<any>>("/movie/get_shot_data", request);

View File

@ -1,5 +1,6 @@
import { useState, useCallback, useMemo } from 'react';
import { RoleEntity, TagEntity, AITextEntity, VideoSegmentEntity } from '../domain/Entities';
import { RoleEntity, AITextEntity, VideoSegmentEntity } from '../domain/Entities';
import { TagValueObject } from '../domain/valueObject';
import { RoleItem, TagItem, TextItem } from '../domain/Item';
import { RoleEditUseCase } from '../usecase/RoleEditUseCase';
import { TagEditUseCase } from '../usecase/TagEditUseCase';

View File

@ -1,5 +1,5 @@
import { useState, useCallback, useMemo } from 'react';
import { SceneEntity, TagEntity, AITextEntity, VideoSegmentEntity } from '../domain/Entities';
import { SceneEntity, TagValueObject, AITextEntity, VideoSegmentEntity } from '../domain/Entities';
import { SceneItem, TagItem, TextItem } from '../domain/Item';
import { SceneEditUseCase } from '../usecase/SceneEditUseCase';
import { TagEditUseCase } from '../usecase/TagEditUseCase';

View File

@ -9,8 +9,6 @@ import { ScriptEditUseCase, ScriptEditKey } from "../usecase/ScriptEditUseCase";
import {
getProjectScript,
abortVideoTask,
pausePlanFlow,
resumePlanFlow,
} from "../../../api/video_flow";
import { parseScriptBlock } from "../domain/service";
import { ScriptBlock } from "@/components/script-renderer/types";

View File

@ -2,6 +2,7 @@ import { useState, useCallback } from "react";
import { VideoSegmentEditUseCase } from "../usecase/ShotEditUsecase";
import { VideoSegmentEntity } from "../domain/Entities";
import { LensType } from "../domain/valueObject";
import { getUploadToken, uploadToQiniu } from "@/api/common";
/**
* Hook接口
@ -40,6 +41,8 @@ export interface UseShotService {
addNewLens: () => void;
/** 删除指定镜头 */
deleteLens: (lensName: string) => void;
/** 获取视频当前帧并上传到七牛云 */
filterRole: (video: HTMLVideoElement) => Promise<string>;
}
/**
@ -165,9 +168,9 @@ export const useShotService = (): UseShotService => {
*
*/
const abortOperation = useCallback((): void => {
vidoEditUseCase.abortOperation();
// vidoEditUseCase.abortOperation();
setLoading(false);
}, [vidoEditUseCase]);
}, []);
/**
*
@ -244,6 +247,54 @@ export const useShotService = (): UseShotService => {
});
}, [selectedSegment]);
/**
* ,
* @param video HTML视频元素
* @returns Promise<string>
*/
const filterRole = useCallback(async (video: HTMLVideoElement): Promise<string> => {
try {
// 创建canvas元素来截取视频帧
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (!ctx) {
throw new Error('无法获取canvas上下文');
}
// 设置canvas尺寸为视频尺寸
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
// 将当前视频帧绘制到canvas上
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
// 将canvas转换为blob
const blob = await new Promise<Blob>((resolve, reject) => {
canvas.toBlob((blob) => {
if (blob) {
resolve(blob);
} else {
reject(new Error('无法将canvas转换为blob'));
}
}, 'image/png');
});
// 创建File对象
const file = new File([blob], `frame_${Date.now()}.png`, { type: 'image/png' });
// 获取上传token
const { token } = await getUploadToken();
// 上传到七牛云
const imageUrl = await uploadToQiniu(file, token);
return imageUrl;
} catch (error) {
console.error('获取视频帧失败:', error);
throw error;
}
}, []);
return {
// 响应式状态
loading,
@ -257,5 +308,6 @@ export const useShotService = (): UseShotService => {
setSelectedSegment: setSelectedSegmentHandler,
addNewLens,
deleteLens,
filterRole,
};
};

View File

@ -3,7 +3,7 @@
*
*/
import { ContentItem, LensType } from "./valueObject";
import { ContentItem, LensType, TagValueObject } from "./valueObject";
/**
*
@ -34,24 +34,12 @@ export interface AITextEntity extends BaseEntity {
export interface RoleEntity extends BaseEntity {
/** 角色名称 */
name: string;
/** 角色提示词Id */
generateTextId: string;
/** 角色提示词 */
generateText: string;
/**角色标签 */
tagIds: string[];
tagIds: TagValueObject[];
/** 角色图片URL */
imageUrl: string;
/** 角色是否已存储 */
isStored: boolean;
}
/**
*
*/
export interface TagEntity extends BaseEntity {
/** 标签名称 */
name: string;
/** 内容标签类型 */
content: number | string;
}
/**
@ -63,9 +51,9 @@ export interface SceneEntity extends BaseEntity {
/** 场景图片URL */
imageUrl: string;
/** 场景标签 */
tagIds: string[];
/** 场景提示词Id */
generateTextId: string;
tagIds: TagValueObject[];
/** 场景提示词 */
generateText: string;
}
/**

View File

@ -2,7 +2,7 @@ import {
BaseEntity,
AITextEntity,
RoleEntity,
TagEntity,
TagValueObject,
SceneEntity,
VideoSegmentEntity
} from './Entities';
@ -87,11 +87,11 @@ export class RoleItem extends EditItem<RoleEntity> {
/**
*
*/
export class TagItem extends EditItem<TagEntity> {
export class TagItem extends EditItem<TagValueObject> {
type: ItemType.TEXT = ItemType.TEXT;
constructor(
entity: TagEntity,
entity: TagValueObject,
metadata: Record<string, any> = {}
) {
super(entity, metadata);

View File

@ -79,6 +79,17 @@ export class LensType {
}
}
/**
*
*/
export interface TagValueObject {
/** 标签名称 */
name: string;
/** 内容标签类型 */
content: number | string;
}
/**
* DDD概念的值对象
*

View File

@ -3,7 +3,7 @@ import { SceneEditUseCase } from '../usecase/SceneEditUseCase';
import { TextEditUseCase } from '../usecase/TextEditUseCase';
import { TagEditUseCase } from '../usecase/TagEditUseCase';
import { SceneItem, TextItem, TagItem } from '../domain/Item';
import { SceneEntity, AITextEntity, TagEntity, VideoSegmentEntity, ShotStatus } from '../domain/Entities';
import { SceneEntity, AITextEntity, TagValueObject, VideoSegmentEntity, ShotStatus } from '../domain/Entities';
// Mock API模块
jest.mock('@/api/video_flow', () => ({
@ -53,7 +53,7 @@ describe('SceneService 业务逻辑测试', () => {
disableEdit: false,
};
const mockTagEntity1: TagEntity = {
const mockTagValueObject1: TagValueObject = {
id: 'tag1',
name: '场景标签1',
content: '场景标签内容1',
@ -62,7 +62,7 @@ describe('SceneService 业务逻辑测试', () => {
disableEdit: false,
};
const mockTagEntity2: TagEntity = {
const mockTagValueObject2: TagValueObject = {
id: 'tag2',
name: '场景标签2',
content: '场景标签内容2',
@ -167,7 +167,7 @@ describe('SceneService 业务逻辑测试', () => {
successful: true,
data: {
text: mockTextEntity,
tags: [mockTagEntity1, mockTagEntity2],
tags: [mockTagValueObject1, mockTagValueObject2],
},
});
@ -176,7 +176,7 @@ describe('SceneService 业务逻辑测试', () => {
expect(getSceneData).toHaveBeenCalledWith({ sceneId: 'scene1' });
expect(result.successful).toBe(true);
expect(result.data.text).toEqual(mockTextEntity);
expect(result.data.tags).toEqual([mockTagEntity1, mockTagEntity2]);
expect(result.data.tags).toEqual([mockTagValueObject1, mockTagValueObject2]);
});
});
@ -202,10 +202,10 @@ describe('SceneService 业务逻辑测试', () => {
});
it('应该成功修改标签内容', async () => {
const updatedTagEntity = { ...mockTagEntity1, content: '更新后的场景标签' };
const updatedTagValueObject = { ...mockTagValueObject1, content: '更新后的场景标签' };
(updateTag as jest.Mock).mockResolvedValue({
successful: true,
data: updatedTagEntity,
data: updatedTagValueObject,
});
const result = await updateTag({
@ -319,14 +319,14 @@ describe('SceneService 业务逻辑测试', () => {
successful: true,
data: {
text: mockTextEntity,
tags: [mockTagEntity1, mockTagEntity2],
tags: [mockTagValueObject1, mockTagValueObject2],
},
});
const sceneDataResult = await getSceneData({ sceneId: 'scene1' });
expect(sceneDataResult.successful).toBe(true);
expect(sceneDataResult.data.text).toEqual(mockTextEntity);
expect(sceneDataResult.data.tags).toEqual([mockTagEntity1, mockTagEntity2]);
expect(sceneDataResult.data.tags).toEqual([mockTagValueObject1, mockTagValueObject2]);
// 模拟用户操作:修改场景提示词
const updatedTextEntity = { ...mockTextEntity, content: '修改后的场景提示词' };
@ -356,10 +356,10 @@ describe('SceneService 业务逻辑测试', () => {
expect(optimizedContentResult).toBe(optimizedContent);
// 模拟用户操作:修改标签
const updatedTagEntity = { ...mockTagEntity1, content: '修改后的标签内容' };
const updatedTagValueObject = { ...mockTagValueObject1, content: '修改后的标签内容' };
(updateTag as jest.Mock).mockResolvedValue({
successful: true,
data: updatedTagEntity,
data: updatedTagValueObject,
});
const updateTagResult = await updateTag({
@ -435,7 +435,7 @@ describe('SceneService 业务逻辑测试', () => {
successful: true,
data: {
text: mockTextEntity,
tags: [mockTagEntity1],
tags: [mockTagValueObject1],
},
});
@ -612,7 +612,7 @@ describe('SceneService 业务逻辑测试', () => {
});
it('TagEditUseCase应该正确初始化', () => {
const tagItem = new TagItem(mockTagEntity1);
const tagItem = new TagItem(mockTagValueObject1);
const useCase = new TagEditUseCase(tagItem);
expect(TagEditUseCase).toHaveBeenCalledWith(tagItem);
@ -637,11 +637,11 @@ describe('SceneService 业务逻辑测试', () => {
expect(textItem.disableEdit).toBe(false);
});
it('TagItem应该正确包装TagEntity', () => {
const tagItem = new TagItem(mockTagEntity1);
it('TagItem应该正确包装TagValueObject', () => {
const tagItem = new TagItem(mockTagValueObject1);
expect(TagItem).toHaveBeenCalledWith(mockTagEntity1);
expect(tagItem.entity).toEqual(mockTagEntity1);
expect(TagItem).toHaveBeenCalledWith(mockTagValueObject1);
expect(tagItem.entity).toEqual(mockTagValueObject1);
expect(tagItem.disableEdit).toBe(false);
});
});
@ -695,7 +695,7 @@ describe('SceneService 业务逻辑测试', () => {
});
it('应该验证标签实体的完整性', () => {
const tagItem = new TagItem(mockTagEntity1);
const tagItem = new TagItem(mockTagValueObject1);
expect(tagItem.entity.id).toBe('tag1');
expect(tagItem.entity.name).toBe('场景标签1');

View File

@ -1,90 +1,191 @@
import { RoleEntity, AITextEntity, TagEntity } from '../domain/Entities';
import { RoleItem, TagItem, TextItem } from '../domain/Item';
import { regenerateRole, applyRoleToShots, getRoleData } from '@/api/video_flow';
import { RoleEntity } from '../domain/Entities';
import { TagValueObject } from '../domain/valueObject';
import {
applyRoleToShots,
getRoleList,
getUserRoleLibrary,
getRoleData,
regenerateRole,
getRoleShots,
replaceRole
} from '@/api/video_flow';
import { TagEditUseCase } from './TagEditUseCase';
/**
*
*
*/
export class RoleEditUseCase {
constructor(private roleItem: RoleItem) {
roleList: RoleEntity[] = [];
selectedRole: RoleEntity | null = null;
selectedRoleTags:TagEditUseCase = new TagEditUseCase([]);
roleLibraryList: RoleEntity[] = [];
constructor() {
}
/**
* @description:
* @param {TextItem} prompt
* @param {TagItem[]} tags
* @return {*}
*
* @param projectId ID
* @returns Promise<RoleEntity[]>
*/
async AIgenerateRole(prompt: TextItem, tags: TagItem[]): Promise<RoleEntity> {
const promptText = prompt.entity.content;
const tagList = tags.map((tag) => tag.entity.content);
// 调用重新生成角色接口
const response = await regenerateRole({
roleId: this.roleItem.entity.id||'',
prompt: promptText,
tagTypes: tagList,
});
if (response.successful) {
const roleEntity = response.data;
this.roleItem.setEntity(roleEntity);
return roleEntity;
} else {
throw new Error(`重新生成角色失败: ${response.message}`);
async getRoleList(projectId: string): Promise<RoleEntity[]> {
try {
const response = await getRoleList({ projectId });
if (response.successful) {
return response.data;
} else {
throw new Error(response.message || '获取角色列表失败');
}
} catch (error) {
console.error('获取角色列表失败:', error);
throw error;
}
}
/**
*
* @returns Promise<RoleEntity[]>
*/
async getRoleLibraryList(): Promise<RoleEntity[]> {
try {
const response = await getUserRoleLibrary();
if (response.successful) {
return response.data;
} else {
throw new Error(response.message || '获取角色库失败');
}
} catch (error) {
console.error('获取角色库失败:', error);
throw error;
}
}
/**
*
* @param tagName
* @param newContent
*/
async updateTag(tagName: string, newContent: string | number): Promise<void> {
await this.selectedRoleTags.updateTag(tagName, newContent);
}
/**
*
* @param roleId ID
*/
async selectRole(roleId: string): Promise<void> {
try {
// 从已获取的角色列表中查找对应的角色实体
const roleEntity = this.roleList.find(role => role.id === roleId);
if (roleEntity) {
this.selectedRole = roleEntity;
// 获取角色数据以获取标签信息
const response = await getRoleData({ roleId });
if (response.successful) {
this.selectedRoleTags = new TagEditUseCase(response.data.tags);
} else {
throw new Error(response.message || '获取角色标签数据失败');
}
} else {
throw new Error('未找到对应的角色实体,请先获取角色列表');
}
} catch (error) {
console.error('选择角色失败:', error);
throw error;
}
}
/**
*
* @param prompt
* @param tags
* @returns Promise<RoleEntity>
*/
async AIgenerateRole(prompt: string, tags: TagValueObject[]): Promise<RoleEntity> {
try {
// 直接使用当前角色的ID不做任何处理
const response = await regenerateRole({
prompt,
tagTypes: tags, // 直接传递完整的标签列表给后端,让后端处理
roleId: this.selectedRole?.id
});
if (response.successful) {
return response.data;
} else {
throw new Error(response.message || '重新生成角色失败');
}
} catch (error) {
console.error('重新生成角色失败:', error);
throw error;
}
}
/**
*
* @param shotIds ID列表
* @param roleId ID
* @returns
*/
async applyRole(shotIds: string[]) {
const roleId = this.roleItem.entity.id;
return await applyRoleToShots({
roleId,
shotIds,
});
async applyRole(shotIds: string[], roleId: string) {
try {
const response = await applyRoleToShots({
roleId,
shotIds,
});
if (response.successful) {
return response.data;
} else {
throw new Error(response.message || '应用角色到分镜失败');
}
} catch (error) {
console.error('应用角色到分镜失败:', error);
throw error;
}
}
/**
*
* @description AI文本和标签数据
* @returns Promise<{ text: AITextEntity; tags: TagEntity[] }> AI文本和标签数据
* @throws {Error} API调用失败时抛出错误
*
* @param roleId ID
* @returns
*/
async refreshRoleData(): Promise<{ text: AITextEntity; tags: TagEntity[] }> {
const roleId = this.roleItem.entity.id;
if (!roleId) {
throw new Error('角色ID不存在无法获取角色数据');
}
const response = await getRoleData({
roleId: roleId
});
if (response.successful) {
// 更新当前角色的实体数据
const { text, tags } = response.data;
// 更新角色实体中的相关字段
const updatedRoleEntity = {
...this.roleItem.entity,
generateTextId: text.id, // 更新AI文本ID
tagIds: tags.map(tag => tag.id), // 更新标签ID列表
updatedAt: Date.now(), // 更新时间戳
};
// 更新当前UseCase中的实体
this.roleItem.setEntity(updatedRoleEntity);
return response.data;
} else {
throw new Error(`获取角色数据失败: ${response.message}`);
async getRoleShotsList(roleId: string) {
try {
const response = await getRoleShots({ roleId });
if (response.successful) {
return response.data;
} else {
throw new Error(response.message || '获取角色分镜列表失败');
}
} catch (error) {
console.error('获取角色分镜列表失败:', error);
throw error;
}
}
/**
*
* @param currentRoleId ID
* @param replaceRoleId ID
* @returns
*/
async replaceRoleById(currentRoleId: string, replaceRoleId: string) {
try {
const response = await replaceRole({
currentRoleId,
replaceRoleId,
});
if (response.successful) {
return response.data;
} else {
throw new Error(response.message || '替换角色失败');
}
} catch (error) {
console.error('替换角色失败:', error);
throw error;
}
}
}

View File

@ -1,4 +1,4 @@
import { SceneEntity, AITextEntity, TagEntity } from '../domain/Entities';
import { SceneEntity, AITextEntity } from '../domain/Entities';
import { SceneItem, TagItem, TextItem } from '../domain/Item';
import { regenerateScene, applySceneToShots, getSceneData } from '@/api/video_flow';
@ -53,10 +53,10 @@ export class SceneEditUseCase {
/**
*
* @description AI文本和标签数据
* @returns Promise<{ text: AITextEntity; tags: TagEntity[] }> AI文本和标签数据
* @returns Promise<{ text: AITextEntity; tags: TagValueObject[] }> AI文本和标签数据
* @throws {Error} API调用失败时抛出错误
*/
async refreshSceneData(): Promise<{ text: AITextEntity; tags: TagEntity[] }> {
async refreshSceneData(): Promise<{ text: AITextEntity; tags: TagValueObject[] }> {
const sceneId = this.sceneItem.entity.id;
if (!sceneId) {

View File

@ -12,7 +12,6 @@ import {
*/
export class VideoSegmentEditUseCase {
private loading: boolean = false;
private abortController: AbortController | null = null;
/**
* @description
@ -55,9 +54,6 @@ export class VideoSegmentEditUseCase {
try {
this.loading = true;
// 创建新的中断控制器
this.abortController = new AbortController();
const response = await regenerateShot({
shotId,
shotPrompt,
@ -71,15 +67,8 @@ export class VideoSegmentEditUseCase {
return response.data;
} catch (error) {
if (this.abortController?.signal.aborted) {
console.log("视频片段重新生成被中断");
throw new Error("操作被中断");
}
console.error("重新生成视频片段失败:", error);
throw error;
} finally {
this.loading = false;
this.abortController = null;
}
}
@ -117,15 +106,7 @@ export class VideoSegmentEditUseCase {
this.loading = false;
}
}
/**
* @description
*/
abortOperation(): void {
if (this.abortController) {
this.abortController.abort();
this.loading = false;
}
}
/**
* @description

View File

@ -1,40 +1,81 @@
import { TagItem } from '../domain/Item';
import { updateTag } from '@/api/video_flow';
import { TagValueObject } from '../domain/valueObject';
/**
*
*
*/
export class TagEditUseCase {
constructor(private readonly tagItem: TagItem) {
this.tagItem = tagItem;
constructor(public tagList: TagValueObject[]) {
}
/**
*
* @param tagName
* @param newContent
* @returns
*/
async updateTag(newContent: string|number): Promise<TagItem> {
if (!this.tagItem) {
throw new Error('标签项未初始化');
}
if (this.tagItem.entity.disableEdit) {
throw new Error('标签项已禁用编辑');
}
// 请求更新接口
const response = await updateTag({
tagId: this.tagItem.entity.id,
content: newContent
});
if (response.successful) {
this.tagItem.setEntity(response.data);
return this.tagItem;
} else {
throw new Error(`修改标签失败: ${response.message}`);
async updateTag(tagName: string, newContent: string | number): Promise<void> {
const tag = this.tagList.find(tag => tag.name === tagName);
if (tag) {
tag.content = newContent;
}
}
/**
*
* @param tagName
* @param content
*/
async addTag(tagName: string, content: string | number = ""): Promise<void> {
// 检查标签是否已存在
const existingTag = this.tagList.find(tag => tag.name === tagName);
if (existingTag) {
throw new Error(`标签 "${tagName}" 已存在`);
}
// 创建新标签
const newTag: TagValueObject = {
name: tagName,
content: content
};
this.tagList.push(newTag);
}
/**
*
* @param tagName
*/
async deleteTag(tagName: string): Promise<void> {
const tagIndex = this.tagList.findIndex(tag => tag.name === tagName);
if (tagIndex === -1) {
throw new Error(`标签 "${tagName}" 不存在`);
}
this.tagList.splice(tagIndex, 1);
}
/**
*
*/
async clearAllTags(): Promise<void> {
this.tagList.length = 0;
}
/**
*
* @returns
*/
getTagList(): TagValueObject[] {
return [...this.tagList];
}
/**
*
* @param tagName
* @returns undefined
*/
getTagByName(tagName: string): TagValueObject | undefined {
return this.tagList.find(tag => tag.name === tagName);
}
}

View File

@ -1,54 +0,0 @@
import { TextItem } from '../domain/Item';
import { updateText } from '@/api/video_flow';
/**
*
*
*/
export class TextEditUseCase {
constructor(private readonly textItem: TextItem) {
this.textItem = textItem;
}
/**
*
* @param newContent
* @returns
*/
async updateText(newContent: string): Promise<TextItem> {
if (!this.textItem) {
throw new Error('文本项未初始化,请先调用 initializeText');
}
if (this.textItem.entity.disableEdit) {
throw new Error('文本项已禁用编辑');
}
const response = await updateText({
textId: this.textItem.entity.id,
content: newContent
});
if (response.successful) {
this.textItem.setEntity(response.data);
return this.textItem;
} else {
throw new Error(`修改文案失败: ${response.message}`);
}
}
/**
*
* @param optimizationOptions
* @returns
*/
async getOptimizedContent(
): Promise<string> {
if (!this.textItem) {
throw new Error('没有内容可优化');
}
return this.textItem.entity.content;
}
}