@mujian/js-sdk 0.0.6-beta.8 → 0.0.6-beta.80
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 +34 -2
- package/dist/index.d.ts +17 -39
- package/dist/index.js +369 -30
- package/dist/lite.d.ts +74 -0
- package/dist/lite.js +120 -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 +4 -0
- package/dist/modules/ai/index.d.ts +3 -2
- package/dist/modules/ai/openai/chat.d.ts +25 -0
- package/dist/modules/ai/openai/completions.d.ts +19 -0
- package/dist/modules/ai/openai/images.d.ts +19 -0
- package/dist/modules/ai/openai/index.d.ts +4 -0
- package/dist/modules/ai/openai/responses.d.ts +20 -0
- package/dist/modules/ai/text/index.d.ts +9 -2
- package/dist/modules/config.d.ts +18 -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 +5 -2
- package/dist/react/chat/useChat/message.d.ts +31 -13
- package/dist/react/components/MdRenderer/index.d.ts +6 -4
- 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 +828 -199
- package/dist/types/index.d.ts +38 -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 +138 -0
- package/dist/umd/react.js.LICENSE.txt +31 -0
- package/dist/utils/log.d.ts +4 -0
- package/package.json +16 -6
- /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,60 +406,185 @@ function messageFormatting(mes, sanitizerOverrides = {}) {
|
|
|
234
406
|
});
|
|
235
407
|
return mes;
|
|
236
408
|
}
|
|
237
|
-
const
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
409
|
+
const MdRendererBase = ({ content, unsafe = false, extra = {} })=>{
|
|
410
|
+
const containerRef = useRef(null);
|
|
411
|
+
const [iframeIdList, setIframeIdList] = useState([]);
|
|
412
|
+
useEffect(()=>{
|
|
413
|
+
let mes = messageFormatting(content);
|
|
414
|
+
mes = mes.replace(/<pre><code(.*)>[\s\S]*?<\/code><\/pre>/g, (match)=>{
|
|
415
|
+
if (!match.includes('<body>') && !match.includes('</body>')) return match;
|
|
416
|
+
const code = match.replace(/<pre><code(.*?)>/g, '').replace(/<\/code><\/pre>/g, '');
|
|
417
|
+
const id = v4();
|
|
418
|
+
const containerId = `MJ-iframe-container-${id}`;
|
|
419
|
+
const iframeId = `MJ-iframe-${id}`;
|
|
420
|
+
const srcdoc = createSrcContent(unescapeHTML(code), iframeId, unsafe, extra);
|
|
421
|
+
setIframeIdList((prev)=>[
|
|
422
|
+
...prev,
|
|
423
|
+
id
|
|
424
|
+
]);
|
|
425
|
+
const escapedSrcdoc = escapeHtmlAttribute(srcdoc);
|
|
426
|
+
return `
|
|
427
|
+
<div class="MJ-iframe-container" id="${containerId}" style="display:flex;width:100%;height:100%;position:relative;">
|
|
428
|
+
<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;">
|
|
429
|
+
<div class="spin-inner wave-text" style="font-weight:500;font-size:16px;color:white;display:flex;justify-content:center;align-items:center;">
|
|
430
|
+
<span>加</span>
|
|
431
|
+
<span>载</span>
|
|
432
|
+
<span>中</span>
|
|
433
|
+
<span>.</span>
|
|
434
|
+
<span>.</span>
|
|
435
|
+
<span>.</span>
|
|
436
|
+
</div>
|
|
437
|
+
</div>
|
|
438
|
+
<iframe id="${iframeId}" class="w-full" sandbox="${unsafe ? "allow-scripts" : "allow-scripts allow-same-origin"}" loading="lazy"
|
|
439
|
+
referrerpolicy="no-referrer" allowTransparency="true"
|
|
440
|
+
style="color-scheme: none;background-color: transparent;width:100%;;border:none;" srcdoc="` + escapedSrcdoc + `"></iframe>
|
|
441
|
+
</div>`;
|
|
442
|
+
});
|
|
443
|
+
if (containerRef.current) containerRef.current.innerHTML = mes;
|
|
444
|
+
}, [
|
|
445
|
+
content
|
|
446
|
+
]);
|
|
447
|
+
useEffect(()=>{
|
|
448
|
+
window.addEventListener('message', function(event) {
|
|
449
|
+
if (event.data?.type === 'MJ_ADJUST_IFRAME_HEIGHT' && event.data?.iframe_id) {
|
|
450
|
+
const targetIframe = containerRef.current?.querySelector('#' + event.data.iframe_id);
|
|
451
|
+
if (!targetIframe) return;
|
|
452
|
+
targetIframe.style.height = `${event.data.height}px`;
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
window.addEventListener('resize', ()=>{
|
|
456
|
+
iframeIdList.forEach((id)=>{
|
|
457
|
+
const iframe = containerRef.current?.querySelector('#MJ-iframe-' + id);
|
|
458
|
+
if (!iframe) return;
|
|
459
|
+
iframe.contentWindow?.postMessage({
|
|
460
|
+
type: 'MJ_UPDATE_VIEWPORT_HEIGHT'
|
|
461
|
+
}, '*');
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
}, []);
|
|
465
|
+
useEffect(()=>{
|
|
466
|
+
iframeIdList.forEach((id)=>{
|
|
467
|
+
const iframe = containerRef.current?.querySelector('#MJ-iframe-' + id);
|
|
468
|
+
if (!iframe) return;
|
|
469
|
+
const removeSpin = ()=>{
|
|
470
|
+
const spinElement = iframe.parentElement?.querySelector('#MJ-spin-' + id);
|
|
471
|
+
if (spinElement) spinElement.remove();
|
|
472
|
+
};
|
|
473
|
+
const timeout = setTimeout(removeSpin, 5000);
|
|
474
|
+
iframe.addEventListener('load', ()=>{
|
|
475
|
+
clearTimeout(timeout);
|
|
476
|
+
removeSpin();
|
|
477
|
+
});
|
|
478
|
+
});
|
|
479
|
+
return ()=>{
|
|
480
|
+
iframeIdList.forEach((id)=>{
|
|
481
|
+
const iframe = containerRef.current?.querySelector('#MJ-iframe-' + id);
|
|
482
|
+
if (!iframe) return;
|
|
483
|
+
const spinElement = iframe.parentElement?.querySelector('#MJ-spin-' + iframe.id);
|
|
484
|
+
if (spinElement) spinElement.remove();
|
|
485
|
+
iframe.removeEventListener('load', ()=>{
|
|
486
|
+
Log.i('iframe loaded', iframe.id);
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
};
|
|
490
|
+
}, [
|
|
491
|
+
iframeIdList
|
|
492
|
+
]);
|
|
268
493
|
return /*#__PURE__*/ jsx("div", {
|
|
269
494
|
className: "mes_text",
|
|
270
|
-
|
|
271
|
-
__html: mes
|
|
272
|
-
}
|
|
495
|
+
ref: containerRef
|
|
273
496
|
});
|
|
274
497
|
};
|
|
275
498
|
const MdRenderer = /*#__PURE__*/ react.memo(MdRendererBase, (prev, next)=>prev.content === next.content);
|
|
276
|
-
MdRendererBase.displayName =
|
|
277
|
-
MdRenderer.displayName =
|
|
278
|
-
|
|
279
|
-
|
|
499
|
+
MdRendererBase.displayName = 'MdRenderer';
|
|
500
|
+
MdRenderer.displayName = 'MdRenderer';
|
|
501
|
+
var events_EVENT = /*#__PURE__*/ function(EVENT) {
|
|
502
|
+
EVENT["MUJIAN_INIT"] = "mujian:init";
|
|
503
|
+
EVENT["MUJIAN_AI_CHAT_STOP"] = "mujian:ai:chat:stop";
|
|
504
|
+
EVENT["MUJIAN_AI_CHAT_COMPLETE"] = "mujian:ai:chat:complete";
|
|
505
|
+
EVENT["MUJIAN_AI_CHAT_APPLY_REGEX"] = "mujian:ai:chat:applyRegex";
|
|
506
|
+
EVENT["MUJIAN_AI_CHAT_RENDER_MESSAGE"] = "mujian:ai:chat:renderMessage";
|
|
507
|
+
EVENT["MUJIAN_AI_TEXT_GENERATE"] = "mujian:ai:text:generate";
|
|
508
|
+
EVENT["MUJIAN_AI_OPENAI_COMPLETIONS_CREATE"] = "mujian:ai:openai:completions:create";
|
|
509
|
+
EVENT["MUJIAN_AI_OPENAI_CHAT_COMPLETIONS_CREATE"] = "mujian:ai:openai:chat:completions:create";
|
|
510
|
+
EVENT["MUJIAN_AI_OPENAI_RESPONSES_CREATE"] = "mujian:ai:openai:responses:create";
|
|
511
|
+
EVENT["MUJIAN_AI_CHAT_MESSAGE_GET_ALL"] = "mujian:ai:chat:message:getAll";
|
|
512
|
+
EVENT["MUJIAN_AI_CHAT_MESSAGE_GET_PAGE"] = "mujian:ai:chat:message:getPage";
|
|
513
|
+
EVENT["MUJIAN_AI_CHAT_PROJECT_GET_INFO"] = "mujian:ai:chat:project:getInfo";
|
|
514
|
+
EVENT["MUJIAN_AI_SETTINGS_PERSONA_GET_ACTIVE"] = "mujian:ai:settings:persona:getActive";
|
|
515
|
+
EVENT["MUJIAN_AI_SETTINGS_PERSONA_SET_ACTIVE"] = "mujian:ai:settings:persona:setActive";
|
|
516
|
+
EVENT["MUJIAN_AI_SETTINGS_MODEL_GET_ALL"] = "mujian:ai:settings:model:getAll";
|
|
517
|
+
EVENT["MUJIAN_AI_SETTINGS_MODEL_SET_ACTIVE"] = "mujian:ai:settings:model:setActive";
|
|
518
|
+
EVENT["MUJIAN_AI_SETTINGS_MODEL_GET_ACTIVE"] = "mujian:ai:settings:model:getActive";
|
|
519
|
+
EVENT["MUJIAN_AI_CHAT_MESSAGE_DELETE_ONE"] = "mujian:ai:chat:message:deleteOne";
|
|
520
|
+
EVENT["MUJIAN_AI_CHAT_MESSAGE_EDIT_ONE"] = "mujian:ai:chat:message:editOne";
|
|
521
|
+
EVENT["MUJIAN_AI_CHAT_MESSAGE_SWIPE"] = "mujian:ai:chat:message:swipe";
|
|
522
|
+
EVENT["MUJIAN_AI_CHAT_MESSAGE_GET_PROMPT"] = "mujian:ai:chat:message:getPrompt";
|
|
523
|
+
EVENT["MUJIAN_AI_OPENAI_IMAGES_GENERATE"] = "mujian:ai:openai:images:generate";
|
|
524
|
+
EVENT["MUJIAN_UTILS_CLIPBOARD_WRITE_TEXT"] = "mujian:utils:clipboard:writeText";
|
|
525
|
+
EVENT["MUJIAN_GET_CONFIG"] = "mujian:getConfig";
|
|
526
|
+
return EVENT;
|
|
527
|
+
}({});
|
|
528
|
+
function wrapOnData(onData) {
|
|
529
|
+
let fullContent = '';
|
|
530
|
+
let buffer = '';
|
|
531
|
+
let questionId;
|
|
532
|
+
let replyId;
|
|
533
|
+
return function(data) {
|
|
534
|
+
buffer += data;
|
|
535
|
+
const lines = buffer.split('\n');
|
|
536
|
+
buffer = lines.pop() || '';
|
|
537
|
+
for (const line of lines)if (line.startsWith('data: ')) try {
|
|
538
|
+
const parsedData = JSON.parse(line.slice(6));
|
|
539
|
+
if (parsedData.question_id) questionId = parsedData.question_id;
|
|
540
|
+
if (parsedData.reply_id) replyId = parsedData.reply_id;
|
|
541
|
+
if (parsedData.isFinished) return void onData({
|
|
542
|
+
isFinished: true,
|
|
543
|
+
deltaContent: '',
|
|
544
|
+
fullContent,
|
|
545
|
+
questionId,
|
|
546
|
+
replyId
|
|
547
|
+
});
|
|
548
|
+
const deltaContent = parsedData?.choices?.[0]?.delta?.content;
|
|
549
|
+
if (deltaContent?.length > 0) {
|
|
550
|
+
fullContent += deltaContent;
|
|
551
|
+
onData({
|
|
552
|
+
isFinished: false,
|
|
553
|
+
deltaContent: deltaContent,
|
|
554
|
+
fullContent,
|
|
555
|
+
questionId,
|
|
556
|
+
replyId
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
} catch (e) {
|
|
560
|
+
onData({
|
|
561
|
+
isFinished: true,
|
|
562
|
+
error: e,
|
|
563
|
+
deltaContent: '',
|
|
564
|
+
fullContent,
|
|
565
|
+
questionId,
|
|
566
|
+
replyId
|
|
567
|
+
});
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
const chat_complete = async function(message, onData, signal, option = {}) {
|
|
573
|
+
await this.call(events_EVENT.MUJIAN_AI_CHAT_COMPLETE, {
|
|
280
574
|
content: message
|
|
281
575
|
}, {
|
|
282
|
-
onData,
|
|
576
|
+
onData: option.parseContent ? wrapOnData(onData) : onData,
|
|
283
577
|
signal
|
|
284
578
|
});
|
|
285
579
|
};
|
|
286
580
|
const applyRegex = async function(props) {
|
|
287
|
-
return await this.call(
|
|
581
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_APPLY_REGEX, props);
|
|
582
|
+
};
|
|
583
|
+
const renderMessage = async function(props) {
|
|
584
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_RENDER_MESSAGE, props);
|
|
288
585
|
};
|
|
289
586
|
const continueComplete = async function(onData, signal) {
|
|
290
|
-
return await this.call(
|
|
587
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_COMPLETE, {
|
|
291
588
|
isContinue: true
|
|
292
589
|
}, {
|
|
293
590
|
onData,
|
|
@@ -295,7 +592,7 @@ const continueComplete = async function(onData, signal) {
|
|
|
295
592
|
});
|
|
296
593
|
};
|
|
297
594
|
const chat_regenerate = async function(onData, signal) {
|
|
298
|
-
return await this.call(
|
|
595
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_COMPLETE, {
|
|
299
596
|
isRegenerate: true
|
|
300
597
|
}, {
|
|
301
598
|
onData,
|
|
@@ -303,61 +600,120 @@ const chat_regenerate = async function(onData, signal) {
|
|
|
303
600
|
});
|
|
304
601
|
};
|
|
305
602
|
const getAll = async function() {
|
|
306
|
-
return await this.call(
|
|
603
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_MESSAGE_GET_ALL);
|
|
307
604
|
};
|
|
308
605
|
const messageDeleteOne = async function(messageId) {
|
|
309
|
-
return await this.call(
|
|
606
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_MESSAGE_DELETE_ONE, {
|
|
310
607
|
messageId
|
|
311
608
|
});
|
|
312
609
|
};
|
|
313
610
|
const messageEditOne = async function(messageId, content) {
|
|
314
|
-
return await this.call(
|
|
611
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_MESSAGE_EDIT_ONE, {
|
|
315
612
|
messageId,
|
|
316
613
|
content
|
|
317
614
|
});
|
|
318
615
|
};
|
|
319
616
|
const messageSwipe = async function(messageId, swipeId) {
|
|
320
|
-
return await this.call(
|
|
617
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_MESSAGE_SWIPE, {
|
|
321
618
|
messageId,
|
|
322
619
|
swipeId
|
|
323
620
|
});
|
|
324
621
|
};
|
|
325
622
|
const getPrompt = async function(messageId) {
|
|
326
|
-
return await this.call(
|
|
623
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_MESSAGE_GET_PROMPT, {
|
|
327
624
|
messageId
|
|
328
625
|
});
|
|
329
626
|
};
|
|
627
|
+
async function getPage(fromCursor, pageSize) {
|
|
628
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_MESSAGE_GET_PAGE, {
|
|
629
|
+
fromCursor,
|
|
630
|
+
pageSize
|
|
631
|
+
});
|
|
632
|
+
}
|
|
330
633
|
const getInfo = async function() {
|
|
331
|
-
return await this.call(
|
|
634
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_PROJECT_GET_INFO);
|
|
332
635
|
};
|
|
333
636
|
const getActive = async function() {
|
|
334
|
-
return await this.call(
|
|
637
|
+
return await this.call(events_EVENT.MUJIAN_AI_SETTINGS_PERSONA_GET_ACTIVE);
|
|
335
638
|
};
|
|
336
639
|
const setActive = async function(personaId) {
|
|
337
|
-
return await this.call(
|
|
640
|
+
return await this.call(events_EVENT.MUJIAN_AI_SETTINGS_PERSONA_SET_ACTIVE, {
|
|
338
641
|
personaId
|
|
339
642
|
});
|
|
340
643
|
};
|
|
341
644
|
const model_getActive = async function() {
|
|
342
|
-
return await this.call(
|
|
645
|
+
return await this.call(events_EVENT.MUJIAN_AI_SETTINGS_MODEL_GET_ACTIVE);
|
|
343
646
|
};
|
|
344
647
|
const model_setActive = async function(modelId) {
|
|
345
|
-
return await this.call(
|
|
648
|
+
return await this.call(events_EVENT.MUJIAN_AI_SETTINGS_MODEL_SET_ACTIVE, {
|
|
346
649
|
modelId
|
|
347
650
|
});
|
|
348
651
|
};
|
|
349
652
|
const model_getAll = async function() {
|
|
350
|
-
return await this.call(
|
|
653
|
+
return await this.call(events_EVENT.MUJIAN_AI_SETTINGS_MODEL_GET_ALL);
|
|
351
654
|
};
|
|
352
|
-
const generate = async function() {
|
|
353
|
-
return await this.call(
|
|
354
|
-
content
|
|
655
|
+
const generate = async function(content) {
|
|
656
|
+
return await this.call(MujianSdk.EVENT.MUJIAN_AI_TEXT_GENERATE, {
|
|
657
|
+
content
|
|
355
658
|
});
|
|
356
659
|
};
|
|
660
|
+
const chat = {
|
|
661
|
+
completions: {
|
|
662
|
+
create: async function(params, options, onData, signal) {
|
|
663
|
+
return await this.call(MujianSdk.EVENT.MUJIAN_AI_OPENAI_CHAT_COMPLETIONS_CREATE, {
|
|
664
|
+
params,
|
|
665
|
+
options
|
|
666
|
+
}, {
|
|
667
|
+
onData,
|
|
668
|
+
signal
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
const completions = {
|
|
674
|
+
create: async function(params, options, onData, signal) {
|
|
675
|
+
return await this.call(MujianSdk.EVENT.MUJIAN_AI_OPENAI_COMPLETIONS_CREATE, {
|
|
676
|
+
params,
|
|
677
|
+
options
|
|
678
|
+
}, {
|
|
679
|
+
onData,
|
|
680
|
+
signal
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
const responses = {
|
|
685
|
+
create: async function(params, options, onData, signal) {
|
|
686
|
+
return await this.call(MujianSdk.EVENT.MUJIAN_AI_OPENAI_RESPONSES_CREATE, {
|
|
687
|
+
params,
|
|
688
|
+
options
|
|
689
|
+
}, {
|
|
690
|
+
onData,
|
|
691
|
+
signal
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
const images_images = {
|
|
696
|
+
generate: async function(params, options, onData, signal) {
|
|
697
|
+
return await this.call(MujianSdk.EVENT.MUJIAN_AI_OPENAI_IMAGES_GENERATE, {
|
|
698
|
+
params,
|
|
699
|
+
options
|
|
700
|
+
}, {
|
|
701
|
+
onData,
|
|
702
|
+
signal
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
async function getConfig() {
|
|
707
|
+
return await this.call(events_EVENT.MUJIAN_GET_CONFIG);
|
|
708
|
+
}
|
|
357
709
|
const saveGame = async function() {};
|
|
358
710
|
const loadGame = async function() {};
|
|
711
|
+
async function writeText(text) {
|
|
712
|
+
return await this.call(events_EVENT.MUJIAN_UTILS_CLIPBOARD_WRITE_TEXT, text);
|
|
713
|
+
}
|
|
359
714
|
class MujianSdk {
|
|
360
715
|
constructor(){}
|
|
716
|
+
static EVENT = events_EVENT;
|
|
361
717
|
static getInstance() {
|
|
362
718
|
if (!window.$mujian) window.$mujian = new MujianSdk();
|
|
363
719
|
return window.$mujian;
|
|
@@ -368,28 +724,59 @@ class MujianSdk {
|
|
|
368
724
|
return this.ready;
|
|
369
725
|
}
|
|
370
726
|
pendingRequests = new Map();
|
|
727
|
+
_config;
|
|
728
|
+
get openapi() {
|
|
729
|
+
return this._config?.openapi;
|
|
730
|
+
}
|
|
731
|
+
initPromise = null;
|
|
371
732
|
async init() {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
733
|
+
if (this.initPromise) return this.initPromise;
|
|
734
|
+
this.initPromise = (async ()=>{
|
|
735
|
+
const handshake = new postmate.Model({
|
|
736
|
+
reply: ({ id, complete, data, error })=>{
|
|
737
|
+
const call = this.pendingRequests.get(id);
|
|
738
|
+
if (!call) return;
|
|
739
|
+
if (error) {
|
|
740
|
+
call.reject(error);
|
|
741
|
+
this.pendingRequests.delete(id);
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
call.onData?.(data);
|
|
745
|
+
if (complete) {
|
|
746
|
+
call.onComplete?.();
|
|
747
|
+
call.resolve(data);
|
|
748
|
+
this.pendingRequests.delete(id);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
});
|
|
752
|
+
try {
|
|
753
|
+
const parent = await handshake;
|
|
754
|
+
this.ready = true;
|
|
755
|
+
this.parent = parent;
|
|
756
|
+
Log.i('mujian sdk client init');
|
|
757
|
+
await this.call(events_EVENT.MUJIAN_INIT);
|
|
758
|
+
const projectInfo = await this.ai.chat.project.getInfo();
|
|
759
|
+
if (projectInfo.config?.customCss) {
|
|
760
|
+
const style = document.createElement('style');
|
|
761
|
+
style.setAttribute('type', 'text/css');
|
|
762
|
+
style.setAttribute('id', 'mujian-custom-css');
|
|
763
|
+
style.textContent = projectInfo.config.customCss;
|
|
764
|
+
document.head.appendChild(style);
|
|
381
765
|
}
|
|
766
|
+
if (projectInfo.config?.customJs) {
|
|
767
|
+
const script = document.createElement("script");
|
|
768
|
+
script.setAttribute('type', "text/javascript");
|
|
769
|
+
script.setAttribute('id', 'mujian-custom-js');
|
|
770
|
+
script.textContent = projectInfo.config.customJs;
|
|
771
|
+
document.head.appendChild(script);
|
|
772
|
+
}
|
|
773
|
+
const config = await getConfig.call(this);
|
|
774
|
+
if (config) this._config = config;
|
|
775
|
+
} catch (error) {
|
|
776
|
+
Log.e('init error', error);
|
|
382
777
|
}
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
const parent = await handshake;
|
|
386
|
-
this.ready = true;
|
|
387
|
-
this.parent = parent;
|
|
388
|
-
console.log('mujian sdk client init');
|
|
389
|
-
await this.call("mujian:init");
|
|
390
|
-
} catch (error) {
|
|
391
|
-
console.log('init error', error);
|
|
392
|
-
}
|
|
778
|
+
})();
|
|
779
|
+
return this.initPromise;
|
|
393
780
|
}
|
|
394
781
|
emit(event, data) {
|
|
395
782
|
if (!this.ready) throw new Error('Mujian is not initialized');
|
|
@@ -415,7 +802,7 @@ class MujianSdk {
|
|
|
415
802
|
data
|
|
416
803
|
});
|
|
417
804
|
controller?.signal?.addEventListener('abort', ()=>{
|
|
418
|
-
this.emit(
|
|
805
|
+
this.emit(events_EVENT.MUJIAN_AI_CHAT_STOP, {
|
|
419
806
|
id: callId
|
|
420
807
|
});
|
|
421
808
|
});
|
|
@@ -439,6 +826,7 @@ class MujianSdk {
|
|
|
439
826
|
},
|
|
440
827
|
complete: chat_complete.bind(this),
|
|
441
828
|
applyRegex: applyRegex.bind(this),
|
|
829
|
+
renderMessage: renderMessage.bind(this),
|
|
442
830
|
continue: continueComplete.bind(this),
|
|
443
831
|
regenerate: chat_regenerate.bind(this),
|
|
444
832
|
message: {
|
|
@@ -446,17 +834,34 @@ class MujianSdk {
|
|
|
446
834
|
deleteOne: messageDeleteOne.bind(this),
|
|
447
835
|
editOne: messageEditOne.bind(this),
|
|
448
836
|
swipe: messageSwipe.bind(this),
|
|
449
|
-
getPrompt: getPrompt.bind(this)
|
|
837
|
+
getPrompt: getPrompt.bind(this),
|
|
838
|
+
getPage: getPage.bind(this)
|
|
450
839
|
}
|
|
451
840
|
},
|
|
452
841
|
text: {
|
|
453
842
|
complete: generate.bind(this)
|
|
843
|
+
},
|
|
844
|
+
openai: {
|
|
845
|
+
completions: {
|
|
846
|
+
create: completions.create.bind(this)
|
|
847
|
+
},
|
|
848
|
+
chat: {
|
|
849
|
+
completions: {
|
|
850
|
+
create: chat.completions.create.bind(this)
|
|
851
|
+
}
|
|
852
|
+
},
|
|
853
|
+
responses: {
|
|
854
|
+
create: responses.create.bind(this)
|
|
855
|
+
},
|
|
856
|
+
images: {
|
|
857
|
+
generate: images_images.generate.bind(this)
|
|
858
|
+
}
|
|
454
859
|
}
|
|
455
860
|
};
|
|
456
861
|
ui = {};
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
862
|
+
utils = {
|
|
863
|
+
clipboard: {
|
|
864
|
+
writeText: writeText.bind(this)
|
|
460
865
|
}
|
|
461
866
|
};
|
|
462
867
|
hybrid = {};
|
|
@@ -474,6 +879,43 @@ class MujianSdk {
|
|
|
474
879
|
}
|
|
475
880
|
};
|
|
476
881
|
}
|
|
882
|
+
const styleSheet = `
|
|
883
|
+
@keyframes spin {
|
|
884
|
+
0% { transform: rotate(0deg); }
|
|
885
|
+
100% { transform: rotate(360deg); }
|
|
886
|
+
}
|
|
887
|
+
`;
|
|
888
|
+
const spinnerStyle = {
|
|
889
|
+
width: 48,
|
|
890
|
+
height: 48,
|
|
891
|
+
animation: 'spin 1s linear infinite'
|
|
892
|
+
};
|
|
893
|
+
const MujianSpinner = ({ className, style })=>/*#__PURE__*/ jsxs(Fragment, {
|
|
894
|
+
children: [
|
|
895
|
+
/*#__PURE__*/ jsx("style", {
|
|
896
|
+
children: styleSheet
|
|
897
|
+
}),
|
|
898
|
+
/*#__PURE__*/ jsx("svg", {
|
|
899
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
900
|
+
width: "24",
|
|
901
|
+
height: "24",
|
|
902
|
+
viewBox: "0 0 24 24",
|
|
903
|
+
fill: "none",
|
|
904
|
+
stroke: "currentColor",
|
|
905
|
+
strokeWidth: "2",
|
|
906
|
+
strokeLinecap: "round",
|
|
907
|
+
strokeLinejoin: "round",
|
|
908
|
+
className: className,
|
|
909
|
+
style: {
|
|
910
|
+
...spinnerStyle,
|
|
911
|
+
...style
|
|
912
|
+
},
|
|
913
|
+
children: /*#__PURE__*/ jsx("path", {
|
|
914
|
+
d: "M21 12a9 9 0 1 1-6.219-8.56"
|
|
915
|
+
})
|
|
916
|
+
})
|
|
917
|
+
]
|
|
918
|
+
});
|
|
477
919
|
const MujianContext = /*#__PURE__*/ createContext(null);
|
|
478
920
|
const MujianProvider = ({ children, loadingComponent })=>{
|
|
479
921
|
const [mujian, setMujian] = useState(null);
|
|
@@ -486,7 +928,20 @@ const MujianProvider = ({ children, loadingComponent })=>{
|
|
|
486
928
|
}, []);
|
|
487
929
|
return /*#__PURE__*/ jsx(MujianContext.Provider, {
|
|
488
930
|
value: mujian,
|
|
489
|
-
children: mujian ? children : loadingComponent ??
|
|
931
|
+
children: mujian ? children : loadingComponent ?? /*#__PURE__*/ jsx("div", {
|
|
932
|
+
style: {
|
|
933
|
+
height: '100%',
|
|
934
|
+
width: '100%',
|
|
935
|
+
display: 'flex',
|
|
936
|
+
justifyContent: 'center',
|
|
937
|
+
alignItems: 'center'
|
|
938
|
+
},
|
|
939
|
+
children: /*#__PURE__*/ jsx(MujianSpinner, {
|
|
940
|
+
style: {
|
|
941
|
+
color: '#EC4342'
|
|
942
|
+
}
|
|
943
|
+
})
|
|
944
|
+
})
|
|
490
945
|
});
|
|
491
946
|
};
|
|
492
947
|
const useMujian = ()=>{
|
|
@@ -504,7 +959,7 @@ const MessageItem = (props)=>{
|
|
|
504
959
|
const { data: renderedMessage } = useRequest(async ()=>{
|
|
505
960
|
const { isStreaming } = message;
|
|
506
961
|
if (isStreaming) return message;
|
|
507
|
-
return await mujian.ai.chat.
|
|
962
|
+
return await mujian.ai.chat.renderMessage({
|
|
508
963
|
message,
|
|
509
964
|
depth,
|
|
510
965
|
index
|
|
@@ -533,28 +988,92 @@ const Thread = {
|
|
|
533
988
|
MessageItem: MessageItem,
|
|
534
989
|
MessageList: MessageList
|
|
535
990
|
};
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
991
|
+
let $mj_ai_chat_complete;
|
|
992
|
+
let $mj_ai_chat_project;
|
|
993
|
+
let $mj_ai_chat_settings_persona;
|
|
994
|
+
let $mj_ai_chat_setFirstMesIndex;
|
|
995
|
+
let $mj_ai_chat_mjv_get;
|
|
996
|
+
let $mj_ai_chat_mjv_getAll;
|
|
997
|
+
const $mj_engine = {
|
|
998
|
+
ai: {
|
|
999
|
+
chat: {
|
|
1000
|
+
get complete () {
|
|
1001
|
+
return $mj_ai_chat_complete;
|
|
1002
|
+
},
|
|
1003
|
+
get project () {
|
|
1004
|
+
return $mj_ai_chat_project;
|
|
1005
|
+
},
|
|
1006
|
+
settings: {
|
|
1007
|
+
get persona () {
|
|
1008
|
+
return $mj_ai_chat_settings_persona;
|
|
1009
|
+
}
|
|
1010
|
+
},
|
|
1011
|
+
get setFirstMesIndex () {
|
|
1012
|
+
return $mj_ai_chat_setFirstMesIndex;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
541
1015
|
}
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
1016
|
+
};
|
|
1017
|
+
window.$mj_engine = {
|
|
1018
|
+
...$mj_engine,
|
|
1019
|
+
bind ({ messageId, swipeId }) {
|
|
1020
|
+
return {
|
|
1021
|
+
ai: {
|
|
1022
|
+
chat: {
|
|
1023
|
+
...$mj_engine.ai.chat,
|
|
1024
|
+
mjv: {
|
|
1025
|
+
get (path) {
|
|
1026
|
+
return $mj_ai_chat_mjv_get?.(messageId, swipeId, path);
|
|
1027
|
+
},
|
|
1028
|
+
getAll () {
|
|
1029
|
+
return $mj_ai_chat_mjv_getAll?.(messageId, swipeId) ?? {};
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
};
|
|
548
1035
|
}
|
|
1036
|
+
};
|
|
1037
|
+
function useMjEngine({ projectInfo, activePersona, onSend, messages, setSwipe }) {
|
|
1038
|
+
useEffect(()=>{
|
|
1039
|
+
$mj_ai_chat_project = projectInfo ?? void 0;
|
|
1040
|
+
$mj_ai_chat_settings_persona = activePersona ?? void 0;
|
|
1041
|
+
}, [
|
|
1042
|
+
projectInfo,
|
|
1043
|
+
activePersona
|
|
1044
|
+
]);
|
|
1045
|
+
useEffect(()=>{
|
|
1046
|
+
$mj_ai_chat_complete = async (message)=>{
|
|
1047
|
+
await onSend(message);
|
|
1048
|
+
};
|
|
1049
|
+
$mj_ai_chat_setFirstMesIndex = async (oneBasedIndex)=>{
|
|
1050
|
+
if (messages.length > 1) throw new Error('已有新消息,不允许切换开场白');
|
|
1051
|
+
if (0 === messages.length) throw new Error('断言失败:没有开场消息,无法切换开场白');
|
|
1052
|
+
const zeroBasedIndex = Math.floor(oneBasedIndex) - 1;
|
|
1053
|
+
const swipeLength = messages[0].swipes.length;
|
|
1054
|
+
if (zeroBasedIndex < 0 || zeroBasedIndex >= swipeLength) return;
|
|
1055
|
+
setSwipe(messages[0].id, zeroBasedIndex);
|
|
1056
|
+
};
|
|
1057
|
+
$mj_ai_chat_mjv_getAll = (messageId, swipeId)=>messages.find((m)=>m.id === messageId)?.swipeInfo[swipeId]?.mjv?.value;
|
|
1058
|
+
$mj_ai_chat_mjv_get = (messageId, swipeId, path)=>{
|
|
1059
|
+
const mjv = $mj_ai_chat_mjv_getAll?.(messageId, swipeId);
|
|
1060
|
+
if (!mjv) return;
|
|
1061
|
+
return get(mjv, path);
|
|
1062
|
+
};
|
|
1063
|
+
}, [
|
|
1064
|
+
onSend,
|
|
1065
|
+
messages,
|
|
1066
|
+
setSwipe
|
|
1067
|
+
]);
|
|
549
1068
|
}
|
|
550
|
-
class
|
|
1069
|
+
class SendMessageError extends Error {
|
|
551
1070
|
constructor(message, cause){
|
|
552
1071
|
super(message);
|
|
553
1072
|
this.name = this.constructor.name;
|
|
554
1073
|
this.cause = cause;
|
|
555
1074
|
}
|
|
556
1075
|
}
|
|
557
|
-
class
|
|
1076
|
+
class UnexpectedSseEndingError extends Error {
|
|
558
1077
|
constructor(message, cause){
|
|
559
1078
|
super(message);
|
|
560
1079
|
this.name = this.constructor.name;
|
|
@@ -569,6 +1088,7 @@ async function* callSdk(mujian, content, type = 'generate', signal) {
|
|
|
569
1088
|
try {
|
|
570
1089
|
const onData = (data)=>{
|
|
571
1090
|
if (error) return;
|
|
1091
|
+
if ('string' != typeof data) return;
|
|
572
1092
|
queue.push(data);
|
|
573
1093
|
if (resolveWait) {
|
|
574
1094
|
resolveWait();
|
|
@@ -603,48 +1123,52 @@ async function* callSdk(mujian, content, type = 'generate', signal) {
|
|
|
603
1123
|
resolveWait = resolve;
|
|
604
1124
|
});
|
|
605
1125
|
}
|
|
606
|
-
const
|
|
1126
|
+
const NOT_SAVED_MSG_ID_PREFIX = 'not_saved';
|
|
1127
|
+
const FALLBACK_MESSAGE = `哎呀,AI线路好像抽风了`;
|
|
1128
|
+
const useChatStreaming = ({ common, setError, setMessages, getMessages, setInput, mujian })=>{
|
|
607
1129
|
const { body } = common;
|
|
608
1130
|
const [isStreaming, setIsStreaming] = useState(false);
|
|
609
1131
|
const chatStreaming = useCallback(async ({ query, regenerate, is_continue, signal })=>{
|
|
610
1132
|
try {
|
|
611
1133
|
setError(void 0);
|
|
612
1134
|
setIsStreaming(true);
|
|
1135
|
+
const backupMessages = getMessages();
|
|
613
1136
|
const userMessage = {
|
|
614
|
-
id: Date.now()
|
|
1137
|
+
id: `${NOT_SAVED_MSG_ID_PREFIX}_user_${Date.now()}`,
|
|
615
1138
|
content: query || '',
|
|
616
1139
|
role: 'user',
|
|
617
1140
|
swipes: [],
|
|
618
1141
|
activeSwipeId: 0,
|
|
619
1142
|
isStreaming: false,
|
|
620
|
-
sendAt: new Date()
|
|
1143
|
+
sendAt: new Date(),
|
|
1144
|
+
swipeInfo: [],
|
|
1145
|
+
flags: {}
|
|
621
1146
|
};
|
|
622
1147
|
const aiMessage = {
|
|
623
|
-
id: Date.now()
|
|
1148
|
+
id: `${NOT_SAVED_MSG_ID_PREFIX}_assistant_${Date.now()}`,
|
|
624
1149
|
content: '',
|
|
625
1150
|
role: 'assistant',
|
|
626
|
-
swipes: [
|
|
1151
|
+
swipes: [
|
|
1152
|
+
''
|
|
1153
|
+
],
|
|
627
1154
|
activeSwipeId: 0,
|
|
628
1155
|
isStreaming: true,
|
|
629
|
-
sendAt: new Date()
|
|
1156
|
+
sendAt: new Date(),
|
|
1157
|
+
swipeInfo: [
|
|
1158
|
+
{}
|
|
1159
|
+
],
|
|
1160
|
+
flags: {}
|
|
630
1161
|
};
|
|
631
|
-
if (regenerate) setMessages((
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
swipes: [
|
|
640
|
-
...lastMessage.swipes,
|
|
641
|
-
''
|
|
642
|
-
],
|
|
643
|
-
content: '',
|
|
644
|
-
isStreaming: true
|
|
1162
|
+
if (regenerate) setMessages(produce((draft)=>{
|
|
1163
|
+
const lastMessage = draft[draft.length - 1];
|
|
1164
|
+
lastMessage.activeSwipeId = lastMessage.swipes.length;
|
|
1165
|
+
lastMessage.swipes.push('');
|
|
1166
|
+
lastMessage.content = '';
|
|
1167
|
+
lastMessage.isStreaming = true;
|
|
1168
|
+
lastMessage.flags = {
|
|
1169
|
+
saved: lastMessage.flags.saved
|
|
645
1170
|
};
|
|
646
|
-
|
|
647
|
-
});
|
|
1171
|
+
}));
|
|
648
1172
|
else is_continue ? setMessages((prev)=>[
|
|
649
1173
|
...prev,
|
|
650
1174
|
aiMessage
|
|
@@ -665,45 +1189,59 @@ const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
|
665
1189
|
const data = line.slice(6);
|
|
666
1190
|
try {
|
|
667
1191
|
const parsedData = JSON.parse(data);
|
|
668
|
-
|
|
1192
|
+
console.log(parsedData);
|
|
1193
|
+
if (regenerate || 'meta' !== parsedData.type) {
|
|
1194
|
+
if ('stream' === parsedData.type) {
|
|
1195
|
+
const partialContent = parsedData.choices[0].delta.content;
|
|
1196
|
+
parsedData.choices[0].delta.reasoning;
|
|
1197
|
+
const chunkFinishReason = parsedData.choices[0].finish_reason;
|
|
1198
|
+
content += partialContent;
|
|
1199
|
+
setMessages(produce((draft)=>{
|
|
1200
|
+
const lastMessage = draft[draft.length - 1];
|
|
1201
|
+
lastMessage.swipes[lastMessage.activeSwipeId] = content;
|
|
1202
|
+
lastMessage.content = content;
|
|
1203
|
+
lastMessage.isStreaming = true;
|
|
1204
|
+
if ('content_filter' === chunkFinishReason) lastMessage.flags.contentFilter = true;
|
|
1205
|
+
}));
|
|
1206
|
+
await new Promise((resolve)=>setTimeout(resolve, 10));
|
|
1207
|
+
} else if ('mjv' === parsedData.type) {
|
|
1208
|
+
const { value, delta, schema } = parsedData;
|
|
1209
|
+
setMessages(produce((draft)=>{
|
|
1210
|
+
const lastMessage = draft[draft.length - 1];
|
|
1211
|
+
const mjv = {
|
|
1212
|
+
value,
|
|
1213
|
+
delta,
|
|
1214
|
+
schema
|
|
1215
|
+
};
|
|
1216
|
+
const swipeInfo = lastMessage.swipeInfo;
|
|
1217
|
+
if (swipeInfo[lastMessage.activeSwipeId]) swipeInfo[lastMessage.activeSwipeId].mjv = mjv;
|
|
1218
|
+
else swipeInfo[lastMessage.activeSwipeId] = {
|
|
1219
|
+
mjv
|
|
1220
|
+
};
|
|
1221
|
+
lastMessage.swipeInfo = swipeInfo;
|
|
1222
|
+
lastMessage.mjv = mjv;
|
|
1223
|
+
}));
|
|
1224
|
+
}
|
|
1225
|
+
} else {
|
|
669
1226
|
const { question_id, reply_id } = parsedData;
|
|
670
1227
|
setMessages((prev)=>{
|
|
671
1228
|
const newMessages = [
|
|
672
1229
|
...prev
|
|
673
1230
|
];
|
|
674
|
-
if (question_id && !is_continue) newMessages[newMessages.length - 2].id = question_id;
|
|
675
|
-
const lastMessage = newMessages[newMessages.length - 1];
|
|
676
|
-
newMessages[newMessages.length - 1] = {
|
|
677
|
-
...lastMessage,
|
|
678
|
-
id: reply_id
|
|
679
|
-
};
|
|
680
1231
|
return newMessages;
|
|
681
1232
|
});
|
|
1233
|
+
setMessages(produce((draft)=>{
|
|
1234
|
+
if (question_id && !is_continue) {
|
|
1235
|
+
const userMsg = draft[draft.length - 2];
|
|
1236
|
+
userMsg.id = question_id;
|
|
1237
|
+
userMsg.flags.saved = true;
|
|
1238
|
+
}
|
|
1239
|
+
const lastMessage = draft[draft.length - 1];
|
|
1240
|
+
lastMessage.id = reply_id;
|
|
1241
|
+
lastMessage.flags.saved = true;
|
|
1242
|
+
}));
|
|
682
1243
|
continue;
|
|
683
1244
|
}
|
|
684
|
-
if (!parsedData.choices?.[0]) continue;
|
|
685
|
-
const partialContent = parsedData.choices[0].delta.content;
|
|
686
|
-
parsedData.choices[0].delta.reasoning;
|
|
687
|
-
content += partialContent;
|
|
688
|
-
if (content || '' === content) {
|
|
689
|
-
setMessages((prev)=>{
|
|
690
|
-
const newMessages = [
|
|
691
|
-
...prev
|
|
692
|
-
];
|
|
693
|
-
const lastMessage = newMessages[newMessages.length - 1];
|
|
694
|
-
lastMessage.swipes[lastMessage.activeSwipeId] = content;
|
|
695
|
-
newMessages[newMessages.length - 1] = {
|
|
696
|
-
...lastMessage,
|
|
697
|
-
content: content,
|
|
698
|
-
isStreaming: true
|
|
699
|
-
};
|
|
700
|
-
return newMessages;
|
|
701
|
-
});
|
|
702
|
-
await new Promise((resolve)=>setTimeout(resolve, 10));
|
|
703
|
-
} else {
|
|
704
|
-
console.error('data', data);
|
|
705
|
-
setError(new InvalidDeltaContentError(data));
|
|
706
|
-
}
|
|
707
1245
|
} catch {
|
|
708
1246
|
if ('[DONE]' !== data) {
|
|
709
1247
|
console.error('Received plain SSE message:', data);
|
|
@@ -712,22 +1250,28 @@ const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
|
712
1250
|
}
|
|
713
1251
|
}
|
|
714
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 setError(new SendMessageError(error.message));
|
|
1259
|
+
else setError(error);
|
|
715
1260
|
} finally{
|
|
716
|
-
|
|
717
|
-
setMessages((
|
|
718
|
-
const
|
|
719
|
-
|
|
720
|
-
]
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
});
|
|
1261
|
+
Log.i('stream end finally');
|
|
1262
|
+
setMessages(produce((draft)=>{
|
|
1263
|
+
const lastMessage = draft[draft.length - 1];
|
|
1264
|
+
lastMessage.isStreaming = false;
|
|
1265
|
+
if (!lastMessage.swipes[lastMessage.activeSwipeId]) {
|
|
1266
|
+
lastMessage.swipes[lastMessage.activeSwipeId] = FALLBACK_MESSAGE;
|
|
1267
|
+
lastMessage.content = FALLBACK_MESSAGE;
|
|
1268
|
+
lastMessage.flags.emptyResponse = true;
|
|
1269
|
+
}
|
|
1270
|
+
}));
|
|
727
1271
|
}
|
|
728
1272
|
} catch (error) {
|
|
729
1273
|
console.error('Error:', error);
|
|
730
|
-
|
|
1274
|
+
setError(new SendMessageError('Send message failed', error));
|
|
731
1275
|
setMessages((prev)=>prev.slice(0, -1));
|
|
732
1276
|
} finally{
|
|
733
1277
|
setIsStreaming(false);
|
|
@@ -741,9 +1285,8 @@ const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
|
741
1285
|
isStreaming
|
|
742
1286
|
};
|
|
743
1287
|
};
|
|
744
|
-
const useChat = ({ body, onError, onFinish })=>{
|
|
1288
|
+
const useChat = ({ body, onError, onFinish, pageSize })=>{
|
|
745
1289
|
const [error, _setError] = useState();
|
|
746
|
-
const [messages, setMessages] = useState([]);
|
|
747
1290
|
const [input, setInput] = useState('');
|
|
748
1291
|
const [abortController, setAbortController] = useState();
|
|
749
1292
|
const mujian = useMujian();
|
|
@@ -751,18 +1294,67 @@ const useChat = ({ body, onError, onFinish })=>{
|
|
|
751
1294
|
_setError(error);
|
|
752
1295
|
if (error) onError?.(error);
|
|
753
1296
|
};
|
|
1297
|
+
const isLoadingMore = useRef(false);
|
|
1298
|
+
const { data, loadMoreAsync, loadingMore, loading, mutate, error: messageLoadError } = useInfiniteScroll(async (current)=>{
|
|
1299
|
+
isLoadingMore.current = true;
|
|
1300
|
+
if (current?.noMore) return {
|
|
1301
|
+
noMore: true,
|
|
1302
|
+
list: []
|
|
1303
|
+
};
|
|
1304
|
+
try {
|
|
1305
|
+
const resp = await mujian.ai.chat.message.getPage(current?.cursor, pageSize);
|
|
1306
|
+
return {
|
|
1307
|
+
cursor: resp.nextCursor,
|
|
1308
|
+
list: resp.messages.map((m)=>({
|
|
1309
|
+
...m,
|
|
1310
|
+
mjv: m.swipeInfo[m.activeSwipeId]?.mjv,
|
|
1311
|
+
flags: {
|
|
1312
|
+
saved: true
|
|
1313
|
+
}
|
|
1314
|
+
})),
|
|
1315
|
+
noMore: !resp.nextCursor
|
|
1316
|
+
};
|
|
1317
|
+
} finally{
|
|
1318
|
+
isLoadingMore.current = false;
|
|
1319
|
+
}
|
|
1320
|
+
}, {
|
|
1321
|
+
direction: 'top'
|
|
1322
|
+
});
|
|
1323
|
+
const loadMoreMessage = async ()=>{
|
|
1324
|
+
if (isLoadingMore.current) return;
|
|
1325
|
+
try {
|
|
1326
|
+
isLoadingMore.current = true;
|
|
1327
|
+
await loadMoreAsync();
|
|
1328
|
+
} finally{
|
|
1329
|
+
isLoadingMore.current = false;
|
|
1330
|
+
}
|
|
1331
|
+
};
|
|
1332
|
+
const messages = data?.list ?? [];
|
|
1333
|
+
const latestData = useLatest(data);
|
|
1334
|
+
const latestListRef = useRef(messages);
|
|
1335
|
+
latestListRef.current = messages;
|
|
1336
|
+
const setMessages = (messages)=>{
|
|
1337
|
+
let newList;
|
|
1338
|
+
newList = 'function' == typeof messages ? messages(latestListRef.current) : messages;
|
|
1339
|
+
latestListRef.current = newList;
|
|
1340
|
+
mutate({
|
|
1341
|
+
...latestData.current,
|
|
1342
|
+
list: newList
|
|
1343
|
+
});
|
|
1344
|
+
};
|
|
1345
|
+
const getMessages = useCallback(()=>latestListRef.current, [
|
|
1346
|
+
latestListRef
|
|
1347
|
+
]);
|
|
754
1348
|
const { chatStreaming, isStreaming } = useChatStreaming({
|
|
755
1349
|
common: {
|
|
756
1350
|
body
|
|
757
1351
|
},
|
|
758
1352
|
setError,
|
|
759
1353
|
setMessages,
|
|
1354
|
+
getMessages,
|
|
1355
|
+
setInput,
|
|
760
1356
|
mujian
|
|
761
1357
|
});
|
|
762
|
-
useMount(async ()=>{
|
|
763
|
-
const resp = await mujian.ai.chat.message.getAll();
|
|
764
|
-
setMessages(resp);
|
|
765
|
-
});
|
|
766
1358
|
useUpdateEffect(()=>{
|
|
767
1359
|
if (!isStreaming) {
|
|
768
1360
|
const lastMessage = messages[messages.length - 1];
|
|
@@ -771,48 +1363,79 @@ const useChat = ({ body, onError, onFinish })=>{
|
|
|
771
1363
|
}, [
|
|
772
1364
|
isStreaming
|
|
773
1365
|
]);
|
|
774
|
-
const append = async (query)=>{
|
|
1366
|
+
const append = useCallback(async (query)=>{
|
|
775
1367
|
if (isStreaming) throw new Error('useChat is streaming already.');
|
|
776
1368
|
const controller = new AbortController();
|
|
777
1369
|
setAbortController(controller);
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
1370
|
+
try {
|
|
1371
|
+
await chatStreaming({
|
|
1372
|
+
query,
|
|
1373
|
+
signal: controller.signal
|
|
1374
|
+
});
|
|
1375
|
+
} catch (e) {
|
|
1376
|
+
setError(e);
|
|
1377
|
+
throw e;
|
|
1378
|
+
} finally{
|
|
1379
|
+
setAbortController(void 0);
|
|
1380
|
+
}
|
|
1381
|
+
}, [
|
|
1382
|
+
isStreaming,
|
|
1383
|
+
chatStreaming
|
|
1384
|
+
]);
|
|
1385
|
+
const regenerate = useCallback(async ()=>{
|
|
785
1386
|
if (isStreaming) throw new Error('useChat is streaming already.');
|
|
786
1387
|
const controller = new AbortController();
|
|
787
1388
|
setAbortController(controller);
|
|
788
1389
|
const lastMessage = messages.findLast((message)=>'user' === message.role);
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
1390
|
+
try {
|
|
1391
|
+
await chatStreaming({
|
|
1392
|
+
query: lastMessage?.content || '',
|
|
1393
|
+
regenerate: true,
|
|
1394
|
+
signal: controller.signal
|
|
1395
|
+
});
|
|
1396
|
+
} catch (e) {
|
|
1397
|
+
setError(e);
|
|
1398
|
+
throw e;
|
|
1399
|
+
} finally{
|
|
1400
|
+
setAbortController(void 0);
|
|
1401
|
+
}
|
|
1402
|
+
}, [
|
|
1403
|
+
isStreaming,
|
|
1404
|
+
messages,
|
|
1405
|
+
chatStreaming
|
|
1406
|
+
]);
|
|
1407
|
+
const continueGenerate = useCallback(async ()=>{
|
|
797
1408
|
if (isStreaming) throw new Error('useChat is streaming already.');
|
|
798
1409
|
const controller = new AbortController();
|
|
799
1410
|
setAbortController(controller);
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
1411
|
+
try {
|
|
1412
|
+
await chatStreaming({
|
|
1413
|
+
query: '',
|
|
1414
|
+
is_continue: true,
|
|
1415
|
+
signal: controller.signal
|
|
1416
|
+
});
|
|
1417
|
+
} catch (e) {
|
|
1418
|
+
setError(e);
|
|
1419
|
+
throw e;
|
|
1420
|
+
} finally{
|
|
1421
|
+
setAbortController(void 0);
|
|
1422
|
+
}
|
|
1423
|
+
}, [
|
|
1424
|
+
isStreaming,
|
|
1425
|
+
chatStreaming
|
|
1426
|
+
]);
|
|
807
1427
|
const stop = ()=>{
|
|
808
1428
|
abortController?.abort();
|
|
809
1429
|
};
|
|
810
1430
|
const setSwipe = async (messageId, swipeId)=>{
|
|
811
|
-
|
|
812
|
-
setMessages((prev)=>prev.map((msg)=>msg.id === messageId ? {
|
|
1431
|
+
if (swipeId < 0) return;
|
|
1432
|
+
setMessages((prev)=>prev.map((msg)=>msg.id === messageId && swipeId < msg.swipes.length ? {
|
|
813
1433
|
...msg,
|
|
814
|
-
activeSwipeId: swipeId
|
|
1434
|
+
activeSwipeId: swipeId,
|
|
1435
|
+
content: msg.swipes[swipeId],
|
|
1436
|
+
mjv: msg.swipeInfo[swipeId]?.mjv
|
|
815
1437
|
} : msg));
|
|
1438
|
+
await mujian.ai.chat.message.swipe(messageId, swipeId);
|
|
816
1439
|
};
|
|
817
1440
|
const editMessage = async (messageId, content)=>{
|
|
818
1441
|
await mujian.ai.chat.message.editOne(messageId, content);
|
|
@@ -832,7 +1455,11 @@ const useChat = ({ body, onError, onFinish })=>{
|
|
|
832
1455
|
setMessages((prev)=>prev.map((msg)=>msg.id === messageId ? patchMessage(msg) : msg));
|
|
833
1456
|
};
|
|
834
1457
|
const deleteMessage = async (messageId)=>{
|
|
835
|
-
|
|
1458
|
+
if (!messageId.startsWith(NOT_SAVED_MSG_ID_PREFIX)) try {
|
|
1459
|
+
await mujian.ai.chat.message.deleteOne(messageId);
|
|
1460
|
+
} catch (e) {
|
|
1461
|
+
if (e?.code !== 2011030004) throw e;
|
|
1462
|
+
}
|
|
836
1463
|
setMessages((prev)=>prev.filter((msg)=>msg.id !== messageId));
|
|
837
1464
|
};
|
|
838
1465
|
return {
|
|
@@ -855,7 +1482,9 @@ const useChat = ({ body, onError, onFinish })=>{
|
|
|
855
1482
|
},
|
|
856
1483
|
setSwipe,
|
|
857
1484
|
editMessage,
|
|
858
|
-
deleteMessage
|
|
1485
|
+
deleteMessage,
|
|
1486
|
+
loadMoreMessage,
|
|
1487
|
+
messagesStatus: messageLoadError ? 'error' : loadingMore || loading ? 'loading' : data?.noMore ? 'all-loaded' : 'has-more'
|
|
859
1488
|
};
|
|
860
1489
|
};
|
|
861
|
-
export { MdRenderer, MujianProvider, Thread, useChat, useMujian };
|
|
1490
|
+
export { MdRenderer, MujianProvider, MujianSpinner, Thread, useChat, useMjEngine, useMujian };
|