feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { withSlardarIdButton } from '@coze-studio/bot-utils';
|
||||
import { logger } from '@coze-arch/logger';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { arrayBufferToObject } from '@coze-arch/bot-utils';
|
||||
import {
|
||||
type GenPicMessage,
|
||||
PicType,
|
||||
} from '@coze-arch/bot-api/playground_api';
|
||||
import { PlaygroundApi } from '@coze-arch/bot-api';
|
||||
import webSocketManager, {
|
||||
type Connection,
|
||||
type FrontierEventMap,
|
||||
} from '@coze-common/websocket-manager-adapter';
|
||||
import { Toast } from '@coze-arch/coze-design';
|
||||
|
||||
import { getBotDetailIsReadonly } from '../get-read-only';
|
||||
import { DotStatus } from '../../types/generate-image';
|
||||
import { useGenerateImageStore } from '../../store/generate-image-store';
|
||||
import { useBotInfoStore } from '../../store/bot-info';
|
||||
|
||||
class AvatarBackgroundWebSocket {
|
||||
private connection: Connection | undefined;
|
||||
private eventListenerList:
|
||||
| Array<{
|
||||
key: keyof FrontierEventMap;
|
||||
listener: (event) => void;
|
||||
}>
|
||||
| undefined;
|
||||
private biz: string;
|
||||
private service: number | undefined;
|
||||
private taskSet = new Set();
|
||||
|
||||
constructor(biz: string, service: number) {
|
||||
this.biz = biz;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
createConnection(retry = true) {
|
||||
if (this.connection) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.connection = webSocketManager.createConnection({
|
||||
biz: this.biz,
|
||||
service: this.service,
|
||||
});
|
||||
this.addWSEventListener();
|
||||
} catch (error) {
|
||||
// 重试一次
|
||||
if (retry) {
|
||||
this.createConnection(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this.connection) {
|
||||
this.eventListenerList?.forEach(({ key, listener }) => {
|
||||
this.connection?.removeEventListener(key, listener);
|
||||
});
|
||||
this.connection?.close();
|
||||
this.connection = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private addWSEventListener() {
|
||||
this.eventListenerList = [
|
||||
{ key: 'message', listener: this.onSocketMessage },
|
||||
{ key: 'error', listener: this.onSocketError },
|
||||
];
|
||||
this.eventListenerList?.forEach(({ key, listener }) => {
|
||||
this.connection?.addEventListener(key, listener);
|
||||
});
|
||||
}
|
||||
|
||||
private onSocketMessage = event => {
|
||||
const payload = arrayBufferToObject(
|
||||
event?.message?.payload,
|
||||
) as GenPicMessage;
|
||||
const task = payload?.pic_task;
|
||||
const taskId = task?.id || '';
|
||||
if (this.taskSet.has(taskId)) {
|
||||
logger.info({
|
||||
message: 'duplicate task',
|
||||
meta: { taskId },
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.taskSet.add(taskId);
|
||||
const botId = useBotInfoStore.getState().botId || '0';
|
||||
|
||||
if (botId !== '0' && getBotDetailIsReadonly()) {
|
||||
return;
|
||||
}
|
||||
const taskBotId = task?.bot_id || '0';
|
||||
if (task && taskBotId === botId) {
|
||||
const {
|
||||
generateAvatarModal,
|
||||
generateBackGroundModal,
|
||||
setGenerateAvatarModalByImmer,
|
||||
setGenerateBackgroundModalByImmer,
|
||||
pushImageList,
|
||||
} = useGenerateImageStore.getState();
|
||||
const {
|
||||
gif: { dotStatus: avatarGifDotStatus },
|
||||
image: { dotStatus: avatarStaticImageDotStatus },
|
||||
} = generateAvatarModal;
|
||||
const {
|
||||
gif: { dotStatus: backgroundGifDotStatus },
|
||||
image: { dotStatus: backgroundStaticImageDotStatus },
|
||||
} = generateBackGroundModal;
|
||||
const { status } = task;
|
||||
// 收到消息后更新头像或背景
|
||||
const updateState = (
|
||||
key: string,
|
||||
setImmer:
|
||||
| typeof setGenerateAvatarModalByImmer
|
||||
| typeof setGenerateBackgroundModalByImmer,
|
||||
currentDotStatus: DotStatus,
|
||||
) => {
|
||||
let dotStatus = DotStatus.None;
|
||||
if (currentDotStatus === DotStatus.Generating) {
|
||||
dotStatus =
|
||||
(status as number) === DotStatus.Success
|
||||
? DotStatus.Success
|
||||
: DotStatus.Fail;
|
||||
} else {
|
||||
// 标为已读
|
||||
if (taskBotId !== '0') {
|
||||
PlaygroundApi.MarkReadNotice({
|
||||
bot_id: taskBotId,
|
||||
pic_type: task.type,
|
||||
});
|
||||
}
|
||||
if ((status as number) === DotStatus.Fail) {
|
||||
Toast.error({
|
||||
content: withSlardarIdButton(
|
||||
payload?.err_msg || I18n.t('profilepicture_toast_failed'),
|
||||
),
|
||||
});
|
||||
} else if ((status as number) === DotStatus.Success) {
|
||||
Toast.success(I18n.t('profilepicture_toast_generated'));
|
||||
}
|
||||
}
|
||||
setImmer(state => {
|
||||
state[key] = {
|
||||
...state[key],
|
||||
loading: false,
|
||||
dotStatus,
|
||||
generateTaskId: '',
|
||||
};
|
||||
if ((status as number) === DotStatus.Success) {
|
||||
state.selectedImage = task;
|
||||
}
|
||||
});
|
||||
if ((status as number) === DotStatus.Success) {
|
||||
pushImageList(task);
|
||||
}
|
||||
};
|
||||
switch (task.type) {
|
||||
case PicType.IconGif: {
|
||||
updateState('gif', setGenerateAvatarModalByImmer, avatarGifDotStatus);
|
||||
break;
|
||||
}
|
||||
case PicType.IconStatic: {
|
||||
updateState(
|
||||
'image',
|
||||
setGenerateAvatarModalByImmer,
|
||||
avatarStaticImageDotStatus,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case PicType.BackgroundGif: {
|
||||
updateState(
|
||||
'gif',
|
||||
setGenerateBackgroundModalByImmer,
|
||||
backgroundGifDotStatus,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case PicType.BackgroundStatic: {
|
||||
updateState(
|
||||
'image',
|
||||
setGenerateBackgroundModalByImmer,
|
||||
backgroundStaticImageDotStatus,
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private onSocketError = event => {
|
||||
// TODO
|
||||
};
|
||||
}
|
||||
|
||||
const getPluginServiceId = () => {
|
||||
// region/service_id映射
|
||||
const regionServiceIdMap = {
|
||||
boe: 16778137,
|
||||
cn: 33554636,
|
||||
sg: 67108932,
|
||||
va: 67108932,
|
||||
};
|
||||
return regionServiceIdMap[IS_BOE ? 'boe' : REGION];
|
||||
};
|
||||
const serviceID = getPluginServiceId();
|
||||
|
||||
export const avatarBackgroundWebSocket = new AvatarBackgroundWebSocket(
|
||||
'EditorPic',
|
||||
serviceID,
|
||||
);
|
||||
|
||||
export function initAvatarBackgroundWebSocket() {
|
||||
// 创建连接
|
||||
setTimeout(() => {
|
||||
const {
|
||||
generateAvatarModal: {
|
||||
gif: { dotStatus: avatarGifDotStatus },
|
||||
image: { dotStatus: avatarStaticImageDotStatus },
|
||||
},
|
||||
generateBackGroundModal: {
|
||||
gif: { dotStatus: backgroundGifDotStatus },
|
||||
image: { dotStatus: backgroundStaticImageDotStatus },
|
||||
},
|
||||
} = useGenerateImageStore.getState();
|
||||
if (
|
||||
[
|
||||
avatarGifDotStatus,
|
||||
avatarStaticImageDotStatus,
|
||||
backgroundGifDotStatus,
|
||||
backgroundStaticImageDotStatus,
|
||||
].includes(DotStatus.Generating)
|
||||
) {
|
||||
avatarBackgroundWebSocket.createConnection();
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { globalVars } from '@coze-arch/web-context';
|
||||
|
||||
export const getExecuteDraftBotRequestId = (): string =>
|
||||
globalVars.LAST_EXECUTE_ID;
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { withSlardarIdButton } from '@coze-studio/bot-utils';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Toast } from '@coze-arch/bot-semi';
|
||||
import { AgentType } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import type { BotMultiAgent, Agent } from '../types/agent';
|
||||
|
||||
export const findFirstAgent = (
|
||||
multiAgent: BotMultiAgent,
|
||||
): Agent | undefined => {
|
||||
const startNode = multiAgent.agents.find(
|
||||
agent => agent.agent_type === AgentType.Start_Agent,
|
||||
);
|
||||
if (!startNode) {
|
||||
Toast.error({
|
||||
content: withSlardarIdButton(I18n.t('chatflow_error_miss_start')),
|
||||
});
|
||||
return;
|
||||
}
|
||||
const firstAgentId = multiAgent.edges.find(
|
||||
edge => edge.sourceNodeID === startNode.id,
|
||||
)?.targetNodeID;
|
||||
if (!firstAgentId) {
|
||||
Toast.error({
|
||||
content: withSlardarIdButton(I18n.t('chatflow_error_miss_start_agent')),
|
||||
});
|
||||
return;
|
||||
}
|
||||
return findTargetAgent(multiAgent.agents, firstAgentId);
|
||||
};
|
||||
|
||||
export const findTargetAgent = (agents: Agent[], agentId?: string) => {
|
||||
if (!agentId) {
|
||||
return;
|
||||
}
|
||||
return agents.find(item => item.id === agentId);
|
||||
};
|
||||
|
||||
/** 寻找某个agent,其中该agent的intent的next_agent_id是当前的agent id */
|
||||
export const findAgentByNextIntentID = (
|
||||
agents: Agent[],
|
||||
nextAgentID?: string,
|
||||
) => {
|
||||
if (!nextAgentID) {
|
||||
return;
|
||||
}
|
||||
return agents.find(item =>
|
||||
(item.intents || []).some(intent => intent.next_agent_id === nextAgentID),
|
||||
);
|
||||
};
|
||||
|
||||
export const findTargetAgentIndex = (agents: Agent[], agentId?: string) => {
|
||||
if (!agentId) {
|
||||
return -1;
|
||||
}
|
||||
return agents.findIndex(item => item.id === agentId);
|
||||
};
|
||||
|
||||
/**
|
||||
* start 节点指向的节点 id
|
||||
*/
|
||||
export const findFirstAgentId = ({
|
||||
agents,
|
||||
}: Pick<BotMultiAgent, 'agents'>): string | undefined => {
|
||||
const startNode = agents.find(
|
||||
agent => agent.agent_type === AgentType.Start_Agent,
|
||||
);
|
||||
return startNode?.intents?.at(0)?.next_agent_id;
|
||||
};
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
GenPicStatus,
|
||||
PicType,
|
||||
type GetPicTaskData,
|
||||
} from '@coze-arch/idl/playground_api';
|
||||
|
||||
import {
|
||||
type GenerateBackGroundModal,
|
||||
type GenerateAvatarModal,
|
||||
DotStatus,
|
||||
GenerateType,
|
||||
} from '../types/generate-image';
|
||||
import { useBotSkillStore } from '../store/bot-skill';
|
||||
import getDotStatus from './get-dot-status';
|
||||
|
||||
export const getInitBackgroundInfo = (
|
||||
data: GetPicTaskData,
|
||||
state: GenerateBackGroundModal,
|
||||
) => {
|
||||
const { tasks = [] } = data;
|
||||
const { backgroundImageInfoList = [] } = useBotSkillStore.getState();
|
||||
// 当前渲染的背景图
|
||||
const uri =
|
||||
backgroundImageInfoList[0]?.mobile_background_image?.origin_image_uri;
|
||||
|
||||
const backgroundGifList = tasks.filter(
|
||||
item => item.type && [PicType.BackgroundGif].includes(item.type),
|
||||
);
|
||||
const backgroundStaticList = tasks.filter(
|
||||
item => item.type && [PicType.BackgroundStatic].includes(item.type),
|
||||
);
|
||||
const imageDotStatus = getDotStatus(
|
||||
data,
|
||||
PicType.BackgroundStatic,
|
||||
) as DotStatus;
|
||||
const gifDotStatus = getDotStatus(data, PicType.BackgroundGif) as DotStatus;
|
||||
|
||||
// 动图相关state
|
||||
state.gif.loading = backgroundGifList.some(
|
||||
item => item.status === GenPicStatus.Generating,
|
||||
);
|
||||
state.gif.text =
|
||||
backgroundGifList.find(item => item?.img_info?.prompt)?.img_info?.prompt
|
||||
?.ori_prompt ?? '';
|
||||
|
||||
state.gif.dotStatus = gifDotStatus;
|
||||
const image = backgroundGifList.find(item => item.img_info?.ori_url);
|
||||
// 第一帧信息
|
||||
if (image) {
|
||||
state.gif.image = {
|
||||
img_info: {
|
||||
tar_uri: image.img_info?.ori_uri,
|
||||
tar_url: image.img_info?.ori_url,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// 静图相关state
|
||||
state.image.loading = backgroundStaticList.some(
|
||||
item => item.status === GenPicStatus.Generating,
|
||||
);
|
||||
state.image.dotStatus = imageDotStatus;
|
||||
state.image.promptInfo =
|
||||
backgroundStaticList.find(item => item?.img_info?.prompt?.ori_prompt)
|
||||
?.img_info?.prompt ?? {};
|
||||
|
||||
const lastImageTask =
|
||||
tasks.find(item => item.type === PicType.BackgroundStatic) ?? {};
|
||||
const lastGifTask =
|
||||
tasks.find(item => item.type === PicType.BackgroundGif) ?? {};
|
||||
// 当前选中的图片: 生成成功的 展示 成功的那个图, 否则找 背景图一致的
|
||||
if (gifDotStatus === DotStatus.Success) {
|
||||
state.selectedImage = lastGifTask;
|
||||
} else if (imageDotStatus === DotStatus.Success) {
|
||||
state.selectedImage = lastImageTask;
|
||||
} else {
|
||||
// 手动上传的 找不到
|
||||
state.selectedImage =
|
||||
tasks.find(item => item.img_info?.tar_uri === uri) ?? {};
|
||||
}
|
||||
// 当前tab:只有在 仅gif在状态不为done时 在gif tab
|
||||
if (gifDotStatus !== DotStatus.None) {
|
||||
state.activeKey = GenerateType.Gif;
|
||||
}
|
||||
// 当前正在生成的taskId
|
||||
if (
|
||||
gifDotStatus === DotStatus.Generating ||
|
||||
imageDotStatus === DotStatus.Generating
|
||||
) {
|
||||
state.generatingTaskId =
|
||||
gifDotStatus === DotStatus.Generating
|
||||
? lastGifTask?.id
|
||||
: lastImageTask?.id;
|
||||
}
|
||||
};
|
||||
|
||||
export const getInitAvatarInfo = (
|
||||
data: GetPicTaskData,
|
||||
state: GenerateAvatarModal,
|
||||
) => {
|
||||
const { tasks = [] } = data || {};
|
||||
const lastImageTask = tasks.find(
|
||||
item => item.type === PicType.IconStatic,
|
||||
) || {
|
||||
id: '',
|
||||
img_info: {},
|
||||
};
|
||||
const lastGifTask = tasks.find(item => item.type === PicType.IconGif) || {
|
||||
id: '',
|
||||
img_info: {},
|
||||
};
|
||||
const gifDotStatus = getDotStatus(data, PicType.IconGif) as DotStatus;
|
||||
const imageDotStatus = getDotStatus(data, PicType.IconStatic) as DotStatus;
|
||||
if (
|
||||
gifDotStatus === DotStatus.Success ||
|
||||
imageDotStatus === DotStatus.Success
|
||||
) {
|
||||
state.selectedImage =
|
||||
gifDotStatus === DotStatus.Success ? lastGifTask : lastImageTask;
|
||||
}
|
||||
|
||||
if (
|
||||
gifDotStatus === DotStatus.Generating ||
|
||||
imageDotStatus === DotStatus.Generating
|
||||
) {
|
||||
state.generatingTaskId =
|
||||
gifDotStatus === DotStatus.Generating
|
||||
? lastGifTask?.id
|
||||
: lastImageTask?.id;
|
||||
}
|
||||
state.gif = {
|
||||
dotStatus: gifDotStatus,
|
||||
text: lastGifTask?.img_info?.prompt?.ori_prompt ?? '',
|
||||
loading: gifDotStatus === DotStatus.Generating,
|
||||
image: {
|
||||
id: lastGifTask.img_info?.ori_uri ?? '',
|
||||
img_info: {
|
||||
tar_uri: lastGifTask.img_info?.ori_uri ?? '',
|
||||
tar_url: lastGifTask.img_info?.ori_url ?? '',
|
||||
},
|
||||
},
|
||||
};
|
||||
state.image = {
|
||||
dotStatus: imageDotStatus,
|
||||
text: lastImageTask.img_info?.prompt?.ori_prompt ?? '',
|
||||
loading: imageDotStatus === DotStatus.Generating,
|
||||
textCustomizable: Boolean(lastImageTask.img_info?.prompt?.ori_prompt),
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
type PicType,
|
||||
type GetPicTaskData,
|
||||
} from '@coze-arch/idl/playground_api';
|
||||
|
||||
import { DotStatus } from '../types/generate-image';
|
||||
|
||||
function getDotStatus(data: GetPicTaskData, picType: PicType) {
|
||||
const { notices = [], tasks = [] } = data || {};
|
||||
const task = tasks.find(item => item.type === picType);
|
||||
return (task?.status as number) === DotStatus.Generating ||
|
||||
notices.some(item => item.type === picType && item.un_read)
|
||||
? task?.status ?? DotStatus.None
|
||||
: DotStatus.None;
|
||||
}
|
||||
|
||||
export default getDotStatus;
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { usePageRuntimeStore } from '../store/page-runtime';
|
||||
import { useCollaborationStore, EditLockStatus } from '../store/collaboration';
|
||||
|
||||
/**
|
||||
* 非响应式;参考 useBotDetailIsReadonly 方法
|
||||
*/
|
||||
export function getBotDetailIsReadonly() {
|
||||
const pageRuntime = usePageRuntimeStore.getState();
|
||||
const collaboration = useCollaborationStore.getState();
|
||||
return getBotDetailIsReadonlyByState({
|
||||
editable: pageRuntime.editable,
|
||||
isPreview: pageRuntime.isPreview,
|
||||
editLockStatus: collaboration.editLockStatus,
|
||||
});
|
||||
}
|
||||
|
||||
export const getBotDetailIsReadonlyByState = ({
|
||||
editable,
|
||||
isPreview,
|
||||
editLockStatus,
|
||||
}: {
|
||||
editable: boolean;
|
||||
isPreview: boolean;
|
||||
editLockStatus?: EditLockStatus;
|
||||
}) => !editable || isPreview || editLockStatus === EditLockStatus.Lose;
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Toast } from '@coze-arch/bot-semi';
|
||||
import { MultiAgentSessionType } from '@coze-arch/bot-api/playground_api';
|
||||
|
||||
import { useMultiAgentStore } from '../store/multi-agent';
|
||||
import { useManuallySwitchAgentStore } from '../store/manually-switch-agent-store';
|
||||
import { saveDeleteAgents } from '../save-manager/manual-save/multi-agent';
|
||||
import { findTargetAgentIndex } from './find-agent';
|
||||
|
||||
/**
|
||||
* FG全量后,默认用结构化的新接口
|
||||
*/
|
||||
export const deleteAgent = async (agentId?: string) => {
|
||||
if (!agentId) {
|
||||
return;
|
||||
}
|
||||
await saveDeleteAgents(agentId);
|
||||
useMultiAgentStore.getState().setMultiAgentByImmer(multiAgent => {
|
||||
const { agents } = multiAgent;
|
||||
// 找到要删除的位置
|
||||
const targetAgentIndex = findTargetAgentIndex(agents, agentId);
|
||||
if (targetAgentIndex < 0) {
|
||||
Toast.error(I18n.t('chatflow_error_delete_failed'));
|
||||
return;
|
||||
}
|
||||
// 删除当前的agent
|
||||
agents.splice(targetAgentIndex, 1);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 用户手动切换 chatting 节点
|
||||
*
|
||||
* host 模式下会一并切换 host 节点
|
||||
*/
|
||||
export const manuallySwitchAgent = (agentID: string) => {
|
||||
const { setMultiAgentByImmer } = useMultiAgentStore.getState();
|
||||
useManuallySwitchAgentStore
|
||||
.getState()
|
||||
.recordAgentIdOnManuallySwitchAgent(agentID);
|
||||
setMultiAgentByImmer(multiAgent => {
|
||||
multiAgent.currentAgentID = agentID;
|
||||
if (multiAgent.chatModeConfig.type === MultiAgentSessionType.Host) {
|
||||
multiAgent.chatModeConfig.currentHostId = agentID;
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type Branch, type Committer } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import { useCollaborationStore } from '../store/collaboration';
|
||||
|
||||
interface HeaderStatusType {
|
||||
branch?: Branch;
|
||||
same_with_online?: boolean;
|
||||
committer?: Committer;
|
||||
commit_version?: string;
|
||||
}
|
||||
|
||||
export function updateHeaderStatus(props: HeaderStatusType) {
|
||||
const { setCollaborationByImmer } = useCollaborationStore.getState();
|
||||
setCollaborationByImmer(store => {
|
||||
store.sameWithOnline = props.same_with_online ?? false;
|
||||
if (props.committer) {
|
||||
store.commit_time = props.committer.commit_time ?? '';
|
||||
store.committer_name = props.committer.name ?? '';
|
||||
}
|
||||
if (props.commit_version) {
|
||||
store.commit_version = props.commit_version;
|
||||
store.baseVersion = props.commit_version;
|
||||
}
|
||||
if (props.branch) {
|
||||
store.branch = props.branch;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { omit } from 'lodash-es';
|
||||
import type { PluginApi } from '@coze-arch/bot-api/playground_api';
|
||||
|
||||
import { type EnabledPluginApi } from '../types/skill';
|
||||
|
||||
// 过滤 debug_example 字段 以免超出模型解析长度
|
||||
export const getPluginApisFilterExample = (
|
||||
pluginApis: PluginApi[],
|
||||
): EnabledPluginApi[] => pluginApis.map(item => omit(item, 'debug_example'));
|
||||
|
||||
export const getSinglePluginApiFilterExample = (
|
||||
tool: PluginApi,
|
||||
): EnabledPluginApi => omit(tool, 'debug_example');
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { PromptType } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
export function replacedBotPrompt(data) {
|
||||
return [
|
||||
{
|
||||
prompt_type: PromptType.SYSTEM,
|
||||
data: data.data,
|
||||
record_id: data.record_id,
|
||||
},
|
||||
{
|
||||
prompt_type: PromptType.USERPREFIX,
|
||||
data: '',
|
||||
},
|
||||
{
|
||||
prompt_type: PromptType.USERSUFFIX,
|
||||
data: '',
|
||||
},
|
||||
];
|
||||
}
|
||||
42
frontend/packages/studio/stores/bot-detail/src/utils/save.ts
Normal file
42
frontend/packages/studio/stores/bot-detail/src/utils/save.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type BotPrompt, PromptType } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import { usePersonaStore } from '../store/persona';
|
||||
|
||||
export interface SaveBotPrompt extends BotPrompt {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export const getReplacedBotPrompt = () => {
|
||||
const { systemMessage } = usePersonaStore.getState();
|
||||
|
||||
return [
|
||||
{
|
||||
prompt_type: PromptType.SYSTEM,
|
||||
data: systemMessage.data,
|
||||
},
|
||||
{
|
||||
prompt_type: PromptType.USERPREFIX,
|
||||
data: '',
|
||||
},
|
||||
{
|
||||
prompt_type: PromptType.USERSUFFIX,
|
||||
data: '',
|
||||
},
|
||||
];
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type create } from 'zustand';
|
||||
|
||||
export interface SetterAction<T> {
|
||||
/**
|
||||
* 增量更新
|
||||
*
|
||||
* @example
|
||||
* // store.x: { a: 1, b: 2 }
|
||||
* setX({a: 2});
|
||||
* // store.x: { a: 2, b: 2 }
|
||||
*/
|
||||
(state: Partial<T>): void;
|
||||
/**
|
||||
* 全量更新
|
||||
*
|
||||
* @example
|
||||
* // store.x: { a: 1, b: 2 }
|
||||
* setX({a: 2}, { replace: true });
|
||||
* // store.x: { a: 2 }
|
||||
*/
|
||||
(state: T, config: { replace: true }): void;
|
||||
}
|
||||
|
||||
export function setterActionFactory<T>(
|
||||
set: Parameters<Parameters<typeof create<T, []>>[0]>[0],
|
||||
): SetterAction<T> {
|
||||
return (state: Partial<T>, config?: { replace: true }) => {
|
||||
if (config?.replace) {
|
||||
set(state);
|
||||
} else {
|
||||
set(prevState => ({ ...prevState, ...state }));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useCollaborationStore } from '../store/collaboration';
|
||||
|
||||
export function createStorage<T extends object>(
|
||||
s: Storage,
|
||||
target: T,
|
||||
prefix = 'common_storage',
|
||||
) {
|
||||
return new Proxy(target, {
|
||||
set: (_, prop: string, value) => {
|
||||
if (typeof value === 'string') {
|
||||
s.setItem(`${prefix}.${prop}`, value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
get: (_, prop: string) => s.getItem(`${prefix}.${prop}`) ?? undefined,
|
||||
deleteProperty: (_, prop): boolean => {
|
||||
if (typeof prop === 'string') {
|
||||
s.removeItem(`${prefix}.${prop}`);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
export const storageLocal = createStorage<Record<string, string | undefined>>(
|
||||
localStorage,
|
||||
{},
|
||||
);
|
||||
|
||||
// NOTICE: 定制逻辑: baseVersion转从 bot_detail_store中获取
|
||||
export const storage = new Proxy(storageLocal, {
|
||||
get: (target, prop: string, receiver) => {
|
||||
if (prop === 'baseVersion') {
|
||||
return useCollaborationStore.getState().getBaseVersion();
|
||||
}
|
||||
return Reflect.get(target, prop, receiver);
|
||||
},
|
||||
set(target, prop, ...rest) {
|
||||
if (prop === 'baseVersion') {
|
||||
console.error(
|
||||
'you should use botDetailStore instead of storage to keep base_commit_version',
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return Reflect.set(target, prop, ...rest);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { UIToast } from '@coze-arch/bot-semi';
|
||||
|
||||
export const hasBraces = (str: string) => {
|
||||
const pattern = /{{/g;
|
||||
return pattern.test(str);
|
||||
};
|
||||
// 判断是所有环境还是 只是release 环境限制{{}} 并弹出toast提示
|
||||
export const verifyBracesAndToast = (str: string, isAll = false) => {
|
||||
if (isAll && hasBraces(str)) {
|
||||
UIToast.warning({
|
||||
showClose: false,
|
||||
content: I18n.t('bot_prompt_bracket_error'),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type VariableItem, VariableKeyErrType } from '../types/skill';
|
||||
|
||||
export function uniqMemoryList(
|
||||
list: VariableItem[],
|
||||
sysVariables: VariableItem[] = [],
|
||||
) {
|
||||
return list.map(i => {
|
||||
const res = { ...i };
|
||||
if (
|
||||
list.filter(j => j.key === i.key).length === 1 &&
|
||||
sysVariables.filter(v => v.key === i.key)?.length === 0
|
||||
) {
|
||||
res.errType = VariableKeyErrType.KEY_CHECK_PASS;
|
||||
} else {
|
||||
res.errType = VariableKeyErrType.KEY_NAME_USED;
|
||||
}
|
||||
if (!i.key) {
|
||||
res.errType = VariableKeyErrType.KEY_IS_NULL;
|
||||
}
|
||||
return res;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user