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