UNPKG

@ant-design/x-sdk

Version:

placeholder for @ant-design/x-sdk

291 lines (286 loc) 10.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = useXChat; var _rcUtil = require("rc-util"); var _react = _interopRequireWildcard(require("react")); var _store = require("./store"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } var MessageStatusEnum = /*#__PURE__*/function (MessageStatusEnum) { MessageStatusEnum["local"] = "local"; MessageStatusEnum["loading"] = "loading"; MessageStatusEnum["updating"] = "updating"; MessageStatusEnum["success"] = "success"; MessageStatusEnum["error"] = "error"; MessageStatusEnum["abort"] = "abort"; return MessageStatusEnum; }(MessageStatusEnum || {}); function toArray(item) { return Array.isArray(item) ? item : [item]; } const IsRequestingMap = new Map(); function useXChat(config) { const { defaultMessages, requestFallback, requestPlaceholder, parser, provider, conversationKey } = config; // ========================= Agent Messages ========================= const idRef = _react.default.useRef(0); const requestHandlerRef = _react.default.useRef(undefined); const [isRequesting, setIsRequesting] = (0, _react.useState)(false); const { messages, setMessages, getMessages, setMessage } = (0, _store.useChatStore)(() => (defaultMessages || []).map((info, index) => ({ id: `default_${index}`, status: 'local', ...info })), conversationKey); const createMessage = (message, status, extra) => { const msg = { id: `msg_${idRef.current}`, message, status }; if (extra) { msg.extra = extra; } idRef.current += 1; return msg; }; // ========================= BubbleMessages ========================= const parsedMessages = _react.default.useMemo(() => { const list = []; messages.forEach(agentMsg => { const rawParsedMsg = parser ? parser(agentMsg.message) : agentMsg.message; const bubbleMsgs = toArray(rawParsedMsg); bubbleMsgs.forEach((bubbleMsg, bubbleMsgIndex) => { let key = agentMsg.id; if (bubbleMsgs.length > 1) { key = `${key}_${bubbleMsgIndex}`; } list.push({ id: key, message: bubbleMsg, status: agentMsg.status }); }); }); return list; }, [messages]); // ============================ Request ============================= const getFilteredMessages = msgs => msgs.filter(info => info.status !== 'loading').map(info => info.message); provider?.injectGetMessages(() => { return getFilteredMessages(getMessages()); }); requestHandlerRef.current = provider?.request; // For agent to use. Will filter out loading and error message const getRequestMessages = () => getFilteredMessages(getMessages()); const innerOnRequest = (requestParams, opts) => { if (!provider) { return; } const { updatingId, reload } = opts || {}; let loadingMsgId = null; const localMessage = provider.transformLocalMessage(requestParams); const messages = (Array.isArray(localMessage) ? localMessage : [localMessage]).map(message => createMessage(message, 'local', opts?.extra)); if (reload) { loadingMsgId = updatingId; setMessages(ori => { const nextMessages = [...ori]; if (requestPlaceholder) { let placeholderMsg; if (typeof requestPlaceholder === 'function') { // typescript has bug that not get real return type when use `typeof function` check placeholderMsg = requestPlaceholder(requestParams, { messages: getFilteredMessages(nextMessages) }); } else { placeholderMsg = requestPlaceholder; } nextMessages.forEach(info => { if (info.id === updatingId) { info.status = 'loading'; info.message = placeholderMsg; if (opts?.extra) { info.extra = opts?.extra; } } }); } return nextMessages; }); } else { // Add placeholder message setMessages(ori => { let nextMessages = [...ori, ...messages]; if (requestPlaceholder) { let placeholderMsg; if (typeof requestPlaceholder === 'function') { // typescript has bug that not get real return type when use `typeof function` check placeholderMsg = requestPlaceholder(requestParams, { messages: getFilteredMessages(nextMessages) }); } else { placeholderMsg = requestPlaceholder; } const loadingMsg = createMessage(placeholderMsg, 'loading'); loadingMsgId = loadingMsg.id; nextMessages = [...nextMessages, loadingMsg]; } return nextMessages; }); } // Request let updatingMsgId = null; const updateMessage = (status, chunk, chunks, responseHeaders) => { let msg = getMessages().find(info => info.id === updatingMsgId); if (!msg) { if (reload && updatingId) { msg = getMessages().find(info => info.id === updatingId); if (msg) { msg.status = status; msg.message = provider.transformMessage({ chunk, status, chunks, responseHeaders }); setMessages(ori => { return [...ori]; }); updatingMsgId = msg.id; } } else { // Create if not exist const transformData = provider.transformMessage({ chunk, status, chunks, responseHeaders }); msg = createMessage(transformData, status); setMessages(ori => { const oriWithoutPending = ori.filter(info => info.id !== loadingMsgId); return [...oriWithoutPending, msg]; }); updatingMsgId = msg.id; } } else { // Update directly setMessages(ori => { return ori.map(info => { if (info.id === updatingMsgId) { const transformData = provider.transformMessage({ originMessage: info.message, chunk, chunks, status, responseHeaders }); return { ...info, message: transformData, status }; } return info; }); }); } return msg; }; provider.injectRequest({ onUpdate: (chunk, headers) => { updateMessage('updating', chunk, [], headers); }, onSuccess: (chunks, headers) => { setIsRequesting(false); conversationKey && IsRequestingMap.delete(conversationKey); updateMessage('success', undefined, chunks, headers); }, onError: async error => { setIsRequesting(false); conversationKey && IsRequestingMap.delete(conversationKey); if (requestFallback) { let fallbackMsg; // Update as error if (typeof requestFallback === 'function') { // typescript has bug that not get real return type when use `typeof function` check const messages = getRequestMessages(); const msg = getMessages().find(info => info.id === loadingMsgId || info.id === updatingMsgId); fallbackMsg = await requestFallback(requestParams, { error, messageInfo: msg, messages }); } else { fallbackMsg = requestFallback; } setMessages(ori => [...ori.filter(info => info.id !== loadingMsgId && info.id !== updatingMsgId), createMessage(fallbackMsg, error.name === 'AbortError' ? 'abort' : 'error')]); } else { // Remove directly setMessages(ori => { return ori.map(info => { if (info.id === loadingMsgId || info.id === updatingMsgId) { return { ...info, status: error.name === 'AbortError' ? 'abort' : 'error' }; } return info; }); }); } } }); setIsRequesting(true); conversationKey && IsRequestingMap.set(conversationKey, true); provider.request.run(provider.transformParams(requestParams, provider.request.options)); }; const onRequest = (0, _rcUtil.useEvent)((requestParams, opts) => { if (!provider) { throw new Error('provider is required'); } innerOnRequest(requestParams, opts); }); const onReload = (id, requestParams, opts) => { if (!provider) { throw new Error('provider is required'); } if (!id || !getMessages().find(info => info.id === id)) { throw new Error(`message [${id}] is not found`); } innerOnRequest(requestParams, { updatingId: id, reload: true, extra: opts?.extra }); }; return { onRequest, messages, parsedMessages, setMessages, setMessage, abort: () => { if (!provider) { throw new Error('provider is required'); } requestHandlerRef.current?.abort(); }, isRequesting: conversationKey ? IsRequestingMap?.get(conversationKey) || false : isRequesting, onReload }; }