@mujian/js-sdk 0.0.6-beta.9 → 0.0.6-beta.91
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.
- package/dist/events/index.d.ts +31 -3
- package/dist/index.d.ts +16 -39
- package/dist/index.js +360 -62
- package/dist/lite.d.ts +73 -0
- package/dist/lite.js +119 -0
- package/dist/modules/ai/chat/chat.d.ts +46 -4
- package/dist/modules/ai/chat/index.d.ts +1 -1
- package/dist/modules/ai/chat/message/index.d.ts +3 -7
- package/dist/modules/ai/chat/settings/index.d.ts +1 -2
- package/dist/modules/ai/chat/settings/persona.d.ts +0 -8
- package/dist/modules/ai/index.d.ts +3 -2
- package/dist/modules/ai/openai/chat.d.ts +22 -0
- package/dist/modules/ai/openai/completions.d.ts +17 -0
- package/dist/modules/ai/openai/images.d.ts +17 -0
- package/dist/modules/ai/openai/index.d.ts +4 -0
- package/dist/modules/ai/openai/responses.d.ts +18 -0
- package/dist/modules/ai/text/index.d.ts +9 -2
- package/dist/modules/config.d.ts +17 -0
- package/dist/modules/utils/clipboard.d.ts +5 -0
- package/dist/modules/utils/index.d.ts +4 -0
- package/dist/react/chat/useChat/index.d.ts +34 -8
- package/dist/react/chat/useChat/inner/chatStreaming.d.ts +4 -2
- package/dist/react/chat/useChat/message.d.ts +31 -13
- package/dist/react/components/MdRenderer/index.d.ts +5 -3
- package/dist/react/components/MdRenderer/utils/height.d.ts +0 -0
- package/dist/react/components/MdRenderer/utils/iframe.d.ts +9 -0
- package/dist/react/components/MdRenderer/utils/scripts.d.ts +4 -0
- package/dist/react/components/MujianSpinner/index.d.ts +7 -0
- package/dist/react/components/index.d.ts +1 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/mjEngine/index.d.ts +48 -0
- package/dist/react.css +65 -4
- package/dist/react.js +834 -188
- package/dist/types/index.d.ts +39 -0
- package/dist/umd/index.js +2 -0
- package/dist/umd/index.js.LICENSE.txt +7 -0
- package/dist/umd/lite.js +2 -0
- package/dist/umd/lite.js.LICENSE.txt +7 -0
- package/dist/umd/react.css +1 -0
- package/dist/umd/react.js +133 -0
- package/dist/umd/react.js.LICENSE.txt +31 -0
- package/dist/utils/is-network-error.d.ts +1 -0
- package/dist/utils/log.d.ts +4 -0
- package/package.json +16 -6
- package/dist/modules/ai/chat/settings/model.d.ts +0 -24
- /package/dist/react/components/MdRenderer/{utils.d.ts → utils/md.d.ts} +0 -0
package/dist/react.js
CHANGED
|
@@ -1,11 +1,183 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import react, { createContext, forwardRef, useCallback, useContext, useEffect, useState } from "react";
|
|
3
|
-
import { jsx } from "react/jsx-runtime";
|
|
1
|
+
import { useInfiniteScroll, useLatest, useRequest, useUpdateEffect } from "ahooks";
|
|
2
|
+
import react, { createContext, forwardRef, useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
import css_tools from "@adobe/css-tools";
|
|
5
5
|
import dompurify from "dompurify";
|
|
6
6
|
import showdown from "showdown";
|
|
7
|
+
import { v4 } from "uuid";
|
|
7
8
|
import postmate from "postmate";
|
|
8
9
|
import { Virtualizer } from "virtua";
|
|
10
|
+
import { get } from "lodash-es";
|
|
11
|
+
import { produce } from "immer";
|
|
12
|
+
const adjustIframeHeight = (iframeId)=>`
|
|
13
|
+
(function () {
|
|
14
|
+
let scheduled = false;
|
|
15
|
+
function measureAndPost() {
|
|
16
|
+
scheduled = false;
|
|
17
|
+
try {
|
|
18
|
+
const doc = window.document;
|
|
19
|
+
const body = doc.body;
|
|
20
|
+
const html = doc.documentElement;
|
|
21
|
+
if (!body || !html) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
let height = 0;
|
|
25
|
+
// srcdoc 模式: 只用 body.scrollHeight
|
|
26
|
+
height = body.scrollHeight;
|
|
27
|
+
if (!Number.isFinite(height) || height <= 0) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
window.parent.postMessage({ type: 'MJ_ADJUST_IFRAME_HEIGHT', iframe_id: \`${iframeId}\`, height: height }, '*');
|
|
31
|
+
} catch {
|
|
32
|
+
console.error('Error measuring iframe height');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function postIframeHeight() {
|
|
37
|
+
if (scheduled) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
scheduled = true;
|
|
41
|
+
if (typeof window.requestAnimationFrame === 'function') {
|
|
42
|
+
window.requestAnimationFrame(measureAndPost);
|
|
43
|
+
} else {
|
|
44
|
+
setTimeout(measureAndPost, 500);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function observeHeightChange() {
|
|
49
|
+
const body = document.body;
|
|
50
|
+
if (!body) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const observer = new ResizeObserver(entries => {
|
|
54
|
+
postIframeHeight();
|
|
55
|
+
});
|
|
56
|
+
observer.observe(body);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function init() {
|
|
60
|
+
postIframeHeight();
|
|
61
|
+
observeHeightChange();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (window.document.readyState === 'loading') {
|
|
65
|
+
window.document.addEventListener('DOMContentLoaded', init, { once: true });
|
|
66
|
+
} else {
|
|
67
|
+
init();
|
|
68
|
+
}
|
|
69
|
+
})();
|
|
70
|
+
`;
|
|
71
|
+
const iframeAdjustViewport = (parentHeight)=>`
|
|
72
|
+
$('html').css('--MJ-viewport-height', \`${parentHeight}px\`);
|
|
73
|
+
window.addEventListener('message', function (event) {
|
|
74
|
+
if (event.data?.type === 'MJ_UPDATE_VIEWPORT_HEIGHT') {
|
|
75
|
+
$('html').css('--MJ-viewport-height', \`${parentHeight}px\`);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
`;
|
|
79
|
+
const init = (_iframeId, unsafe, extra)=>unsafe ? '' : `
|
|
80
|
+
(async function () {
|
|
81
|
+
const extra = JSON.parse(${JSON.stringify(JSON.stringify(extra))})
|
|
82
|
+
window.$mujian = window.parent.$mj_engine.bind(extra);
|
|
83
|
+
})();
|
|
84
|
+
`;
|
|
85
|
+
const thirdParty = `
|
|
86
|
+
<script src="https://cdn.jsdmirror.com/npm/@fortawesome/fontawesome-free/js/all.min.js"></script>
|
|
87
|
+
<script src="https://cdn.jsdmirror.com/npm/@tailwindcss/browser/dist/index.global.min.js"></script>
|
|
88
|
+
<script src="https://cdn.jsdmirror.com/npm/jquery/dist/jquery.min.js"></script>
|
|
89
|
+
<script src="https://cdn.jsdmirror.com/npm/jquery-ui/dist/jquery-ui.min.js"></script>
|
|
90
|
+
<link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/jquery-ui/themes/base/theme.min.css" />
|
|
91
|
+
<script src="https://cdn.jsdmirror.com/npm/jquery-ui-touch-punch"></script>
|
|
92
|
+
`;
|
|
93
|
+
const unescapeHTML = (str)=>{
|
|
94
|
+
const named = {
|
|
95
|
+
amp: '&',
|
|
96
|
+
lt: '<',
|
|
97
|
+
gt: '>',
|
|
98
|
+
quot: '"',
|
|
99
|
+
apos: "'",
|
|
100
|
+
nbsp: '\u00A0'
|
|
101
|
+
};
|
|
102
|
+
return str.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (_m, body)=>{
|
|
103
|
+
if ('#' === body[0]) {
|
|
104
|
+
const isHex = body[1]?.toLowerCase() === 'x';
|
|
105
|
+
const numStr = isHex ? body.slice(2) : body.slice(1);
|
|
106
|
+
const codePoint = parseInt(numStr, isHex ? 16 : 10);
|
|
107
|
+
if (Number.isFinite(codePoint)) try {
|
|
108
|
+
return String.fromCodePoint(codePoint);
|
|
109
|
+
} catch {}
|
|
110
|
+
return _m;
|
|
111
|
+
}
|
|
112
|
+
const lower = body.toLowerCase();
|
|
113
|
+
return Object.hasOwn(named, lower) ? named[lower] : _m;
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
const replaceVhInContent = (content)=>{
|
|
117
|
+
const has_css_min_vh = /min-height\s*:\s*[^;{}]*\d+(?:\.\d+)?vh/gi.test(content);
|
|
118
|
+
const has_inline_style_vh = /style\s*=\s*(["'])[\s\S]*?min-height\s*:\s*[^;]*?\d+(?:\.\d+)?vh[\s\S]*?\1/gi.test(content);
|
|
119
|
+
const has_js_vh = /(\.style\.minHeight\s*=\s*(["']))([\s\S]*?vh)(\2)/gi.test(content) || /(setProperty\s*\(\s*(["'])min-height\2\s*,\s*(["']))([\s\S]*?vh)(\3\s*\))/gi.test(content);
|
|
120
|
+
if (!has_css_min_vh && !has_inline_style_vh && !has_js_vh) return content;
|
|
121
|
+
const convertVhToVariable = (value)=>value.replace(/(\d+(?:\.\d+)?)vh\b/gi, (match, value)=>{
|
|
122
|
+
const parsed = parseFloat(value);
|
|
123
|
+
if (!isFinite(parsed)) return match;
|
|
124
|
+
const VARIABLE_EXPRESSION = "var(--MJ-viewport-height)";
|
|
125
|
+
if (100 === parsed) return VARIABLE_EXPRESSION;
|
|
126
|
+
return `calc(${VARIABLE_EXPRESSION} * ${parsed / 100})`;
|
|
127
|
+
});
|
|
128
|
+
content = content.replace(/(min-height\s*:\s*)([^;{}]*?\d+(?:\.\d+)?vh)(?=\s*[;}])/gi, (_m, prefix, value)=>`${prefix}${convertVhToVariable(value)}`);
|
|
129
|
+
content = content.replace(/(style\s*=\s*(["']))([^"'"]*?)(\2)/gi, (match, prefix, _quote, styleContent, suffix)=>{
|
|
130
|
+
if (!/min-height\s*:\s*[^;]*vh/i.test(styleContent)) return match;
|
|
131
|
+
const replaced = styleContent.replace(/(min-height\s*:\s*)([^;]*?\d+(?:\.\d+)?vh)/gi, (_m, p1, p2)=>`${p1}${convertVhToVariable(p2)}`);
|
|
132
|
+
return `${prefix}${replaced}${suffix}`;
|
|
133
|
+
});
|
|
134
|
+
content = content.replace(/(\.style\.minHeight\s*=\s*(["']))([\s\S]*?)(\2)/gi, (match, prefix, _q, val, suffix)=>{
|
|
135
|
+
if (!/\b\d+(?:\.\d+)?vh\b/i.test(val)) return match;
|
|
136
|
+
const converted = convertVhToVariable(val);
|
|
137
|
+
return `${prefix}${converted}${suffix}`;
|
|
138
|
+
});
|
|
139
|
+
content = content.replace(/(setProperty\s*\(\s*(["'])min-height\2\s*,\s*(["']))([\s\S]*?)(\3\s*\))/gi, (match, prefix, _q1, _q2, val, suffix)=>{
|
|
140
|
+
if (!/\b\d+(?:\.\d+)?vh\b/i.test(val)) return match;
|
|
141
|
+
const converted = convertVhToVariable(val);
|
|
142
|
+
return `${prefix}${converted}${suffix}`;
|
|
143
|
+
});
|
|
144
|
+
return content;
|
|
145
|
+
};
|
|
146
|
+
function escapeHtmlAttribute(value) {
|
|
147
|
+
return value.replace(/"/g, '"').replace(/'/g, ''');
|
|
148
|
+
}
|
|
149
|
+
function createSrcContent(content, iframeId, unsafe, extra) {
|
|
150
|
+
content = replaceVhInContent(content);
|
|
151
|
+
return `
|
|
152
|
+
<html>
|
|
153
|
+
<head>
|
|
154
|
+
<meta charset="utf-8">
|
|
155
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
156
|
+
<style>
|
|
157
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
158
|
+
html,body{margin:0!important;padding:0;overflow:hidden!important;max-width:100%!important;}
|
|
159
|
+
</style>
|
|
160
|
+
${thirdParty}
|
|
161
|
+
<script>
|
|
162
|
+
${init(iframeId, unsafe, extra)}
|
|
163
|
+
${adjustIframeHeight(iframeId)}
|
|
164
|
+
${iframeAdjustViewport(window.innerHeight)}
|
|
165
|
+
</script>
|
|
166
|
+
</head>
|
|
167
|
+
<body>
|
|
168
|
+
${content}
|
|
169
|
+
</body>
|
|
170
|
+
</html>
|
|
171
|
+
`;
|
|
172
|
+
}
|
|
173
|
+
const Log = {
|
|
174
|
+
i (...msg) {
|
|
175
|
+
console.log('[MujianSDK] ', ...msg);
|
|
176
|
+
},
|
|
177
|
+
e (...msg) {
|
|
178
|
+
console.error('[MujianSDK] ', ...msg);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
9
181
|
addDOMPurifyHooks();
|
|
10
182
|
function canUseNegativeLookbehind() {
|
|
11
183
|
try {
|
|
@@ -95,7 +267,7 @@ function addDOMPurifyHooks() {
|
|
|
95
267
|
* @returns {string} Encoded message text
|
|
96
268
|
* @copyright https://github.com/kwaroran/risuAI
|
|
97
269
|
*/ function encodeStyleTags(text) {
|
|
98
|
-
const styleRegex = /<style>(
|
|
270
|
+
const styleRegex = /<style>([\s\S]+?)<\/style>/gi;
|
|
99
271
|
return text.replaceAll(styleRegex, (_, match)=>`<custom-style>${encodeURIComponent(match)}</custom-style>`);
|
|
100
272
|
}
|
|
101
273
|
/**
|
|
@@ -159,7 +331,7 @@ function addDOMPurifyHooks() {
|
|
|
159
331
|
const markdownUnderscoreExt = ()=>{
|
|
160
332
|
try {
|
|
161
333
|
if (!canUseNegativeLookbehind()) {
|
|
162
|
-
|
|
334
|
+
Log.i('Showdown-underscore extension: Negative lookbehind not supported. Skipping.');
|
|
163
335
|
return [];
|
|
164
336
|
}
|
|
165
337
|
return [
|
|
@@ -234,31 +406,187 @@ function messageFormatting(mes, sanitizerOverrides = {}) {
|
|
|
234
406
|
});
|
|
235
407
|
return mes;
|
|
236
408
|
}
|
|
237
|
-
const
|
|
238
|
-
|
|
409
|
+
const loadingTranslates = {
|
|
410
|
+
'zh-hans': '加载中...',
|
|
411
|
+
'zh-hant': '載入中...',
|
|
412
|
+
en: 'Loading...',
|
|
413
|
+
ja: '読み込み中...',
|
|
414
|
+
th: 'กำลังโหลด...'
|
|
415
|
+
};
|
|
416
|
+
const MdRendererBase = ({ content, unsafe = false, extra = {}, lang })=>{
|
|
417
|
+
const containerRef = useRef(null);
|
|
418
|
+
const [iframeIdList, setIframeIdList] = useState([]);
|
|
419
|
+
useEffect(()=>{
|
|
420
|
+
let mes = messageFormatting(content);
|
|
421
|
+
mes = mes.replace(/<pre><code(.*)>[\s\S]*?<\/code><\/pre>/g, (match)=>{
|
|
422
|
+
if (!match.includes('<body>') && !match.includes('</body>')) return match;
|
|
423
|
+
const code = match.replace(/<pre><code(.*?)>/g, '').replace(/<\/code><\/pre>/g, '');
|
|
424
|
+
const id = v4();
|
|
425
|
+
const containerId = `MJ-iframe-container-${id}`;
|
|
426
|
+
const iframeId = `MJ-iframe-${id}`;
|
|
427
|
+
const srcdoc = createSrcContent(unescapeHTML(code), iframeId, unsafe, extra);
|
|
428
|
+
setIframeIdList((prev)=>[
|
|
429
|
+
...prev,
|
|
430
|
+
id
|
|
431
|
+
]);
|
|
432
|
+
const escapedSrcdoc = escapeHtmlAttribute(srcdoc);
|
|
433
|
+
const loadingText = loadingTranslates[lang ?? 'zh-hans'] || loadingTranslates['zh-hans'];
|
|
434
|
+
return `
|
|
435
|
+
<div class="MJ-iframe-container" id="${containerId}" style="display:flex;width:100%;height:100%;position:relative;">
|
|
436
|
+
<div class="spin-overlay" id="MJ-spin-${id}" style="width:100%;height:100%;position:absolute;top:0;left:0;z-index:1000;background-color:rgba(0,0,0,0.5);display:flex;justify-content:center;align-items:center;">
|
|
437
|
+
<div class="spin-inner wave-text" style="font-weight:500;font-size:16px;color:white;display:flex;justify-content:center;align-items:center;">
|
|
438
|
+
${loadingText.split('').map((t)=>`<span>${t}</span>`).join('')}
|
|
439
|
+
</div>
|
|
440
|
+
</div>
|
|
441
|
+
<iframe id="${iframeId}" class="w-full" sandbox="${unsafe ? "allow-scripts" : "allow-scripts allow-same-origin"}" loading="lazy"
|
|
442
|
+
referrerpolicy="no-referrer" allowTransparency="true"
|
|
443
|
+
style="color-scheme: none;background-color: transparent;width:100%;;border:none;" srcdoc="` + escapedSrcdoc + `"></iframe>
|
|
444
|
+
</div>`;
|
|
445
|
+
});
|
|
446
|
+
if (containerRef.current) containerRef.current.innerHTML = mes;
|
|
447
|
+
}, [
|
|
448
|
+
content
|
|
449
|
+
]);
|
|
450
|
+
useEffect(()=>{
|
|
451
|
+
window.addEventListener('message', function(event) {
|
|
452
|
+
if (event.data?.type === 'MJ_ADJUST_IFRAME_HEIGHT' && event.data?.iframe_id) {
|
|
453
|
+
const targetIframe = containerRef.current?.querySelector('#' + event.data.iframe_id);
|
|
454
|
+
if (!targetIframe) return;
|
|
455
|
+
targetIframe.style.height = `${event.data.height}px`;
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
window.addEventListener('resize', ()=>{
|
|
459
|
+
iframeIdList.forEach((id)=>{
|
|
460
|
+
const iframe = containerRef.current?.querySelector('#MJ-iframe-' + id);
|
|
461
|
+
if (!iframe) return;
|
|
462
|
+
iframe.contentWindow?.postMessage({
|
|
463
|
+
type: 'MJ_UPDATE_VIEWPORT_HEIGHT'
|
|
464
|
+
}, '*');
|
|
465
|
+
});
|
|
466
|
+
});
|
|
467
|
+
}, []);
|
|
468
|
+
useEffect(()=>{
|
|
469
|
+
iframeIdList.forEach((id)=>{
|
|
470
|
+
const iframe = containerRef.current?.querySelector('#MJ-iframe-' + id);
|
|
471
|
+
if (!iframe) return;
|
|
472
|
+
const removeSpin = ()=>{
|
|
473
|
+
const spinElement = iframe.parentElement?.querySelector('#MJ-spin-' + id);
|
|
474
|
+
if (spinElement) spinElement.remove();
|
|
475
|
+
};
|
|
476
|
+
const timeout = setTimeout(removeSpin, 5000);
|
|
477
|
+
iframe.addEventListener('load', ()=>{
|
|
478
|
+
clearTimeout(timeout);
|
|
479
|
+
removeSpin();
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
return ()=>{
|
|
483
|
+
iframeIdList.forEach((id)=>{
|
|
484
|
+
const iframe = containerRef.current?.querySelector('#MJ-iframe-' + id);
|
|
485
|
+
if (!iframe) return;
|
|
486
|
+
const spinElement = iframe.parentElement?.querySelector('#MJ-spin-' + iframe.id);
|
|
487
|
+
if (spinElement) spinElement.remove();
|
|
488
|
+
iframe.removeEventListener('load', ()=>{
|
|
489
|
+
Log.i('iframe loaded', iframe.id);
|
|
490
|
+
});
|
|
491
|
+
});
|
|
492
|
+
};
|
|
493
|
+
}, [
|
|
494
|
+
iframeIdList
|
|
495
|
+
]);
|
|
239
496
|
return /*#__PURE__*/ jsx("div", {
|
|
240
497
|
className: "mes_text",
|
|
241
|
-
|
|
242
|
-
__html: mes
|
|
243
|
-
}
|
|
498
|
+
ref: containerRef
|
|
244
499
|
});
|
|
245
500
|
};
|
|
246
501
|
const MdRenderer = /*#__PURE__*/ react.memo(MdRendererBase, (prev, next)=>prev.content === next.content);
|
|
247
502
|
MdRendererBase.displayName = 'MdRenderer';
|
|
248
503
|
MdRenderer.displayName = 'MdRenderer';
|
|
249
|
-
|
|
250
|
-
|
|
504
|
+
var events_EVENT = /*#__PURE__*/ function(EVENT) {
|
|
505
|
+
EVENT["MUJIAN_INIT"] = "mujian:init";
|
|
506
|
+
EVENT["MUJIAN_AI_CHAT_STOP"] = "mujian:ai:chat:stop";
|
|
507
|
+
EVENT["MUJIAN_AI_CHAT_COMPLETE"] = "mujian:ai:chat:complete";
|
|
508
|
+
EVENT["MUJIAN_AI_CHAT_APPLY_REGEX"] = "mujian:ai:chat:applyRegex";
|
|
509
|
+
EVENT["MUJIAN_AI_CHAT_RENDER_MESSAGE"] = "mujian:ai:chat:renderMessage";
|
|
510
|
+
EVENT["MUJIAN_AI_TEXT_GENERATE"] = "mujian:ai:text:generate";
|
|
511
|
+
EVENT["MUJIAN_AI_OPENAI_COMPLETIONS_CREATE"] = "mujian:ai:openai:completions:create";
|
|
512
|
+
EVENT["MUJIAN_AI_OPENAI_CHAT_COMPLETIONS_CREATE"] = "mujian:ai:openai:chat:completions:create";
|
|
513
|
+
EVENT["MUJIAN_AI_OPENAI_RESPONSES_CREATE"] = "mujian:ai:openai:responses:create";
|
|
514
|
+
EVENT["MUJIAN_AI_CHAT_MESSAGE_GET_ALL"] = "mujian:ai:chat:message:getAll";
|
|
515
|
+
EVENT["MUJIAN_AI_CHAT_MESSAGE_GET_PAGE"] = "mujian:ai:chat:message:getPage";
|
|
516
|
+
EVENT["MUJIAN_AI_CHAT_PROJECT_GET_INFO"] = "mujian:ai:chat:project:getInfo";
|
|
517
|
+
EVENT["MUJIAN_AI_SETTINGS_PERSONA_GET_ACTIVE"] = "mujian:ai:settings:persona:getActive";
|
|
518
|
+
EVENT["MUJIAN_AI_SETTINGS_PERSONA_SET_ACTIVE"] = "mujian:ai:settings:persona:setActive";
|
|
519
|
+
EVENT["MUJIAN_AI_SETTINGS_MODEL_GET_ALL"] = "mujian:ai:settings:model:getAll";
|
|
520
|
+
EVENT["MUJIAN_AI_SETTINGS_MODEL_SET_ACTIVE"] = "mujian:ai:settings:model:setActive";
|
|
521
|
+
EVENT["MUJIAN_AI_SETTINGS_MODEL_GET_ACTIVE"] = "mujian:ai:settings:model:getActive";
|
|
522
|
+
EVENT["MUJIAN_AI_CHAT_MESSAGE_DELETE_ONE"] = "mujian:ai:chat:message:deleteOne";
|
|
523
|
+
EVENT["MUJIAN_AI_CHAT_MESSAGE_EDIT_ONE"] = "mujian:ai:chat:message:editOne";
|
|
524
|
+
EVENT["MUJIAN_AI_CHAT_MESSAGE_SWIPE"] = "mujian:ai:chat:message:swipe";
|
|
525
|
+
EVENT["MUJIAN_AI_OPENAI_IMAGES_GENERATE"] = "mujian:ai:openai:images:generate";
|
|
526
|
+
EVENT["MUJIAN_UTILS_CLIPBOARD_WRITE_TEXT"] = "mujian:utils:clipboard:writeText";
|
|
527
|
+
EVENT["MUJIAN_GET_CONFIG"] = "mujian:getConfig";
|
|
528
|
+
return EVENT;
|
|
529
|
+
}({});
|
|
530
|
+
function wrapOnData(onData) {
|
|
531
|
+
let fullContent = '';
|
|
532
|
+
let buffer = '';
|
|
533
|
+
let questionId;
|
|
534
|
+
let replyId;
|
|
535
|
+
return function(data) {
|
|
536
|
+
buffer += data;
|
|
537
|
+
const lines = buffer.split('\n');
|
|
538
|
+
buffer = lines.pop() || '';
|
|
539
|
+
for (const line of lines)if (line.startsWith('data: ')) try {
|
|
540
|
+
const parsedData = JSON.parse(line.slice(6));
|
|
541
|
+
if (parsedData.question_id) questionId = parsedData.question_id;
|
|
542
|
+
if (parsedData.reply_id) replyId = parsedData.reply_id;
|
|
543
|
+
if (parsedData.isFinished) return void onData({
|
|
544
|
+
isFinished: true,
|
|
545
|
+
deltaContent: '',
|
|
546
|
+
fullContent,
|
|
547
|
+
questionId,
|
|
548
|
+
replyId
|
|
549
|
+
});
|
|
550
|
+
const deltaContent = parsedData?.choices?.[0]?.delta?.content;
|
|
551
|
+
if (deltaContent?.length > 0) {
|
|
552
|
+
fullContent += deltaContent;
|
|
553
|
+
onData({
|
|
554
|
+
isFinished: false,
|
|
555
|
+
deltaContent: deltaContent,
|
|
556
|
+
fullContent,
|
|
557
|
+
questionId,
|
|
558
|
+
replyId
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
} catch (e) {
|
|
562
|
+
onData({
|
|
563
|
+
isFinished: true,
|
|
564
|
+
error: e,
|
|
565
|
+
deltaContent: '',
|
|
566
|
+
fullContent,
|
|
567
|
+
questionId,
|
|
568
|
+
replyId
|
|
569
|
+
});
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
const chat_complete = async function(message, onData, signal, option = {}) {
|
|
575
|
+
await this.call(events_EVENT.MUJIAN_AI_CHAT_COMPLETE, {
|
|
251
576
|
content: message
|
|
252
577
|
}, {
|
|
253
|
-
onData,
|
|
578
|
+
onData: option.parseContent ? wrapOnData(onData) : onData,
|
|
254
579
|
signal
|
|
255
580
|
});
|
|
256
581
|
};
|
|
257
582
|
const applyRegex = async function(props) {
|
|
258
|
-
return await this.call(
|
|
583
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_APPLY_REGEX, props);
|
|
584
|
+
};
|
|
585
|
+
const renderMessage = async function(props) {
|
|
586
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_RENDER_MESSAGE, props);
|
|
259
587
|
};
|
|
260
588
|
const continueComplete = async function(onData, signal) {
|
|
261
|
-
return await this.call(
|
|
589
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_COMPLETE, {
|
|
262
590
|
isContinue: true
|
|
263
591
|
}, {
|
|
264
592
|
onData,
|
|
@@ -266,7 +594,7 @@ const continueComplete = async function(onData, signal) {
|
|
|
266
594
|
});
|
|
267
595
|
};
|
|
268
596
|
const chat_regenerate = async function(onData, signal) {
|
|
269
|
-
return await this.call(
|
|
597
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_COMPLETE, {
|
|
270
598
|
isRegenerate: true
|
|
271
599
|
}, {
|
|
272
600
|
onData,
|
|
@@ -274,61 +602,99 @@ const chat_regenerate = async function(onData, signal) {
|
|
|
274
602
|
});
|
|
275
603
|
};
|
|
276
604
|
const getAll = async function() {
|
|
277
|
-
return await this.call(
|
|
605
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_MESSAGE_GET_ALL);
|
|
278
606
|
};
|
|
279
607
|
const messageDeleteOne = async function(messageId) {
|
|
280
|
-
return await this.call(
|
|
608
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_MESSAGE_DELETE_ONE, {
|
|
281
609
|
messageId
|
|
282
610
|
});
|
|
283
611
|
};
|
|
284
612
|
const messageEditOne = async function(messageId, content) {
|
|
285
|
-
return await this.call(
|
|
613
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_MESSAGE_EDIT_ONE, {
|
|
286
614
|
messageId,
|
|
287
615
|
content
|
|
288
616
|
});
|
|
289
617
|
};
|
|
290
618
|
const messageSwipe = async function(messageId, swipeId) {
|
|
291
|
-
return await this.call(
|
|
619
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_MESSAGE_SWIPE, {
|
|
292
620
|
messageId,
|
|
293
621
|
swipeId
|
|
294
622
|
});
|
|
295
623
|
};
|
|
296
|
-
|
|
297
|
-
return await this.call(
|
|
298
|
-
|
|
624
|
+
async function getPage(fromCursor, pageSize) {
|
|
625
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_MESSAGE_GET_PAGE, {
|
|
626
|
+
fromCursor,
|
|
627
|
+
pageSize
|
|
299
628
|
});
|
|
300
|
-
}
|
|
629
|
+
}
|
|
301
630
|
const getInfo = async function() {
|
|
302
|
-
return await this.call(
|
|
631
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_PROJECT_GET_INFO);
|
|
303
632
|
};
|
|
304
633
|
const getActive = async function() {
|
|
305
|
-
return await this.call(
|
|
634
|
+
return await this.call(events_EVENT.MUJIAN_AI_SETTINGS_PERSONA_GET_ACTIVE);
|
|
306
635
|
};
|
|
307
|
-
const
|
|
308
|
-
return await this.call(
|
|
309
|
-
|
|
636
|
+
const generate = async function(content) {
|
|
637
|
+
return await this.call(MujianSdk.EVENT.MUJIAN_AI_TEXT_GENERATE, {
|
|
638
|
+
content
|
|
310
639
|
});
|
|
311
640
|
};
|
|
312
|
-
const
|
|
313
|
-
|
|
641
|
+
const chat = {
|
|
642
|
+
completions: {
|
|
643
|
+
create: async function(params, options, onData, signal) {
|
|
644
|
+
return await this.call(MujianSdk.EVENT.MUJIAN_AI_OPENAI_CHAT_COMPLETIONS_CREATE, {
|
|
645
|
+
params,
|
|
646
|
+
options
|
|
647
|
+
}, {
|
|
648
|
+
onData,
|
|
649
|
+
signal
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
}
|
|
314
653
|
};
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
654
|
+
const completions = {
|
|
655
|
+
create: async function(params, options, onData, signal) {
|
|
656
|
+
return await this.call(MujianSdk.EVENT.MUJIAN_AI_OPENAI_COMPLETIONS_CREATE, {
|
|
657
|
+
params,
|
|
658
|
+
options
|
|
659
|
+
}, {
|
|
660
|
+
onData,
|
|
661
|
+
signal
|
|
662
|
+
});
|
|
663
|
+
}
|
|
319
664
|
};
|
|
320
|
-
const
|
|
321
|
-
|
|
665
|
+
const responses = {
|
|
666
|
+
create: async function(params, options, onData, signal) {
|
|
667
|
+
return await this.call(MujianSdk.EVENT.MUJIAN_AI_OPENAI_RESPONSES_CREATE, {
|
|
668
|
+
params,
|
|
669
|
+
options
|
|
670
|
+
}, {
|
|
671
|
+
onData,
|
|
672
|
+
signal
|
|
673
|
+
});
|
|
674
|
+
}
|
|
322
675
|
};
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
676
|
+
const images_images = {
|
|
677
|
+
generate: async function(params, options, onData, signal) {
|
|
678
|
+
return await this.call(MujianSdk.EVENT.MUJIAN_AI_OPENAI_IMAGES_GENERATE, {
|
|
679
|
+
params,
|
|
680
|
+
options
|
|
681
|
+
}, {
|
|
682
|
+
onData,
|
|
683
|
+
signal
|
|
684
|
+
});
|
|
685
|
+
}
|
|
327
686
|
};
|
|
687
|
+
async function getConfig() {
|
|
688
|
+
return await this.call(events_EVENT.MUJIAN_GET_CONFIG);
|
|
689
|
+
}
|
|
328
690
|
const saveGame = async function() {};
|
|
329
691
|
const loadGame = async function() {};
|
|
692
|
+
async function writeText(text) {
|
|
693
|
+
return await this.call(events_EVENT.MUJIAN_UTILS_CLIPBOARD_WRITE_TEXT, text);
|
|
694
|
+
}
|
|
330
695
|
class MujianSdk {
|
|
331
696
|
constructor(){}
|
|
697
|
+
static EVENT = events_EVENT;
|
|
332
698
|
static getInstance() {
|
|
333
699
|
if (!window.$mujian) window.$mujian = new MujianSdk();
|
|
334
700
|
return window.$mujian;
|
|
@@ -339,33 +705,59 @@ class MujianSdk {
|
|
|
339
705
|
return this.ready;
|
|
340
706
|
}
|
|
341
707
|
pendingRequests = new Map();
|
|
708
|
+
_config;
|
|
709
|
+
get openapi() {
|
|
710
|
+
return this._config?.openapi;
|
|
711
|
+
}
|
|
712
|
+
initPromise = null;
|
|
342
713
|
async init() {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
call
|
|
349
|
-
|
|
350
|
-
|
|
714
|
+
if (this.initPromise) return this.initPromise;
|
|
715
|
+
this.initPromise = (async ()=>{
|
|
716
|
+
const handshake = new postmate.Model({
|
|
717
|
+
reply: ({ id, complete, data, error })=>{
|
|
718
|
+
const call = this.pendingRequests.get(id);
|
|
719
|
+
if (!call) return;
|
|
720
|
+
if (error) {
|
|
721
|
+
call.reject(error);
|
|
722
|
+
this.pendingRequests.delete(id);
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
call.onData?.(data);
|
|
726
|
+
if (complete) {
|
|
727
|
+
call.onComplete?.();
|
|
728
|
+
call.resolve(data);
|
|
729
|
+
this.pendingRequests.delete(id);
|
|
730
|
+
}
|
|
351
731
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
732
|
+
});
|
|
733
|
+
try {
|
|
734
|
+
const parent = await handshake;
|
|
735
|
+
this.ready = true;
|
|
736
|
+
this.parent = parent;
|
|
737
|
+
Log.i('mujian sdk client init');
|
|
738
|
+
await this.call(events_EVENT.MUJIAN_INIT);
|
|
739
|
+
const projectInfo = await this.ai.chat.project.getInfo();
|
|
740
|
+
if (projectInfo.config?.customCss) {
|
|
741
|
+
const style = document.createElement('style');
|
|
742
|
+
style.setAttribute('type', 'text/css');
|
|
743
|
+
style.setAttribute('id', 'mujian-custom-css');
|
|
744
|
+
style.textContent = projectInfo.config.customCss;
|
|
745
|
+
document.head.appendChild(style);
|
|
746
|
+
}
|
|
747
|
+
if (projectInfo.config?.customJs) {
|
|
748
|
+
const script = document.createElement("script");
|
|
749
|
+
script.setAttribute('type', "text/javascript");
|
|
750
|
+
script.setAttribute('id', 'mujian-custom-js');
|
|
751
|
+
script.textContent = projectInfo.config.customJs;
|
|
752
|
+
document.head.appendChild(script);
|
|
357
753
|
}
|
|
754
|
+
const config = await getConfig.call(this);
|
|
755
|
+
if (config) this._config = config;
|
|
756
|
+
} catch (error) {
|
|
757
|
+
Log.e('init error', error);
|
|
358
758
|
}
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
const parent = await handshake;
|
|
362
|
-
this.ready = true;
|
|
363
|
-
this.parent = parent;
|
|
364
|
-
console.log('mujian sdk client init');
|
|
365
|
-
await this.call("mujian:init");
|
|
366
|
-
} catch (error) {
|
|
367
|
-
console.log('init error', error);
|
|
368
|
-
}
|
|
759
|
+
})();
|
|
760
|
+
return this.initPromise;
|
|
369
761
|
}
|
|
370
762
|
emit(event, data) {
|
|
371
763
|
if (!this.ready) throw new Error('Mujian is not initialized');
|
|
@@ -391,7 +783,7 @@ class MujianSdk {
|
|
|
391
783
|
data
|
|
392
784
|
});
|
|
393
785
|
controller?.signal?.addEventListener('abort', ()=>{
|
|
394
|
-
this.emit(
|
|
786
|
+
this.emit(events_EVENT.MUJIAN_AI_CHAT_STOP, {
|
|
395
787
|
id: callId
|
|
396
788
|
});
|
|
397
789
|
});
|
|
@@ -403,18 +795,13 @@ class MujianSdk {
|
|
|
403
795
|
getInfo: getInfo.bind(this)
|
|
404
796
|
},
|
|
405
797
|
settings: {
|
|
406
|
-
model: {
|
|
407
|
-
getAll: model_getAll.bind(this),
|
|
408
|
-
getActive: model_getActive.bind(this),
|
|
409
|
-
setActive: model_setActive.bind(this)
|
|
410
|
-
},
|
|
411
798
|
persona: {
|
|
412
|
-
getActive: getActive.bind(this)
|
|
413
|
-
setActive: setActive.bind(this)
|
|
799
|
+
getActive: getActive.bind(this)
|
|
414
800
|
}
|
|
415
801
|
},
|
|
416
802
|
complete: chat_complete.bind(this),
|
|
417
803
|
applyRegex: applyRegex.bind(this),
|
|
804
|
+
renderMessage: renderMessage.bind(this),
|
|
418
805
|
continue: continueComplete.bind(this),
|
|
419
806
|
regenerate: chat_regenerate.bind(this),
|
|
420
807
|
message: {
|
|
@@ -422,17 +809,33 @@ class MujianSdk {
|
|
|
422
809
|
deleteOne: messageDeleteOne.bind(this),
|
|
423
810
|
editOne: messageEditOne.bind(this),
|
|
424
811
|
swipe: messageSwipe.bind(this),
|
|
425
|
-
|
|
812
|
+
getPage: getPage.bind(this)
|
|
426
813
|
}
|
|
427
814
|
},
|
|
428
815
|
text: {
|
|
429
816
|
complete: generate.bind(this)
|
|
817
|
+
},
|
|
818
|
+
openai: {
|
|
819
|
+
completions: {
|
|
820
|
+
create: completions.create.bind(this)
|
|
821
|
+
},
|
|
822
|
+
chat: {
|
|
823
|
+
completions: {
|
|
824
|
+
create: chat.completions.create.bind(this)
|
|
825
|
+
}
|
|
826
|
+
},
|
|
827
|
+
responses: {
|
|
828
|
+
create: responses.create.bind(this)
|
|
829
|
+
},
|
|
830
|
+
images: {
|
|
831
|
+
generate: images_images.generate.bind(this)
|
|
832
|
+
}
|
|
430
833
|
}
|
|
431
834
|
};
|
|
432
835
|
ui = {};
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
836
|
+
utils = {
|
|
837
|
+
clipboard: {
|
|
838
|
+
writeText: writeText.bind(this)
|
|
436
839
|
}
|
|
437
840
|
};
|
|
438
841
|
hybrid = {};
|
|
@@ -450,6 +853,43 @@ class MujianSdk {
|
|
|
450
853
|
}
|
|
451
854
|
};
|
|
452
855
|
}
|
|
856
|
+
const styleSheet = `
|
|
857
|
+
@keyframes spin {
|
|
858
|
+
0% { transform: rotate(0deg); }
|
|
859
|
+
100% { transform: rotate(360deg); }
|
|
860
|
+
}
|
|
861
|
+
`;
|
|
862
|
+
const spinnerStyle = {
|
|
863
|
+
width: 48,
|
|
864
|
+
height: 48,
|
|
865
|
+
animation: 'spin 1s linear infinite'
|
|
866
|
+
};
|
|
867
|
+
const MujianSpinner = ({ className, style })=>/*#__PURE__*/ jsxs(Fragment, {
|
|
868
|
+
children: [
|
|
869
|
+
/*#__PURE__*/ jsx("style", {
|
|
870
|
+
children: styleSheet
|
|
871
|
+
}),
|
|
872
|
+
/*#__PURE__*/ jsx("svg", {
|
|
873
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
874
|
+
width: "24",
|
|
875
|
+
height: "24",
|
|
876
|
+
viewBox: "0 0 24 24",
|
|
877
|
+
fill: "none",
|
|
878
|
+
stroke: "currentColor",
|
|
879
|
+
strokeWidth: "2",
|
|
880
|
+
strokeLinecap: "round",
|
|
881
|
+
strokeLinejoin: "round",
|
|
882
|
+
className: className,
|
|
883
|
+
style: {
|
|
884
|
+
...spinnerStyle,
|
|
885
|
+
...style
|
|
886
|
+
},
|
|
887
|
+
children: /*#__PURE__*/ jsx("path", {
|
|
888
|
+
d: "M21 12a9 9 0 1 1-6.219-8.56"
|
|
889
|
+
})
|
|
890
|
+
})
|
|
891
|
+
]
|
|
892
|
+
});
|
|
453
893
|
const MujianContext = /*#__PURE__*/ createContext(null);
|
|
454
894
|
const MujianProvider = ({ children, loadingComponent })=>{
|
|
455
895
|
const [mujian, setMujian] = useState(null);
|
|
@@ -462,7 +902,20 @@ const MujianProvider = ({ children, loadingComponent })=>{
|
|
|
462
902
|
}, []);
|
|
463
903
|
return /*#__PURE__*/ jsx(MujianContext.Provider, {
|
|
464
904
|
value: mujian,
|
|
465
|
-
children: mujian ? children : loadingComponent ??
|
|
905
|
+
children: mujian ? children : loadingComponent ?? /*#__PURE__*/ jsx("div", {
|
|
906
|
+
style: {
|
|
907
|
+
height: '100%',
|
|
908
|
+
width: '100%',
|
|
909
|
+
display: 'flex',
|
|
910
|
+
justifyContent: 'center',
|
|
911
|
+
alignItems: 'center'
|
|
912
|
+
},
|
|
913
|
+
children: /*#__PURE__*/ jsx(MujianSpinner, {
|
|
914
|
+
style: {
|
|
915
|
+
color: '#EC4342'
|
|
916
|
+
}
|
|
917
|
+
})
|
|
918
|
+
})
|
|
466
919
|
});
|
|
467
920
|
};
|
|
468
921
|
const useMujian = ()=>{
|
|
@@ -480,7 +933,7 @@ const MessageItem = (props)=>{
|
|
|
480
933
|
const { data: renderedMessage } = useRequest(async ()=>{
|
|
481
934
|
const { isStreaming } = message;
|
|
482
935
|
if (isStreaming) return message;
|
|
483
|
-
return await mujian.ai.chat.
|
|
936
|
+
return await mujian.ai.chat.renderMessage({
|
|
484
937
|
message,
|
|
485
938
|
depth,
|
|
486
939
|
index
|
|
@@ -509,28 +962,116 @@ const Thread = {
|
|
|
509
962
|
MessageItem: MessageItem,
|
|
510
963
|
MessageList: MessageList
|
|
511
964
|
};
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
965
|
+
let $mj_ai_chat_complete;
|
|
966
|
+
let $mj_ai_chat_project;
|
|
967
|
+
let $mj_ai_chat_settings_persona;
|
|
968
|
+
let $mj_ai_chat_setFirstMesIndex;
|
|
969
|
+
let $mj_ai_chat_mjv_get;
|
|
970
|
+
let $mj_ai_chat_mjv_getAll;
|
|
971
|
+
const $mj_engine = {
|
|
972
|
+
ai: {
|
|
973
|
+
chat: {
|
|
974
|
+
get complete () {
|
|
975
|
+
return $mj_ai_chat_complete;
|
|
976
|
+
},
|
|
977
|
+
get project () {
|
|
978
|
+
return $mj_ai_chat_project;
|
|
979
|
+
},
|
|
980
|
+
settings: {
|
|
981
|
+
get persona () {
|
|
982
|
+
return $mj_ai_chat_settings_persona;
|
|
983
|
+
}
|
|
984
|
+
},
|
|
985
|
+
get setFirstMesIndex () {
|
|
986
|
+
return $mj_ai_chat_setFirstMesIndex;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
517
989
|
}
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
990
|
+
};
|
|
991
|
+
window.$mj_engine = {
|
|
992
|
+
...$mj_engine,
|
|
993
|
+
bind ({ messageId, swipeId }) {
|
|
994
|
+
return {
|
|
995
|
+
ai: {
|
|
996
|
+
chat: {
|
|
997
|
+
mjv: {
|
|
998
|
+
get (path) {
|
|
999
|
+
return $mj_ai_chat_mjv_get?.(messageId, swipeId, path);
|
|
1000
|
+
},
|
|
1001
|
+
getAll () {
|
|
1002
|
+
return $mj_ai_chat_mjv_getAll?.(messageId, swipeId) ?? {};
|
|
1003
|
+
}
|
|
1004
|
+
},
|
|
1005
|
+
get complete () {
|
|
1006
|
+
return $mj_ai_chat_complete;
|
|
1007
|
+
},
|
|
1008
|
+
get project () {
|
|
1009
|
+
return $mj_ai_chat_project;
|
|
1010
|
+
},
|
|
1011
|
+
settings: {
|
|
1012
|
+
get persona () {
|
|
1013
|
+
return $mj_ai_chat_settings_persona;
|
|
1014
|
+
}
|
|
1015
|
+
},
|
|
1016
|
+
get setFirstMesIndex () {
|
|
1017
|
+
return $mj_ai_chat_setFirstMesIndex;
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
524
1022
|
}
|
|
1023
|
+
};
|
|
1024
|
+
function useMjEngine({ projectInfo, activePersona, onSend, messages, setSwipe }) {
|
|
1025
|
+
useEffect(()=>{
|
|
1026
|
+
$mj_ai_chat_project = projectInfo ?? void 0;
|
|
1027
|
+
$mj_ai_chat_settings_persona = activePersona ?? void 0;
|
|
1028
|
+
}, [
|
|
1029
|
+
projectInfo,
|
|
1030
|
+
activePersona
|
|
1031
|
+
]);
|
|
1032
|
+
useEffect(()=>{
|
|
1033
|
+
$mj_ai_chat_complete = async (message)=>{
|
|
1034
|
+
await onSend(message);
|
|
1035
|
+
};
|
|
1036
|
+
$mj_ai_chat_setFirstMesIndex = async (oneBasedIndex)=>{
|
|
1037
|
+
if (messages.length > 1) throw new Error('已有新消息,不允许切换开场白');
|
|
1038
|
+
if (0 === messages.length) throw new Error('断言失败:没有开场消息,无法切换开场白');
|
|
1039
|
+
const zeroBasedIndex = Math.floor(oneBasedIndex) - 1;
|
|
1040
|
+
const swipeLength = messages[0].swipes.length;
|
|
1041
|
+
if (zeroBasedIndex < 0 || zeroBasedIndex >= swipeLength) return;
|
|
1042
|
+
setSwipe(messages[0].id, zeroBasedIndex);
|
|
1043
|
+
};
|
|
1044
|
+
$mj_ai_chat_mjv_getAll = (messageId, swipeId)=>messages.find((m)=>m.id === messageId)?.swipeInfo[swipeId]?.mjv?.value;
|
|
1045
|
+
$mj_ai_chat_mjv_get = (messageId, swipeId, path)=>{
|
|
1046
|
+
const mjv = $mj_ai_chat_mjv_getAll?.(messageId, swipeId);
|
|
1047
|
+
if (!mjv) return;
|
|
1048
|
+
return get(mjv, path);
|
|
1049
|
+
};
|
|
1050
|
+
}, [
|
|
1051
|
+
onSend,
|
|
1052
|
+
messages,
|
|
1053
|
+
setSwipe
|
|
1054
|
+
]);
|
|
525
1055
|
}
|
|
526
|
-
|
|
1056
|
+
const errorMessages = [
|
|
1057
|
+
'network error',
|
|
1058
|
+
'NetworkError when attempting to fetch resource.',
|
|
1059
|
+
'The Internet connection appears to be offline.',
|
|
1060
|
+
'Network request failed',
|
|
1061
|
+
'Load failed',
|
|
1062
|
+
'Failed to fetch'
|
|
1063
|
+
];
|
|
1064
|
+
function isNetworkError(message) {
|
|
1065
|
+
return errorMessages.some((m)=>message.includes(m));
|
|
1066
|
+
}
|
|
1067
|
+
class SendMessageError extends Error {
|
|
527
1068
|
constructor(message, cause){
|
|
528
1069
|
super(message);
|
|
529
1070
|
this.name = this.constructor.name;
|
|
530
1071
|
this.cause = cause;
|
|
531
1072
|
}
|
|
532
1073
|
}
|
|
533
|
-
class
|
|
1074
|
+
class UnexpectedSseEndingError extends Error {
|
|
534
1075
|
constructor(message, cause){
|
|
535
1076
|
super(message);
|
|
536
1077
|
this.name = this.constructor.name;
|
|
@@ -545,6 +1086,7 @@ async function* callSdk(mujian, content, type = 'generate', signal) {
|
|
|
545
1086
|
try {
|
|
546
1087
|
const onData = (data)=>{
|
|
547
1088
|
if (error) return;
|
|
1089
|
+
if ('string' != typeof data) return;
|
|
548
1090
|
queue.push(data);
|
|
549
1091
|
if (resolveWait) {
|
|
550
1092
|
resolveWait();
|
|
@@ -580,13 +1122,14 @@ async function* callSdk(mujian, content, type = 'generate', signal) {
|
|
|
580
1122
|
});
|
|
581
1123
|
}
|
|
582
1124
|
const NOT_SAVED_MSG_ID_PREFIX = 'not_saved';
|
|
583
|
-
const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
1125
|
+
const useChatStreaming = ({ common, setError, setMessages, getMessages, setInput, mujian })=>{
|
|
584
1126
|
const { body } = common;
|
|
585
1127
|
const [isStreaming, setIsStreaming] = useState(false);
|
|
586
1128
|
const chatStreaming = useCallback(async ({ query, regenerate, is_continue, signal })=>{
|
|
587
1129
|
try {
|
|
588
1130
|
setError(void 0);
|
|
589
1131
|
setIsStreaming(true);
|
|
1132
|
+
const backupMessages = getMessages();
|
|
590
1133
|
const userMessage = {
|
|
591
1134
|
id: `${NOT_SAVED_MSG_ID_PREFIX}_user_${Date.now()}`,
|
|
592
1135
|
content: query || '',
|
|
@@ -594,34 +1137,35 @@ const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
|
594
1137
|
swipes: [],
|
|
595
1138
|
activeSwipeId: 0,
|
|
596
1139
|
isStreaming: false,
|
|
597
|
-
sendAt: new Date()
|
|
1140
|
+
sendAt: new Date(),
|
|
1141
|
+
swipeInfo: [],
|
|
1142
|
+
flags: {}
|
|
598
1143
|
};
|
|
599
1144
|
const aiMessage = {
|
|
600
1145
|
id: `${NOT_SAVED_MSG_ID_PREFIX}_assistant_${Date.now()}`,
|
|
601
1146
|
content: '',
|
|
602
1147
|
role: 'assistant',
|
|
603
|
-
swipes: [
|
|
1148
|
+
swipes: [
|
|
1149
|
+
''
|
|
1150
|
+
],
|
|
604
1151
|
activeSwipeId: 0,
|
|
605
1152
|
isStreaming: true,
|
|
606
|
-
sendAt: new Date()
|
|
1153
|
+
sendAt: new Date(),
|
|
1154
|
+
swipeInfo: [
|
|
1155
|
+
{}
|
|
1156
|
+
],
|
|
1157
|
+
flags: {}
|
|
607
1158
|
};
|
|
608
|
-
if (regenerate) setMessages((
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
swipes: [
|
|
617
|
-
...lastMessage.swipes,
|
|
618
|
-
''
|
|
619
|
-
],
|
|
620
|
-
content: '',
|
|
621
|
-
isStreaming: true
|
|
1159
|
+
if (regenerate) setMessages(produce((draft)=>{
|
|
1160
|
+
const lastMessage = draft[draft.length - 1];
|
|
1161
|
+
lastMessage.activeSwipeId = lastMessage.swipes.length;
|
|
1162
|
+
lastMessage.swipes.push('');
|
|
1163
|
+
lastMessage.content = '';
|
|
1164
|
+
lastMessage.isStreaming = true;
|
|
1165
|
+
lastMessage.flags = {
|
|
1166
|
+
saved: lastMessage.flags.saved
|
|
622
1167
|
};
|
|
623
|
-
|
|
624
|
-
});
|
|
1168
|
+
}));
|
|
625
1169
|
else is_continue ? setMessages((prev)=>[
|
|
626
1170
|
...prev,
|
|
627
1171
|
aiMessage
|
|
@@ -642,45 +1186,58 @@ const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
|
642
1186
|
const data = line.slice(6);
|
|
643
1187
|
try {
|
|
644
1188
|
const parsedData = JSON.parse(data);
|
|
645
|
-
if (
|
|
1189
|
+
if (regenerate || 'meta' !== parsedData.type) {
|
|
1190
|
+
if ('stream' === parsedData.type) {
|
|
1191
|
+
const partialContent = parsedData.choices[0].delta.content;
|
|
1192
|
+
parsedData.choices[0].delta.reasoning;
|
|
1193
|
+
const chunkFinishReason = parsedData.choices[0].finish_reason;
|
|
1194
|
+
content += partialContent;
|
|
1195
|
+
setMessages(produce((draft)=>{
|
|
1196
|
+
const lastMessage = draft[draft.length - 1];
|
|
1197
|
+
lastMessage.swipes[lastMessage.activeSwipeId] = content;
|
|
1198
|
+
lastMessage.content = content;
|
|
1199
|
+
lastMessage.isStreaming = true;
|
|
1200
|
+
if ('content_filter' === chunkFinishReason) lastMessage.flags.contentFilter = true;
|
|
1201
|
+
}));
|
|
1202
|
+
await new Promise((resolve)=>setTimeout(resolve, 10));
|
|
1203
|
+
} else if ('mjv' === parsedData.type) {
|
|
1204
|
+
const { value, delta, schema } = parsedData;
|
|
1205
|
+
setMessages(produce((draft)=>{
|
|
1206
|
+
const lastMessage = draft[draft.length - 1];
|
|
1207
|
+
const mjv = {
|
|
1208
|
+
value,
|
|
1209
|
+
delta,
|
|
1210
|
+
schema
|
|
1211
|
+
};
|
|
1212
|
+
const swipeInfo = lastMessage.swipeInfo;
|
|
1213
|
+
if (swipeInfo[lastMessage.activeSwipeId]) swipeInfo[lastMessage.activeSwipeId].mjv = mjv;
|
|
1214
|
+
else swipeInfo[lastMessage.activeSwipeId] = {
|
|
1215
|
+
mjv
|
|
1216
|
+
};
|
|
1217
|
+
lastMessage.swipeInfo = swipeInfo;
|
|
1218
|
+
lastMessage.mjv = mjv;
|
|
1219
|
+
}));
|
|
1220
|
+
}
|
|
1221
|
+
} else {
|
|
646
1222
|
const { question_id, reply_id } = parsedData;
|
|
647
1223
|
setMessages((prev)=>{
|
|
648
1224
|
const newMessages = [
|
|
649
1225
|
...prev
|
|
650
1226
|
];
|
|
651
|
-
if (question_id && !is_continue) newMessages[newMessages.length - 2].id = question_id;
|
|
652
|
-
const lastMessage = newMessages[newMessages.length - 1];
|
|
653
|
-
newMessages[newMessages.length - 1] = {
|
|
654
|
-
...lastMessage,
|
|
655
|
-
id: reply_id
|
|
656
|
-
};
|
|
657
1227
|
return newMessages;
|
|
658
1228
|
});
|
|
1229
|
+
setMessages(produce((draft)=>{
|
|
1230
|
+
if (question_id && !is_continue) {
|
|
1231
|
+
const userMsg = draft[draft.length - 2];
|
|
1232
|
+
userMsg.id = question_id;
|
|
1233
|
+
userMsg.flags.saved = true;
|
|
1234
|
+
}
|
|
1235
|
+
const lastMessage = draft[draft.length - 1];
|
|
1236
|
+
lastMessage.id = reply_id;
|
|
1237
|
+
lastMessage.flags.saved = true;
|
|
1238
|
+
}));
|
|
659
1239
|
continue;
|
|
660
1240
|
}
|
|
661
|
-
if (!parsedData.choices?.[0]) continue;
|
|
662
|
-
const partialContent = parsedData.choices[0].delta.content;
|
|
663
|
-
parsedData.choices[0].delta.reasoning;
|
|
664
|
-
content += partialContent;
|
|
665
|
-
if (content || '' === content) {
|
|
666
|
-
setMessages((prev)=>{
|
|
667
|
-
const newMessages = [
|
|
668
|
-
...prev
|
|
669
|
-
];
|
|
670
|
-
const lastMessage = newMessages[newMessages.length - 1];
|
|
671
|
-
lastMessage.swipes[lastMessage.activeSwipeId] = content;
|
|
672
|
-
newMessages[newMessages.length - 1] = {
|
|
673
|
-
...lastMessage,
|
|
674
|
-
content: content,
|
|
675
|
-
isStreaming: true
|
|
676
|
-
};
|
|
677
|
-
return newMessages;
|
|
678
|
-
});
|
|
679
|
-
await new Promise((resolve)=>setTimeout(resolve, 10));
|
|
680
|
-
} else {
|
|
681
|
-
console.error('data', data);
|
|
682
|
-
setError(new InvalidDeltaContentError(data));
|
|
683
|
-
}
|
|
684
1241
|
} catch {
|
|
685
1242
|
if ('[DONE]' !== data) {
|
|
686
1243
|
console.error('Received plain SSE message:', data);
|
|
@@ -689,22 +1246,26 @@ const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
|
689
1246
|
}
|
|
690
1247
|
}
|
|
691
1248
|
}
|
|
1249
|
+
setMessages(produce((draft)=>{
|
|
1250
|
+
const lastMessage = draft[draft.length - 1];
|
|
1251
|
+
if (!lastMessage.swipes[lastMessage.activeSwipeId] && !signal?.aborted && !lastMessage.flags.contentFilter) lastMessage.flags.emptyResponse = true;
|
|
1252
|
+
}));
|
|
1253
|
+
} catch (error) {
|
|
1254
|
+
Log.e('Stream error', error);
|
|
1255
|
+
if ('object' == typeof error && error && 'message' in error && 'string' == typeof error.message) if ('code' in error && 2011030001 === error.code) {
|
|
1256
|
+
setMessages(backupMessages);
|
|
1257
|
+
if (!regenerate && !is_continue && query) setInput(query);
|
|
1258
|
+
} else isNetworkError(error.message) ? setError(new SendMessageError('网络好像断开了,检查一下再试吧~')) : setError(new SendMessageError(error.message));
|
|
1259
|
+
else setError(error);
|
|
692
1260
|
} finally{
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
];
|
|
698
|
-
newMessages[newMessages.length - 1] = {
|
|
699
|
-
...newMessages[newMessages.length - 1],
|
|
700
|
-
isStreaming: false
|
|
701
|
-
};
|
|
702
|
-
return newMessages;
|
|
703
|
-
});
|
|
1261
|
+
setMessages(produce((draft)=>{
|
|
1262
|
+
const lastMessage = draft[draft.length - 1];
|
|
1263
|
+
lastMessage.isStreaming = false;
|
|
1264
|
+
}));
|
|
704
1265
|
}
|
|
705
1266
|
} catch (error) {
|
|
706
1267
|
console.error('Error:', error);
|
|
707
|
-
|
|
1268
|
+
setError(new SendMessageError('Send message failed', error));
|
|
708
1269
|
setMessages((prev)=>prev.slice(0, -1));
|
|
709
1270
|
} finally{
|
|
710
1271
|
setIsStreaming(false);
|
|
@@ -718,9 +1279,8 @@ const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
|
718
1279
|
isStreaming
|
|
719
1280
|
};
|
|
720
1281
|
};
|
|
721
|
-
const useChat = ({ body, onError, onFinish })=>{
|
|
1282
|
+
const useChat = ({ body, onError, onFinish, pageSize })=>{
|
|
722
1283
|
const [error, _setError] = useState();
|
|
723
|
-
const [messages, setMessages] = useState([]);
|
|
724
1284
|
const [input, setInput] = useState('');
|
|
725
1285
|
const [abortController, setAbortController] = useState();
|
|
726
1286
|
const mujian = useMujian();
|
|
@@ -728,18 +1288,67 @@ const useChat = ({ body, onError, onFinish })=>{
|
|
|
728
1288
|
_setError(error);
|
|
729
1289
|
if (error) onError?.(error);
|
|
730
1290
|
};
|
|
1291
|
+
const isLoadingMore = useRef(false);
|
|
1292
|
+
const { data, loadMoreAsync, loadingMore, loading, mutate, error: messageLoadError } = useInfiniteScroll(async (current)=>{
|
|
1293
|
+
isLoadingMore.current = true;
|
|
1294
|
+
if (current?.noMore) return {
|
|
1295
|
+
noMore: true,
|
|
1296
|
+
list: []
|
|
1297
|
+
};
|
|
1298
|
+
try {
|
|
1299
|
+
const resp = await mujian.ai.chat.message.getPage(current?.cursor, pageSize);
|
|
1300
|
+
return {
|
|
1301
|
+
cursor: resp.nextCursor,
|
|
1302
|
+
list: resp.messages.map((m)=>({
|
|
1303
|
+
...m,
|
|
1304
|
+
mjv: m.swipeInfo[m.activeSwipeId]?.mjv,
|
|
1305
|
+
flags: {
|
|
1306
|
+
saved: true
|
|
1307
|
+
}
|
|
1308
|
+
})),
|
|
1309
|
+
noMore: !resp.nextCursor
|
|
1310
|
+
};
|
|
1311
|
+
} finally{
|
|
1312
|
+
isLoadingMore.current = false;
|
|
1313
|
+
}
|
|
1314
|
+
}, {
|
|
1315
|
+
direction: 'top'
|
|
1316
|
+
});
|
|
1317
|
+
const loadMoreMessage = async ()=>{
|
|
1318
|
+
if (isLoadingMore.current) return;
|
|
1319
|
+
try {
|
|
1320
|
+
isLoadingMore.current = true;
|
|
1321
|
+
await loadMoreAsync();
|
|
1322
|
+
} finally{
|
|
1323
|
+
isLoadingMore.current = false;
|
|
1324
|
+
}
|
|
1325
|
+
};
|
|
1326
|
+
const messages = data?.list ?? [];
|
|
1327
|
+
const latestData = useLatest(data);
|
|
1328
|
+
const latestListRef = useRef(messages);
|
|
1329
|
+
latestListRef.current = messages;
|
|
1330
|
+
const setMessages = (messages)=>{
|
|
1331
|
+
let newList;
|
|
1332
|
+
newList = 'function' == typeof messages ? messages(latestListRef.current) : messages;
|
|
1333
|
+
latestListRef.current = newList;
|
|
1334
|
+
mutate({
|
|
1335
|
+
...latestData.current,
|
|
1336
|
+
list: newList
|
|
1337
|
+
});
|
|
1338
|
+
};
|
|
1339
|
+
const getMessages = useCallback(()=>latestListRef.current, [
|
|
1340
|
+
latestListRef
|
|
1341
|
+
]);
|
|
731
1342
|
const { chatStreaming, isStreaming } = useChatStreaming({
|
|
732
1343
|
common: {
|
|
733
1344
|
body
|
|
734
1345
|
},
|
|
735
1346
|
setError,
|
|
736
1347
|
setMessages,
|
|
1348
|
+
getMessages,
|
|
1349
|
+
setInput,
|
|
737
1350
|
mujian
|
|
738
1351
|
});
|
|
739
|
-
useMount(async ()=>{
|
|
740
|
-
const resp = await mujian.ai.chat.message.getAll();
|
|
741
|
-
setMessages(resp);
|
|
742
|
-
});
|
|
743
1352
|
useUpdateEffect(()=>{
|
|
744
1353
|
if (!isStreaming) {
|
|
745
1354
|
const lastMessage = messages[messages.length - 1];
|
|
@@ -748,48 +1357,79 @@ const useChat = ({ body, onError, onFinish })=>{
|
|
|
748
1357
|
}, [
|
|
749
1358
|
isStreaming
|
|
750
1359
|
]);
|
|
751
|
-
const append = async (query)=>{
|
|
1360
|
+
const append = useCallback(async (query)=>{
|
|
752
1361
|
if (isStreaming) throw new Error('useChat is streaming already.');
|
|
753
1362
|
const controller = new AbortController();
|
|
754
1363
|
setAbortController(controller);
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
1364
|
+
try {
|
|
1365
|
+
await chatStreaming({
|
|
1366
|
+
query,
|
|
1367
|
+
signal: controller.signal
|
|
1368
|
+
});
|
|
1369
|
+
} catch (e) {
|
|
1370
|
+
setError(e);
|
|
1371
|
+
throw e;
|
|
1372
|
+
} finally{
|
|
1373
|
+
setAbortController(void 0);
|
|
1374
|
+
}
|
|
1375
|
+
}, [
|
|
1376
|
+
isStreaming,
|
|
1377
|
+
chatStreaming
|
|
1378
|
+
]);
|
|
1379
|
+
const regenerate = useCallback(async ()=>{
|
|
762
1380
|
if (isStreaming) throw new Error('useChat is streaming already.');
|
|
763
1381
|
const controller = new AbortController();
|
|
764
1382
|
setAbortController(controller);
|
|
765
1383
|
const lastMessage = messages.findLast((message)=>'user' === message.role);
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
1384
|
+
try {
|
|
1385
|
+
await chatStreaming({
|
|
1386
|
+
query: lastMessage?.content || '',
|
|
1387
|
+
regenerate: true,
|
|
1388
|
+
signal: controller.signal
|
|
1389
|
+
});
|
|
1390
|
+
} catch (e) {
|
|
1391
|
+
setError(e);
|
|
1392
|
+
throw e;
|
|
1393
|
+
} finally{
|
|
1394
|
+
setAbortController(void 0);
|
|
1395
|
+
}
|
|
1396
|
+
}, [
|
|
1397
|
+
isStreaming,
|
|
1398
|
+
messages,
|
|
1399
|
+
chatStreaming
|
|
1400
|
+
]);
|
|
1401
|
+
const continueGenerate = useCallback(async ()=>{
|
|
774
1402
|
if (isStreaming) throw new Error('useChat is streaming already.');
|
|
775
1403
|
const controller = new AbortController();
|
|
776
1404
|
setAbortController(controller);
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
1405
|
+
try {
|
|
1406
|
+
await chatStreaming({
|
|
1407
|
+
query: '',
|
|
1408
|
+
is_continue: true,
|
|
1409
|
+
signal: controller.signal
|
|
1410
|
+
});
|
|
1411
|
+
} catch (e) {
|
|
1412
|
+
setError(e);
|
|
1413
|
+
throw e;
|
|
1414
|
+
} finally{
|
|
1415
|
+
setAbortController(void 0);
|
|
1416
|
+
}
|
|
1417
|
+
}, [
|
|
1418
|
+
isStreaming,
|
|
1419
|
+
chatStreaming
|
|
1420
|
+
]);
|
|
784
1421
|
const stop = ()=>{
|
|
785
1422
|
abortController?.abort();
|
|
786
1423
|
};
|
|
787
1424
|
const setSwipe = async (messageId, swipeId)=>{
|
|
788
|
-
|
|
789
|
-
setMessages((prev)=>prev.map((msg)=>msg.id === messageId ? {
|
|
1425
|
+
if (swipeId < 0) return;
|
|
1426
|
+
setMessages((prev)=>prev.map((msg)=>msg.id === messageId && swipeId < msg.swipes.length ? {
|
|
790
1427
|
...msg,
|
|
791
|
-
activeSwipeId: swipeId
|
|
1428
|
+
activeSwipeId: swipeId,
|
|
1429
|
+
content: msg.swipes[swipeId],
|
|
1430
|
+
mjv: msg.swipeInfo[swipeId]?.mjv
|
|
792
1431
|
} : msg));
|
|
1432
|
+
await mujian.ai.chat.message.swipe(messageId, swipeId);
|
|
793
1433
|
};
|
|
794
1434
|
const editMessage = async (messageId, content)=>{
|
|
795
1435
|
await mujian.ai.chat.message.editOne(messageId, content);
|
|
@@ -809,7 +1449,11 @@ const useChat = ({ body, onError, onFinish })=>{
|
|
|
809
1449
|
setMessages((prev)=>prev.map((msg)=>msg.id === messageId ? patchMessage(msg) : msg));
|
|
810
1450
|
};
|
|
811
1451
|
const deleteMessage = async (messageId)=>{
|
|
812
|
-
if (!messageId.startsWith(NOT_SAVED_MSG_ID_PREFIX))
|
|
1452
|
+
if (!messageId.startsWith(NOT_SAVED_MSG_ID_PREFIX)) try {
|
|
1453
|
+
await mujian.ai.chat.message.deleteOne(messageId);
|
|
1454
|
+
} catch (e) {
|
|
1455
|
+
if (e?.code !== 2011030004) throw e;
|
|
1456
|
+
}
|
|
813
1457
|
setMessages((prev)=>prev.filter((msg)=>msg.id !== messageId));
|
|
814
1458
|
};
|
|
815
1459
|
return {
|
|
@@ -832,7 +1476,9 @@ const useChat = ({ body, onError, onFinish })=>{
|
|
|
832
1476
|
},
|
|
833
1477
|
setSwipe,
|
|
834
1478
|
editMessage,
|
|
835
|
-
deleteMessage
|
|
1479
|
+
deleteMessage,
|
|
1480
|
+
loadMoreMessage,
|
|
1481
|
+
messagesStatus: messageLoadError ? 'error' : loadingMore || loading ? 'loading' : data?.noMore ? 'all-loaded' : 'has-more'
|
|
836
1482
|
};
|
|
837
1483
|
};
|
|
838
|
-
export { MdRenderer, MujianProvider, Thread, useChat, useMujian };
|
|
1484
|
+
export { MdRenderer, MujianProvider, MujianSpinner, Thread, useChat, useMjEngine, useMujian };
|