@myun/gimi-chat 0.1.5 → 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.
@@ -12,5 +12,5 @@ interface AiExplainProps {
12
12
  setSpeech: (value: boolean) => void;
13
13
  handleHangUp?: () => void;
14
14
  }
15
- declare const AiExplain: React.ForwardRefExoticComponent<AiExplainProps & React.RefAttributes<unknown>>;
15
+ declare const AiExplain: ({ paper, setSpeech, handleHangUp }: AiExplainProps) => React.ReactPortal;
16
16
  export default AiExplain;
@@ -18,7 +18,7 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
18
18
  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; }
19
19
  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; } }
20
20
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
21
- import React, { forwardRef, useEffect, useMemo, useRef, useState } from 'react';
21
+ import React, { useEffect, useMemo, useRef, useState } from 'react';
22
22
  import LottieImg from "../lottie-img";
23
23
  import styles from "./index.module.css";
24
24
  import classNames from 'classnames';
@@ -37,7 +37,7 @@ import { useDispatch } from 'react-redux';
37
37
 
38
38
  // 2. 定义组件完整的 Props 接口
39
39
 
40
- var AiExplain = /*#__PURE__*/forwardRef(function (_ref) {
40
+ var AiExplain = function AiExplain(_ref) {
41
41
  var paper = _ref.paper,
42
42
  setSpeech = _ref.setSpeech,
43
43
  _ref$handleHangUp = _ref.handleHangUp,
@@ -1052,5 +1052,5 @@ var AiExplain = /*#__PURE__*/forwardRef(function (_ref) {
1052
1052
  type: "icon-a-mti-guaduanshi",
1053
1053
  size: 34
1054
1054
  }))))))))), document.body);
1055
- });
1055
+ };
1056
1056
  export default AiExplain;
@@ -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 {
@@ -166,7 +166,7 @@ var ChatInput = /*#__PURE__*/React.forwardRef(function (props, ref) {
166
166
  return Toast.info('最多上传一个文件哦');
167
167
  };
168
168
  var UploadFileTool = React.useMemo(function () {
169
- if (!props.enableFileUpload || messageList.length > 0) {
169
+ if (!props.enableFileUpload || messageList.length > 0 || (agentObj === null || agentObj === void 0 ? void 0 : agentObj.openUploadFile) === 0) {
170
170
  return null;
171
171
  }
172
172
  return /*#__PURE__*/React.createElement(FileUpload, {
@@ -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 || [];
@@ -393,14 +392,19 @@ var ChatInput = /*#__PURE__*/React.forwardRef(function (props, ref) {
393
392
  };
394
393
  React.useEffect(function () {
395
394
  if (messageList.length === 0 && !conversationIdRef.current) {
396
- var _inputRef$current7;
397
395
  var defaultContent = transformToInputSlots(props.defaultPrompt || '', props.titleSlot || '');
398
- (_inputRef$current7 = inputRef.current) === null || _inputRef$current7 === void 0 || _inputRef$current7.setContent(defaultContent);
396
+ // 解决 Semi UI AIChatInput setContent useEffect 中触发 flushSync 警告的问题
397
+ Promise.resolve().then(function () {
398
+ var _inputRef$current7;
399
+ (_inputRef$current7 = inputRef.current) === null || _inputRef$current7 === void 0 || _inputRef$current7.setContent(defaultContent);
400
+ });
399
401
  setHasContent(!!props.defaultPrompt);
400
402
  preInputValueRef.current = props.defaultPrompt || '';
401
403
  } else {
402
- var _inputRef$current8;
403
- (_inputRef$current8 = inputRef.current) === null || _inputRef$current8 === void 0 || _inputRef$current8.setContent('');
404
+ Promise.resolve().then(function () {
405
+ var _inputRef$current8;
406
+ (_inputRef$current8 = inputRef.current) === null || _inputRef$current8 === void 0 || _inputRef$current8.setContent('');
407
+ });
404
408
  setHasContent(false);
405
409
  }
406
410
  }, [props.defaultPrompt, messageList.length, props.titleSlot]);
@@ -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
  }
@@ -2,7 +2,7 @@ function _extends() { _extends = Object.assign ? Object.assign.bind() : function
2
2
  import React from 'react';
3
3
  import { store } from "../../store";
4
4
  import { useAppDispatch, useAppSelector } from "../../store/hooks";
5
- import { setBaseUrl, setToken, setPlatform, setConversationId, setAgentDetail, setBussinessParams, setMessageList } from "../../store/slices/gimiMenuSlice";
5
+ import { setBaseUrl, setToken, setPlatform, setConversationId, setAgentDetail, setBussinessParams } from "../../store/slices/gimiMenuSlice";
6
6
  import useCommonChatAPI from "../../hooks/useCommonChatAPI";
7
7
  import { replaceBraces } from "../../utils/tools";
8
8
  import styles from "./index.module.css";
@@ -49,7 +49,6 @@ var CommonChat = /*#__PURE__*/React.forwardRef(function (props, ref) {
49
49
  var dispatch = useAppDispatch();
50
50
  var containerRef = React.useRef(null);
51
51
  var chatInputRef = React.useRef(null);
52
- var resetKeyRef = React.useRef('');
53
52
  var messageList = useAppSelector(function (state) {
54
53
  return state.gimiMenu.messageList;
55
54
  });
@@ -72,7 +71,7 @@ var CommonChat = /*#__PURE__*/React.forwardRef(function (props, ref) {
72
71
  playTTSByText = _useChatVoice.playTTSByText,
73
72
  stopTTSByText = _useChatVoice.stopTTSByText,
74
73
  isPlaying = _useChatVoice.isPlaying;
75
- var _useCommonChatAPI = useCommonChatAPI(containerRef, platform, stopTTSByText, isPlaying, agentId, props === null || props === void 0 ? void 0 : props.reloadAgentKey, (_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),
76
75
  headerValue = _useCommonChatAPI.headerValue,
77
76
  msgLoading = _useCommonChatAPI.msgLoading,
78
77
  onSucessExcel = _useCommonChatAPI.onSucessExcel,
@@ -110,27 +109,22 @@ var CommonChat = /*#__PURE__*/React.forwardRef(function (props, ref) {
110
109
  dispatch(setPlatform({
111
110
  platform: platform
112
111
  }));
112
+ }, [baseUrl, token, platform]);
113
+ React.useEffect(function () {
113
114
  dispatch(setConversationId({
114
115
  conversationId: conversationId || null
115
116
  }));
117
+ }, [conversationId]);
118
+ React.useEffect(function () {
116
119
  dispatch(setAgentDetail({
117
120
  agentDetail: agentDetail || {}
118
121
  }));
122
+ }, [agentDetail]);
123
+ React.useEffect(function () {
119
124
  dispatch(setBussinessParams({
120
125
  bussinessParams: bussinessParams || {}
121
126
  }));
122
- }, [baseUrl, token, agentDetail, platform, conversationId, bussinessParams]);
123
- React.useEffect(function () {
124
- if (props.resetKey !== resetKeyRef.current) {
125
- resetKeyRef.current = props.resetKey || '';
126
- dispatch(setConversationId({
127
- conversationId: null
128
- }));
129
- dispatch(setMessageList({
130
- messageList: []
131
- }));
132
- }
133
- }, [props.resetKey]);
127
+ }, [bussinessParams]);
134
128
  React.useEffect(function () {
135
129
  if (bussinessParams !== null && bussinessParams !== void 0 && bussinessParams.QUESTION_ID && bussinessParams !== null && bussinessParams !== void 0 && bussinessParams.ANSWER_ID && businessType === 'correction' && storedBaseUrl && storedToken) {
136
130
  startAICorrection(bussinessParams.ANSWER_ID, bussinessParams.QUESTION_ID);
@@ -151,20 +145,16 @@ var CommonChat = /*#__PURE__*/React.forwardRef(function (props, ref) {
151
145
  var _chatInputRef$current;
152
146
  (_chatInputRef$current = chatInputRef.current) === null || _chatInputRef$current === void 0 || _chatInputRef$current.setValue(content);
153
147
  }, []);
154
-
155
- // const onInputValueChange = React.useCallback((content: string) => {
156
- // setInputValue(content);
157
- // }, []);
158
-
159
148
  var handleInputSend = React.useCallback(function (val, agent, isSystemAuto) {
160
149
  var _chatInputRef$current2;
161
150
  (_chatInputRef$current2 = chatInputRef.current) === null || _chatInputRef$current2 === void 0 || _chatInputRef$current2.setValue('');
151
+ var conversationId = store.getState().gimiMenu.conversationId;
162
152
  if (!conversationId) {
163
153
  startConversationAndChat(val);
164
154
  return;
165
155
  }
166
156
  handleSend(val, agent, isSystemAuto);
167
- }, [handleSend, startConversationAndChat, conversationId]);
157
+ }, [handleSend, startConversationAndChat]);
168
158
  return /*#__PURE__*/React.createElement("div", {
169
159
  className: styles.main,
170
160
  id: "myun_gimi_design_chat"
@@ -208,8 +198,7 @@ var CommonChat = /*#__PURE__*/React.forwardRef(function (props, ref) {
208
198
  }, /*#__PURE__*/React.createElement(IconChevronDown, {
209
199
  size: "large"
210
200
  }))), showInput && !isMoreLoading && /*#__PURE__*/React.createElement(ChatInput, _extends({
211
- ref: chatInputRef
212
- }, chatInputConfig, {
201
+ ref: chatInputRef,
213
202
  onSend: handleInputSend,
214
203
  disabled: disableSend || isMoreLoading,
215
204
  placeholder: (agentObj === null || agentObj === void 0 ? void 0 : agentObj.inputPrompt) || '',
@@ -227,7 +216,7 @@ var CommonChat = /*#__PURE__*/React.forwardRef(function (props, ref) {
227
216
  disableVoiceCommunication: disableVoiceCommunication,
228
217
  onHistoryReload: onHistoryReload,
229
218
  platform: platform
230
- }, props.chatInputConfig)), showPrologue && messageList.length === 0 && !isMoreLoading && quickQuestionListPosition === 'bottom' && /*#__PURE__*/React.createElement(PresetAgentContent, {
219
+ }, chatInputConfig)), showPrologue && messageList.length === 0 && !isMoreLoading && quickQuestionListPosition === 'bottom' && /*#__PURE__*/React.createElement(PresetAgentContent, {
231
220
  prologue: '',
232
221
  questionList: (agentObj === null || agentObj === void 0 ? void 0 : agentObj.questionList) || [],
233
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, 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, 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,
@@ -129,6 +129,10 @@ var useCommonChatAPI = function useCommonChatAPI(containerRef, platform, stopTTS
129
129
  var historyListRef = useRef(historyList || []);
130
130
  var baseUrlRef = useRef(baseUrl || '');
131
131
  var tokenRef = useRef(token || '');
132
+ // 重置key ref
133
+ var resetKeyRef = useRef(resetKey || '');
134
+ // 中断key ref
135
+ var interruptKeyRef = useRef(interruptKey || '');
132
136
 
133
137
  // 更细Ref的值
134
138
  messageListRef.current = messageList;
@@ -328,7 +332,8 @@ var useCommonChatAPI = function useCommonChatAPI(containerRef, platform, stopTTS
328
332
  }
329
333
  setMsgLoading(false);
330
334
  step.current = 0; // 重置步骤状态
331
- case 16:
335
+ onSendEnd === null || onSendEnd === void 0 || onSendEnd(messageList[messageList.length - 1]);
336
+ case 17:
332
337
  case "end":
333
338
  return _context3.stop();
334
339
  }
@@ -607,7 +612,6 @@ var useCommonChatAPI = function useCommonChatAPI(containerRef, platform, stopTTS
607
612
  dispatch(setMessageList({
608
613
  messageList: newMessageList
609
614
  }));
610
- onSendEnd === null || onSendEnd === void 0 || onSendEnd(newMessageList[newMessageList.length - 1]);
611
615
  if (type === 'ask' || type === 'skill') {
612
616
  scrollBottomForce();
613
617
  }
@@ -616,18 +620,19 @@ var useCommonChatAPI = function useCommonChatAPI(containerRef, platform, stopTTS
616
620
  // 获取最新的agent详情,防止redux异步更新
617
621
  agentDetail = agentInfo || agentObjRef.current;
618
622
  if (!((agentDetail === null || agentDetail === void 0 ? void 0 : agentDetail.isEnableRelated) === 1 && (type === 'end' || type === 'COMPLETED'))) {
619
- _context8.next = 11;
623
+ _context8.next = 10;
620
624
  break;
621
625
  }
622
- _context8.next = 11;
626
+ _context8.next = 10;
623
627
  return getRecommendList(newMessageList, lastId, statusRef.current);
624
- case 11:
628
+ case 10:
625
629
  if (valueRef.current) {
626
630
  setStatus(1);
627
631
  } else {
628
632
  setStatus(0);
629
633
  }
630
634
  setMsgLoading(false);
635
+ onSendEnd === null || onSendEnd === void 0 || onSendEnd(newMessageList[newMessageList.length - 1]);
631
636
  case 13:
632
637
  case "end":
633
638
  return _context8.stop();
@@ -657,6 +662,7 @@ var useCommonChatAPI = function useCommonChatAPI(containerRef, platform, stopTTS
657
662
  setStatus(0);
658
663
  }
659
664
  setMsgLoading(false);
665
+ onSendEnd === null || onSendEnd === void 0 || onSendEnd(newMessageList[newMessageList.length - 1]);
660
666
  });
661
667
  case 5:
662
668
  case "end":
@@ -996,14 +1002,15 @@ var useCommonChatAPI = function useCommonChatAPI(containerRef, platform, stopTTS
996
1002
  } else {
997
1003
  Toast.error(res.message);
998
1004
  }
999
- _context14.next = 17;
1005
+ _context14.next = 18;
1000
1006
  break;
1001
1007
  case 13:
1002
1008
  _context14.prev = 13;
1003
1009
  _context14.t0 = _context14["catch"](5);
1010
+ Toast.error('创建会话失败');
1004
1011
  console.log('error', _context14.t0);
1005
1012
  setMsgLoading(false);
1006
- case 17:
1013
+ case 18:
1007
1014
  case "end":
1008
1015
  return _context14.stop();
1009
1016
  }
@@ -1012,12 +1019,26 @@ var useCommonChatAPI = function useCommonChatAPI(containerRef, platform, stopTTS
1012
1019
  return function (_x25) {
1013
1020
  return _ref14.apply(this, arguments);
1014
1021
  };
1015
- }(), [fetchAgentDetail]);
1022
+ }(), []);
1016
1023
  React.useEffect(function () {
1017
1024
  if (agentId && baseUrl) {
1018
1025
  fetchAgentDetail(agentId);
1019
1026
  }
1020
1027
  }, [agentId, reloadAgentKey, baseUrl]);
1028
+ React.useEffect(function () {
1029
+ if (resetKey !== resetKeyRef.current) {
1030
+ var _controllerRef$curren, _streamEsAbortRef$cur;
1031
+ resetKeyRef.current = resetKey || '';
1032
+ (_controllerRef$curren = controllerRef.current) === null || _controllerRef$curren === void 0 || _controllerRef$curren.abort();
1033
+ (_streamEsAbortRef$cur = streamEsAbortRef.current) === null || _streamEsAbortRef$cur === void 0 || _streamEsAbortRef$cur.abort();
1034
+ dispatch(setConversationId({
1035
+ conversationId: null
1036
+ }));
1037
+ dispatch(setMessageList({
1038
+ messageList: []
1039
+ }));
1040
+ }
1041
+ }, [resetKey]);
1021
1042
  var handleSend = React.useCallback( /*#__PURE__*/function () {
1022
1043
  var _ref15 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee15(val) {
1023
1044
  var agent,
@@ -1253,6 +1274,25 @@ var useCommonChatAPI = function useCommonChatAPI(containerRef, platform, stopTTS
1253
1274
  inputModelRef.current = _inputModel;
1254
1275
  handleSend('重试');
1255
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]);
1256
1296
  return {
1257
1297
  headerValue: headerValue,
1258
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.5",
3
+ "version": "0.1.7",
4
4
  "description": "> TODO: description",
5
5
  "homepage": "",
6
6
  "license": "ISC",