chore: replace all cn comments of fe to en version by volc api (#320)

This commit is contained in:
tecvan
2025-07-31 10:32:15 +08:00
committed by GitHub
parent 716ec0cba8
commit 71f6245a01
2960 changed files with 15545 additions and 15545 deletions

View File

@@ -20,7 +20,7 @@ import classNames from 'classnames';
import s from './index.module.less';
// TODO 后续迭代扩展时props可细化
// Props can be refined when subsequent iterations of TODO are expanded
interface ActionBarHoverContainerProps {
style?: React.CSSProperties;
}

View File

@@ -47,16 +47,16 @@ export const CopyTextMessage: React.FC<
const [isCopySuccessful, setIsCopySuccessful] = useState<boolean>(false);
const trigger = useTooltipTrigger('hover');
// 单位s
// Unit s
const COUNT_DOWN_TIME = 3;
// 单位s转化为ms的倍数
// The unit's is converted to a multiple of ms
const TIMES = 1000;
const handleCopy = () => {
const resp = copy(content);
if (resp) {
// 复制成功
// Copy successful
setIsCopySuccessful(true);
setTimeout(() => setIsCopySuccessful(false), COUNT_DOWN_TIME * TIMES);
Toast.success({
@@ -68,7 +68,7 @@ export const CopyTextMessage: React.FC<
eventName: ReportEventNames.CopyTextMessage,
});
} else {
// 复制失败
// Copy failed
Toast.warning({
content: I18n.t('copy_failed'),
showClose: false,

View File

@@ -58,7 +58,7 @@ export const DeleteMessage: React.FC<PropsWithChildren<DeleteMessageProps>> = ({
/>
}
onClick={() => {
// 通过 groupId 索引即可
// Just index through groupId.
deleteMessageGroup(groupId);
}}
color="secondary"

View File

@@ -57,7 +57,7 @@ export interface FrownUponUIProps extends FrownUponProps {
isMobile: boolean;
}
// 点踩按钮
// Click the button
export const FrownUpon: React.FC<PropsWithChildren<FrownUponProps>> = ({
onClick,
isFrownUponPanelVisible,
@@ -81,7 +81,7 @@ export const FrownUpon: React.FC<PropsWithChildren<FrownUponProps>> = ({
: [MessageFeedbackDetailType.UnlikeDefault],
},
}).then(() => {
// 接口调用后再切换展示状态
// Switch the display state after the interface is called.
onClick?.();
});
};
@@ -108,7 +108,7 @@ export const FrownUponUI: React.FC<FrownUponUIProps> = ({
}) => {
const toolTipWrapperRef = useRef<HTMLDivElement>(null);
const isHovering = useHover(toolTipWrapperRef);
// 解决点踩填写原因面板展开收起过程中点踩按钮的tooltip展示错乱问题
// Solve the problem that the tooltip display of the click button is disordered during the process of clicking and filling in the reason panel.
useDispatchMouseLeave(toolTipWrapperRef, isFrownUponPanelVisible);
return (
<div style={{ position: 'relative' }} ref={toolTipWrapperRef}>
@@ -172,7 +172,7 @@ export interface FrownUponPanelUIProps {
wrapReasons: boolean | undefined;
style?: CSSProperties;
}
// 点踩填写原因面板
// Click to fill in the reason panel
export const FrownUponPanel: React.FC<
PropsWithChildren<FrownUponPanelProps>
> = ({ containerStyle, onCancel, onSubmit, wrapReasons }) => {
@@ -191,7 +191,7 @@ export const FrownUponPanel: React.FC<
: undefined,
},
}).then(() => {
// 接口调用后再切换展示状态
// Switch the display state after the interface is called.
onSubmit?.();
});
};

View File

@@ -43,7 +43,7 @@ export const MoreOperations: React.FC<MoreOperationsProps> = ({
disabled={isDeleteMessageLock}
icon={<IconCozTrashCan className="coz-fg-hglt-red" />}
onClick={() => {
// 通过 groupId 索引即可
// Just index through groupId.
deleteMessageGroup(groupId);
}}
type="danger"

View File

@@ -61,13 +61,13 @@ export const QuoteMessage: React.FC<
};
/**
* 哥哥们改动这里要小心一点喔,QuoteMessageImpl的前置依赖项是 message-grab
* Brothers, be careful with changes here. The pre-dependency of QuoteMessageImpl is message-grab.
*/
export const QuoteMessageImpl: React.FC<
PropsWithChildren<QuoteMessageProps>
> = ({ className, ...props }) => {
// INFO: 这里使用 as 是因为明确的知道 父组件提前尝试取 plugin 并且提前拦截的情况
// 后续如果有改动,请务必注意这里
// INFO: As is used here because it is clear that the parent component tries to fetch the plugin in advance and intercepts it in advance
// If there are any changes in the future, please be sure to pay attention here.
const plugin = useQuotePlugin() as WriteableChatAreaPlugin<
GrabPluginBizContext,
unknown

View File

@@ -65,7 +65,7 @@ export const ThumbsUp: React.FC<ThumbsUpProps> = ({
: MessageFeedbackType.Like,
},
}).then(() => {
// 接口调用后再切换展示状态
// Switch the display state after the interface is called.
onClick?.();
});
};

View File

@@ -17,10 +17,10 @@
import { type RefObject, useEffect } from 'react';
/**
* 点击赞、踩按钮,可以关闭打开原因填写面板
* 填写面板关闭的时候, 会造成一次 Reflow。此时赞、踩按钮的位置会发生变化 鼠标已经不在按钮上,但是对应按钮元素不会处罚 mouseleave 事件
* 由于不触发 mouseleave 造成按钮上的 tooltip 不消失、错位等问题
* 所以需要在面板 visible 变化时 patch 一个 mouseleave 事件
* Click the like and step on the button to close the reason for opening and fill in the panel.
* When the fill panel is closed, a Reflow will be caused. At this time, the position of the like and step buttons will change, and the mouse is no longer on the button, but the corresponding button element will not penalize the mouseleave event.
* Because the mouseleave is not triggered, the tooltip on the button does not disappear, misplaced, etc.
* So you need to patch a mouseleave event when the panel changes visible
*/
export const useDispatchMouseLeave = (
ref: RefObject<HTMLDivElement>,

View File

@@ -30,7 +30,7 @@ import { ReportEventNames } from '../report-events';
import { useReportMessageFeedbackFn } from '../context/report-message-feedback';
/**
* @description 消息点赞/点踩
* @description Message Like/Click
*/
export const useReportMessageFeedback = () => {
const { reporter } = useChatArea();
@@ -64,19 +64,19 @@ export const useReportMessageFeedback = () => {
};
/**
* @description 获取 点赞按钮组件/点踩按钮组件/点踩原因填写面板组件 props
* @description Get, like button component/click button component/click button reason Fill in the panel component props
*/
export const useReportMessageFeedbackHelpers = () => {
// 点赞成功标识
// Like success logo
const [isThumbsUpSuccessful, { toggle: toogleIsThumbsUpSuccessful }] =
useToggle<boolean>(false);
// 点踩成功标识
// Click on the success sign
const [isFrownUponSuccessful, { toggle: toogleIsFrownUponSuccessful }] =
useToggle<boolean>(false);
// 点踩原因填写面板展示
// Click on the reason to fill in the panel display
const [
isFrownUponPanelVisible,
{
@@ -85,20 +85,20 @@ export const useReportMessageFeedbackHelpers = () => {
},
] = useToggle<boolean>(false);
// 点赞按钮组件onClick事件
// Like button component onClick event
const thumbsUpOnClick = () => {
toogleIsThumbsUpSuccessful();
// 点赞/点踩互斥
// Like/click on mutual exclusion
if (!isThumbsUpSuccessful && isFrownUponSuccessful) {
toogleIsFrownUponSuccessful();
setIsFrownUponPanelVisibleFalse();
}
};
// 点踩按钮组件onClick事件
// Click button component onClick event
const frownUponOnClick = () => {
toogleIsFrownUponSuccessful();
// 点赞/点踩互斥
// Like/click on mutual exclusion
if (!isFrownUponSuccessful && isThumbsUpSuccessful) {
toogleIsThumbsUpSuccessful();
}
@@ -110,15 +110,15 @@ export const useReportMessageFeedbackHelpers = () => {
}
};
// 点踩原因填写面板组件onCancel事件
// Click on the reason to fill in the panel component onCancel event
const frownUponPanelonCancel = () => {
setIsFrownUponPanelVisibleFalse();
};
// 点踩原因填写面板组件onSubmit事件
// Click on the reason to fill in the panel component onSubmit event
const frownUponPanelonSubmit = () => {
setIsFrownUponPanelVisibleFalse();
// 点赞/点踩互斥
// Like/click on mutual exclusion
if (isThumbsUpSuccessful) {
toogleIsThumbsUpSuccessful();
}

View File

@@ -15,10 +15,10 @@
*/
export enum ReportEventNames {
/** 原名: chat_area_tts_voice_ws */
/** Original name: chat_area_tts_voice_ws */
TtsVoiceWs = 'chat_answer_action_start_TTS',
/** 原名: chat_area_report_message */
/** Original name: chat_area_report_message */
ReportMessage = 'chat_answer_action_message_feedback',
/** 原名: chat_area_copy_text_message */
/** Original name: chat_area_copy_text_message */
CopyTextMessage = 'chat_answer_action_copy_text_message',
}

View File

@@ -30,13 +30,13 @@ export const getShowFeedback = ({
>;
latestSectionId: string;
}): boolean => {
// 是否是推送的消息
// Is it a pushed message?
const isPushedMessage = getIsPushedMessage(message);
if (isPushedMessage) {
return false;
}
// 来自最后一个消息组的 final answer
// The final answer from the last message group
return (
meta.isGroupLastAnswerMessage &&
meta.isFromLatestGroup &&

View File

@@ -28,12 +28,12 @@ export const getShowRegenerate = ({
meta: Pick<MessageMeta, 'isFromLatestGroup' | 'sectionId'>;
latestSectionId: string;
}): boolean => {
// 是否是推送的消息
// Is it a pushed message?
const isPushedMessage = getIsPushedMessage(message);
if (isPushedMessage) {
return false;
}
// 来自最后一个消息组
// From the last message group
return getIsLastGroup({ meta, latestSectionId });
};

View File

@@ -39,7 +39,7 @@ export const BizMessageInnerAddonBottom: FC<IProps> = memo(
return () => {
ref.current = p.message.reasoning_content;
};
// content 用来触发 reasoning rerender
// Content used to trigger reasoning rerender
}, [p.message.reasoning_content, p.message.content]);
return p.message.role === 'assistant' && p.message.reasoning_content ? (

View File

@@ -19,16 +19,16 @@ import { type PluginRegistryEntry } from '@coze-common/chat-area';
import { type PluginBizContext } from './types/biz-context';
import { BizPlugin } from './plugin';
// eslint-disable-next-line @typescript-eslint/naming-convention -- 插件命名大写开头符合预期
// eslint-disable-next-line @typescript-eslint/naming-convention -- Plugin names start with uppercase as expected
export const ReasoningPluginRegistry: PluginRegistryEntry<PluginBizContext> = {
/**
* 贯穿插件生命周期、组件的上下文
* Context of components throughout the plug-in lifecycle
*/
createPluginBizContext() {
return {};
},
/**
* 插件本体
* plug-in ontology
*/
Plugin: BizPlugin,
};

View File

@@ -28,19 +28,19 @@ import { BizMessageInnerAddonBottom } from './custom-components/message-inner-ad
export class BizPlugin extends ReadonlyChatAreaPlugin<PluginBizContext> {
/**
* 插件类型
* PluginMode.Readonly = 只读模式
* PluginMode.Writeable = 可写模式
* plugin type
* PluginMode. Readonly = read-only mode
* PluginMode. Writeable = Writable Mode
*/
public pluginMode = PluginMode.Readonly;
/**
* 插件名称
* 请点 PluginName 里面去定义
* plugin name
* Please click PluginName to define it.
*/
public pluginName = PluginName.Demo;
/**
* 生命周期服务
* lifecycle services
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public lifeCycleServices: any = createReadonlyLifeCycleServices(
@@ -49,7 +49,7 @@ export class BizPlugin extends ReadonlyChatAreaPlugin<PluginBizContext> {
);
/**
* 自定义组件
* custom component
*/
public customComponents = createCustomComponents({
TextMessageInnerTopSlot: BizMessageInnerAddonBottom,

View File

@@ -161,8 +161,8 @@ const testUserMessage: TextMessage = {
plugin: '',
execute_display_name: '',
},
/** 正常、打断状态 拉消息列表时使用chat运行时没有这个字段 */
/** 打断位置 */
/** Normal, interrupted state, used when pulling the message list, this field is not available when chat is running. */
/** interrupt position */
broken_pos: 9999999,
sender_id: '',
mention_list: [],
@@ -225,8 +225,8 @@ const randomTestMessageList: Message<ContentType>[] = Mock.mock({
tool_name: '@string',
plugin: '@string',
},
/** 正常、打断状态 拉消息列表时使用chat运行时没有这个字段 */
/** 打断位置 */
/** Normal, interrupted state, used when pulling the message list, this field is not available when chat is running. */
/** interrupt position */
broken_pos: 9999999,
sender_id: '77777',
mention_list: [],

View File

@@ -42,7 +42,7 @@ vi.mock('@coze-common/chat-core', () => ({
},
}));
// 固定一下参数
// Fix the parameters
vi.mock('../../../src/constants/message', () => ({
MIN_MESSAGE_INDEX_DIFF_TO_ABORT_CURRENT: 10,
}));

View File

@@ -19,21 +19,21 @@ import { findRespondRecord, type Responding } from '../../src/store/waiting';
vi.mock('@coze-common/chat-core', () => ({
ContentType: vi.fn(),
VerboseMsgType: {
/** 跳转节点 */
/** jump node */
JUMP_TO: 'multi_agents_jump_to_agent',
/** 回溯节点 */
/** backtracking node */
BACK_WORD: 'multi_agents_backwards',
/** 长期记忆节点 */
/** long-term memory node */
LONG_TERM_MEMORY: 'time_capsule_recall',
/** finish answer*/
GENERATE_ANSWER_FINISH: 'generate_answer_finish',
/** 流式插件调用状态 */
/** Streaming plugin call status */
STREAM_PLUGIN_FINISH: 'stream_plugin_finish',
/** 知识库召回 */
/** knowledge base recall */
KNOWLEDGE_RECALL: 'knowledge_recall',
/** 中断消息:目前只用于地理位置授权 */
/** Interrupt message: Currently only used for geolocation authorization */
INTERRUPT: 'interrupt',
/** hooks调用 */
/** Hooks call */
HOOK_CALL: 'hook_call',
},
Scene: {

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { proxyFreeze } from '../../src/utils/proxy-freeze';
vi.stubGlobal('IS_DEV_MODE', true);
@@ -21,7 +21,7 @@ vi.stubGlobal('IS_DEV_MODE', true);
describe('proxyFreeze', () => {
it('should return the same object for non-objects', () => {
const nonObject = 42;
// @ts-expect-error -- 测试使用
// @ts-expect-error -- test use
expect(proxyFreeze(nonObject)).toBe(nonObject);
});

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ContentType, type Message } from '@coze-common/chat-core';
import {
@@ -28,21 +28,21 @@ import {
vi.mock('@coze-common/chat-core', () => ({
ContentType: vi.fn(),
VerboseMsgType: {
/** 跳转节点 */
/** jump node */
JUMP_TO: 'multi_agents_jump_to_agent',
/** 回溯节点 */
/** backtracking node */
BACK_WORD: 'multi_agents_backwards',
/** 长期记忆节点 */
/** long-term memory node */
LONG_TERM_MEMORY: 'time_capsule_recall',
/** finish answer*/
GENERATE_ANSWER_FINISH: 'generate_answer_finish',
/** 流式插件调用状态 */
/** Streaming plugin call status */
STREAM_PLUGIN_FINISH: 'stream_plugin_finish',
/** 知识库召回 */
/** knowledge base recall */
KNOWLEDGE_RECALL: 'knowledge_recall',
/** 中断消息:目前只用于地理位置授权 */
/** Interrupt message: Currently only used for geolocation authorization */
INTERRUPT: 'interrupt',
/** hooks调用 */
/** Hooks call */
HOOK_CALL: 'hook_call',
},
Scene: {
@@ -159,7 +159,7 @@ describe('normal text message', () => {
startSending(sentMessage);
// 检测 Sending 是否存在
// Check if Sending exists
const { sending } = useWaitingStore.getState();
@@ -171,11 +171,11 @@ describe('normal text message', () => {
startSending(sentMessage);
// 检测 Sending 是否存在
// Check if Sending exists
const { sending } = useWaitingStore.getState();
expect(sending).toStrictEqual(sentMessage);
// 清除 Sending
// Clear Sending
clearSending();
const { sending: afterClearSending } = useWaitingStore.getState();
@@ -198,7 +198,7 @@ describe('normal text message', () => {
});
it('update responding is correct', () => {
// 检测 responding 是否存在
// Detection of responding presence
const { updateResponding } = useWaitingStore.getState();
updateResponding(llmMessage);
@@ -225,7 +225,7 @@ describe('normal text message', () => {
is_finish: true,
};
// @ts-expect-error -- 单测
// @ts-expect-error -- single test
updateResponding(allFinishedMessage);
const { responding } = useWaitingStore.getState();
@@ -241,7 +241,7 @@ describe('normal text message', () => {
type: 'tool_response',
};
// @ts-expect-error -- 单测
// @ts-expect-error -- single test
updateResponding(toolResponseMessage);
const { responding } = useWaitingStore.getState();
@@ -254,7 +254,7 @@ describe('normal text message', () => {
updateResponding(llmMessage);
// 修改 reply_id 造成冲突假象
// Modifying reply_id creates the illusion of conflict
const modifiedMessage = {
...llmMessage,
reply_id: '嘤嘤嘤',
@@ -281,7 +281,7 @@ describe('normal text message', () => {
}),
};
// @ts-expect-error -- 测试
// @ts-expect-error -- test
updateResponding(verboseMessage);
const finishedMessage = {
@@ -292,7 +292,7 @@ describe('normal text message', () => {
}),
};
// @ts-expect-error -- 测试
// @ts-expect-error -- test
updateResponding(finishedMessage);
@@ -329,7 +329,7 @@ describe('normal text message', () => {
type: 'function_call',
};
// @ts-expect-error -- 测试
// @ts-expect-error -- test
updateResponding(functionCallMessage);
const respondingMessage = {
@@ -338,7 +338,7 @@ describe('normal text message', () => {
index: 2,
};
// @ts-expect-error -- 测试
// @ts-expect-error -- test
updateResponding(respondingMessage);
const { responding } = useWaitingStore.getState();
@@ -410,7 +410,7 @@ describe('normal text message', () => {
type: 'function_call',
};
// @ts-expect-error -- 测试
// @ts-expect-error -- test
updateResponding(functionCallMessage);
const respondingMessage = {
@@ -419,14 +419,14 @@ describe('normal text message', () => {
index: -1,
};
// @ts-expect-error -- 测试
// @ts-expect-error -- test
updateResponding(respondingMessage);
const { responding } = useWaitingStore.getState();
expect(responding).toStrictEqual({
replyId: llmMessage.reply_id,
// @ts-expect-error -- 测试
// @ts-expect-error -- test
response: [getResponse(functionCallMessage)],
});
});
@@ -439,7 +439,7 @@ describe('normal text message', () => {
type: 'function_call',
};
// @ts-expect-error -- 测试
// @ts-expect-error -- test
updateResponding(functionCallMessage);
const respondingMessage = {
@@ -448,14 +448,14 @@ describe('normal text message', () => {
index: 'hhhh',
};
// @ts-expect-error -- 测试
// @ts-expect-error -- test
updateResponding(respondingMessage);
const { responding } = useWaitingStore.getState();
expect(responding).toStrictEqual({
replyId: llmMessage.reply_id,
// @ts-expect-error -- 测试
// @ts-expect-error -- test
response: [getResponse(functionCallMessage)],
});
});
@@ -468,7 +468,7 @@ describe('normal text message', () => {
type: 'function_call',
};
// @ts-expect-error -- 测试
// @ts-expect-error -- test
updateResponding(functionCallMessage);
const functionCallMessage2 = {
@@ -481,7 +481,7 @@ describe('normal text message', () => {
type: 'function_call',
};
// @ts-expect-error -- 测试
// @ts-expect-error -- test
updateResponding(functionCallMessage2);
const { responding } = useWaitingStore.getState();
@@ -489,9 +489,9 @@ describe('normal text message', () => {
expect(responding).toStrictEqual({
replyId: llmMessage.reply_id,
response: [
// @ts-expect-error -- 测试
// @ts-expect-error -- test
getResponse(functionCallMessage),
// @ts-expect-error -- 测试
// @ts-expect-error -- test
getResponse(functionCallMessage2),
],
});

View File

@@ -166,7 +166,7 @@ const ChatAreaMain: FC<ChatAreaMainProps> = ({
>
<div className={styles['header-node']}>{headerNode}</div>
{customMessageListFloatSlotList.map(
// eslint-disable-next-line @typescript-eslint/naming-convention -- 符合预期
// eslint-disable-next-line @typescript-eslint/naming-convention -- as expected
({ pluginName, Component }) => (
<PluginScopeContextProvider
pluginName={pluginName}
@@ -197,7 +197,7 @@ const ChatAreaMain: FC<ChatAreaMainProps> = ({
<DragUploadArea />
</div>
{customComponentList.map(
// eslint-disable-next-line @typescript-eslint/naming-convention -- 符合预期
// eslint-disable-next-line @typescript-eslint/naming-convention -- as expected
({ pluginName, Component }, index) => (
<PluginScopeContextProvider pluginName={pluginName}>
<Component key={`${index}ScrollViewBottom`} />

View File

@@ -101,7 +101,7 @@ type OverrideProps = Omit<
export interface ChatInputProps<T extends OverrideProps> {
/**
* 传递给 Component 的 props类型为 T
* Props passed to Component of type T.
*/
componentProps?: T;
getChatInputController?: (controller: {
@@ -204,7 +204,7 @@ export const ChatInput: <T extends OverrideProps>(
sendTextMessage(payload, 'inputAndSend');
};
// TODO: 再封装一个 hook @gaoyuanhan
// TODO: encapsulate another hook @gaoyuanhan
const handleSendMultimodalMessage = (inputPayload: SendMessagePayload) => {
const fileDataList = useBatchFileUploadStore.getState().getFileDataList();
const strategy = getSendMultimodalMessageStrategy(
@@ -351,7 +351,7 @@ export const ChatInput: <T extends OverrideProps>(
{!!InputAddonTop && <InputAddonTop />}
{enableMultimodalUpload ? <BatchUploadFileList /> : null}
{customInputAddonTopList.map(
/* eslint-disable-next-line @typescript-eslint/naming-convention -- 符合预期的命名 */
/* eslint-disable-next-line @typescript-eslint/naming-convention -- matches the expected naming */
({ pluginName, Component }, index) => (
<PluginScopeContextProvider
pluginName={pluginName}

View File

@@ -88,7 +88,7 @@ export const BuildInContentBox: FC<ContentBoxProps> = props => {
return (
<>
{
// eslint-disable-next-line @typescript-eslint/naming-convention -- 符合预期的命名
// eslint-disable-next-line @typescript-eslint/naming-convention -- matches the expected naming
customContentBoxList.map(({ pluginName, Component }) => (
<PluginScopeContextProvider pluginName={pluginName}>
<Component
@@ -126,7 +126,7 @@ export const BuildInContentBox: FC<ContentBoxProps> = props => {
multimodalTextContentAddonTop={
<>
{customTextMessageInnerTopSlotList.map(
// eslint-disable-next-line @typescript-eslint/naming-convention -- 符合预期的命名
// eslint-disable-next-line @typescript-eslint/naming-convention -- matches the expected naming
({ pluginName, Component }, index) => (
<PluginScopeContextProvider
pluginName={pluginName}

View File

@@ -50,7 +50,7 @@ export const ContextDivider = ({ text }: ContextDividerProps) => {
<div
className={classNames(
styles['divider-line'],
// ui 要求分割线颜色特别处理 不使用 token
// UI requires special handling of divider color, no token is used
styles['coz-divider-line-style'],
{
'!coz-bg-images-secondary': showBackground,

View File

@@ -131,7 +131,7 @@ const getHeaderConfig = (
} = headerProps;
if (isTopLevelOfTheNestedPanel) {
const topLevelConfig = getTopLevelOfTheNestedPanelHeaderConfig(headerProps);
// 没有匹配上就用对应对话最后一个 function call unit 来渲染
// If there is no match, use the last function call unit of the corresponding dialogue to render
if (topLevelConfig) {
return topLevelConfig;
}
@@ -148,7 +148,7 @@ const getHeaderConfig = (
}
const { apiResponse, llmOutput, isFinish } = messageUnit;
// 流式插件、异步插件比较特殊,只有收到结束消息才算结束
// Streaming plugins and asynchronous plugins are special, and the end is only counted when the end message is received.
const hasResponse = apiResponse && isFinish;
const functionCallIconAndName = getFunctionCallMessageIconAndNameOptimization(
{
@@ -159,9 +159,9 @@ const getHeaderConfig = (
},
);
// response为空
// Response is empty
if (!hasResponse) {
// 历史消息对话
// Chat history
if (!isMessageFromOngoingChat) {
return {
icon: functionCallIconAndName.icon,
@@ -169,7 +169,7 @@ const getHeaderConfig = (
status: 'interrupt',
};
}
// 当前进行中的对话
// Current conversation in progress
return {
icon: <IconCozLoading className="animate-spin" />,
title: functionCallIconAndName.title,
@@ -177,7 +177,7 @@ const getHeaderConfig = (
};
}
// 正常返回逻辑
// normal return logic
return {
icon: functionCallIconAndName.icon,
title: functionCallIconAndName.title,

View File

@@ -175,7 +175,7 @@ const getVerboseContent = (llmContent: string) => {
}
switch (msg_type) {
// 回溯节点文案
// backtracking node copy
case VerboseMsgType.BACK_WORD: {
const startMode = I18n.t(
'agentflow_transfer_ conversation_settings_backtrack_start',
@@ -187,24 +187,24 @@ const getVerboseContent = (llmContent: string) => {
contentData?.restart ? startMode : previousMode
}`;
}
// 跳转节点文案
// jump node copy
case VerboseMsgType.JUMP_TO: {
return `${I18n.t('agentflow_jump_running_process_trigger_condition')}${
contentData?.condition ?? ''
}`;
}
// 长期记忆节点文案
// long-term memory node copy
case VerboseMsgType.LONG_TERM_MEMORY: {
return contentData?.wraped_text ?? '';
}
//默认直接展示json
//Default direct display json
default: {
return llmContent;
}
}
};
// hook_call类型
// hook_call type
const renderHooksMessage = (messageUnit: FunctionCallMessageUnit) => {
const reportError = (error: Error) => {
reporter.error({

View File

@@ -46,11 +46,11 @@ import { KNOWLEDGE_OPEN_SEARCH_ERROR } from './knowledge-recall';
import s from './index.module.less';
// 失败状态
// failure state
const FAILED = '1';
/**
* coze home插件展示,这里保留为兜底逻辑
* Coze home plugin display, keep it as fallback logic here
*/
const specialPluginNameMap = {
'ts-bot_creator-bot_creator': {
@@ -94,7 +94,7 @@ export const HeaderTitleText: React.FC<
</>
);
// Bot调试区调用插件兜底逻辑(原逻辑)
// Bot debugging area calls plugin fallback logic (original logic)
const getFunctionCallMessageIconAndName: (props: {
content: string;
ext: MessageExt;
@@ -134,7 +134,7 @@ const getFunctionCallMessageIconAndName: (props: {
};
}
// coze home相关提示
// Coze home related tips
const specialPluginNameText = getPluginNameText(name);
const prefix = isLoading ? I18n.t('Using') : I18n.t('Used');
@@ -157,7 +157,7 @@ const getFunctionCallMessageIconAndName: (props: {
};
};
// Bot调试区调用插件提示优化
// Bot debugging area call plug-in prompt optimization
export const getFunctionCallMessageIconAndNameOptimization: (props: {
content: string;
ext: MessageExt;
@@ -172,7 +172,7 @@ export const getFunctionCallMessageIconAndNameOptimization: (props: {
ext?.execute_display_name || '',
null,
);
// 只有等于1的时候是失败0或者空字符串的时候都是成功
// It only fails when it is equal to 1, and succeeds when it is 0 or empty string.
const message = resExt
? resExt.plugin_status === FAILED
? executeDisplayName?.value?.name_execute_failed
@@ -180,8 +180,8 @@ export const getFunctionCallMessageIconAndNameOptimization: (props: {
: executeDisplayName?.value?.name_executing;
if (!message) {
// 兜底走原逻辑
// TODO: 兜底逻辑处理和@徐雯沟通完后续放到服务端处理 --@李慧文
// Go through the original logic
// TODO: fallback logic processing After communicating with @Xu Wen, it will be processed at the server level -- @Li Huiwen
return getFunctionCallMessageIconAndName({
content,
ext,
@@ -194,7 +194,7 @@ export const getFunctionCallMessageIconAndNameOptimization: (props: {
title: <HeaderTitleText>{message}</HeaderTitleText>,
};
} catch {
// 兜底走原逻辑
// Go through the original logic
return getFunctionCallMessageIconAndName({
content,
ext,
@@ -336,7 +336,7 @@ export const getVerboseMessageHeaderConfig = ({
const contentData = safeJSONParse(content.data);
if (isVerboseContentData(contentData)) {
/** 长期记忆 */
/** long-term memory */
if (content?.msg_type === VerboseMsgType.LONG_TERM_MEMORY) {
if (
isLatestFunctionCallOfRelatedChat &&
@@ -359,7 +359,7 @@ export const getVerboseMessageHeaderConfig = ({
};
}
/** 跳转、回溯,无loading */
/** Jump, backtrack, no loading */
return {
icon: <IconCozJump />,
title: (
@@ -374,7 +374,7 @@ export const getVerboseMessageHeaderConfig = ({
}
}
/** 兜底 */
/** bottom line */
return {
icon: <IconCozJump />,
title: '',

View File

@@ -103,7 +103,7 @@
width: 100%;
min-height: 32px;
/** 高度限制 */
/** height limit */
max-height: 272px;
padding: 6px 12px;

View File

@@ -102,7 +102,7 @@ export const FunctionCallMessagesCollapse: React.FC<
const content = safeJSONParse(cur.llmOutput.content);
if (isVerboseContent(content)) {
/** 跳转和长期记忆分别统计耗时 */
/** Time-consuming for jump and long-term memory statistics */
if (content.msg_type === VerboseMsgType.LONG_TERM_MEMORY) {
prev.longTerm += time;
} else {

View File

@@ -23,7 +23,7 @@ import { type KnowledgeRecallSlice } from '../../../../store/types';
const getRecallEmptyText = () => I18n.t('recall_knowledge_no_related_slices');
// 云搜索鉴权失败的错误代码
// BigInt with failed cloud search authentication
export const KNOWLEDGE_OPEN_SEARCH_ERROR = 708882003;
const getMessageWithStatusCode = (statusCode?: number) => {

View File

@@ -81,10 +81,10 @@ const FunctionCallMessageBoxImpl: ComponentTypesMap['functionCallMessageBox'] =
return !getIsVisibleMessageMeta(meta, configs);
});
// footer位置的answer actions所需要props通过useMessageBoxContext透传
// Answer actions for footer location, required props pass through useMessageBoxContext
const ActionBarFooter = MessageBoxActionBarFooter;
// hover才展示的answer actions所需要props通过useMessageBoxContext透传
// Hover just show the answer actions, the required props pass through useMessageBoxContext
const ActionBarHoverContent = MessageBoxActionBarHoverContent;
if (!messageUnitList.length || isInvisible) {
@@ -133,7 +133,7 @@ export const FunctionCallMessageBox: React.FC<{
Boolean(state.responding?.replyId === messageGroup.groupId),
);
// 收到final answer
// Received final answer
const isRelatedChatComplete = useIsGroupAnswerFinish(messageGroup);
const isFakeInterruptAnswer = useIsGroupFakeInterruptAnswer(messageGroup);

View File

@@ -53,7 +53,7 @@ export const LoadMore = ({
const spinRef = useRef<HTMLSpanElement>(null);
const [inViewport] = useInViewport(() => spinRef.current);
// 防止连续触发两次请求loading 变化早于 IconSpin 组件显隐变化)
// Prevent two consecutive requests from being triggered (loading changes earlier than explicit changes in the IconSpin component)
const deferredLoading = useDeferredValue(loading);
useEffect(() => {

View File

@@ -45,7 +45,7 @@ export const Actions = ({ message }: { message: Message }) => {
},
},
];
// TODO: Trigger类型适配
// TODO: Trigger type adaptation
return (
<div className={styles.actions}>
{menuConfigs.map((prop, idx) => (

View File

@@ -42,9 +42,9 @@ import { RevealTrigger } from './reveal-trigger';
import styles from './index.module.less';
// TODO: 在这里区分 用户的消息和模型的消息组件
// TODO: Here, distinguish between the user's message and the model's message component
// eslint-disable-next-line @coze-arch/max-line-per-function -- TODO 后期拆分一下
// eslint-disable-next-line @coze-arch/max-line-per-function -- TODO will split it later.
export const MessageBox: React.FC = memo(() => {
const { configs, reporter } = useChatAreaContext();
@@ -113,10 +113,10 @@ export const MessageBox: React.FC = memo(() => {
const ReceiveMessageBox = receiveMessageBox ?? BuildInReceiveMessageBox;
const SendMessageBox = sendMessageBox ?? BuildInSendMessageBox;
// footer位置的answer actions所需要props通过useMessageBoxContext透传
// Answer actions for footer location, required props pass through useMessageBoxContext
const ActionBarFooter = MessageBoxActionBarFooter;
// hover才展示的answer actions所需要props通过useMessageBoxContext透传
// Hover just show the answer actions, the required props pass through useMessageBoxContext
const ActionBarHoverContent = MessageBoxActionBarHoverContent;
const MessageBoxUI = isSendMessage ? SendMessageBox : ReceiveMessageBox;
@@ -124,25 +124,25 @@ export const MessageBox: React.FC = memo(() => {
const { imageAutoSizeContainerWidth, enableImageAutoSize } =
useUIKitMessageImageAutoSizeConfig();
// 老机制的自定义ContentBox
// Custom ContentBox for the old mechanism
const UsedContentBox = ContentBox ?? BuildInContentBox;
// Render调用生命周期用于判断是否需要使用业务组件进行渲染 - 与插件化做结合
// The Render call life cycle is used to determine whether business components need to be used for rendering - in combination with plug-ins
const { MessageBox: DynamicCustomMessageBox } =
lifeCycleService.render.onMessageBoxRender({ ctx: { message, meta } }) ??
{};
const staticCustomMessageBoxConfig =
usePluginCustomComponents('MessageBox').at(0); // 谁先谁来 只选一个
usePluginCustomComponents('MessageBox').at(0); // Whoever comes first, choose only one.
// 插件化机制提供的自定义MessageBox
// Custom MessageBox provided by plug-in mechanism
const StaticCustomMessageBox = staticCustomMessageBoxConfig?.Component;
// 使用的自定义MessageBox (如果有,否则返回undefined
// The custom MessageBox used (if any, otherwise return undefined)
const UsedCustomMessageBox =
DynamicCustomMessageBox ?? StaticCustomMessageBox;
// 最终使用的MessageBox
// The final used MessageBox
const UsedMessageBox = UsedCustomMessageBox ?? MessageBoxUI;
const reportError = (error: unknown) => {
@@ -217,7 +217,7 @@ export const MessageBox: React.FC = memo(() => {
{message.content_type === ContentType.Text && (
<>
{customTextMessageInnerTopComponentList?.map(
// eslint-disable-next-line @typescript-eslint/naming-convention -- 命名符合预期
// eslint-disable-next-line @typescript-eslint/naming-convention -- naming as expected
({ pluginName, Component }, index) => (
<PluginScopeContextProvider
pluginName={pluginName}
@@ -229,7 +229,7 @@ export const MessageBox: React.FC = memo(() => {
)}
</>
)}
{/* 这里是内部实现机制不准备告诉外面所以只有不存在自定义组件的时候才渲染children */}
{/* This is the internal implementation mechanism, and we are not going to tell the outside, so we only render children when there is no custom component. */}
{UsedCustomMessageBox ? null : (
<UsedContentBox
isContentLoading={isContentLoading}
@@ -247,7 +247,7 @@ export const MessageBox: React.FC = memo(() => {
)}
<div className={styles['footer-slot-style']}>
{customMessageInnerBottomComponentList?.map(
// eslint-disable-next-line @typescript-eslint/naming-convention -- 符合预期的命名
// eslint-disable-next-line @typescript-eslint/naming-convention -- matches the expected naming
({ pluginName, Component }) => (
<PluginScopeContextProvider
pluginName={pluginName}

View File

@@ -63,7 +63,7 @@ export const MessageGroupList = forwardRef<
const messageGroupIdList = useMessagesStore(
useShallow(state =>
// TODO: 这里需要考虑怎么业务接入进来,暂时先按照调试区做吧
// TODO: You need to consider how to access the business here. For the time being, let's follow the debugging area.
state.messageGroupList.map(group => group.groupId),
),
);

View File

@@ -58,7 +58,7 @@ export const MessageGroupBody: ComponentTypesMap['messageGroupBody'] = memo(
);
})}
{Boolean(functionCallMessageIdList.length) && (
// 看起来 functioncall 消息的 answer action 挑战了 MessageBoxProvider 的设计
// It seems that the functioncall answer action challenges the design of the MessageBoxProvider
<MessageBoxProvider
groupId={groupId}
messageUniqKey={functionCallMessageIdList.at(0) ?? ''}
@@ -67,7 +67,7 @@ export const MessageGroupBody: ComponentTypesMap['messageGroupBody'] = memo(
isFirstUserOrFinalAnswerMessage={false}
isLastUserOrFinalAnswerMessage={false}
>
{/* function call运行过程 */}
{/* Function call */}
<FunctionCallMessageBox
messageGroup={messageGroup}
getBotInfo={getBotInfo}

View File

@@ -125,7 +125,7 @@ export const MessageGroupWrapper: React.FC<
return findMessageById(state.metaList, userMessageId);
}, isEqual);
// TODO: 目前服务端不支持打断本地消息。不能删除正在发送中的消息。需要标志这个状态
// TODO: Current server level does not support interrupting local messages. Sending messages cannot be deleted. This status needs to be flagged
const isSendingMessage = Boolean(userMessageMeta?.isSending);
const deleteMessageGroup = useDeleteMessageGroup();

View File

@@ -135,7 +135,7 @@ export const OnboardingMessage: FC<IProps> = props => {
<CustomeUIKitMessageBox
messageType="receive"
messageId={null}
// fixme 这里没有 sender id
// Fixme no sender id here.
senderInfo={{ url: avatar, nickname: name, id: '' }}
showUserInfo={true}
theme={getOnboardingMessageBoxTheme({

View File

@@ -36,7 +36,7 @@ const getMixContent = (list: MixMessageContent['item_list']) => {
if (item.type === ContentType.Image) {
return `[${I18n.t('editor_toolbar_image')}]`;
} else if (item.type === ContentType.File) {
// TODO: jq - 如果后期支持多个的时候 可能会有问题
// TODO: jq - If multiple are supported later, there may be problems.
return item?.file?.file_name ? `[${item?.file?.file_name}]` : '';
} else if (item.type === ContentType.Text) {
return item.text;
@@ -46,12 +46,12 @@ const getMixContent = (list: MixMessageContent['item_list']) => {
return info?.join(' ');
};
// 仅对 message_type === plugin_async 的 answer 进行使用引用样式
// Use reference styles only for answers message_type === plugin_async
export const PluginAsyncQuote: FC<PluginAsyncQuoteProps> = props => {
const { message } = props;
const replyMessage = message?.reply_message;
// 只有回复的消息是文本的才添加引用
// Add citations only if the reply message is text.
if (
!(
message?.source === messageSource.AsyncResult &&
@@ -62,7 +62,7 @@ export const PluginAsyncQuote: FC<PluginAsyncQuoteProps> = props => {
return null;
}
// 引用的原始消息是 图片 或者文件 采用固定形式
// The original message quoted is a picture, or file, in a fixed form
const isImage = replyMessage?.content_type === ContentType.Image;
const isFile = replyMessage?.content_type === ContentType.File;
const isMix = replyMessage?.content_type === ContentType.Mix;

View File

@@ -39,7 +39,7 @@ export const Preview: FC<{ layout?: Layout }> = ({ layout }) => {
};
return (
<ImagePreview
// image preview 的默认 z index 比 toast 要高,调小一些
// The default z index for image preview is higher than toast and smaller
zIndex={1009}
previewCls={layout === Layout.MOBILE ? s['image-preview-mobile'] : ''}
src={previewURL}

View File

@@ -49,12 +49,12 @@ export const SendStatus: FC<SendStatusProps> = props => {
return (
<div
className={classNames(styles['message-right'], {
// 适配移动端 解决移动端loading遮盖问题
// Adapt mobile end to solve the problem of mobile end loading and covering
[styles['message-right-mobile'] as string]: layout === Layout.MOBILE,
[styles['message-right-pc'] as string]: layout === Layout.PC,
})}
>
{/* 消息发送状态 */}
{/* message sending status */}
{meta.isSending ? (
<IconSpin className={classNames(styles['icon-sending'])} spin />
) : null}

View File

@@ -34,7 +34,7 @@ import s from './index.module.less';
export const SuggestionInChat = () => {
const { useMessagesStore, useSuggestionsStore } = useChatAreaStoreSet();
const { enableMention } = usePreference();
// fixme 之前直接取最后一条消息进行处理不可靠,修改后仍存在问题,考虑 suggestion 存储时存入 sender_id
// Before fixme, it is unreliable to directly take the last message for processing, and there are still problems after modification. Consider the suggestion stored in the sender_id
const latestGroup = useMessagesStore(state => state.messageGroupList.at(0));
const senderId = useMessagesStore(
state =>
@@ -42,8 +42,8 @@ export const SuggestionInChat = () => {
latestGroup?.memberSet.llmAnswerMessageIdList.includes(msg.message_id),
)?.sender_id,
);
// 注意 notice manual trigger 类型的消息groupId 是由 message_id 拼接获得。
// 所以一定无法基于 replyId 反向索引
// Note that for notice or manual trigger type messages, groupId is obtained by message_id stitching.
// So it must not be possible to reverse index based on replyId
const replyId = latestGroup?.groupId;
const { latestSectionHasMessage } = useMessagesOverview();
const suggestionBatch = useSuggestionsStore(state =>
@@ -63,7 +63,7 @@ export const SuggestionInChat = () => {
<div
className={classNames(s['suggestion-fail-wrap'], {
[s['suggestion-fail-wrap-selectable'] as string]: selectable,
// 适配移动端 解决 suggestion error 边距问题
// Adapt mobile end to solve suggestion error margin problem
[s['suggestion-fail-wrap-mobile'] as string]:
layout === Layout.MOBILE,
[s['suggestion-fail-wrap-pc'] as string]: layout === Layout.PC,
@@ -125,7 +125,7 @@ export const Suggestions = ({
suggestions: string[];
isInNewConversation?: boolean;
/**
* 上层的 SuggestionInChat enableMention false 时不会传值
* SuggestionInChat does not pass a value when enableMention false
*/
senderId: string | undefined;
suggestionsShowMode?: SuggestedQuestionsShowMode;
@@ -147,7 +147,7 @@ export const Suggestions = ({
<div
data-testid="chat-area.suggestion-list"
className={classNames(s.suggestions, {
// 适配移动端 解决 suggestion 边距问题
// Adapt mobile end to solve the suggestion margin problem
[s['suggestion-with-selectable-in-new-conversation'] as string]:
selectable && isInNewConversation,
[s['suggestions-mobile'] as string]: layout === Layout.MOBILE,

View File

@@ -47,7 +47,7 @@ export interface MessageBoxProps {
isMessageGroupFirstMessage?: boolean;
isMessageGroupLastMessage?: boolean;
renderFooter?: (refreshContainerWidth: () => void) => React.ReactNode;
/** 鼠标悬浮时展示的组件 */
/** Components displayed while the mouse is hovering */
hoverContent?: React.ReactNode;
children?: React.ReactNode;
readonly?: boolean;
@@ -55,15 +55,15 @@ export interface MessageBoxProps {
layout: Layout;
showBackground: boolean;
/**
* 右上角插槽
* Upper right slot
*/
topRightSlot?: React.ReactNode;
/*
* 开启图片自适应大小
* Turn on the picture auto-resizing.
*/
enableImageAutoSize?: boolean;
/**
* 图片自适应大小容器宽度
* Image auto-resizing container width
*/
imageAutoSizeContainerWidth?: number;
eventCallbacks?: IEventCallbacks;
@@ -84,11 +84,11 @@ export interface ContentBoxProps {
layout: Layout;
showBackground: boolean;
/**
* 开启图片自适应大小
* Turn on the picture auto-resizing.
*/
enableImageAutoSize?: boolean;
/**
* 图片自适应大小容器宽度
* Image auto-resizing container width
*/
isCardDisabled?: boolean;
isContentLoading?: boolean;
@@ -122,22 +122,22 @@ export interface ComponentTypesMap {
functionCallMessageBox: ComponentType<{
functionCallMessageList: Message[];
/**
* message 对应的一轮对话是否结束 没被打断 final answer 有返回完毕不管 suggest
* Whether the conversation corresponding to the message is over, not interrupted, and the final answer is returned, regardless of whether it is suggested
*/
isRelatedChatComplete: boolean;
/**
* message 对应的一轮对话是否为假意打断
* Whether the conversation corresponding to the message is a false interruption
*/
isFakeInterruptAnswer: boolean;
/**
* 消息是否来自正在进行的对话根据responding.replyId判断
* Whether the message is from an ongoing conversation, as determined by respond.replyId
*/
isMessageFromOngoingChat: boolean;
getBotInfo: GetBotInfo;
}>;
messageActionBarFooter: ComponentType<{ refreshContainerWidth: () => void }>;
messageActionBarHoverContent: ComponentType;
// TODO: 组件要细化到 message_type 渲染
// TODO: Components to be refined to message_type rendering
receiveMessageBox: ComponentType<ReceiveMessageBoxProps>;
receiveMessageBoxTopRightSlot: ComponentType;
sendMessageBox: ComponentType<SendMessageBoxProps>;
@@ -164,15 +164,15 @@ export interface ComponentTypesMap {
}>;
clearContextIcon: ComponentType;
/**
* 输入框整体顶部附加物
* Text box overall top add-on
*/
inputAboveOutside: ComponentType;
/**
* 输入框内部上方附加物
* Add-on inside text box
*/
inputAddonTop: ComponentType;
/**
* 输入框内部右侧插槽
* Text box inside right slot
*/
inputRightActions?: ComponentType;
chatInputTooltip?: ComponentType;

View File

@@ -16,8 +16,8 @@
import { AgentType } from '@coze-arch/bot-api/developer_api';
// TODO: 这里为啥没i18n需要做
// 节点类型名称映射关系
// TODO: Why is there no i18n to do here?
// Node type name mapping relationship
export const agentTypeNameMap: { [key in AgentType]: string | undefined } = {
[AgentType.LLM_Agent]: 'Agent',
[AgentType.Bot_Agent]: 'Bot',

View File

@@ -29,7 +29,7 @@ export const MARK_MESSAGE_READ_DEBOUNCE_MAX_WAIT = 3000;
export const LOAD_SILENTLY_MAX_NEW_ADDED_COUNT = 6;
// 5s 内调用 get_message_list 超过 3 次,则对请求排队,排队间隔1s
// If the get_message_list is called more than 3 times in 5s, the request is queued, and the queuing interval is 1s.
export const LOAD_MORE_CALL_GET_HISTORY_LIST_TIME_WINDOW = 5000;
export const LOAD_MORE_CALL_GET_HISTORY_LIST_LIMIT = 3;
export const LOAD_MORE_CALL_GET_HISTORY_LIST_EXCEED_RATE_DELAY = 1000;
@@ -38,9 +38,9 @@ export const CURSOR_TO_LOAD_LATEST_MESSAGE = '0';
export const CURSOR_TO_LOAD_LAST_READ_MESSAGE = '-1';
export const LOAD_EAGERLY_LOAD_MESSAGE_COUNT = 20;
/** 并没有做多页同步加载的机制,因此丢弃策略数量与 eagerly 最大加载数量对齐 */
/** There is no mechanism to do multi-page simultaneous loading, so the number of discarded policies is aligned with the eagerly maximum number of loads */
export const MIN_MESSAGE_INDEX_DIFF_TO_ABORT_CURRENT =
LOAD_EAGERLY_LOAD_MESSAGE_COUNT - 1;
/** 服务端没有 reply_id 时可能给这种值 */
/** This value may be given when the server level has no reply_id */
export const SERVER_MESSAGE_REPLY_ID_PLACEHOLDER_VALUES = ['0', '-1'];

View File

@@ -16,7 +16,7 @@
export const SCROLL_VIEW_BOTTOM_DISTANCE_TO_SHOW_NEWEST_TIP = 600;
/**
* 向下加载更多时,模拟 overflow anchor 效果,但是同时稍微移动视图内容,把新增内容稍微多展示一下
* When downloading more, simulate the overflow anchor effect, but at the same time move the view content slightly to show the new content a little more
*/
export const LOAD_NEXT_ANCHOR_ADDITIONAL_MOVE_DISTANCE = 50;
export const LOAD_NEXT_LOCK_DELAY = 30;

View File

@@ -19,7 +19,7 @@ import { createContext } from 'react';
import { type MarkReadService } from '../../service/mark-read';
/**
* 不需要放到最外层 Provider 里的 service 实例提供 Context
* Context provided by a service instance that does not need to be placed in the outermost provider
*/
export interface AfterInitService {

View File

@@ -49,19 +49,19 @@ export interface MessageCallbackParams {
export type SendMessageCallback = (
params: MessageCallbackParams,
from: SendMessageFrom,
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type -- 为什么上层在使用的时候被推断为 void
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type -- why is the upper layer inferred as void when used
) => MessageCallbackParams | void;
export type SendMessageFailedCallback = (
params: MessageCallbackParams,
from: SendMessageFrom,
error: unknown,
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type -- 为什么上层在使用的时候被推断为 void
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type -- why is the upper layer inferred as void when used
) => MessageCallbackParams | void;
export type MessageCallback = (
params: MessageCallbackParams,
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type -- 为什么上层在使用的时候被推断为 void
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type -- why is the upper layer inferred as void when used
) => MessageCallbackParams | void;
export interface SelectionChangeParams {
@@ -85,15 +85,15 @@ export type OnboardingSelectChangeCallback = (
isAlreadyHasSelect: boolean,
) => void;
/**
* 由 ChatArea 向外部发送的事件
* 外部响应
* Events sent externally by ChatArea
* external response
*/
export interface ChatAreaLifeCycleEventMap {
onInitSuccess: () => void;
onInitError: () => void;
onDestroy: () => void;
/**
* @param params 被 freeze
* @param params frozen
*/
onBeforeMessageSend: SendMessageCallback;
onMessageSendFail: SendMessageFailedCallback;
@@ -119,7 +119,7 @@ export interface ChatAreaLifeCycleEventMap {
}) => void;
onAfterStopResponding: OnAfterStopRespondingCallback;
/**
* @deprecated 临时使用,后面考虑切换实现
* @Deprecated temporary use, consider switching implementation later
*/
onParseReceiveMessageBoxTheme?: OnParseReceiveMessageBoxTheme;
}

View File

@@ -27,7 +27,7 @@ export const generateChatCoreBiz = (
return 'coze_home';
case Scene.Playground:
return 'bot_editor';
// 现在没有 bot store 场景
// There is no bot store now
default:
return 'third_part';
}

View File

@@ -43,7 +43,7 @@ import {
import { NullableChatAreaContext } from './context';
/**
* requestToInit 变化可能导致重新初始化(extendDataLifecycle会影响)
* requestToInit changes may cause reinitialization (extendDataLifecycle affects)
*/
export const ChatAreaProviderNew = forwardRef<
ChatAreaProviderMethod,
@@ -120,7 +120,7 @@ export const ChatAreaProviderNew = forwardRef<
[],
);
/* TODO: 拆分一下 context */
/* TODO: Split the context */
return (
<NullableChatAreaContext.Provider
value={{

View File

@@ -21,7 +21,7 @@ import {
type ChatAreaProviderProps,
} from './type';
/**
* 代码 1 周后删除,暂时保留以防万一
* Delete the code after 1 week and keep it temporarily just in case.
*/
import { ChatAreaProviderNew } from './provider-new';

View File

@@ -75,18 +75,18 @@ export interface MixInitResponse {
botVersion?: string;
botInfoMap?: SenderInfoMap;
userInfoMap?: UserInfoMap;
/** hasMore指导前继数据nextHasMore指导后继数据 */
/** hasMore guides predecessor data, nextHasMore guides successor data */
next_has_more?: boolean;
/** cursor指导向前翻页nextCursor指导向后翻页 */
/** Cursor guides page forward, nextCursor guides page backward */
next_cursor: string | undefined;
/** 当前读取到的message_index */
/** Currently read message_index */
read_message_index?: string;
backgroundInfo?: BackgroundImageInfo;
}
/**
* 目前都是来自 verbose 的子类型;
* 影响深远,慎重调整
* Currently all are subtypes from verbose;
* Far-reaching impact, carefully adjusted
*/
export enum IgnoreMessageType {
Knowledge,
@@ -102,11 +102,11 @@ export const allIgnorableMessageTypes = [
IgnoreMessageType.Backwards,
];
// TODO: 感觉preference需要赶紧与configs合并否则初始化的地方拿不到数据provider外)
// TODO: I feel that preference needs to be merged with configs quickly, otherwise the data cannot be obtained at the initialization place (outside the provider)
export interface ChatAreaConfigs {
ignoreMessageConfigList: IgnoreMessageType[];
showFunctionCallDetail: boolean;
// 是否group用户消息合并头像
// Whether to group user messages (merge avatars)
groupUserMessage: boolean;
uploadPlugin: typeof UploadPlugin;
}
@@ -119,7 +119,7 @@ export type ExtendDataLifecycle = 'disable' | 'full-site';
export interface ChatAreaProviderProps
extends Partial<ProviderPassThroughPreference> {
// botId presetBot 必须提供其一, 加了运行时检查
// botId presetBot must provide one, plus runtime check
botId?: string;
spaceId?: string;
presetBot?: PresetBot;
@@ -129,7 +129,7 @@ export interface ChatAreaProviderProps
botVersion?: string;
requestToInit: () => Promise<MixInitResponse>;
/**
* @deprecated 废弃了,请使用插件化方案
* @Deprecated deprecated, please use plugin scheme
*/
eventCallback?: ChatAreaEventCallback;
/**
@@ -140,20 +140,20 @@ export interface ChatAreaProviderProps
*/
createChatCoreOverrideConfig?: CreateChatCoreOverrideConfig;
/**
* @deprecated 不好。后续新增配置参考 ProviderPassThroughPreference
* @Deprecated is not good. Subsequent new configuration reference ProviderPassThroughPreference
*/
configs?: Partial<ChatAreaConfigs>;
/** 是否延长数据生命周期,以超出 provider 自身限制 */
/** Whether to extend the data lifecycle beyond the provider's own limitations */
extendDataLifecycle?: ExtendDataLifecycle;
enableChatCoreDebug?: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
pluginRegistryList?: RegisterPlugin<any>[];
/**
* @deprecated 后续下线该参数,不应该随意使用
* @Deprecated This parameter should not be used at will
*/
enableInitServiceRefactor?: boolean;
/**
* 自定义停止回复按钮的等待状态
* Customize the wait state of the stop reply button
*/
stopRespondOverrideWaiting?: boolean;
}
@@ -211,15 +211,15 @@ export interface ChatAreaContext
export interface ChatAreaProviderMethod {
resetStateFullSite: () => void;
/** !!!给 coze home 开的后门,不要用!!! */
/** !!! The back door to the coze home, don't use it!!! */
updateSenderInfo: UpdateBotInfoByImmer;
/**
* !!!又加了一个后门我快不行了
* !!! Added another back door and I'm dying
*/
updateWaitingSenderId: (id: WaitingSenderId) => void;
// bot store加的后门
// Backdoor to the bot store
/**
* @deprecated 废弃,后续禁止使用
* @deprecated, subsequent use is prohibited
*/
refreshMessageList: () => void;
}

View File

@@ -20,7 +20,7 @@ import { type ComponentTypesMap } from '../components/types';
export interface ChatAreaCustomComponents {
/**
* @deprecated 废弃,请使用插件化方案
* @Deprecated, please use the plugin scheme
*/
componentTypes?: Partial<ComponentTypesMap>;
}

View File

@@ -28,7 +28,7 @@ export const LoadMoreContext = createContext<{
});
/**
* 反模式起飞
* Anti-pattern takeoff
*/
export const LoadMoreProvider = (
props: PropsWithChildren<{

View File

@@ -18,7 +18,7 @@ import { createContext } from 'react';
import { type MessageMeta, type Message } from '../../store/types';
// TODO 可以再优化
// TODO can be further optimized.
export interface MessageBoxContextProviderProps {
messageUniqKey: string;
groupId: string;
@@ -28,7 +28,7 @@ export interface MessageBoxContextProviderProps {
isFirstUserOrFinalAnswerMessage: boolean;
isLastUserOrFinalAnswerMessage: boolean;
functionCallMessageIdList?: string[];
/** 这条消息属于的 group 是否正在进行对话 */
/** Is the group to which this message belongs having a conversation? */
isGroupChatActive: boolean;
}

View File

@@ -30,7 +30,7 @@ export const useMessageBoxContext = () => {
};
/**
* 如果上下文可能同时出现于 onboarding 等无 messageBoxContext 的场景中;
* 如果被调用环境属于正常 message box 内,使用常规 useMessageBoxContext
* If the context may also appear in scenarios without messageBoxContext, such as onboarding;
* If the invoked environment is inside a normal message box, use regular useMessageBoxContext
*/
export const useUnsafeMessageBoxContext = () => useContext(MessageBoxContext);

View File

@@ -42,13 +42,13 @@ export const MessageBoxProvider: React.FC<
const isGroupChatActive = useWaitingStore(state =>
getIsGroupChatActive({ ...state, groupId }),
);
// 通过messageId获取message
// Get message by messageId
const message = useMessagesStore(
state => state.findMessage(messageUniqKey),
isEqual,
);
// 通过messageId获取message meta
// Get message meta by messageId
const meta = useMessageMetaStore(
state => state.getMetaByMessage(messageUniqKey),
isEqual,

View File

@@ -24,80 +24,80 @@ import {
export type NewMessageInterruptScenario = 'replying' | 'suggesting' | 'never';
export interface ProviderPassThroughPreference {
/** 启用双向加载机制 */
/** Enable bidirectional loading mechanism */
enableTwoWayLoad: boolean;
/** 启用已读上报能力 */
/** Enable read report capability */
enableMarkRead: boolean;
showUserExtendedInfo: boolean;
/** 启用图片动态适应能力 */
/** Enable image dynamic adaptability */
enableImageAutoSize: boolean;
/**
* 用于计算图片尺寸的宽度(手动传入,则采用手动传入的)
* Used to calculate the width of the image size (manually passed in, manually passed in)
*/
imageAutoSizeContainerWidth: number | undefined;
/** 启动粘贴上传能力 */
/** Activate paste upload capability */
enablePasteUpload: boolean;
/**
* 输入框是否只读
* Text box read-only
*/
isInputReadonly: boolean;
/**
* 开启拖拽上传
* Enable drag and drop upload
*/
enableDragUpload: boolean;
/** 启用用户交互锁能力 */
/** enable user interlock capability */
enableChatActionLock?: boolean;
/**
* 开场白是否可选
* Is the opening statement optional?
*/
enableSelectOnboarding: boolean;
/**
* 配置输入框中的按钮状态
* Configure button status in text box
*/
uikitChatInputButtonStatus: Partial<UiKitChatInputButtonStatus>;
/**
* 开场白显示模式: wrap, random
* Prologue display mode: wrap, random
*/
onboardingSuggestionsShowMode: SuggestedQuestionsShowMode;
/**
* 背景图是否展示
* Is the background cover displayed?
*/
showBackground: boolean;
/**
* 自定义停止回复按钮的等待状态
* Customize the wait state of the stop reply button
*/
stopRespondOverrideWaiting: boolean | undefined;
}
/**
* @deprecated NOTICE: 勿在此新增属性,后逐渐替换为 ProviderPassThroughPreference
* @Deprecated NOTICE: Do not add attributes here, then gradually replace them with ProviderPassThroughPreference
*/
export interface PreferenceContextInterface {
/**
* 可打断并发送新会话场景
* - replying: 发送后, 回复过程中可打断
* - suggesting: 回复完成, 生成建议中可打断
* - never: 不可打断
* Can interrupt and send new session scenarios
* - replying: after sending, the reply process can be interrupted
* - suggesting: reply completed, can be interrupted in generating suggestions
* - never: never interrupt
*/
newMessageInterruptScenario: NewMessageInterruptScenario;
/**
* 是否启用Message Answer Actions功能
* Whether to enable Message Answer Actions
*/
enableMessageBoxActionBar: boolean;
/**
* 是否开始选择模式
* Whether to start selecting mode
*/
selectable: boolean;
/**
* 清除上下文是否显示清除线
* Clear whether the context shows clear lines
*/
showClearContextDivider: boolean;
/**
* 消息列表宽度
* message list width
*/
messageWidth: string;
/**
* 是否只读
* Is it read-only?
*/
readonly: boolean;
/**
@@ -105,59 +105,59 @@ export interface PreferenceContextInterface {
*/
uiKitChatInputButtonConfig: Partial<UiKitChatInputButtonConfig>;
/**
* UIKit 按钮状态
* @deprecated -- 请用Provider中的该属性
* UIKit button status
* @Deprecated -- please use this property in the Provider
*/
uikitChatInputButtonStatus: Partial<UiKitChatInputButtonStatus>;
/**
* 主题样式
* Theme Style
*/
theme: 'debug' | 'store' | 'home';
/**
* 开启多模态上传模式
* 用户可以上传文件展示到 Input 区域上方
* 文件和文字可以同时发送
* Enable multimodal upload mode
* Users can upload files to display above the Input area
* Documents and text can be sent simultaneously
*/
enableMultimodalUpload: boolean;
/**
* 用户上传文件后立即发送一条消息
* 文件和文字不可以同时发送
* The user sends a message immediately after uploading the file
* Documents and text cannot be sent at the same time
*/
enableLegacyUpload: boolean;
/** 启动mention功能目前为 coze home \@bot 使用 */
/** Start the mentioned function, currently used by coze home\ @bot */
enableMention: boolean;
/** 最大可上传的文件数量 */
/** Maximum number of files that can be uploaded */
fileLimit: number;
/**
* 是否展示Input区域
* Whether to display the Input area
*/
showInputArea: boolean;
/**
* 是否展示开场白的消息
* Whether to show the opening message
*/
showOnboardingMessage: boolean;
/**
* 开场白是否居中展示
* Is the opening statement centered?
*/
isOnboardingCentered: boolean;
/**
* 是否展示 停止回复
* Whether to show, stop replying
*/
showStopRespond: boolean;
/**
* 是否强制展示开场白消息(跳过默认开场白页面)
* Whether to force the opening statement message to be displayed (skip the default opening statement page)
*/
forceShowOnboardingMessage: boolean;
/**
* 布局方式
* layout
*/
layout: Layout;
/**
* 是否强制展示停止回复按钮
* Whether to force the stop reply button to be displayed
*/
stopRespondOverrideWaiting: boolean | undefined;
}

View File

@@ -50,7 +50,7 @@ class ListenMessageLengthChange {
};
}
// todo: review 很屌很危险 ⚡️️☠️
// Todo: review is dick and dangerous ⚡☠️
export const useListenMessagesLengthChangeLayoutEffect = (
useMessagesStore: MessagesStore,
) => {
@@ -72,7 +72,7 @@ export const useListenMessagesLengthChangeLayoutEffect = (
}, []);
/**
* 监听后仅生效一次
* It only takes effect once after monitoring
*/
return (fn: Listener) => fnsRef.current.push(fn);
};

View File

@@ -72,7 +72,7 @@ export const usePrepareLoadMore = ({
useEffect(() => forceDispose, []);
const loadMoreEnv = useMemo(() => {
// action 都是稳定引用,无需现场计算
// Actions are all stable references, no on-site calculations required
const {
updateCursor,
updateIndex,
@@ -112,7 +112,7 @@ export const usePrepareLoadMore = ({
useGlobalInitStore.getState().conversationId ||
'',
}),
// 取值,需要运行时现场计算
// Value, requires on-site calculation at runtime
readEnvValues: () => {
const state = useMessageIndexStore.getState();
const waitingState = useWaitingStore.getState();

View File

@@ -21,7 +21,7 @@ import { StoreSetContext } from '../../context/store-set';
import { NullableChatAreaContext } from '../../context/chat-area-context/context';
/**
* 内部使用, 这个千万不要对外导出
* For internal use, this must not be exported externally.
*/
export const useChatAreaContext = () => {
const chatAreaContext = useContext(NullableChatAreaContext);
@@ -34,7 +34,7 @@ export const useChatAreaContext = () => {
};
/**
* only for 内部使用
* Only for internal use
*/
export const useChatAreaStoreSet = () => {
const storeSetContext = useContext(StoreSetContext);

View File

@@ -87,7 +87,7 @@ export const useSubscribeStore = ({
useMessageIndexStore,
} = storeSet;
// 初始化时录入
// Enter during initialization
useEffect(() => {
if (extendDataLifecycle === 'full-site') {
recordLifecycleExtendedData(scene, storeSet);
@@ -229,7 +229,7 @@ export const useCreateAllStoreSet = ({
[],
);
// TODO: 后续把插件注册的时机提前解决渲染中变更state的问题 @lihuiwen @liushuoyan
// TODO: In the future, the timing of plugin registration will be advanced to solve the problem of changing state during rendering @lihuiwen @liushuoyan
onAfterCallback({
messageIndexStore: getMessageIndexStoreMethods(useMessageIndexStore),
});

View File

@@ -23,7 +23,7 @@ import {
} from './use-chat-area-context';
/**
* 获取容器,供非响应式环境使用
* Acquire containers for use in non-responsive environments
*/
export const useMethodCommonDeps = (): MethodCommonDeps => {
const context = useChatAreaContext();

View File

@@ -64,7 +64,7 @@ export const useChatAreaController = () => {
.messageGroupList.filter(messageGroup => messageGroup.selectable);
const replyIdList = selectableMessageGroupList
// TODO: 需要确认下 发送的消息 ack 前 groupId 不是 replyId
// TODO: You need to confirm that the groupId before the ack is not a replyId.
.map(messageGroup => messageGroup.groupId)
.filter((id): id is string => Boolean(id));

View File

@@ -45,7 +45,7 @@ export const useDragUpload = (closeDelay = 100) => {
useEffect(() => {
const target = ref.current;
/**
* 拖拽上传功能需要配合多模态消息功能使用
* The drag-and-drop upload function needs to be used with the multi-modal message function.
*/
if (!enableMultimodalUpload || !enableDragUpload) {
return;
@@ -69,10 +69,10 @@ export const useDragUpload = (closeDelay = 100) => {
const onDragOver = (e: HTMLElementEventMap['dragover']) => {
/**
* {@link https://segmentfault.com/q/1010000011746669}
* 原理:
* 这里阻止的默认行为是开启可编辑模式,具体就是document.designMode属性,
* 该属性默认是off关闭的当开启之后就可以对网页进行编辑
* 开启的方式就是document.designMode = "on"; 开启之后就不用在监听dragover事件中阻止默认了
* Principle:
* The default behavior blocked here is to enable editable mode, specifically the document.designMode property,
* This property is turned off by default, and when turned on, you can edit the webpage.
* The way to open it is document.designMode = "on"; after opening it, there is no need to block the default in the monitor dragover event.
*/
e.preventDefault();
clearTimer();
@@ -84,8 +84,8 @@ export const useDragUpload = (closeDelay = 100) => {
};
const onDragLeave = (e: HTMLElementEventMap['dragleave']) => {
clearTimer();
// 第一次触发 onDragEnter 事件的 target 也将在最后触发一次 onDragLeave, 这两个事件 target 相同
// drag 图中, 进入到 child dom 时会触发 onDragLeave 但是这个事件的 target 和第一次触发的 target 不同
// The target that fires the onDragEnter event for the first time will also fire onDragLeave for the last time, both events have the same target
// In the drag diagram, onDragLeave will be triggered when entering child dom, but the target of this event is different from the target fired for the first time.
localLog('dragleave', {
e,
});
@@ -107,7 +107,7 @@ export const useDragUpload = (closeDelay = 100) => {
const verifiedFileList = validateFileList({ fileLimit, fileList });
// 文件校验
// file validation
if (!verifiedFileList.length) {
return;
}

View File

@@ -35,17 +35,17 @@ export const usePasteUpload = () => {
const fileList = getFileListByPaste(e);
// 如果粘贴的文件数量为空,则返回
// If the number of pasted files is empty, return
if (!fileList.length) {
return;
}
// 阻止默认的粘贴行为
// Block default paste behavior
e.preventDefault();
const verifiedFileList = validateFileList({ fileLimit, fileList });
// 文件校验
// file validation
if (!verifiedFileList.length) {
return;
}

View File

@@ -37,7 +37,7 @@ export const useValidateFileList = () => {
const hasExceedSizeFile = !fileList.every(isFileSizeNotExceed);
const hasEmptyFile = !fileList.every(isNotEmptyFile);
// TODO: 遇到了 file.size 错误的 case 需要再检查
// TODO: The case of file.size error needs to be checked again.
if (hasExceedSizeFile) {
Toast.warning({
content: getFileSizeReachLimitI18n({

View File

@@ -88,7 +88,7 @@ export const useCreateAndUpdateInitService = ({
}
/**
* 动态更新 initService 中的 context 信息,便于业务方调用 refreshMessageList 的动态更新
* Dynamically update the context information in initService, which is convenient for the business party to call the dynamic update of refreshMessageList
*/
initControllerRef.current.updateContext({
requestToInit,

View File

@@ -137,7 +137,7 @@ export const useInitChatArea = ({
return requestToInit();
},
{
// 指定了 manual 时 refreshDeps 无效; 在外部显式基于 requestToInit 变更进行重新初始化
// Invalid refreshDeps when manual is specified; explicitly reinitializes externally based on requestToInit changes
manual: true,
onBefore: () => {
setInitStatus('loading');
@@ -165,7 +165,7 @@ export const useInitChatArea = ({
return;
}
// 至少你得加载一会儿吧,除非有本地缓存?
// At least you have to load it for a while, unless there is a local cache?
if (initStatus === 'unInit') {
return;
}
@@ -174,12 +174,12 @@ export const useInitChatArea = ({
return;
}
// 理论上这里应该是没有问题的需要等lifeCycleService Ready后再进行初始化否则生命周期无法被触发
// In theory, there should be no problem here. You need to wait for lifeCycleService Ready before initializing, otherwise the life cycle cannot be triggered.
if (!lifeCycleService) {
return;
}
// 这是新加的,理论上应该是安全的
// This is a new addition and should be safe in theory.
if (!data) {
return;
}
@@ -254,10 +254,10 @@ export const useInitChatArea = ({
}, [data, requestLoading, lifeCycleService]);
/**
* 一个看起来安全的 init chat-area 的副作用清理,含有:
* - chat core 的清除
* - chat core 的监听清除
* - useRequest 的状态清理(ready => false, cancel)
* A seemingly safe init chat-area side effect cleanup, containing:
* - Clear chat core
* - chat core monitoring clear
* - useRequest status cleanup (ready = > false, cancel)
*/
const clearInitSideEffect = () => {
clearSenderInfoStore();
@@ -355,13 +355,13 @@ const useUpdateSenderInfo = (
}, [userInfoInStore, userInfo]);
const updateSenderInfo = (data: MixInitResponse) => {
// 更新用户信息
// Update user information
const { botInfoMap, userInfoMap } = data;
if (botInfoMap) {
setBotInfoMap(botInfoMap);
// todo: remove 临时逻辑
// Todo: remove temporary logic
const botInfo = Object.values(botInfoMap).at(0);
recordBotInfo({
name: botInfo?.nickname,

View File

@@ -63,7 +63,7 @@ export const useIsGroupAnswerFinish = ({ memberSet }: MessageGroup) => {
});
};
// 非真实运行中止的消息
// Message of non-real operation abort
export const useIsGroupFakeInterruptAnswer = ({ memberSet }: MessageGroup) => {
const { useMessagesStore } = useChatAreaStoreSet();

View File

@@ -36,7 +36,7 @@ import { useStopResponding } from './use-stop-responding';
const DELAY_TIME = 150;
/**
* 清除会话上下文
* Clear session context
*/
export const useClearContext = () => {
@@ -128,10 +128,10 @@ export const useClearContext = () => {
);
/**
* TODO: 临时解决方案
* 造成问题的原因是Card的加载是异步的layoutEffect兜不住;
* 临时解决方案是先用setTimeout解决现象
* 长期方案需要card提供渲染完成的eventCallback通过收集渲染完成的事件在进行滚动
* TODO: Temporary Solutions
* The reason for the problem is that the loading of Card is asynchronous and cannot be covered by layoutEffect;
* Temporary solution: use setTimeout to solve the phenomenon first
* Long-term plan: The card is required to provide the rendered eventCallback, and the rendered events are scrolled by collecting the rendered events
*/
if (hasCardMessage) {
const taskId = setTimeout(() => {

View File

@@ -60,8 +60,8 @@ export const getClearHistoryImplement =
fileManager.emit(FileManagerEventNames.CANCEL_UPLOAD_FILE);
/**
* 请注意,这里的顺序一定是先调用 break_message 接口,然后再调用 clear_history 接口
* 顺序不能变,否则接口会报错
* Note that the order here must be to call the break_message interface first, then the clear_history interface
* The order cannot be changed, otherwise the interface will report an error.
*/
await stopResponding();
const res = await chatCore.clearHistory();

View File

@@ -21,7 +21,7 @@ import {
import { deleteMessageGroupById } from '../../utils/message-group/message-group';
import { useChatActionLockService } from '../../context/chat-action-lock';
// 正在上传中的文件消息、图片消息被删除 需要清除副作用 &
// File messages and picture messages that are being uploaded are deleted, and side effects need to be cleared &
export const useDeleteMessageGroup = () => {
const context = useChatAreaContext();
const storeSet = useChatAreaStoreSet();

View File

@@ -38,7 +38,7 @@ export const usePrepareMarkMessageReadService = () => {
});
const controller = useMemo(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- 哥,指定有
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- brother, specify yes
() => new MarkReadService(() => helperRef.current!),
[],
);
@@ -46,8 +46,8 @@ export const usePrepareMarkMessageReadService = () => {
};
/**
* UI 组件用这个,进行消息已读上报.
* 遵守 `enableMarkRead` (默认为 false)配置
* The UI component uses this to read and report the message.
* Comply with'enableMarkRead ' (default false) configuration
*/
export const useMarkMessageRead = () => {
const markReadService = useMarkReadService();

View File

@@ -19,7 +19,7 @@ import { useEffect } from 'react';
import { type StoreSet } from '../../context/chat-area-context/type';
/**
* 销毁时额外清除一下 setScrollViewFarFromBottom,主要针对 coze home 场景
* When destroying, remove an additional setScrollViewFarFromBottom, mainly for the coze home scene
*/
export const useResetToNewestTip = (storeSet: StoreSet) => {
useEffect(

View File

@@ -112,7 +112,7 @@ const getSendMessageAndAutoUpdateImplement =
try {
await stopRespondingPromise;
// TODO: 暂时需要用到的粗糙实现 后续需要好好实现
// TODO: A rough implementation that needs to be used temporarily, and needs to be implemented in the future
const handledMessageAndOptions = eventCallback?.onBeforeMessageSend?.(
{
message: proxyFreeze(toSenDMessage),
@@ -178,13 +178,13 @@ const getSendMessageAndAutoUpdateImplement =
if (isError(e)) {
const errorData = parseErrorInfoFromErrorMessage(e.message);
/**
* 没有进入 sse 的错误
* 服务端还在梳理报错消息 只能 toast 白名单中已经梳理的 message
* No error entering sse.
* The server level is still combing the error message, and can only toast the messages that have been combed in the whitelist.
*/
if (isChatCoreError(e) && isToastErrorMessage(e.ext.code)) {
Toast.error({ content: e.message, showClose: false });
}
// 进入 sse 流程但是第一个 chunk 就是 error
// Enter the sse process but the first chunk is an error
if (
errorData?.code &&
[
@@ -304,7 +304,7 @@ export const getSendNewMessageImplement =
},
);
// ASR 过程异常 删除上屏消息 退出
// The ASR process is abnormal, delete the screen message, and exit.
if (!preReadySendMessage) {
revertVoiceMessageConditionally({
message: processedMessage,

View File

@@ -99,7 +99,7 @@ export const useRegenerateMessage = () => {
};
/**
* 根据message_id重新发送消息
* Resend messages according to message_id
*/
export const useRegenerateMessageByUserMessageId = () => {
const regenerateMessage = useRegenerateMessage();

View File

@@ -46,7 +46,7 @@ const getCreateTextMessageImplement =
};
/**
* 发送文本消息,需要初始化成功后使用
* Send a text message, which needs to be used after successful initialization.
*/
export const useSendTextMessage = () => {
const deps = useMethodCommonDeps();

View File

@@ -42,7 +42,7 @@ export const useBotInfoWithSenderId = (senderId?: string) => {
};
/**
* 返回 action,稳定引用
* Return action, stable reference
*/
export const useSetBotInfoBatch = () => {
const { useSenderInfoStore } = useChatAreaStoreSet();

View File

@@ -24,12 +24,12 @@ export const useMessagesOverview = () => {
const latestSectionId = useSectionIdStore(state => state.latestSectionId);
/**
* 过滤插入的消息
* Filter inserted messages
*/
const { isEmpty, latestSectionHasMessage } = useMessagesStore(
useShallow(state => ({
isEmpty: state.messages.length === 0,
// todo 优化为 group 判断,无需全量扫描 messages
// Todo is optimized for group judgment, no need to scan all messages
latestSectionHasMessage: !!state.messages.filter(
msg => msg.section_id === latestSectionId,
).length,

View File

@@ -19,7 +19,7 @@ import { usePreference } from '../../context/preference';
export const useOnboardingCenterOffset = ({
onboardingHeight = 0,
// 默认最小 margin by ui 设计顶部预留 24px 由 top-safe-area 撑起
// Default minimum margin by ui design Top reserved 24px supported by top-safe-area
minOffset = 0,
}: {
onboardingHeight?: number;

View File

@@ -27,9 +27,9 @@ interface UseBackgroundScrollReturnType {
showGradient: boolean;
}
// 背景图模式下scrollView增加以下处理
// 1. 当存在顶部Node时滚动后增加 一层高度固定的黑色渐变div页面向下滚动不僵硬
// 2. 对话区域增加一层蒙版,底部会话区域渐变消失,会话元素底部不僵硬
// In background cover mode scrollView adds the following processing:
// 1. When there is a top Node, add it after scrolling, a layer of fixed height black gradual change div, the page scrolls down without stiffness
// 2. Add a layer of mask to the dialogue area, the bottom conversation area gradually changes and disappears, and the bottom of the conversation element is not stiff
export const useBackgroundScroll = ({
hasHeaderNode,
maskNode,
@@ -48,7 +48,7 @@ export const useBackgroundScroll = ({
beforeClassName: showBackground ? 'absolute left-0' : '',
beforeNode:
showGradient && hasHeaderNode && showBackground ? maskNode : null,
// 增加蒙版,处理聊天会话底部无渐变生硬问题
// Add mask, deal with the bottom of the chat session without gradual change blunt problem
maskClassName: showBackground ? styles['scroll-mask'] ?? '' : '',
showGradient,
};

View File

@@ -170,11 +170,11 @@ export { ChatInput, type ChatInputProps } from './components/chat-input';
export { useGetRegisteredPlugin } from './hooks/plugins/use-get-chatcore-plugin';
export { FileStatus } from './store/types';
/**
* @deprecated 废弃,后续会移除对外导出
* @Deprecated, the export will be removed later
*/
export { useChatAreaContext } from './hooks/context/use-chat-area-context';
/**
* @deprecated 废弃,后续会移除对外导出
* @Deprecated, the export will be removed later
*/
export { useChatAreaStoreSet } from './hooks/context/use-chat-area-context';
@@ -187,7 +187,7 @@ export { getContentConfigs } from './constants/content';
export { useFile } from './hooks/public/use-file';
/**
* 插件化系统导出 Start
* Plug-in System Export Start
*/
export { usePluginPublicMethods } from './plugin/hooks/use-plugin-public-methods';
@@ -280,7 +280,7 @@ export {
ReadonlyRenderLifeCycleServiceGenerator,
} from './plugin/types/utils/create-life-cycle-service';
/**
* 插件化系统导出 End
* Plug-in System Export End
*/
export { useLatestSectionId } from './hooks/public/use-latest-section-id';
export { PluginAsyncQuote } from './components/plugin-async-quote';

View File

@@ -28,9 +28,9 @@ export const enum PluginName {
ChatPlayground = 'ChatPlayground',
PremiumPlans = 'PremiumPlans',
TemplateMessageSelector = 'TemplateMessageSelector',
WebsdkChatCozeSdkPlugin = 'WebsdkChatCozeSdkPlugin', // WebSdk的走openApiplugin
WebsdkDefaultChatPlugin = 'WebsdkDefaultChatPlugin', // WebSdk的默认plugin
WebsdkChatCommonPlugin = 'WebsdkChatCommonPlugin', // WebSdk的公共plugin
WebsdkChatCozeSdkPlugin = 'WebsdkChatCozeSdkPlugin', // WebSdk go openApi plugin
WebsdkDefaultChatPlugin = 'WebsdkDefaultChatPlugin', // Default plugin for WebSdk
WebsdkChatCommonPlugin = 'WebsdkChatCommonPlugin', // WebSdk public plugin
UIBuilderChatUIPlugin = 'UIBuilderChatUIPlugin', // UIBuilderChatPlugin
UIBuilderEventcallbackPlugin = 'UIBuilderEventcallbackPlugin', // UIBuilderEventcallbackPlugin
AgentTemplateSubScene = 'AgentTemplateSubScene',

View File

@@ -23,10 +23,10 @@ export const enum PluginMode {
}
/**
* 按照领域进行分层设计
* AppLifeCycle处理SDK整个生命周期例如初始化、销毁等
* MessageLifeCycle:处理消息链路的生命周期
* CommandLifeCycle:指令、事件相关
* Layered design by domain
* AppLifeCycle: Handles the entire SDK lifecycle, such as initialization, destruction, etc
* MessageLifeCycle: Handling the lifecycle of the message link
* CommandLifeCycle: Instructions, events related
*/
export type AppLifeCycle =
| 'onAfterCreateStores'

View File

@@ -20,7 +20,7 @@ import { usePluginList } from './use-plugin-list';
interface ComponentConfig<K extends keyof CustomComponent> {
pluginName: PluginName;
// eslint-disable-next-line @typescript-eslint/naming-convention -- 符合预期
// eslint-disable-next-line @typescript-eslint/naming-convention -- as expected
Component: CustomComponent[K];
}

View File

@@ -30,7 +30,7 @@ type Expect<T extends true> = T;
type TestClassIncludeAppLifeCycleKeys =
AppLifeCycle extends keyof SystemAppLifeCycleService ? true : false;
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars -- 检测类型使用
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars -- detect type usage
type _ = Expect<TestClassIncludeAppLifeCycleKeys>;
export class SystemAppLifeCycleService {

View File

@@ -37,7 +37,7 @@ type Expect<T extends true> = T;
type TestClassIncludeCommandLifeCycleKeys =
CommandLifeCycle extends keyof SystemCommandLifeCycleService ? true : false;
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars -- 检测类型使用
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars -- detect type usage
type _ = Expect<TestClassIncludeCommandLifeCycleKeys>;
export class SystemCommandLifeCycleService {

View File

@@ -43,7 +43,7 @@ type Expect<T extends true> = T;
type TestClassIncludeMessageLifeCycleKeys =
MessageLifeCycle extends keyof SystemMessageLifeCycleService ? true : false;
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars -- 检测类型使用
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars -- detect type usage
type _ = Expect<TestClassIncludeMessageLifeCycleKeys>;
export class SystemMessageLifeCycleService {

View File

@@ -28,7 +28,7 @@ type Expect<T extends true> = T;
type TestClassIncludeRenderLifeCycleKeys =
RenderLifeCycle extends keyof SystemRenderLifeCycleService ? true : false;
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars -- 检测类型使用
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars -- detect type usage
type _ = Expect<TestClassIncludeRenderLifeCycleKeys>;
export class SystemRenderLifeCycleService {

View File

@@ -24,25 +24,25 @@ export abstract class ChatAreaPlugin<
K = unknown,
> {
/**
* 业务方自持的业务Context信息
* Business Context Information Owned by Business Parties
*/
public pluginBizContext: T;
/**
* 插件名称
* plugin name
*/
public abstract pluginName: PluginName;
/**
* 插件模式
* @enum PluginMode.Readonly - 只读
* @enum PluginMode.Writeable - 可写
* plugin pattern
* @enum PluginMode. Readonly - Read Only
* @enum PluginMode. Writeable
*/
public pluginMode: PluginMode = PluginMode.Readonly;
/**
* ChatArea提供的上下文
* Context provided by ChatArea
*/
public chatAreaPluginContext: ChatAreaPluginContext<U>;
/**
* 自定义组件
* custom component
*/
public customComponents?: Partial<CustomComponent>;
constructor(
@@ -53,7 +53,7 @@ export abstract class ChatAreaPlugin<
this.chatAreaPluginContext = chatAreaPluginContext;
}
/**
* 业务方请勿使用:注入ChatAreaContext信息
* Business parties should not use: Inject ChatAreaContext information
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
public _injectChatAreaContext(
@@ -68,7 +68,7 @@ export abstract class ChatAreaPlugin<
}
/**
* 对外暴露的公共方法
* Public methods of exposure
*/
public publicMethods?: K;
}
@@ -77,7 +77,7 @@ export abstract class ReadonlyChatAreaPlugin<
T = unknown,
K = unknown,
> extends ChatAreaPlugin<PluginMode.Readonly, T, K> {
// eslint-disable-next-line @typescript-eslint/no-useless-constructor -- 需要透传
// eslint-disable-next-line @typescript-eslint/no-useless-constructor -- pass-through required
constructor(
pluginBizContext: T,
chatAreaPluginContext: ChatAreaPluginContext<PluginMode.Readonly>,

View File

@@ -39,49 +39,49 @@ type OnBeforeListenChatCore = (
) => { abortListen: boolean } | undefined;
/**
* ! 希望你注意到生命周期的上下文信息都放在ctx
* ! 如果判断只是上下文请你注意收敛到ctx中请勿增加新的参数
* ! CodeReview的时候辛苦也注重一下这里
* ! Hope you noticed that the context information for the lifecycle is placed in ctx
* ! If the judgment is just context, please pay attention to the convergence into ctx and do not add new parameters
* ! Please pay attention here when CodeReview.
*/
export abstract class ReadonlyAppLifeCycleService<
T = unknown,
K = unknown,
> extends ReadonlyLifeCycleService<T, K> {
/**
* PluginStore初始化后
* 后续需要支持的话,写法为 void | Promise<void>
* After PluginStore initialization
* If you need support in the future, write it as void | Promise < void >
*/
onAfterCreateStores?(stores: OnAfterCallback): void;
/**
* ChatArea初始化之前(暂时不支持异步调用,在Hooks中)
* 后续需要支持的话,写法为 void | Promise<void>
* Before ChatArea is initialized (asynchronous calls are temporarily not supported, in Hooks)
* If you need support in the future, write it as void | Promise < void >
*/
onBeforeInitial?(): void;
/**
* ChatArea初始化之后成功暂时不支持异步调用Hooks中)
* 后续需要支持的话,写法为 void | Promise<void>
* After the ChatArea is initialized (successfully) (asynchronous calls are temporarily not supported, in Hooks)
* If you need support in the future, write it as void | Promise < void >
*/
onAfterInitial?(ctx: OnAfterInitialContext): void;
/**
* ChatArea初始化失败(暂时不支持异步调用,在Hooks中)
* 后续需要支持的话,写法为 void | Promise<void>
* ChatArea initialization failed (asynchronous calls are temporarily not supported, in Hooks)
* If you need support in the future, write it as void | Promise < void >
*/
onInitialError?(): void;
/**
* ChatArea销毁之前(暂时不支持异步调用,在Hooks中)
* 后续需要支持的话,写法为 void | Promise<void>
* Before ChatArea is destroyed (asynchronous calls are temporarily not supported, in Hooks)
* If you need support in the future, write it as void | Promise < void >
*/
onBeforeDestroy?(): void;
/**
* 刷新消息列表前
* Before refreshing the message list
*/
onBeforeRefreshMessageList?(): void;
/**
* 刷新消息列表后
* After refreshing the message list
*/
onAfterRefreshMessageList?(): void;
/**
* 刷新消息列表失败
* Failed to refresh message list
*/
onRefreshMessageListError?(ctx: OnRefreshMessageListError): void;
onBeforeListenChatCore?: OnBeforeListenChatCore;
@@ -92,40 +92,40 @@ export abstract class WriteableAppLifeCycleService<
K = unknown,
> extends WriteableLifeCycleService<T, K> {
/**
* PluginStore初始化后
* 后续需要支持的话,写法为 void | Promise<void>
* After PluginStore initialization
* If you need support in the future, write it as void | Promise < void >
*/
onAfterCreateStores?(stores: OnAfterCallback): void;
/**
* ChatArea初始化之前(暂时不支持异步调用,在Hooks中)
* 后续需要支持的话,写法为 void | Promise<void>
* Before ChatArea is initialized (asynchronous calls are temporarily not supported, in Hooks)
* If you need support in the future, write it as void | Promise < void >
*/
onBeforeInitial?(): void;
/**
* ChatArea初始化之后成功暂时不支持异步调用Hooks中)
* 后续需要支持的话,写法为 void | Promise<void>
* After the ChatArea is initialized (successfully) (asynchronous calls are temporarily not supported, in Hooks)
* If you need support in the future, write it as void | Promise < void >
*/
onAfterInitial?(ctx: OnAfterInitialContext): void;
/**
* ChatArea初始化失败(暂时不支持异步调用,在Hooks中)
* 后续需要支持的话,写法为 void | Promise<void>
* ChatArea initialization failed (asynchronous calls are temporarily not supported, in Hooks)
* If you need support in the future, write it as void | Promise < void >
*/
onInitialError?(): void;
/**
* ChatArea销毁之前(暂时不支持异步调用,在Hooks中)
* 后续需要支持的话,写法为 void | Promise<void>
* Before ChatArea is destroyed (asynchronous calls are temporarily not supported, in Hooks)
* If you need support in the future, write it as void | Promise < void >
*/
onBeforeDestroy?(): void;
/**
* 刷新消息列表前
* Before refreshing the message list
*/
onBeforeRefreshMessageList?(): void;
/**
* 刷新消息列表后
* After refreshing the message list
*/
onAfterRefreshMessageList?(): void;
/**
* 刷新消息列表失败
* Failed to refresh message list
*/
onRefreshMessageListError?(ctx: OnRefreshMessageListError): void;
onBeforeListenChatCore?: OnBeforeListenChatCore;

View File

@@ -32,100 +32,100 @@ import {
} from './life-cycle-service';
/**
* ! 希望你注意到生命周期的上下文信息都放在ctx
* ! 如果判断只是上下文请你注意收敛到ctx中请勿增加新的参数
* ! CodeReview的时候辛苦也注重一下这里
* ! Hope you noticed that the context information for the lifecycle is placed in ctx
* ! If the judgment is just context, please pay attention to the convergence into ctx and do not add new parameters
* ! Please pay attention here when CodeReview.
*/
export abstract class ReadonlyCommandLifeCycleService<
T = unknown,
K = unknown,
> extends ReadonlyLifeCycleService<T, K> {
/**
* 清除历史消息之前
* Before clearing chat history
*/
onBeforeClearHistory?(): Promise<void> | void;
/**
* 清除历史消息之后
* After clearing the chat history
*/
onAfterClearHistory?(): Promise<void> | void;
/**
* 清除上下文之前
* Before clearing the context
*/
onBeforeClearContext?(ctx: OnBeforeClearContextContext): Promise<void> | void;
/**
* 清除上下文之后
* After clearing the context
*/
onAfterClearContext?(): Promise<void> | void;
/**
* 清除上下文失败
* Failed to clear context
*/
onClearContextError?(): Promise<void> | void;
/**
* 停止响应之前
* Before stopping responding
*/
onBeforeStopResponding?(): Promise<void> | void;
/**
* 停止响应之后
* After stopping responding
*/
onAfterStopResponding?(): Promise<void> | void;
/**
* 停止响应失败
* Stop response failed
*/
onStopRespondingError?(
ctx: OnStopRespondingErrorContext,
): Promise<void> | void;
/**
* 开场白选中事件
* Opening remarks Selected events
*/
onOnboardingSelectChange?(
ctx: OnOnboardingSelectChangeContext,
): Promise<void> | void;
/**
* input点击事件
* Input click event
*/
onInputClick?(): Promise<void> | void;
/**
* selection store数据发生变化
* Selection store data changes
*/
onSelectionChange?(ctx: OnSelectionChangeContext): Promise<void> | void;
/**
* 图片点击事件
* image click event
*/
onImageClick?(ctx: OnImageClickContext): Promise<void> | void;
/**
* 输入框粘贴事件
* Text box paste event
*/
onInputPaste?(ctx: OnInputPasteContext): Promise<void> | void;
/**
* 滚动事件处理
* rolling event handling
*/
onViewScroll?(): void;
/**
* 卡片类型的链接鼠标移入(包括图片)按照 CardBuilder 开发者的意思,后续只要是类似场景都复用这个
* The link of the card type is moved by mouse (including pictures). According to the meaning of the CardBuilder developers, this will be reused in the future as long as it is a similar scene.
*/
onCardLinkElementMouseEnter?(ctx: OnLinkElementContext): void;
/**
* 卡片类型的链接鼠标移出(包括图片)按照 CardBuilder 开发者的意思,后续只要是类似场景都复用这个
* The link of the card type is moved out with the mouse (including pictures). According to the meaning of the CardBuilder developers, this will be reused in the future as long as it is a similar scene.
*/
onCardLinkElementMouseLeave?(ctx: OnLinkElementContext): void;
/**
* MdBox类型的图片鼠标移入
* MdBox type image mouse in
*/
onMdBoxImageElementMouseEnter?(ctx: OnImageElementContext): void;
/**
* MdBox类型的图片鼠标移出
* MdBox type image mouse out
*/
onMdBoxImageElementMouseLeave?(ctx: OnImageElementContext): void;
/**
* MdBox类型的Link鼠标移入
* MdBox Type Link Mouse In
*/
onMdBoxLinkElementMouseEnter?(ctx: OnLinkElementContext): void;
/**
* MdBox类型的Link鼠标移出
* MdBox type Link mouse out
*/
onMdBoxLinkElementMouseLeave?(ctx: OnLinkElementContext): void;
/**
* Link 点击
* Link Click
*/
onMessageLinkClick?(ctx: Omit<OnMessageLinkClickContext, 'event'>): void;
}
@@ -135,95 +135,95 @@ export abstract class WriteableCommandLifeCycleService<
K = unknown,
> extends WriteableLifeCycleService<T, K> {
/**
* 清除历史消息之前
* Before clearing chat history
*/
onBeforeClearHistory?(): Promise<void> | void;
/**
* 清除历史消息之后
* After clearing the chat history
*/
onAfterClearHistory?(): Promise<void> | void;
/**
* 清除上下文之前
* Before clearing the context
*/
onBeforeClearContext?(
ctx: OnBeforeClearContextContext,
): Promise<OnBeforeClearContextContext> | OnBeforeClearContextContext;
/**
* 清除上下文之后
* After clearing the context
*/
onAfterClearContext?(): Promise<void> | void;
/**
* 清除上下文失败
* Failed to clear context
*/
onClearContextError?(): Promise<void> | void;
/**
* 停止响应之前
* Before stopping responding
*/
onBeforeStopResponding?(): Promise<void> | void;
/**
* 停止响应之后
* After stopping responding
*/
onAfterStopResponding?(
ctx: OnAfterStopRespondingContext,
): Promise<void> | void;
/**
* 停止响应失败
* Stop response failed
*/
onStopRespondingError?(
ctx: OnStopRespondingErrorContext,
): Promise<void> | void;
/**
* 开场白选中事件
* Opening remarks Selected events
*/
onOnboardingSelectChange?(
ctx: OnOnboardingSelectChangeContext,
): Promise<void> | void;
/**
* input点击事件
* Input click event
*/
onInputClick?(): Promise<void> | void;
/**
* selection store数据发生变化
* Selection store data changes
*/
onSelectionChange?(ctx: OnSelectionChangeContext): Promise<void> | void;
/**
* 图片点击事件
* image click event
*/
onImageClick?(ctx: OnImageClickContext): Promise<void> | void;
/**
* 输入框粘贴事件
* Text box paste event
*/
onInputPaste?(ctx: OnInputPasteContext): Promise<void> | void;
/**
* 滚动事件处理
* rolling event handling
*/
onViewScroll?(): void;
/**
* 卡片类型的链接鼠标移入(包括图片)按照 CardBuilder 开发者的意思,后续只要是类似场景都复用这个
* The link of the card type is moved by mouse (including pictures). According to the meaning of the CardBuilder developers, this will be reused in the future as long as it is a similar scene.
*/
onCardLinkElementMouseEnter?(ctx: OnLinkElementContext): void;
/**
* 卡片类型的链接鼠标移出(包括图片)按照 CardBuilder 开发者的意思,后续只要是类似场景都复用这个
* The link of the card type is moved out with the mouse (including pictures). According to the meaning of the CardBuilder developers, this will be reused in the future as long as it is a similar scene.
*/
onCardLinkElementMouseLeave?(ctx: OnLinkElementContext): void;
/**
* MdBox类型的图片鼠标移入
* MdBox type image mouse in
*/
onMdBoxImageElementMouseEnter?(ctx: OnImageElementContext): void;
/**
* MdBox类型的图片鼠标移出
* MdBox type image mouse out
*/
onMdBoxImageElementMouseLeave?(ctx: OnImageElementContext): void;
/**
* MdBox类型的Link鼠标移入
* MdBox Type Link Mouse In
*/
onMdBoxLinkElementMouseEnter?(ctx: OnLinkElementContext): void;
/**
* MdBox类型的Link鼠标移出
* MdBox type Link mouse out
*/
onMdBoxLinkElementMouseLeave?(ctx: OnLinkElementContext): void;
/**
* Link 点击
* Link Click
*/
onMessageLinkClick?(ctx: OnMessageLinkClickContext): void;
}

View File

@@ -38,90 +38,90 @@ import {
} from './life-cycle-service';
/**
* ! 希望你注意到生命周期的上下文信息都放在ctx
* ! 如果判断只是上下文请你注意收敛到ctx中请勿增加新的参数
* ! CodeReview的时候辛苦也注重一下这里
* ! Hope you noticed that the context information for the lifecycle is placed in ctx
* ! If the judgment is just context, please pay attention to the convergence into ctx and do not add new parameters
* ! Please pay attention here when CodeReview.
*/
export abstract class ReadonlyMessageLifeCycleService<
T = unknown,
K = unknown,
> extends ReadonlyLifeCycleService<T, K> {
/**
* 发送消息之前
* Before sending a message
*/
onBeforeSendMessage?(ctx: OnBeforeSendMessageContext): Promise<void> | void;
/**
* 发送消息之后
* After sending the message
*/
onAfterSendMessage?(ctx: OnAfterSendMessageContext): Promise<void> | void;
/**
* 发送消息失败
* Failed to send message
*/
onSendMessageError?(ctx: OnSendMessageErrorContext): Promise<void> | void;
/**
* 处理某条消息的时候开始处理之前(消息过滤之前)
* When processing a message, before starting processing (before message filtering)
*/
onBeforeReceiveMessage?(ctx: OnBeforeReceiveMessageContext): void;
/**
* 处理某条消息的时候开始处理之前
* When processing a message, before starting processing
*/
onBeforeProcessReceiveMessage?(
ctx: OnBeforeProcessReceiveMessageContext,
): void;
/**
* 处理消息组
* Processing message groups
*/
onBeforeMessageGroupListUpdate?(
ctx: OnBeforeMessageGroupListUpdateContext,
): void;
/**
* 接收消息处理之后的时候
* When receiving the message after processing
*/
onAfterProcessReceiveMessage?(ctx: OnAfterProcessReceiveMessageContext): void;
/**
* 删除消息之前
* Before deleting the message
*/
onBeforeDeleteMessage?(
ctx: OnBeforeDeleteMessageContext,
): Promise<void> | void;
/**
* 删除消息之后
* After deleting the message
*/
onAfterDeleteMessage?(ctx: OnAfterDeleteMessageContext): Promise<void> | void;
/**
* 删除消息失败
* Failed to delete message
*/
onDeleteMessageError?(ctx: OnDeleteMessageErrorContext): Promise<void> | void;
/**
* 获取历史消息之前
* Before getting chat history
*/
onBeforeGetMessageHistoryList?(
ctx: OnBeforeGetMessageHistoryListContext,
): Promise<void> | void;
/**
* 发送者消息进入Store之前假消息上屏前
* Before the sender message enters the Store (before the fake message is displayed on the screen)
*/
onBeforeAppendSenderMessageIntoStore?(
ctx: OnBeforeAppendSenderMessageIntoStore,
): Promise<void> | void;
/**
* 发送者消息进入Store之后假消息上屏后
* After the sender message enters the Store (after the fake message is uploaded to the screen)
*/
onAfterAppendSenderMessageIntoStore?(
ctx: OnAfterAppendSenderMessageIntoStore,
): Promise<void> | void;
/**
* MemberSet分类
* MemberSet classification
*/
onBeforeDistributeMessageIntoMemberSet?(
ctx: OnBeforeDistributeMessageIntoMemberSetContent,
): void;
/**
* 消息拉流状态错误
* Message pull status error
*/
onMessagePullingError?(ctx: OnMessagePullingErrorContext): void;
/**
* 消息拉流状态成功
* Message pull flow status successful
*/
onMessagePullingSuccess?(ctx: OnMessagePullingSuccessContext): void;
}
@@ -131,55 +131,55 @@ export abstract class WriteableMessageLifeCycleService<
K = unknown,
> extends WriteableLifeCycleService<T, K> {
/**
* 发送消息之前
* Before sending a message
*/
onBeforeSendMessage?(
ctx: OnBeforeSendMessageContext,
): Promise<OnBeforeSendMessageContext> | OnBeforeSendMessageContext;
/**
* 发送消息之后
* After sending the message
*/
onAfterSendMessage?(ctx: OnAfterSendMessageContext): Promise<void> | void;
/**
* 发送消息失败
* Failed to send message
*/
onSendMessageError?(ctx: OnSendMessageErrorContext): Promise<void> | void;
/**
* 处理某条消息的时候开始处理之前(消息过滤之前)
* When processing a message, before starting processing (before message filtering)
*/
onBeforeReceiveMessage?(ctx: OnBeforeReceiveMessageContext): void;
/**
* 处理某条消息的时候开始处理之前
* When processing a message, before starting processing
*/
onBeforeProcessReceiveMessage?(
ctx: OnBeforeProcessReceiveMessageContext,
): OnBeforeProcessReceiveMessageContext;
/**
* 处理消息组并更新数据
* Process message groups and update data
*/
onBeforeMessageGroupListUpdate?(
ctx: OnBeforeMessageGroupListUpdateContext,
): OnBeforeMessageGroupListUpdateContext;
/**
* 接收消息处理之后的时候
* When receiving the message after processing
*/
onAfterProcessReceiveMessage?(ctx: OnAfterProcessReceiveMessageContext): void;
/**
* 删除消息之前
* Before deleting the message
*/
onBeforeDeleteMessage?(
ctx: OnBeforeDeleteMessageContext,
): Promise<void> | void;
/**
* 删除消息之后
* After deleting the message
*/
onAfterDeleteMessage?(ctx: OnAfterDeleteMessageContext): Promise<void> | void;
/**
* 删除消息失败
* Failed to delete message
*/
onDeleteMessageError?(ctx: OnDeleteMessageErrorContext): Promise<void> | void;
/**
* 获取历史消息之前
* Before getting chat history
*/
onBeforeGetMessageHistoryList?(
ctx: OnBeforeGetMessageHistoryListContext,
@@ -187,7 +187,7 @@ export abstract class WriteableMessageLifeCycleService<
| Promise<OnBeforeGetMessageHistoryListContext>
| OnBeforeGetMessageHistoryListContext;
/**
* 发送者消息进入Store之前假消息上屏前
* Before the sender message enters the Store (before the fake message is displayed on the screen)
* @param ctx
*/
onBeforeAppendSenderMessageIntoStore?(
@@ -196,23 +196,23 @@ export abstract class WriteableMessageLifeCycleService<
| Promise<OnBeforeAppendSenderMessageIntoStore>
| OnBeforeAppendSenderMessageIntoStore;
/**
* 发送者消息进入Store之后假消息上屏后
* After the sender message enters the Store (after the fake message is uploaded to the screen)
*/
onAfterAppendSenderMessageIntoStore?(
ctx: OnAfterAppendSenderMessageIntoStore,
): Promise<void> | void;
/**
* MemberSet分类
* MemberSet classification
*/
onBeforeDistributeMessageIntoMemberSet?(
ctx: OnBeforeDistributeMessageIntoMemberSetContent,
): OnBeforeDistributeMessageIntoMemberSetContent;
/**
* 消息拉流状态错误
* Message pull status error
*/
onMessagePullingError?(ctx: OnMessagePullingErrorContext): void;
/**
* 消息拉流状态成功
* Message pull flow status successful
*/
onMessagePullingSuccess?(ctx: OnMessagePullingSuccessContext): void;
}

View File

@@ -24,9 +24,9 @@ import {
} from './life-cycle-service';
/**
* ! 希望你注意到生命周期的上下文信息都放在ctx
* ! 如果判断只是上下文请你注意收敛到ctx中请勿增加新的参数
* ! CodeReview的时候辛苦也注重一下这里
* ! Hope you noticed that the context information for the lifecycle is placed in ctx
* ! If the judgment is just context, please pay attention to the convergence into ctx and do not add new parameters
* ! Please pay attention here when CodeReview.
*/
export abstract class ReadonlyRenderLifeCycleService<
T = unknown,

View File

@@ -44,7 +44,7 @@ export interface OnStopRespondingErrorContext {
}
export interface OnInputPasteContext {
// 原始事件
// original event
event: ClipboardEvent<HTMLTextAreaElement>;
}

View File

@@ -27,12 +27,12 @@ export interface OnTextContentRenderingContext {
export interface OnMessageBoxRenderContext {
/**
* 动态注入的自定义渲染组件
* Dynamic injection of custom rendering components
*/
// eslint-disable-next-line @typescript-eslint/naming-convention -- 符合预期的命名
// eslint-disable-next-line @typescript-eslint/naming-convention -- matches the expected naming
MessageBox?: CustomComponent['MessageBox'];
/**
* 消息体
* message body
*/
message: Message<ContentType>;
/**

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
type ReadonlyChatAreaPlugin,
type WriteableChatAreaPlugin,
@@ -21,16 +21,16 @@ import {
import { type ChatAreaPluginContext } from './plugin-class/chat-area-plugin-context';
/**
* @deprecated 废弃 使用 PluginRegistryEntry
* @deprecated, use PluginRegistryEntry
*/
export interface RegisterPlugin<T = unknown> {
// 用于创建上下文的函数,期待返回插件上下文类型
// Function to create a context, expecting to return the plug-in context type
createPluginBizContext: () => T;
// 插件实现类
// plugin implementation class
// eslint-disable-next-line @typescript-eslint/naming-convention
Plugin: new (
context: T,
// @ts-expect-error -- 这里应该就是需要unknown
// @ts-expect-error -- unknown should be required here.
chatAreaPluginContext: ChatAreaPluginContext<unknown>,
) => ReadonlyChatAreaPlugin<T> | WriteableChatAreaPlugin<T>;
}

View File

@@ -17,7 +17,7 @@
import { type CustomComponent } from '../types/plugin-component';
/**
* 创建 自定义组件 的辅助函数
* Create a custom component helper function
*/
export const createCustomComponents = (
customComponents: Partial<CustomComponent>,

View File

@@ -30,7 +30,7 @@ import {
} from '../plugin-class/plugin';
/**
* 创建 可写生命周期 的辅助函数
* To create a helper function for a writable lifecycle
*/
export const createWriteableLifeCycleServices = <T = unknown, K = unknown>(
plugin: WriteableChatAreaPlugin<T, K>,
@@ -38,7 +38,7 @@ export const createWriteableLifeCycleServices = <T = unknown, K = unknown>(
): WriteableLifeCycleServiceCollection<T, K> => {
const lifeCycleService = generator(plugin);
// 为了不影响历史逻辑,返回值会过滤掉 pluginInstance 属性
// In order not to affect the historical logic, the return value filters out the pluginInstance property
bindPluginInstance<T, K>(
lifeCycleService as unknown as WriteableLifeCycleServiceCollection<T, K>,
plugin,
@@ -51,7 +51,7 @@ export const createWriteableLifeCycleServices = <T = unknown, K = unknown>(
};
/**
* 创建 可写生命周期 的辅助函数
* To create a helper function for a writable lifecycle
*/
export const createReadonlyLifeCycleServices = <T = unknown, K = unknown>(
plugin: ReadonlyChatAreaPlugin<T, K>,
@@ -59,7 +59,7 @@ export const createReadonlyLifeCycleServices = <T = unknown, K = unknown>(
): ReadonlyLifeCycleServiceCollection<T, K> => {
const lifeCycleService = generator(plugin);
// 为了不影响历史逻辑,返回值会过滤掉 pluginInstance 属性
// In order not to affect the historical logic, the return value filters out the pluginInstance property
bindPluginInstance<T, K>(
lifeCycleService as unknown as ReadonlyLifeCycleServiceCollection<T, K>,
plugin,
@@ -72,7 +72,7 @@ export const createReadonlyLifeCycleServices = <T = unknown, K = unknown>(
};
/**
* 针对历史逻辑的适配,支持通过 pluginInstance 继续访问数据
* For adaptation of historical logic, support for continued access to data through pluginInstance
*/
const bindPluginInstance = <T = unknown, K = unknown>(
lifeCycleService:

Some files were not shown because too many files have changed in this diff Show More