@myun/gimi-chat 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,25 +2,78 @@ import { Extension } from '@tiptap/core';
2
2
  export default Extension.create(function () {
3
3
  function onCreate() {}
4
4
  function onUpdate() {}
5
- var validate = function validate(_ref) {
6
- var editor = _ref.editor;
5
+ var getTitleSlotInfo = function getTitleSlotInfo(editor) {
7
6
  var doc = editor.state.doc;
8
- var hasTitleSlot = false;
9
- doc.descendants(function (node) {
7
+ var titleSlotPos = null;
8
+ var titleSlotSize = 0;
9
+ doc.descendants(function (node, pos) {
10
10
  if (node.type.name === 'titleSlot') {
11
- hasTitleSlot = true;
11
+ titleSlotPos = pos;
12
+ titleSlotSize = node.nodeSize;
12
13
  return false;
13
14
  }
14
15
  return true;
15
16
  });
16
- var selectionPos = editor.state.selection.from;
17
- return hasTitleSlot ? !(selectionPos > 2) : false;
17
+ if (titleSlotPos === null) {
18
+ return null;
19
+ }
20
+ return {
21
+ pos: titleSlotPos,
22
+ size: titleSlotSize
23
+ };
24
+ };
25
+ var handleArrowLeft = function handleArrowLeft(_ref) {
26
+ var editor = _ref.editor;
27
+ var info = getTitleSlotInfo(editor);
28
+ if (!info) {
29
+ return false;
30
+ }
31
+ var selection = editor.state.selection;
32
+ if (!selection.empty) {
33
+ return false;
34
+ }
35
+ return selection.from <= info.pos + info.size;
36
+ };
37
+ var handleDelete = function handleDelete(_ref2) {
38
+ var editor = _ref2.editor;
39
+ var info = getTitleSlotInfo(editor);
40
+ if (!info) {
41
+ return false;
42
+ }
43
+ var selection = editor.state.selection;
44
+ var from = selection.from,
45
+ to = selection.to;
46
+ var titleSlotEnd = info.pos + info.size;
47
+ if (selection.empty) {
48
+ return from <= titleSlotEnd;
49
+ }
50
+ var includesTitleSlot = from <= info.pos && to >= titleSlotEnd;
51
+ if (!includesTitleSlot) {
52
+ return false;
53
+ }
54
+ var tr = editor.state.tr;
55
+ var currentFrom = from;
56
+ var currentTo = to;
57
+ var currentTitlePos = info.pos;
58
+ if (currentFrom < currentTitlePos) {
59
+ var beforeEnd = Math.min(currentTitlePos, currentTo);
60
+ tr = tr.delete(currentFrom, beforeEnd);
61
+ var deletedBefore = beforeEnd - currentFrom;
62
+ currentTo -= deletedBefore;
63
+ currentTitlePos -= deletedBefore;
64
+ }
65
+ var currentTitleEnd = currentTitlePos + info.size;
66
+ if (currentTo > currentTitleEnd) {
67
+ tr = tr.delete(currentTitleEnd, currentTo);
68
+ }
69
+ editor.view.dispatch(tr);
70
+ return true;
18
71
  };
19
72
  function addKeyboardShortcuts() {
20
73
  return {
21
- ArrowLeft: validate,
22
- Backspace: validate,
23
- Delete: validate
74
+ ArrowLeft: handleArrowLeft,
75
+ Backspace: handleDelete,
76
+ Delete: handleDelete
24
77
  };
25
78
  }
26
79
  return {
@@ -187,7 +187,7 @@ var ChatInput = /*#__PURE__*/React.forwardRef(function (props, ref) {
187
187
  src: 'https://simg01.gaodunwangxiao.com/uploadimgs/tmp/upload/202509/24/6726e_20250924141448.png',
188
188
  alt: ""
189
189
  }))));
190
- }, [props.enableFileUpload, messageList]);
190
+ }, [props.enableFileUpload, messageList, agentObj === null || agentObj === void 0 ? void 0 : agentObj.openUploadFile]);
191
191
  var openChatCommunication = React.useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
192
192
  var params, res, _props$onConversation;
193
193
  return _regeneratorRuntime().wrap(function _callee$(_context) {
@@ -278,12 +278,11 @@ var ChatInput = /*#__PURE__*/React.forwardRef(function (props, ref) {
278
278
  };
279
279
  }(), [props.shortAsrClick]);
280
280
  var VoiceTools = React.useMemo(function () {
281
- var _agentObjRef$current;
282
281
  if (!props.enableVoiceChat && !props.enableVoiceRecord) {
283
282
  return null;
284
283
  }
285
284
  return /*#__PURE__*/React.createElement(VoiceCheckDialog, {
286
- trigger: /*#__PURE__*/React.createElement(React.Fragment, null, props.enableVoiceChat && ((_agentObjRef$current = agentObjRef.current) === null || _agentObjRef$current === void 0 ? void 0 : _agentObjRef$current.isEnableVoiceCall) === 1 && /*#__PURE__*/React.createElement(VoiceCommunication, {
285
+ trigger: /*#__PURE__*/React.createElement(React.Fragment, null, props.enableVoiceChat && (agentObj === null || agentObj === void 0 ? void 0 : agentObj.isEnableVoiceCall) === 1 && /*#__PURE__*/React.createElement(VoiceCommunication, {
287
286
  disabled: props.disabled || props.disableVoiceCommunication || props.isVoiceGetting || isMsgRecieving,
288
287
  onClick: openChatCommunication
289
288
  }), props.enableVoiceRecord && /*#__PURE__*/React.createElement(VoiceRecord, {
@@ -291,7 +290,7 @@ var ChatInput = /*#__PURE__*/React.forwardRef(function (props, ref) {
291
290
  disabled: props.disabled || isMsgRecieving || props.isVoiceGetting
292
291
  }))
293
292
  });
294
- }, [props.enableVoiceChat, props.enableVoiceRecord, props.disabled, props.disableVoiceCommunication, props.isVoiceGetting, isMsgRecieving, openChatCommunication, props.shortAsrClick]);
293
+ }, [props.enableVoiceChat, props.enableVoiceRecord, props.disabled, props.disableVoiceCommunication, props.isVoiceGetting, isMsgRecieving, openChatCommunication, props.shortAsrClick, agentObj === null || agentObj === void 0 ? void 0 : agentObj.isEnableVoiceCall]);
295
294
  var renderActionArea = React.useCallback(function (renderProps) {
296
295
  return /*#__PURE__*/React.createElement("div", {
297
296
  className: renderProps.className,
@@ -307,7 +306,7 @@ var ChatInput = /*#__PURE__*/React.forwardRef(function (props, ref) {
307
306
  marginLeft: 8
308
307
  }
309
308
  })), renderProps.menuItem);
310
- }, [VoiceTools, UploadFileTool]);
309
+ }, [VoiceTools, UploadFileTool, props.enableSourceQuote]);
311
310
  var onMessageSend = React.useCallback(function (content) {
312
311
  var _props$onBeforeSend, _props$onSend;
313
312
  var inputContents = content.inputContents || [];
@@ -44,6 +44,6 @@
44
44
  .chatInput {
45
45
  width: 100%;
46
46
  box-shadow: inset 0 2px #fff, 0 2px 10px rgba(84, 105, 140, 0.15);
47
- margin: 10px;
47
+ margin: 0px 10px 10px 10px;
48
48
  padding: 16px;
49
49
  }
@@ -71,7 +71,7 @@ var CommonChat = /*#__PURE__*/React.forwardRef(function (props, ref) {
71
71
  playTTSByText = _useChatVoice.playTTSByText,
72
72
  stopTTSByText = _useChatVoice.stopTTSByText,
73
73
  isPlaying = _useChatVoice.isPlaying;
74
- var _useCommonChatAPI = useCommonChatAPI(containerRef, platform, stopTTSByText, isPlaying, agentId, props === null || props === void 0 ? void 0 : props.reloadAgentKey, props === null || props === void 0 ? void 0 : props.resetKey, (_props$chatInputConfi2 = props.chatInputConfig) === null || _props$chatInputConfi2 === void 0 ? void 0 : _props$chatInputConfi2.onConversationCreated, (_props$chatInputConfi3 = props.chatInputConfig) === null || _props$chatInputConfi3 === void 0 ? void 0 : _props$chatInputConfi3.onSendEnd),
74
+ var _useCommonChatAPI = useCommonChatAPI(containerRef, platform, stopTTSByText, isPlaying, agentId, props === null || props === void 0 ? void 0 : props.reloadAgentKey, props === null || props === void 0 ? void 0 : props.resetKey, props === null || props === void 0 ? void 0 : props.interruptKey, (_props$chatInputConfi2 = props.chatInputConfig) === null || _props$chatInputConfi2 === void 0 ? void 0 : _props$chatInputConfi2.onConversationCreated, (_props$chatInputConfi3 = props.chatInputConfig) === null || _props$chatInputConfi3 === void 0 ? void 0 : _props$chatInputConfi3.onSendEnd),
75
75
  headerValue = _useCommonChatAPI.headerValue,
76
76
  msgLoading = _useCommonChatAPI.msgLoading,
77
77
  onSucessExcel = _useCommonChatAPI.onSucessExcel,
@@ -198,8 +198,7 @@ var CommonChat = /*#__PURE__*/React.forwardRef(function (props, ref) {
198
198
  }, /*#__PURE__*/React.createElement(IconChevronDown, {
199
199
  size: "large"
200
200
  }))), showInput && !isMoreLoading && /*#__PURE__*/React.createElement(ChatInput, _extends({
201
- ref: chatInputRef
202
- }, chatInputConfig, {
201
+ ref: chatInputRef,
203
202
  onSend: handleInputSend,
204
203
  disabled: disableSend || isMoreLoading,
205
204
  placeholder: (agentObj === null || agentObj === void 0 ? void 0 : agentObj.inputPrompt) || '',
@@ -217,7 +216,7 @@ var CommonChat = /*#__PURE__*/React.forwardRef(function (props, ref) {
217
216
  disableVoiceCommunication: disableVoiceCommunication,
218
217
  onHistoryReload: onHistoryReload,
219
218
  platform: platform
220
- })), showPrologue && messageList.length === 0 && !isMoreLoading && quickQuestionListPosition === 'bottom' && /*#__PURE__*/React.createElement(PresetAgentContent, {
219
+ }, chatInputConfig)), showPrologue && messageList.length === 0 && !isMoreLoading && quickQuestionListPosition === 'bottom' && /*#__PURE__*/React.createElement(PresetAgentContent, {
221
220
  prologue: '',
222
221
  questionList: (agentObj === null || agentObj === void 0 ? void 0 : agentObj.questionList) || [],
223
222
  setInputValue: setInputValue,
@@ -17,7 +17,7 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
17
17
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
18
18
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
19
19
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
20
- import React, { useCallback, useEffect, useRef } from 'react';
20
+ import React, { useCallback, useEffect, useRef, useLayoutEffect } from 'react';
21
21
  import { useAppDispatch, useAppSelector } from "../store/hooks";
22
22
  import { setMessageList } from "../store/slices/gimiMenuSlice";
23
23
  import useApi from "../apis/useApi";
@@ -66,11 +66,35 @@ var useChatHistory = function useChatHistory(checkUnfinishedMessage, scrollBotto
66
66
  var isMoreLoadingRef = useRef(isMoreLoading);
67
67
  var isMsgRecievingRef = useRef(isMsgRecieving);
68
68
  var conversationIdRef = useRef(conversationId);
69
+ var bussinessParamsRef = useRef(bussinessParams);
70
+ var historyScrollRef = useRef(null);
69
71
  messageListRef.current = messageList;
70
72
  isMsgRecievingRef.current = isMsgRecieving;
71
73
  agentObjRef.current = agentObj;
72
74
  isMoreLoadingRef.current = isMoreLoading;
73
75
  conversationIdRef.current = conversationId;
76
+ bussinessParamsRef.current = bussinessParams;
77
+
78
+ // 处理加载历史后的滚动补偿
79
+ useLayoutEffect(function () {
80
+ if (historyScrollRef.current && containerRef.current) {
81
+ var _historyScrollRef$cur = historyScrollRef.current,
82
+ height = _historyScrollRef$cur.height,
83
+ top = _historyScrollRef$cur.top;
84
+ var container = containerRef.current;
85
+ var newHeight = container.scrollHeight;
86
+ var heightDiff = newHeight - height;
87
+
88
+ // 只有当高度确实增加时才调整滚动位置,且只有当增加的高度大于阈值时才认为加载了新内容
89
+ if (heightDiff > 0) {
90
+ // 使用 requestAnimationFrame 确保在渲染后执行滚动调整
91
+ requestAnimationFrame(function () {
92
+ container.scrollTop = top + heightDiff;
93
+ });
94
+ }
95
+ historyScrollRef.current = null;
96
+ }
97
+ }, [messageList]);
74
98
 
75
99
  // 处理滚动事件
76
100
  useEffect(function () {
@@ -98,6 +122,7 @@ var useChatHistory = function useChatHistory(checkUnfinishedMessage, scrollBotto
98
122
 
99
123
  // 获取对话记录
100
124
  var getContentMessageList = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
125
+ var _bussinessParamsRef$c;
101
126
  var pageIndex,
102
127
  curPageSize,
103
128
  currentMessageList,
@@ -112,8 +137,6 @@ var useChatHistory = function useChatHistory(checkUnfinishedMessage, scrollBotto
112
137
  lastMessage,
113
138
  _lastUserRequestMessa,
114
139
  container,
115
- prevScrollHeight,
116
- prevScrollTop,
117
140
  _args = arguments;
118
141
  return _regeneratorRuntime().wrap(function _callee$(_context) {
119
142
  while (1) switch (_context.prev = _context.next) {
@@ -122,7 +145,7 @@ var useChatHistory = function useChatHistory(checkUnfinishedMessage, scrollBotto
122
145
  curPageSize = _args.length > 1 && _args[1] !== undefined ? _args[1] : param.pageSize;
123
146
  currentMessageList = messageListRef.current;
124
147
  currentAgentObj = agentObjRef.current;
125
- currentBussinessParams = _objectSpread({}, bussinessParams.bussinessParams);
148
+ currentBussinessParams = _objectSpread({}, ((_bussinessParamsRef$c = bussinessParamsRef.current) === null || _bussinessParamsRef$c === void 0 ? void 0 : _bussinessParamsRef$c.bussinessParams) || {});
126
149
  _context.prev = 5;
127
150
  params = {
128
151
  pageIndex: pageIndex,
@@ -139,7 +162,7 @@ var useChatHistory = function useChatHistory(checkUnfinishedMessage, scrollBotto
139
162
  case 10:
140
163
  res = _context.sent;
141
164
  if (!(res && res.status === 0)) {
142
- _context.next = 38;
165
+ _context.next = 36;
143
166
  break;
144
167
  }
145
168
  resData = formatFields(res.result.data, res.result.first ? [] : currentMessageList) || [];
@@ -166,56 +189,53 @@ var useChatHistory = function useChatHistory(checkUnfinishedMessage, scrollBotto
166
189
  setTimeout(function () {
167
190
  scrollBottomForce();
168
191
  }, 0);
169
- _context.next = 36;
192
+ _context.next = 34;
170
193
  break;
171
194
  case 26:
172
195
  container = containerRef.current;
173
- prevScrollHeight = (container === null || container === void 0 ? void 0 : container.scrollHeight) || 0;
174
- prevScrollTop = (container === null || container === void 0 ? void 0 : container.scrollTop) || 0; // 2. 更新数据
196
+ if (container) {
197
+ historyScrollRef.current = {
198
+ height: container.scrollHeight,
199
+ top: container.scrollTop
200
+ };
201
+ }
202
+
203
+ // 2. 更新数据
175
204
  // 判断是否需要重写推荐列表
176
205
  if (!((currentAgentObj === null || currentAgentObj === void 0 ? void 0 : currentAgentObj.isEnableRelated) === 1 && !((_lastUserRequestMessa = lastUserRequestMessage) !== null && _lastUserRequestMessa !== void 0 && _lastUserRequestMessa.relatedResourceList) && ((lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.moduleType) === 'end' || (lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.moduleType) === 'COMPLETED'))) {
177
- _context.next = 34;
206
+ _context.next = 33;
178
207
  break;
179
208
  }
180
- _context.next = 32;
209
+ _context.next = 31;
181
210
  return rewriteRecommendListFormHistory(newChatList, lastUserRequestMessage.chatId);
182
- case 32:
183
- _context.next = 35;
211
+ case 31:
212
+ _context.next = 34;
184
213
  break;
185
- case 34:
214
+ case 33:
186
215
  dispatch(setMessageList({
187
216
  messageList: newChatList
188
217
  }));
189
- case 35:
190
- // 3. 在下一帧补偿高度差
191
- requestAnimationFrame(function () {
192
- var newScrollHeight = (container === null || container === void 0 ? void 0 : container.scrollHeight) || 0;
193
- var heightDiff = newScrollHeight - prevScrollHeight;
194
- if (container) {
195
- container.scrollTop = prevScrollTop + heightDiff;
196
- }
197
- });
198
- case 36:
199
- _context.next = 39;
218
+ case 34:
219
+ _context.next = 37;
200
220
  break;
201
- case 38:
221
+ case 36:
202
222
  if (res.status === 1034) {
203
223
  Toast.error(res.message || '获取历史记录失败');
204
224
  }
205
- case 39:
225
+ case 37:
206
226
  setIsMoreLoading(false);
207
- _context.next = 45;
227
+ _context.next = 43;
208
228
  break;
209
- case 42:
210
- _context.prev = 42;
229
+ case 40:
230
+ _context.prev = 40;
211
231
  _context.t0 = _context["catch"](5);
212
232
  console.error(_context.t0);
213
- case 45:
233
+ case 43:
214
234
  case "end":
215
235
  return _context.stop();
216
236
  }
217
- }, _callee, null, [[5, 42]]);
218
- })), [conversationId, bussinessParams]);
237
+ }, _callee, null, [[5, 40]]);
238
+ })), [conversationId]);
219
239
  return {
220
240
  getContentMessageList: getContentMessageList,
221
241
  isMoreLoading: isMoreLoading,
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { IChatMessageItem } from "../interfaces/chatMessage";
3
- declare const useCommonChatAPI: (containerRef: React.RefObject<HTMLDivElement>, platform: string, stopTTSByText?: () => void, isPlaying?: boolean, agentId?: number, reloadAgentKey?: string, resetKey?: string, onConversationCreated?: ((conversationId: number) => void) | undefined, onSendEnd?: ((message: IChatMessageItem) => void) | undefined) => {
3
+ declare const useCommonChatAPI: (containerRef: React.RefObject<HTMLDivElement>, platform: string, stopTTSByText?: () => void, isPlaying?: boolean, agentId?: number, reloadAgentKey?: string, resetKey?: string, interruptKey?: string, onConversationCreated?: ((conversationId: number) => void) | undefined, onSendEnd?: ((message: IChatMessageItem) => void) | undefined) => {
4
4
  headerValue: string;
5
5
  getHeaderValue: (conversationId: number) => Promise<void>;
6
6
  msgLoading: boolean;
@@ -32,7 +32,7 @@ import { useChatRecommend } from "./useChatRecommend";
32
32
  import { set, cloneDeep } from 'lodash';
33
33
  import { FileStatus } from "../interfaces/fileInterface";
34
34
  import useChatHistory from "./useChatHistory";
35
- var useCommonChatAPI = function useCommonChatAPI(containerRef, platform, stopTTSByText, isPlaying, agentId, reloadAgentKey, resetKey, onConversationCreated, onSendEnd) {
35
+ var useCommonChatAPI = function useCommonChatAPI(containerRef, platform, stopTTSByText, isPlaying, agentId, reloadAgentKey, resetKey, interruptKey, onConversationCreated, onSendEnd) {
36
36
  var _useApi = useApi(),
37
37
  getMessageTitle = _useApi.getMessageTitle,
38
38
  stopStreamOut = _useApi.stopStreamOut,
@@ -131,6 +131,8 @@ var useCommonChatAPI = function useCommonChatAPI(containerRef, platform, stopTTS
131
131
  var tokenRef = useRef(token || '');
132
132
  // 重置key ref
133
133
  var resetKeyRef = useRef(resetKey || '');
134
+ // 中断key ref
135
+ var interruptKeyRef = useRef(interruptKey || '');
134
136
 
135
137
  // 更细Ref的值
136
138
  messageListRef.current = messageList;
@@ -1272,6 +1274,25 @@ var useCommonChatAPI = function useCommonChatAPI(containerRef, platform, stopTTS
1272
1274
  inputModelRef.current = _inputModel;
1273
1275
  handleSend('重试');
1274
1276
  }, []);
1277
+ React.useEffect(function () {
1278
+ if (interruptKey !== interruptKeyRef.current) {
1279
+ interruptKeyRef.current = interruptKey || '';
1280
+ if (streamEsAbortRef.current && step.current === 2) {
1281
+ handleInterrupt();
1282
+ } else {
1283
+ var _controllerRef$curren2;
1284
+ (_controllerRef$curren2 = controllerRef.current) === null || _controllerRef$curren2 === void 0 || _controllerRef$curren2.abort();
1285
+ if (valueRef.current) {
1286
+ setStatus(1);
1287
+ } else {
1288
+ setStatus(0);
1289
+ }
1290
+ setMsgLoading(false);
1291
+ step.current = 0; // 重置步骤状态
1292
+ onSendEnd === null || onSendEnd === void 0 || onSendEnd(messageList[messageList.length - 1]);
1293
+ }
1294
+ }
1295
+ }, [interruptKey, onSendEnd, handleInterrupt]);
1275
1296
  return {
1276
1297
  headerValue: headerValue,
1277
1298
  getHeaderValue: getHeaderValue,
@@ -7,7 +7,6 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
7
7
  import React from 'react';
8
8
  import { throttle } from 'lodash';
9
9
  var useScroll = function useScroll(containerRef) {
10
- var _containerRef$current4;
11
10
  var bottomPosition = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 20;
12
11
  var _React$useState = React.useState(0),
13
12
  _React$useState2 = _slicedToArray(_React$useState, 2),
@@ -51,8 +50,16 @@ var useScroll = function useScroll(containerRef) {
51
50
 
52
51
  // 基础滚动到底部
53
52
  var scrollBottom = React.useCallback(function () {
54
- if (containerRef.current) {
55
- containerRef.current.scrollTop = containerRef.current.scrollHeight;
53
+ var container = containerRef.current;
54
+ if (container) {
55
+ // 使用 requestAnimationFrame 确保在浏览器渲染前执行,
56
+ // 并且如果一次不行,尝试在下一帧再做一次,以应对复杂的布局变化
57
+ var doScroll = function doScroll() {
58
+ container.scrollTop = container.scrollHeight;
59
+ };
60
+ requestAnimationFrame(doScroll);
61
+ // 双重保证
62
+ setTimeout(doScroll, 0);
56
63
  }
57
64
  }, [containerRef.current]);
58
65
 
@@ -66,12 +73,13 @@ var useScroll = function useScroll(containerRef) {
66
73
  // 强制滚动到底部
67
74
  var scrollBottomForce = React.useCallback(function () {
68
75
  var animate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
69
- if (containerRef.current) {
76
+ var container = containerRef.current;
77
+ if (container) {
70
78
  markUserInteraction(false); // 重置为用户非交互状态
71
79
 
72
80
  if (animate) {
73
- containerRef.current.scrollTo({
74
- top: containerRef.current.scrollHeight,
81
+ container.scrollTo({
82
+ top: container.scrollHeight,
75
83
  behavior: 'smooth'
76
84
  });
77
85
  } else {
@@ -151,22 +159,36 @@ var useScroll = function useScroll(containerRef) {
151
159
 
152
160
  // 内容变化时自动滚动
153
161
  React.useEffect(function () {
154
- if (!containerRef.current || refs.isUserInteracting) return;
155
- var _containerRef$current3 = containerRef.current,
156
- scrollTop = _containerRef$current3.scrollTop,
157
- scrollHeight = _containerRef$current3.scrollHeight,
158
- clientHeight = _containerRef$current3.clientHeight;
159
- var distanceToBottom = scrollHeight - clientHeight - scrollTop;
160
-
161
- // 只有当距离底部较近时才自动滚动
162
- if (distanceToBottom <= bottomPosition * 2) {
163
- requestAnimationFrame(function () {
164
- if (containerRef.current) {
165
- containerRef.current.scrollTop = containerRef.current.scrollHeight;
166
- }
167
- });
168
- }
169
- }, [(_containerRef$current4 = containerRef.current) === null || _containerRef$current4 === void 0 ? void 0 : _containerRef$current4.scrollHeight, bottomPosition]);
162
+ var container = containerRef.current;
163
+ if (!container) return;
164
+
165
+ // 使用 MutationObserver 监听内容变化
166
+ var observer = new MutationObserver(function () {
167
+ if (refs.isUserInteracting) return;
168
+ var scrollTop = container.scrollTop,
169
+ scrollHeight = container.scrollHeight,
170
+ clientHeight = container.clientHeight;
171
+ var distanceToBottom = scrollHeight - clientHeight - scrollTop;
172
+
173
+ // 如果之前就在底部附近,则在新内容加入时保持在底部
174
+ // 注意:这里的判定逻辑需要考虑到新内容可能还没撑开高度
175
+ // 所以我们直接尝试在下一帧滚动
176
+ if (distanceToBottom <= bottomPosition * 5) {
177
+ // 稍微放宽判定范围,因为新内容可能已经改变了 scrollHeight
178
+ requestAnimationFrame(function () {
179
+ container.scrollTop = container.scrollHeight;
180
+ });
181
+ }
182
+ });
183
+ observer.observe(container, {
184
+ childList: true,
185
+ subtree: true,
186
+ characterData: true
187
+ });
188
+ return function () {
189
+ return observer.disconnect();
190
+ };
191
+ }, [containerRef.current, bottomPosition]);
170
192
  return [throttledScrollToBottom, scrollBottomForce, currentPosition, scrollBottom, updateScrollHeight, isScrolling, isUserScroll];
171
193
  };
172
194
  export default useScroll;
@@ -115,6 +115,7 @@ export interface CommonChatProps {
115
115
  messageConfig?: MessageConfig;
116
116
  resetKey?: string;
117
117
  reloadAgentKey?: string;
118
+ interruptKey?: string;
118
119
  }
119
120
 
120
121
  export interface MessageConfig {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myun/gimi-chat",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "> TODO: description",
5
5
  "homepage": "",
6
6
  "license": "ISC",