@mujian/js-sdk 0.0.6-beta.8 → 0.0.6-beta.81
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 +841 -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/is-network-error.d.ts +1 -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,103 @@ 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
|
-
|
|
1069
|
+
const errorMessages = [
|
|
1070
|
+
'network error',
|
|
1071
|
+
'NetworkError when attempting to fetch resource.',
|
|
1072
|
+
'The Internet connection appears to be offline.',
|
|
1073
|
+
'Network request failed',
|
|
1074
|
+
'Load failed',
|
|
1075
|
+
'Failed to fetch'
|
|
1076
|
+
];
|
|
1077
|
+
function isNetworkError(message) {
|
|
1078
|
+
return errorMessages.some((m)=>message.includes(m));
|
|
1079
|
+
}
|
|
1080
|
+
class SendMessageError extends Error {
|
|
551
1081
|
constructor(message, cause){
|
|
552
1082
|
super(message);
|
|
553
1083
|
this.name = this.constructor.name;
|
|
554
1084
|
this.cause = cause;
|
|
555
1085
|
}
|
|
556
1086
|
}
|
|
557
|
-
class
|
|
1087
|
+
class UnexpectedSseEndingError extends Error {
|
|
558
1088
|
constructor(message, cause){
|
|
559
1089
|
super(message);
|
|
560
1090
|
this.name = this.constructor.name;
|
|
@@ -569,6 +1099,7 @@ async function* callSdk(mujian, content, type = 'generate', signal) {
|
|
|
569
1099
|
try {
|
|
570
1100
|
const onData = (data)=>{
|
|
571
1101
|
if (error) return;
|
|
1102
|
+
if ('string' != typeof data) return;
|
|
572
1103
|
queue.push(data);
|
|
573
1104
|
if (resolveWait) {
|
|
574
1105
|
resolveWait();
|
|
@@ -603,48 +1134,52 @@ async function* callSdk(mujian, content, type = 'generate', signal) {
|
|
|
603
1134
|
resolveWait = resolve;
|
|
604
1135
|
});
|
|
605
1136
|
}
|
|
606
|
-
const
|
|
1137
|
+
const NOT_SAVED_MSG_ID_PREFIX = 'not_saved';
|
|
1138
|
+
const FALLBACK_MESSAGE = `哎呀,AI线路好像抽风了`;
|
|
1139
|
+
const useChatStreaming = ({ common, setError, setMessages, getMessages, setInput, mujian })=>{
|
|
607
1140
|
const { body } = common;
|
|
608
1141
|
const [isStreaming, setIsStreaming] = useState(false);
|
|
609
1142
|
const chatStreaming = useCallback(async ({ query, regenerate, is_continue, signal })=>{
|
|
610
1143
|
try {
|
|
611
1144
|
setError(void 0);
|
|
612
1145
|
setIsStreaming(true);
|
|
1146
|
+
const backupMessages = getMessages();
|
|
613
1147
|
const userMessage = {
|
|
614
|
-
id: Date.now()
|
|
1148
|
+
id: `${NOT_SAVED_MSG_ID_PREFIX}_user_${Date.now()}`,
|
|
615
1149
|
content: query || '',
|
|
616
1150
|
role: 'user',
|
|
617
1151
|
swipes: [],
|
|
618
1152
|
activeSwipeId: 0,
|
|
619
1153
|
isStreaming: false,
|
|
620
|
-
sendAt: new Date()
|
|
1154
|
+
sendAt: new Date(),
|
|
1155
|
+
swipeInfo: [],
|
|
1156
|
+
flags: {}
|
|
621
1157
|
};
|
|
622
1158
|
const aiMessage = {
|
|
623
|
-
id: Date.now()
|
|
1159
|
+
id: `${NOT_SAVED_MSG_ID_PREFIX}_assistant_${Date.now()}`,
|
|
624
1160
|
content: '',
|
|
625
1161
|
role: 'assistant',
|
|
626
|
-
swipes: [
|
|
1162
|
+
swipes: [
|
|
1163
|
+
''
|
|
1164
|
+
],
|
|
627
1165
|
activeSwipeId: 0,
|
|
628
1166
|
isStreaming: true,
|
|
629
|
-
sendAt: new Date()
|
|
1167
|
+
sendAt: new Date(),
|
|
1168
|
+
swipeInfo: [
|
|
1169
|
+
{}
|
|
1170
|
+
],
|
|
1171
|
+
flags: {}
|
|
630
1172
|
};
|
|
631
|
-
if (regenerate) setMessages((
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
swipes: [
|
|
640
|
-
...lastMessage.swipes,
|
|
641
|
-
''
|
|
642
|
-
],
|
|
643
|
-
content: '',
|
|
644
|
-
isStreaming: true
|
|
1173
|
+
if (regenerate) setMessages(produce((draft)=>{
|
|
1174
|
+
const lastMessage = draft[draft.length - 1];
|
|
1175
|
+
lastMessage.activeSwipeId = lastMessage.swipes.length;
|
|
1176
|
+
lastMessage.swipes.push('');
|
|
1177
|
+
lastMessage.content = '';
|
|
1178
|
+
lastMessage.isStreaming = true;
|
|
1179
|
+
lastMessage.flags = {
|
|
1180
|
+
saved: lastMessage.flags.saved
|
|
645
1181
|
};
|
|
646
|
-
|
|
647
|
-
});
|
|
1182
|
+
}));
|
|
648
1183
|
else is_continue ? setMessages((prev)=>[
|
|
649
1184
|
...prev,
|
|
650
1185
|
aiMessage
|
|
@@ -656,6 +1191,7 @@ const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
|
656
1191
|
const stream = callSdk(mujian, query || '', is_continue ? 'continue' : regenerate ? 'regenerate' : 'generate', signal);
|
|
657
1192
|
let buffer = '';
|
|
658
1193
|
let content = '';
|
|
1194
|
+
let finishReason;
|
|
659
1195
|
try {
|
|
660
1196
|
for await (const chunk of stream){
|
|
661
1197
|
buffer += chunk;
|
|
@@ -665,45 +1201,60 @@ const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
|
665
1201
|
const data = line.slice(6);
|
|
666
1202
|
try {
|
|
667
1203
|
const parsedData = JSON.parse(data);
|
|
668
|
-
|
|
1204
|
+
console.log(parsedData);
|
|
1205
|
+
if (regenerate || 'meta' !== parsedData.type) {
|
|
1206
|
+
if ('stream' === parsedData.type) {
|
|
1207
|
+
const partialContent = parsedData.choices[0].delta.content;
|
|
1208
|
+
parsedData.choices[0].delta.reasoning;
|
|
1209
|
+
const chunkFinishReason = parsedData.choices[0].finish_reason;
|
|
1210
|
+
content += partialContent;
|
|
1211
|
+
setMessages(produce((draft)=>{
|
|
1212
|
+
const lastMessage = draft[draft.length - 1];
|
|
1213
|
+
lastMessage.swipes[lastMessage.activeSwipeId] = content;
|
|
1214
|
+
lastMessage.content = content;
|
|
1215
|
+
lastMessage.isStreaming = true;
|
|
1216
|
+
if ('content_filter' === chunkFinishReason) lastMessage.flags.contentFilter = true;
|
|
1217
|
+
}));
|
|
1218
|
+
if (chunkFinishReason) finishReason = chunkFinishReason;
|
|
1219
|
+
await new Promise((resolve)=>setTimeout(resolve, 10));
|
|
1220
|
+
} else if ('mjv' === parsedData.type) {
|
|
1221
|
+
const { value, delta, schema } = parsedData;
|
|
1222
|
+
setMessages(produce((draft)=>{
|
|
1223
|
+
const lastMessage = draft[draft.length - 1];
|
|
1224
|
+
const mjv = {
|
|
1225
|
+
value,
|
|
1226
|
+
delta,
|
|
1227
|
+
schema
|
|
1228
|
+
};
|
|
1229
|
+
const swipeInfo = lastMessage.swipeInfo;
|
|
1230
|
+
if (swipeInfo[lastMessage.activeSwipeId]) swipeInfo[lastMessage.activeSwipeId].mjv = mjv;
|
|
1231
|
+
else swipeInfo[lastMessage.activeSwipeId] = {
|
|
1232
|
+
mjv
|
|
1233
|
+
};
|
|
1234
|
+
lastMessage.swipeInfo = swipeInfo;
|
|
1235
|
+
lastMessage.mjv = mjv;
|
|
1236
|
+
}));
|
|
1237
|
+
}
|
|
1238
|
+
} else {
|
|
669
1239
|
const { question_id, reply_id } = parsedData;
|
|
670
1240
|
setMessages((prev)=>{
|
|
671
1241
|
const newMessages = [
|
|
672
1242
|
...prev
|
|
673
1243
|
];
|
|
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
1244
|
return newMessages;
|
|
681
1245
|
});
|
|
1246
|
+
setMessages(produce((draft)=>{
|
|
1247
|
+
if (question_id && !is_continue) {
|
|
1248
|
+
const userMsg = draft[draft.length - 2];
|
|
1249
|
+
userMsg.id = question_id;
|
|
1250
|
+
userMsg.flags.saved = true;
|
|
1251
|
+
}
|
|
1252
|
+
const lastMessage = draft[draft.length - 1];
|
|
1253
|
+
lastMessage.id = reply_id;
|
|
1254
|
+
lastMessage.flags.saved = true;
|
|
1255
|
+
}));
|
|
682
1256
|
continue;
|
|
683
1257
|
}
|
|
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
1258
|
} catch {
|
|
708
1259
|
if ('[DONE]' !== data) {
|
|
709
1260
|
console.error('Received plain SSE message:', data);
|
|
@@ -712,22 +1263,28 @@ const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
|
712
1263
|
}
|
|
713
1264
|
}
|
|
714
1265
|
}
|
|
1266
|
+
} catch (error) {
|
|
1267
|
+
Log.e('Stream error', error);
|
|
1268
|
+
if ('object' == typeof error && error && 'message' in error && 'string' == typeof error.message) if ('code' in error && 2011030001 === error.code) {
|
|
1269
|
+
setMessages(backupMessages);
|
|
1270
|
+
if (!regenerate && !is_continue && query) setInput(query);
|
|
1271
|
+
} else isNetworkError(error.message) ? setError(new SendMessageError('网络好像断开了,检查一下再试吧~')) : setError(new SendMessageError(error.message));
|
|
1272
|
+
else setError(error);
|
|
715
1273
|
} finally{
|
|
716
|
-
|
|
717
|
-
setMessages((
|
|
718
|
-
const
|
|
719
|
-
|
|
720
|
-
]
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
});
|
|
1274
|
+
Log.i('stream end finally');
|
|
1275
|
+
setMessages(produce((draft)=>{
|
|
1276
|
+
const lastMessage = draft[draft.length - 1];
|
|
1277
|
+
lastMessage.isStreaming = false;
|
|
1278
|
+
if (!lastMessage.swipes[lastMessage.activeSwipeId] && !signal?.aborted && 'stop' === finishReason) {
|
|
1279
|
+
lastMessage.swipes[lastMessage.activeSwipeId] = FALLBACK_MESSAGE;
|
|
1280
|
+
lastMessage.content = FALLBACK_MESSAGE;
|
|
1281
|
+
lastMessage.flags.emptyResponse = true;
|
|
1282
|
+
}
|
|
1283
|
+
}));
|
|
727
1284
|
}
|
|
728
1285
|
} catch (error) {
|
|
729
1286
|
console.error('Error:', error);
|
|
730
|
-
|
|
1287
|
+
setError(new SendMessageError('Send message failed', error));
|
|
731
1288
|
setMessages((prev)=>prev.slice(0, -1));
|
|
732
1289
|
} finally{
|
|
733
1290
|
setIsStreaming(false);
|
|
@@ -741,9 +1298,8 @@ const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
|
741
1298
|
isStreaming
|
|
742
1299
|
};
|
|
743
1300
|
};
|
|
744
|
-
const useChat = ({ body, onError, onFinish })=>{
|
|
1301
|
+
const useChat = ({ body, onError, onFinish, pageSize })=>{
|
|
745
1302
|
const [error, _setError] = useState();
|
|
746
|
-
const [messages, setMessages] = useState([]);
|
|
747
1303
|
const [input, setInput] = useState('');
|
|
748
1304
|
const [abortController, setAbortController] = useState();
|
|
749
1305
|
const mujian = useMujian();
|
|
@@ -751,18 +1307,67 @@ const useChat = ({ body, onError, onFinish })=>{
|
|
|
751
1307
|
_setError(error);
|
|
752
1308
|
if (error) onError?.(error);
|
|
753
1309
|
};
|
|
1310
|
+
const isLoadingMore = useRef(false);
|
|
1311
|
+
const { data, loadMoreAsync, loadingMore, loading, mutate, error: messageLoadError } = useInfiniteScroll(async (current)=>{
|
|
1312
|
+
isLoadingMore.current = true;
|
|
1313
|
+
if (current?.noMore) return {
|
|
1314
|
+
noMore: true,
|
|
1315
|
+
list: []
|
|
1316
|
+
};
|
|
1317
|
+
try {
|
|
1318
|
+
const resp = await mujian.ai.chat.message.getPage(current?.cursor, pageSize);
|
|
1319
|
+
return {
|
|
1320
|
+
cursor: resp.nextCursor,
|
|
1321
|
+
list: resp.messages.map((m)=>({
|
|
1322
|
+
...m,
|
|
1323
|
+
mjv: m.swipeInfo[m.activeSwipeId]?.mjv,
|
|
1324
|
+
flags: {
|
|
1325
|
+
saved: true
|
|
1326
|
+
}
|
|
1327
|
+
})),
|
|
1328
|
+
noMore: !resp.nextCursor
|
|
1329
|
+
};
|
|
1330
|
+
} finally{
|
|
1331
|
+
isLoadingMore.current = false;
|
|
1332
|
+
}
|
|
1333
|
+
}, {
|
|
1334
|
+
direction: 'top'
|
|
1335
|
+
});
|
|
1336
|
+
const loadMoreMessage = async ()=>{
|
|
1337
|
+
if (isLoadingMore.current) return;
|
|
1338
|
+
try {
|
|
1339
|
+
isLoadingMore.current = true;
|
|
1340
|
+
await loadMoreAsync();
|
|
1341
|
+
} finally{
|
|
1342
|
+
isLoadingMore.current = false;
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
1345
|
+
const messages = data?.list ?? [];
|
|
1346
|
+
const latestData = useLatest(data);
|
|
1347
|
+
const latestListRef = useRef(messages);
|
|
1348
|
+
latestListRef.current = messages;
|
|
1349
|
+
const setMessages = (messages)=>{
|
|
1350
|
+
let newList;
|
|
1351
|
+
newList = 'function' == typeof messages ? messages(latestListRef.current) : messages;
|
|
1352
|
+
latestListRef.current = newList;
|
|
1353
|
+
mutate({
|
|
1354
|
+
...latestData.current,
|
|
1355
|
+
list: newList
|
|
1356
|
+
});
|
|
1357
|
+
};
|
|
1358
|
+
const getMessages = useCallback(()=>latestListRef.current, [
|
|
1359
|
+
latestListRef
|
|
1360
|
+
]);
|
|
754
1361
|
const { chatStreaming, isStreaming } = useChatStreaming({
|
|
755
1362
|
common: {
|
|
756
1363
|
body
|
|
757
1364
|
},
|
|
758
1365
|
setError,
|
|
759
1366
|
setMessages,
|
|
1367
|
+
getMessages,
|
|
1368
|
+
setInput,
|
|
760
1369
|
mujian
|
|
761
1370
|
});
|
|
762
|
-
useMount(async ()=>{
|
|
763
|
-
const resp = await mujian.ai.chat.message.getAll();
|
|
764
|
-
setMessages(resp);
|
|
765
|
-
});
|
|
766
1371
|
useUpdateEffect(()=>{
|
|
767
1372
|
if (!isStreaming) {
|
|
768
1373
|
const lastMessage = messages[messages.length - 1];
|
|
@@ -771,48 +1376,79 @@ const useChat = ({ body, onError, onFinish })=>{
|
|
|
771
1376
|
}, [
|
|
772
1377
|
isStreaming
|
|
773
1378
|
]);
|
|
774
|
-
const append = async (query)=>{
|
|
1379
|
+
const append = useCallback(async (query)=>{
|
|
775
1380
|
if (isStreaming) throw new Error('useChat is streaming already.');
|
|
776
1381
|
const controller = new AbortController();
|
|
777
1382
|
setAbortController(controller);
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
1383
|
+
try {
|
|
1384
|
+
await chatStreaming({
|
|
1385
|
+
query,
|
|
1386
|
+
signal: controller.signal
|
|
1387
|
+
});
|
|
1388
|
+
} catch (e) {
|
|
1389
|
+
setError(e);
|
|
1390
|
+
throw e;
|
|
1391
|
+
} finally{
|
|
1392
|
+
setAbortController(void 0);
|
|
1393
|
+
}
|
|
1394
|
+
}, [
|
|
1395
|
+
isStreaming,
|
|
1396
|
+
chatStreaming
|
|
1397
|
+
]);
|
|
1398
|
+
const regenerate = useCallback(async ()=>{
|
|
785
1399
|
if (isStreaming) throw new Error('useChat is streaming already.');
|
|
786
1400
|
const controller = new AbortController();
|
|
787
1401
|
setAbortController(controller);
|
|
788
1402
|
const lastMessage = messages.findLast((message)=>'user' === message.role);
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
1403
|
+
try {
|
|
1404
|
+
await chatStreaming({
|
|
1405
|
+
query: lastMessage?.content || '',
|
|
1406
|
+
regenerate: true,
|
|
1407
|
+
signal: controller.signal
|
|
1408
|
+
});
|
|
1409
|
+
} catch (e) {
|
|
1410
|
+
setError(e);
|
|
1411
|
+
throw e;
|
|
1412
|
+
} finally{
|
|
1413
|
+
setAbortController(void 0);
|
|
1414
|
+
}
|
|
1415
|
+
}, [
|
|
1416
|
+
isStreaming,
|
|
1417
|
+
messages,
|
|
1418
|
+
chatStreaming
|
|
1419
|
+
]);
|
|
1420
|
+
const continueGenerate = useCallback(async ()=>{
|
|
797
1421
|
if (isStreaming) throw new Error('useChat is streaming already.');
|
|
798
1422
|
const controller = new AbortController();
|
|
799
1423
|
setAbortController(controller);
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
1424
|
+
try {
|
|
1425
|
+
await chatStreaming({
|
|
1426
|
+
query: '',
|
|
1427
|
+
is_continue: true,
|
|
1428
|
+
signal: controller.signal
|
|
1429
|
+
});
|
|
1430
|
+
} catch (e) {
|
|
1431
|
+
setError(e);
|
|
1432
|
+
throw e;
|
|
1433
|
+
} finally{
|
|
1434
|
+
setAbortController(void 0);
|
|
1435
|
+
}
|
|
1436
|
+
}, [
|
|
1437
|
+
isStreaming,
|
|
1438
|
+
chatStreaming
|
|
1439
|
+
]);
|
|
807
1440
|
const stop = ()=>{
|
|
808
1441
|
abortController?.abort();
|
|
809
1442
|
};
|
|
810
1443
|
const setSwipe = async (messageId, swipeId)=>{
|
|
811
|
-
|
|
812
|
-
setMessages((prev)=>prev.map((msg)=>msg.id === messageId ? {
|
|
1444
|
+
if (swipeId < 0) return;
|
|
1445
|
+
setMessages((prev)=>prev.map((msg)=>msg.id === messageId && swipeId < msg.swipes.length ? {
|
|
813
1446
|
...msg,
|
|
814
|
-
activeSwipeId: swipeId
|
|
1447
|
+
activeSwipeId: swipeId,
|
|
1448
|
+
content: msg.swipes[swipeId],
|
|
1449
|
+
mjv: msg.swipeInfo[swipeId]?.mjv
|
|
815
1450
|
} : msg));
|
|
1451
|
+
await mujian.ai.chat.message.swipe(messageId, swipeId);
|
|
816
1452
|
};
|
|
817
1453
|
const editMessage = async (messageId, content)=>{
|
|
818
1454
|
await mujian.ai.chat.message.editOne(messageId, content);
|
|
@@ -832,7 +1468,11 @@ const useChat = ({ body, onError, onFinish })=>{
|
|
|
832
1468
|
setMessages((prev)=>prev.map((msg)=>msg.id === messageId ? patchMessage(msg) : msg));
|
|
833
1469
|
};
|
|
834
1470
|
const deleteMessage = async (messageId)=>{
|
|
835
|
-
|
|
1471
|
+
if (!messageId.startsWith(NOT_SAVED_MSG_ID_PREFIX)) try {
|
|
1472
|
+
await mujian.ai.chat.message.deleteOne(messageId);
|
|
1473
|
+
} catch (e) {
|
|
1474
|
+
if (e?.code !== 2011030004) throw e;
|
|
1475
|
+
}
|
|
836
1476
|
setMessages((prev)=>prev.filter((msg)=>msg.id !== messageId));
|
|
837
1477
|
};
|
|
838
1478
|
return {
|
|
@@ -855,7 +1495,9 @@ const useChat = ({ body, onError, onFinish })=>{
|
|
|
855
1495
|
},
|
|
856
1496
|
setSwipe,
|
|
857
1497
|
editMessage,
|
|
858
|
-
deleteMessage
|
|
1498
|
+
deleteMessage,
|
|
1499
|
+
loadMoreMessage,
|
|
1500
|
+
messagesStatus: messageLoadError ? 'error' : loadingMore || loading ? 'loading' : data?.noMore ? 'all-loaded' : 'has-more'
|
|
859
1501
|
};
|
|
860
1502
|
};
|
|
861
|
-
export { MdRenderer, MujianProvider, Thread, useChat, useMujian };
|
|
1503
|
+
export { MdRenderer, MujianProvider, MujianSpinner, Thread, useChat, useMjEngine, useMujian };
|