@mujian/js-sdk 0.0.6-beta.mjv.68 → 0.1.0-beta.1
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 +25 -5
- package/dist/index.d.ts +41 -2
- package/dist/index.js +143 -184
- package/dist/lite.d.ts +73 -0
- package/dist/lite.js +124 -0
- package/dist/modules/ai/chat/chat.d.ts +18 -26
- package/dist/modules/ai/chat/index.d.ts +1 -1
- package/dist/modules/ai/chat/message/index.d.ts +7 -16
- package/dist/modules/ai/chat/settings/index.d.ts +1 -2
- package/dist/modules/ai/chat/settings/persona.d.ts +0 -8
- package/dist/modules/ai/openai/chat.d.ts +0 -3
- package/dist/modules/ai/openai/completions.d.ts +0 -2
- package/dist/modules/ai/openai/images.d.ts +0 -2
- package/dist/modules/ai/openai/responses.d.ts +0 -2
- package/dist/modules/config.d.ts +17 -0
- package/dist/react/chat/useChat/index.d.ts +27 -5
- package/dist/react/chat/useChat/inner/chatStreaming.d.ts +8 -4
- package/dist/react/chat/useChat/inner/stream.d.ts +25 -2
- package/dist/react/chat/useChat/message.d.ts +27 -38
- package/dist/react/components/MdRenderer/index.d.ts +3 -2
- package/dist/react/components/MujianProvider/index.d.ts +4 -0
- package/dist/react/components/Thread/MessageItem.d.ts +6 -0
- package/dist/react/components/index.d.ts +1 -1
- package/dist/react/index.d.ts +1 -0
- package/dist/react/mjEngine/index.d.ts +48 -0
- package/dist/react.js +443 -343
- package/dist/types/index.d.ts +1 -0
- package/dist/umd/index.js +1 -791
- package/dist/umd/lite.js +2 -0
- package/dist/umd/lite.js.LICENSE.txt +7 -0
- package/dist/umd/react.css +1 -343
- package/dist/umd/react.js +95 -8807
- package/dist/umd/react.js.LICENSE.txt +1 -1
- package/dist/utils/is-network-error.d.ts +1 -0
- package/package.json +14 -6
- package/dist/modules/ai/chat/settings/model.d.ts +0 -24
package/dist/react.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useInfiniteScroll, useLatest, useRequest, useUpdateEffect } from "ahooks";
|
|
1
|
+
import { useInfiniteScroll, useLatest, useRequest, useUnmount, useUpdateEffect } from "ahooks";
|
|
2
2
|
import react, { createContext, forwardRef, useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
import css_tools from "@adobe/css-tools";
|
|
@@ -7,6 +7,9 @@ import showdown from "showdown";
|
|
|
7
7
|
import { v4 } from "uuid";
|
|
8
8
|
import postmate from "postmate";
|
|
9
9
|
import { Virtualizer } from "virtua";
|
|
10
|
+
import { get } from "lodash-es";
|
|
11
|
+
import { produce } from "immer";
|
|
12
|
+
import { z } from "zod";
|
|
10
13
|
const adjustIframeHeight = (iframeId)=>`
|
|
11
14
|
(function () {
|
|
12
15
|
let scheduled = false;
|
|
@@ -404,7 +407,14 @@ function messageFormatting(mes, sanitizerOverrides = {}) {
|
|
|
404
407
|
});
|
|
405
408
|
return mes;
|
|
406
409
|
}
|
|
407
|
-
const
|
|
410
|
+
const loadingTranslates = {
|
|
411
|
+
'zh-hans': '加载中...',
|
|
412
|
+
'zh-hant': '載入中...',
|
|
413
|
+
en: 'Loading...',
|
|
414
|
+
ja: '読み込み中...',
|
|
415
|
+
th: 'กำลังโหลด...'
|
|
416
|
+
};
|
|
417
|
+
const MdRendererBase = ({ content, unsafe = false, extra = {}, lang })=>{
|
|
408
418
|
const containerRef = useRef(null);
|
|
409
419
|
const [iframeIdList, setIframeIdList] = useState([]);
|
|
410
420
|
useEffect(()=>{
|
|
@@ -421,16 +431,12 @@ const MdRendererBase = ({ content, unsafe = false, extra = {} })=>{
|
|
|
421
431
|
id
|
|
422
432
|
]);
|
|
423
433
|
const escapedSrcdoc = escapeHtmlAttribute(srcdoc);
|
|
434
|
+
const loadingText = loadingTranslates[lang ?? 'zh-hans'] || loadingTranslates['zh-hans'];
|
|
424
435
|
return `
|
|
425
436
|
<div class="MJ-iframe-container" id="${containerId}" style="display:flex;width:100%;height:100%;position:relative;">
|
|
426
437
|
<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;">
|
|
427
438
|
<div class="spin-inner wave-text" style="font-weight:500;font-size:16px;color:white;display:flex;justify-content:center;align-items:center;">
|
|
428
|
-
|
|
429
|
-
<span>载</span>
|
|
430
|
-
<span>中</span>
|
|
431
|
-
<span>.</span>
|
|
432
|
-
<span>.</span>
|
|
433
|
-
<span>.</span>
|
|
439
|
+
${loadingText.split('').map((t)=>`<span>${t}</span>`).join('')}
|
|
434
440
|
</div>
|
|
435
441
|
</div>
|
|
436
442
|
<iframe id="${iframeId}" class="w-full" sandbox="${unsafe ? "allow-scripts" : "allow-scripts allow-same-origin"}" loading="lazy"
|
|
@@ -509,6 +515,11 @@ var events_EVENT = /*#__PURE__*/ function(EVENT) {
|
|
|
509
515
|
EVENT["MUJIAN_AI_CHAT_MESSAGE_GET_ALL"] = "mujian:ai:chat:message:getAll";
|
|
510
516
|
EVENT["MUJIAN_AI_CHAT_MESSAGE_GET_PAGE"] = "mujian:ai:chat:message:getPage";
|
|
511
517
|
EVENT["MUJIAN_AI_CHAT_PROJECT_GET_INFO"] = "mujian:ai:chat:project:getInfo";
|
|
518
|
+
EVENT["MUJIAN_AI_CHAT_V2_COMPLETE"] = "mujian:ai:chat_v2:complete";
|
|
519
|
+
EVENT["MUJIAN_AI_CHAT_V2_RECOVER"] = "mujian:ai:chat_v2:recover";
|
|
520
|
+
EVENT["MUJIAN_AI_CHAT_V2_STOP"] = "mujian:ai:chat_v2:stop";
|
|
521
|
+
EVENT["MUJIAN_AI_CHAT_V2_MESSAGE_GET_PAGE"] = "mujian:ai:chat_v2:message:getPage";
|
|
522
|
+
EVENT["MUJIAN_AI_CHAT_V2_RENDER_MESSAGE"] = "mujian:ai:chat_v2:renderMessage";
|
|
512
523
|
EVENT["MUJIAN_AI_SETTINGS_PERSONA_GET_ACTIVE"] = "mujian:ai:settings:persona:getActive";
|
|
513
524
|
EVENT["MUJIAN_AI_SETTINGS_PERSONA_SET_ACTIVE"] = "mujian:ai:settings:persona:setActive";
|
|
514
525
|
EVENT["MUJIAN_AI_SETTINGS_MODEL_GET_ALL"] = "mujian:ai:settings:model:getAll";
|
|
@@ -517,87 +528,51 @@ var events_EVENT = /*#__PURE__*/ function(EVENT) {
|
|
|
517
528
|
EVENT["MUJIAN_AI_CHAT_MESSAGE_DELETE_ONE"] = "mujian:ai:chat:message:deleteOne";
|
|
518
529
|
EVENT["MUJIAN_AI_CHAT_MESSAGE_EDIT_ONE"] = "mujian:ai:chat:message:editOne";
|
|
519
530
|
EVENT["MUJIAN_AI_CHAT_MESSAGE_SWIPE"] = "mujian:ai:chat:message:swipe";
|
|
520
|
-
EVENT["MUJIAN_AI_CHAT_MESSAGE_GET_PROMPT"] = "mujian:ai:chat:message:getPrompt";
|
|
521
531
|
EVENT["MUJIAN_AI_OPENAI_IMAGES_GENERATE"] = "mujian:ai:openai:images:generate";
|
|
522
532
|
EVENT["MUJIAN_UTILS_CLIPBOARD_WRITE_TEXT"] = "mujian:utils:clipboard:writeText";
|
|
533
|
+
EVENT["MUJIAN_GET_CONFIG"] = "mujian:getConfig";
|
|
523
534
|
return EVENT;
|
|
524
535
|
}({});
|
|
525
|
-
function
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
let replyId;
|
|
530
|
-
return function(data) {
|
|
531
|
-
buffer += data;
|
|
532
|
-
const lines = buffer.split('\n');
|
|
533
|
-
buffer = lines.pop() || '';
|
|
534
|
-
for (const line of lines)if (line.startsWith('data: ')) try {
|
|
535
|
-
const parsedData = JSON.parse(line.slice(6));
|
|
536
|
-
if (parsedData.question_id) questionId = parsedData.question_id;
|
|
537
|
-
if (parsedData.reply_id) replyId = parsedData.reply_id;
|
|
538
|
-
if (parsedData.isFinished) return void onData({
|
|
539
|
-
isFinished: true,
|
|
540
|
-
deltaContent: '',
|
|
541
|
-
fullContent,
|
|
542
|
-
questionId,
|
|
543
|
-
replyId
|
|
544
|
-
});
|
|
545
|
-
const deltaContent = parsedData?.choices?.[0]?.delta?.content;
|
|
546
|
-
if (deltaContent?.length > 0) {
|
|
547
|
-
fullContent += deltaContent;
|
|
548
|
-
onData({
|
|
549
|
-
isFinished: false,
|
|
550
|
-
deltaContent: deltaContent,
|
|
551
|
-
fullContent,
|
|
552
|
-
questionId,
|
|
553
|
-
replyId
|
|
554
|
-
});
|
|
555
|
-
}
|
|
556
|
-
} catch (e) {
|
|
557
|
-
onData({
|
|
558
|
-
isFinished: true,
|
|
559
|
-
error: e,
|
|
560
|
-
deltaContent: '',
|
|
561
|
-
fullContent,
|
|
562
|
-
questionId,
|
|
563
|
-
replyId
|
|
564
|
-
});
|
|
565
|
-
return;
|
|
566
|
-
}
|
|
567
|
-
};
|
|
568
|
-
}
|
|
569
|
-
const chat_complete = async function(message, onData, signal, option = {}) {
|
|
570
|
-
await this.call(events_EVENT.MUJIAN_AI_CHAT_COMPLETE, {
|
|
571
|
-
content: message
|
|
536
|
+
const chat_complete = async function(message, conversationVersion, onData) {
|
|
537
|
+
await this.call(events_EVENT.MUJIAN_AI_CHAT_V2_COMPLETE, {
|
|
538
|
+
content: message,
|
|
539
|
+
conversationVersion
|
|
572
540
|
}, {
|
|
573
|
-
onData
|
|
574
|
-
signal
|
|
541
|
+
onData
|
|
575
542
|
});
|
|
576
543
|
};
|
|
577
|
-
const applyRegex = async function(props) {
|
|
578
|
-
return await this.call(events_EVENT.MUJIAN_AI_CHAT_APPLY_REGEX, props);
|
|
579
|
-
};
|
|
580
544
|
const renderMessage = async function(props) {
|
|
581
|
-
return await this.call(events_EVENT.
|
|
545
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_V2_RENDER_MESSAGE, props);
|
|
582
546
|
};
|
|
583
|
-
const continueComplete = async function(
|
|
584
|
-
return await this.call(events_EVENT.
|
|
585
|
-
isContinue: true
|
|
547
|
+
const continueComplete = async function(conversationVersion, onData) {
|
|
548
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_V2_COMPLETE, {
|
|
549
|
+
isContinue: true,
|
|
550
|
+
conversationVersion
|
|
586
551
|
}, {
|
|
587
|
-
onData
|
|
588
|
-
signal
|
|
552
|
+
onData
|
|
589
553
|
});
|
|
590
554
|
};
|
|
591
|
-
const chat_regenerate = async function(
|
|
592
|
-
return await this.call(events_EVENT.
|
|
593
|
-
isRegenerate: true
|
|
555
|
+
const chat_regenerate = async function(conversationVersion, onData) {
|
|
556
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_V2_COMPLETE, {
|
|
557
|
+
isRegenerate: true,
|
|
558
|
+
conversationVersion
|
|
594
559
|
}, {
|
|
595
|
-
onData
|
|
596
|
-
|
|
560
|
+
onData
|
|
561
|
+
});
|
|
562
|
+
};
|
|
563
|
+
const chat_stop = async function(conversationVersion, assisMsgId) {
|
|
564
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_V2_STOP, {
|
|
565
|
+
conversationVersion,
|
|
566
|
+
assisMsgId
|
|
597
567
|
});
|
|
598
568
|
};
|
|
599
|
-
const
|
|
600
|
-
return await this.call(events_EVENT.
|
|
569
|
+
const recover = async function(conversationVersion, assisMsgId, onData) {
|
|
570
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_V2_RECOVER, {
|
|
571
|
+
conversationVersion,
|
|
572
|
+
assisMsgId
|
|
573
|
+
}, {
|
|
574
|
+
onData
|
|
575
|
+
});
|
|
601
576
|
};
|
|
602
577
|
const messageDeleteOne = async function(messageId) {
|
|
603
578
|
return await this.call(events_EVENT.MUJIAN_AI_CHAT_MESSAGE_DELETE_ONE, {
|
|
@@ -616,13 +591,8 @@ const messageSwipe = async function(messageId, swipeId) {
|
|
|
616
591
|
swipeId
|
|
617
592
|
});
|
|
618
593
|
};
|
|
619
|
-
const getPrompt = async function(messageId) {
|
|
620
|
-
return await this.call(events_EVENT.MUJIAN_AI_CHAT_MESSAGE_GET_PROMPT, {
|
|
621
|
-
messageId
|
|
622
|
-
});
|
|
623
|
-
};
|
|
624
594
|
async function getPage(fromCursor, pageSize) {
|
|
625
|
-
return await this.call(events_EVENT.
|
|
595
|
+
return await this.call(events_EVENT.MUJIAN_AI_CHAT_V2_MESSAGE_GET_PAGE, {
|
|
626
596
|
fromCursor,
|
|
627
597
|
pageSize
|
|
628
598
|
});
|
|
@@ -633,22 +603,6 @@ const getInfo = async function() {
|
|
|
633
603
|
const getActive = async function() {
|
|
634
604
|
return await this.call(events_EVENT.MUJIAN_AI_SETTINGS_PERSONA_GET_ACTIVE);
|
|
635
605
|
};
|
|
636
|
-
const setActive = async function(personaId) {
|
|
637
|
-
return await this.call(events_EVENT.MUJIAN_AI_SETTINGS_PERSONA_SET_ACTIVE, {
|
|
638
|
-
personaId
|
|
639
|
-
});
|
|
640
|
-
};
|
|
641
|
-
const model_getActive = async function() {
|
|
642
|
-
return await this.call(events_EVENT.MUJIAN_AI_SETTINGS_MODEL_GET_ACTIVE);
|
|
643
|
-
};
|
|
644
|
-
const model_setActive = async function(modelId) {
|
|
645
|
-
return await this.call(events_EVENT.MUJIAN_AI_SETTINGS_MODEL_SET_ACTIVE, {
|
|
646
|
-
modelId
|
|
647
|
-
});
|
|
648
|
-
};
|
|
649
|
-
const model_getAll = async function() {
|
|
650
|
-
return await this.call(events_EVENT.MUJIAN_AI_SETTINGS_MODEL_GET_ALL);
|
|
651
|
-
};
|
|
652
606
|
const generate = async function(content) {
|
|
653
607
|
return await this.call(MujianSdk.EVENT.MUJIAN_AI_TEXT_GENERATE, {
|
|
654
608
|
content
|
|
@@ -700,6 +654,9 @@ const images_images = {
|
|
|
700
654
|
});
|
|
701
655
|
}
|
|
702
656
|
};
|
|
657
|
+
async function getConfig() {
|
|
658
|
+
return await this.call(events_EVENT.MUJIAN_GET_CONFIG);
|
|
659
|
+
}
|
|
703
660
|
const saveGame = async function() {};
|
|
704
661
|
const loadGame = async function() {};
|
|
705
662
|
async function writeText(text) {
|
|
@@ -718,48 +675,59 @@ class MujianSdk {
|
|
|
718
675
|
return this.ready;
|
|
719
676
|
}
|
|
720
677
|
pendingRequests = new Map();
|
|
678
|
+
_config;
|
|
679
|
+
get openapi() {
|
|
680
|
+
return this._config?.openapi;
|
|
681
|
+
}
|
|
682
|
+
initPromise = null;
|
|
721
683
|
async init() {
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
call
|
|
728
|
-
|
|
729
|
-
|
|
684
|
+
if (this.initPromise) return this.initPromise;
|
|
685
|
+
this.initPromise = (async ()=>{
|
|
686
|
+
const handshake = new postmate.Model({
|
|
687
|
+
reply: ({ id, complete, data, error })=>{
|
|
688
|
+
const call = this.pendingRequests.get(id);
|
|
689
|
+
if (!call) return;
|
|
690
|
+
if (error) {
|
|
691
|
+
call.reject(error);
|
|
692
|
+
this.pendingRequests.delete(id);
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
call.onData?.(data);
|
|
696
|
+
if (complete) {
|
|
697
|
+
call.onComplete?.();
|
|
698
|
+
call.resolve(data);
|
|
699
|
+
this.pendingRequests.delete(id);
|
|
700
|
+
}
|
|
730
701
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
702
|
+
});
|
|
703
|
+
try {
|
|
704
|
+
const parent = await handshake;
|
|
705
|
+
this.ready = true;
|
|
706
|
+
this.parent = parent;
|
|
707
|
+
Log.i('mujian sdk client init');
|
|
708
|
+
await this.call(events_EVENT.MUJIAN_INIT);
|
|
709
|
+
const projectInfo = await this.ai.chat.project.getInfo();
|
|
710
|
+
if (projectInfo.config?.customCss) {
|
|
711
|
+
const style = document.createElement('style');
|
|
712
|
+
style.setAttribute('type', 'text/css');
|
|
713
|
+
style.setAttribute('id', 'mujian-custom-css');
|
|
714
|
+
style.textContent = projectInfo.config.customCss;
|
|
715
|
+
document.head.appendChild(style);
|
|
736
716
|
}
|
|
717
|
+
if (projectInfo.config?.customJs) {
|
|
718
|
+
const script = document.createElement("script");
|
|
719
|
+
script.setAttribute('type', "text/javascript");
|
|
720
|
+
script.setAttribute('id', 'mujian-custom-js');
|
|
721
|
+
script.textContent = projectInfo.config.customJs;
|
|
722
|
+
document.head.appendChild(script);
|
|
723
|
+
}
|
|
724
|
+
const config = await getConfig.call(this);
|
|
725
|
+
if (config) this._config = config;
|
|
726
|
+
} catch (error) {
|
|
727
|
+
Log.e('init error', error);
|
|
737
728
|
}
|
|
738
|
-
});
|
|
739
|
-
|
|
740
|
-
const parent = await handshake;
|
|
741
|
-
this.ready = true;
|
|
742
|
-
this.parent = parent;
|
|
743
|
-
Log.i('mujian sdk client init');
|
|
744
|
-
await this.call(events_EVENT.MUJIAN_INIT);
|
|
745
|
-
const projectInfo = await this.ai.chat.project.getInfo();
|
|
746
|
-
if (projectInfo.config?.customCss) {
|
|
747
|
-
const style = document.createElement('style');
|
|
748
|
-
style.setAttribute('type', 'text/css');
|
|
749
|
-
style.setAttribute('id', 'mujian-custom-css');
|
|
750
|
-
style.textContent = projectInfo.config.customCss;
|
|
751
|
-
document.head.appendChild(style);
|
|
752
|
-
}
|
|
753
|
-
if (projectInfo.config?.customJs) {
|
|
754
|
-
const script = document.createElement("script");
|
|
755
|
-
script.setAttribute('type', "text/javascript");
|
|
756
|
-
script.setAttribute('id', 'mujian-custom-js');
|
|
757
|
-
script.textContent = projectInfo.config.customJs;
|
|
758
|
-
document.head.appendChild(script);
|
|
759
|
-
}
|
|
760
|
-
} catch (error) {
|
|
761
|
-
Log.e('init error', error);
|
|
762
|
-
}
|
|
729
|
+
})();
|
|
730
|
+
return this.initPromise;
|
|
763
731
|
}
|
|
764
732
|
emit(event, data) {
|
|
765
733
|
if (!this.ready) throw new Error('Mujian is not initialized');
|
|
@@ -797,27 +765,20 @@ class MujianSdk {
|
|
|
797
765
|
getInfo: getInfo.bind(this)
|
|
798
766
|
},
|
|
799
767
|
settings: {
|
|
800
|
-
model: {
|
|
801
|
-
getAll: model_getAll.bind(this),
|
|
802
|
-
getActive: model_getActive.bind(this),
|
|
803
|
-
setActive: model_setActive.bind(this)
|
|
804
|
-
},
|
|
805
768
|
persona: {
|
|
806
|
-
getActive: getActive.bind(this)
|
|
807
|
-
setActive: setActive.bind(this)
|
|
769
|
+
getActive: getActive.bind(this)
|
|
808
770
|
}
|
|
809
771
|
},
|
|
810
772
|
complete: chat_complete.bind(this),
|
|
811
|
-
applyRegex: applyRegex.bind(this),
|
|
812
773
|
renderMessage: renderMessage.bind(this),
|
|
813
774
|
continue: continueComplete.bind(this),
|
|
814
775
|
regenerate: chat_regenerate.bind(this),
|
|
776
|
+
stop: chat_stop.bind(this),
|
|
777
|
+
recover: recover.bind(this),
|
|
815
778
|
message: {
|
|
816
|
-
getAll: getAll.bind(this),
|
|
817
779
|
deleteOne: messageDeleteOne.bind(this),
|
|
818
780
|
editOne: messageEditOne.bind(this),
|
|
819
781
|
swipe: messageSwipe.bind(this),
|
|
820
|
-
getPrompt: getPrompt.bind(this),
|
|
821
782
|
getPage: getPage.bind(this)
|
|
822
783
|
}
|
|
823
784
|
},
|
|
@@ -900,8 +861,10 @@ const MujianSpinner = ({ className, style })=>/*#__PURE__*/ jsxs(Fragment, {
|
|
|
900
861
|
]
|
|
901
862
|
});
|
|
902
863
|
const MujianContext = /*#__PURE__*/ createContext(null);
|
|
864
|
+
const ChatContext = /*#__PURE__*/ createContext(null);
|
|
903
865
|
const MujianProvider = ({ children, loadingComponent })=>{
|
|
904
866
|
const [mujian, setMujian] = useState(null);
|
|
867
|
+
const [messageTypeWritingCount, setMessageTypeWritingCount] = useState(0);
|
|
905
868
|
useEffect(()=>{
|
|
906
869
|
(async ()=>{
|
|
907
870
|
const mujian = MujianSdk.getInstance();
|
|
@@ -911,18 +874,26 @@ const MujianProvider = ({ children, loadingComponent })=>{
|
|
|
911
874
|
}, []);
|
|
912
875
|
return /*#__PURE__*/ jsx(MujianContext.Provider, {
|
|
913
876
|
value: mujian,
|
|
914
|
-
children:
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
alignItems: 'center'
|
|
877
|
+
children: /*#__PURE__*/ jsx(ChatContext.Provider, {
|
|
878
|
+
value: {
|
|
879
|
+
messageTypeWritingCount,
|
|
880
|
+
updateMessageTypeWritingCount (dir) {
|
|
881
|
+
setMessageTypeWritingCount((p)=>Math.max(p + ('add' === dir ? 1 : -1), 0));
|
|
882
|
+
}
|
|
921
883
|
},
|
|
922
|
-
children: /*#__PURE__*/ jsx(
|
|
884
|
+
children: mujian ? children : loadingComponent ?? /*#__PURE__*/ jsx("div", {
|
|
923
885
|
style: {
|
|
924
|
-
|
|
925
|
-
|
|
886
|
+
height: '100%',
|
|
887
|
+
width: '100%',
|
|
888
|
+
display: 'flex',
|
|
889
|
+
justifyContent: 'center',
|
|
890
|
+
alignItems: 'center'
|
|
891
|
+
},
|
|
892
|
+
children: /*#__PURE__*/ jsx(MujianSpinner, {
|
|
893
|
+
style: {
|
|
894
|
+
color: '#EC4342'
|
|
895
|
+
}
|
|
896
|
+
})
|
|
926
897
|
})
|
|
927
898
|
})
|
|
928
899
|
});
|
|
@@ -936,12 +907,86 @@ const useMujian = ()=>{
|
|
|
936
907
|
}
|
|
937
908
|
return mujian;
|
|
938
909
|
};
|
|
910
|
+
const useChatContext = ()=>{
|
|
911
|
+
const mujian = useContext(ChatContext);
|
|
912
|
+
if (!mujian) {
|
|
913
|
+
const message = 'Context is not initialized. Please check that useChatContext is called inside MujianProvider';
|
|
914
|
+
console.error(message);
|
|
915
|
+
throw new Error(message);
|
|
916
|
+
}
|
|
917
|
+
return mujian;
|
|
918
|
+
};
|
|
939
919
|
const MessageItem = (props)=>{
|
|
940
|
-
const { message, children, depth, index
|
|
920
|
+
const { message, children, depth, index, typingOpts = {
|
|
921
|
+
chunkSize: 2,
|
|
922
|
+
delay: 40
|
|
923
|
+
} } = props;
|
|
941
924
|
const mujian = useMujian();
|
|
925
|
+
const { updateMessageTypeWritingCount } = useChatContext();
|
|
926
|
+
const lastMessage = useLatest(message);
|
|
927
|
+
const [typeWritingPos, setTypeWritingPos] = useState(null);
|
|
928
|
+
const typeWritingIntervalId = useRef(null);
|
|
929
|
+
function stopTypeWriting() {
|
|
930
|
+
if (typeWritingIntervalId.current) {
|
|
931
|
+
clearTimeout(typeWritingIntervalId.current);
|
|
932
|
+
typeWritingIntervalId.current = null;
|
|
933
|
+
setTimeout(()=>{
|
|
934
|
+
updateMessageTypeWritingCount('sub');
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
function startTypeWriting() {
|
|
939
|
+
updateMessageTypeWritingCount('add');
|
|
940
|
+
stopTypeWriting();
|
|
941
|
+
let lastTimestamp = Date.now();
|
|
942
|
+
typeWritingIntervalId.current = setInterval(()=>{
|
|
943
|
+
function calcTimeFrames() {
|
|
944
|
+
const now = Date.now();
|
|
945
|
+
const deltaTime = now - lastTimestamp;
|
|
946
|
+
lastTimestamp = now;
|
|
947
|
+
return Math.round(deltaTime / typingOpts.delay);
|
|
948
|
+
}
|
|
949
|
+
setTypeWritingPos((p)=>{
|
|
950
|
+
const frames = calcTimeFrames();
|
|
951
|
+
const posIncrement = frames * typingOpts.chunkSize;
|
|
952
|
+
const message = lastMessage.current;
|
|
953
|
+
const content = message.swipes[message.activeSwipeId].content;
|
|
954
|
+
const maxPos = content.length;
|
|
955
|
+
const nextPos = Math.min((p || 0) + posIncrement, maxPos);
|
|
956
|
+
if (!message.isGenerating && maxPos === nextPos) {
|
|
957
|
+
stopTypeWriting();
|
|
958
|
+
return null;
|
|
959
|
+
}
|
|
960
|
+
return nextPos;
|
|
961
|
+
});
|
|
962
|
+
}, typingOpts.delay);
|
|
963
|
+
}
|
|
964
|
+
useUnmount(()=>{
|
|
965
|
+
stopTypeWriting();
|
|
966
|
+
});
|
|
967
|
+
useEffect(()=>{
|
|
968
|
+
if (message.isGenerating) {
|
|
969
|
+
const content = message.swipes[message.activeSwipeId].content;
|
|
970
|
+
setTypeWritingPos(content.length);
|
|
971
|
+
startTypeWriting();
|
|
972
|
+
}
|
|
973
|
+
}, [
|
|
974
|
+
message.isGenerating
|
|
975
|
+
]);
|
|
942
976
|
const { data: renderedMessage } = useRequest(async ()=>{
|
|
943
|
-
|
|
944
|
-
|
|
977
|
+
if (null !== typeWritingPos) {
|
|
978
|
+
const pos = typeWritingPos;
|
|
979
|
+
return {
|
|
980
|
+
...message,
|
|
981
|
+
swipes: message.swipes.map((s, i)=>{
|
|
982
|
+
if (i !== message.activeSwipeId) return s;
|
|
983
|
+
return {
|
|
984
|
+
...s,
|
|
985
|
+
content: s.content.slice(0, pos)
|
|
986
|
+
};
|
|
987
|
+
})
|
|
988
|
+
};
|
|
989
|
+
}
|
|
945
990
|
return await mujian.ai.chat.renderMessage({
|
|
946
991
|
message,
|
|
947
992
|
depth,
|
|
@@ -949,7 +994,8 @@ const MessageItem = (props)=>{
|
|
|
949
994
|
});
|
|
950
995
|
}, {
|
|
951
996
|
refreshDeps: [
|
|
952
|
-
message
|
|
997
|
+
message,
|
|
998
|
+
typeWritingPos
|
|
953
999
|
]
|
|
954
1000
|
});
|
|
955
1001
|
return children(renderedMessage || message, message);
|
|
@@ -971,28 +1017,116 @@ const Thread = {
|
|
|
971
1017
|
MessageItem: MessageItem,
|
|
972
1018
|
MessageList: MessageList
|
|
973
1019
|
};
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1020
|
+
let $mj_ai_chat_complete;
|
|
1021
|
+
let $mj_ai_chat_project;
|
|
1022
|
+
let $mj_ai_chat_settings_persona;
|
|
1023
|
+
let $mj_ai_chat_setFirstMesIndex;
|
|
1024
|
+
let $mj_ai_chat_mjv_get;
|
|
1025
|
+
let $mj_ai_chat_mjv_getAll;
|
|
1026
|
+
const $mj_engine = {
|
|
1027
|
+
ai: {
|
|
1028
|
+
chat: {
|
|
1029
|
+
get complete () {
|
|
1030
|
+
return $mj_ai_chat_complete;
|
|
1031
|
+
},
|
|
1032
|
+
get project () {
|
|
1033
|
+
return $mj_ai_chat_project;
|
|
1034
|
+
},
|
|
1035
|
+
settings: {
|
|
1036
|
+
get persona () {
|
|
1037
|
+
return $mj_ai_chat_settings_persona;
|
|
1038
|
+
}
|
|
1039
|
+
},
|
|
1040
|
+
get setFirstMesIndex () {
|
|
1041
|
+
return $mj_ai_chat_setFirstMesIndex;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
979
1044
|
}
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1045
|
+
};
|
|
1046
|
+
window.$mj_engine = {
|
|
1047
|
+
...$mj_engine,
|
|
1048
|
+
bind ({ messageId, swipeId }) {
|
|
1049
|
+
return {
|
|
1050
|
+
ai: {
|
|
1051
|
+
chat: {
|
|
1052
|
+
mjv: {
|
|
1053
|
+
get (path) {
|
|
1054
|
+
return $mj_ai_chat_mjv_get?.(messageId, swipeId, path);
|
|
1055
|
+
},
|
|
1056
|
+
getAll () {
|
|
1057
|
+
return $mj_ai_chat_mjv_getAll?.(messageId, swipeId) ?? {};
|
|
1058
|
+
}
|
|
1059
|
+
},
|
|
1060
|
+
get complete () {
|
|
1061
|
+
return $mj_ai_chat_complete;
|
|
1062
|
+
},
|
|
1063
|
+
get project () {
|
|
1064
|
+
return $mj_ai_chat_project;
|
|
1065
|
+
},
|
|
1066
|
+
settings: {
|
|
1067
|
+
get persona () {
|
|
1068
|
+
return $mj_ai_chat_settings_persona;
|
|
1069
|
+
}
|
|
1070
|
+
},
|
|
1071
|
+
get setFirstMesIndex () {
|
|
1072
|
+
return $mj_ai_chat_setFirstMesIndex;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
986
1077
|
}
|
|
1078
|
+
};
|
|
1079
|
+
function useMjEngine({ projectInfo, activePersona, onSend, messages, setSwipe }) {
|
|
1080
|
+
useEffect(()=>{
|
|
1081
|
+
$mj_ai_chat_project = projectInfo ?? void 0;
|
|
1082
|
+
$mj_ai_chat_settings_persona = activePersona ?? void 0;
|
|
1083
|
+
}, [
|
|
1084
|
+
projectInfo,
|
|
1085
|
+
activePersona
|
|
1086
|
+
]);
|
|
1087
|
+
useEffect(()=>{
|
|
1088
|
+
$mj_ai_chat_complete = async (message)=>{
|
|
1089
|
+
await onSend(message);
|
|
1090
|
+
};
|
|
1091
|
+
$mj_ai_chat_setFirstMesIndex = async (oneBasedIndex)=>{
|
|
1092
|
+
if (messages.length > 1) throw new Error('已有新消息,不允许切换开场白');
|
|
1093
|
+
if (0 === messages.length) throw new Error('断言失败:没有开场消息,无法切换开场白');
|
|
1094
|
+
const zeroBasedIndex = Math.floor(oneBasedIndex) - 1;
|
|
1095
|
+
const swipeLength = messages[0].swipes.length;
|
|
1096
|
+
if (zeroBasedIndex < 0 || zeroBasedIndex >= swipeLength) return;
|
|
1097
|
+
setSwipe(messages[0].id, zeroBasedIndex);
|
|
1098
|
+
};
|
|
1099
|
+
$mj_ai_chat_mjv_getAll = (messageId, swipeId)=>messages.find((m)=>m.id === messageId)?.swipes[swipeId]?.mjv?.value;
|
|
1100
|
+
$mj_ai_chat_mjv_get = (messageId, swipeId, path)=>{
|
|
1101
|
+
const mjv = $mj_ai_chat_mjv_getAll?.(messageId, swipeId);
|
|
1102
|
+
if (!mjv) return;
|
|
1103
|
+
return get(mjv, path);
|
|
1104
|
+
};
|
|
1105
|
+
}, [
|
|
1106
|
+
onSend,
|
|
1107
|
+
messages,
|
|
1108
|
+
setSwipe
|
|
1109
|
+
]);
|
|
1110
|
+
}
|
|
1111
|
+
const errorMessages = [
|
|
1112
|
+
'network error',
|
|
1113
|
+
'NetworkError when attempting to fetch resource.',
|
|
1114
|
+
'The Internet connection appears to be offline.',
|
|
1115
|
+
'Network request failed',
|
|
1116
|
+
'Load failed',
|
|
1117
|
+
'Failed to fetch'
|
|
1118
|
+
];
|
|
1119
|
+
function isNetworkError(message) {
|
|
1120
|
+
return errorMessages.some((m)=>message.includes(m));
|
|
987
1121
|
}
|
|
988
|
-
class
|
|
1122
|
+
class SendMessageError extends Error {
|
|
989
1123
|
constructor(message, cause){
|
|
990
1124
|
super(message);
|
|
991
1125
|
this.name = this.constructor.name;
|
|
992
1126
|
this.cause = cause;
|
|
993
1127
|
}
|
|
994
1128
|
}
|
|
995
|
-
async function* callSdk(mujian, content, type = 'generate',
|
|
1129
|
+
async function* callSdk(mujian, content, type = 'generate', conversationVersion, assisMsgId) {
|
|
996
1130
|
const queue = [];
|
|
997
1131
|
let resolveWait = null;
|
|
998
1132
|
let done = false;
|
|
@@ -1000,7 +1134,6 @@ async function* callSdk(mujian, content, type = 'generate', signal) {
|
|
|
1000
1134
|
try {
|
|
1001
1135
|
const onData = (data)=>{
|
|
1002
1136
|
if (error) return;
|
|
1003
|
-
if ('string' != typeof data) return;
|
|
1004
1137
|
queue.push(data);
|
|
1005
1138
|
if (resolveWait) {
|
|
1006
1139
|
resolveWait();
|
|
@@ -1021,9 +1154,13 @@ async function* callSdk(mujian, content, type = 'generate', signal) {
|
|
|
1021
1154
|
resolveWait = null;
|
|
1022
1155
|
}
|
|
1023
1156
|
};
|
|
1024
|
-
if ('generate' === type) mujian.ai.chat.complete(content,
|
|
1025
|
-
else if ('regenerate' === type) mujian.ai.chat.regenerate(
|
|
1026
|
-
else mujian.ai.chat.continue(
|
|
1157
|
+
if ('generate' === type) mujian.ai.chat.complete(content, conversationVersion, onData).then(then).catch(catcher);
|
|
1158
|
+
else if ('regenerate' === type) mujian.ai.chat.regenerate(conversationVersion, onData).then(then).catch(catcher);
|
|
1159
|
+
else if ('continue' === type) mujian.ai.chat.continue(conversationVersion, onData).then(then).catch(catcher);
|
|
1160
|
+
else {
|
|
1161
|
+
if (!assisMsgId) throw new Error('call recover without assisMsgId');
|
|
1162
|
+
mujian.ai.chat.recover(conversationVersion, assisMsgId, onData).then(then).catch(catcher);
|
|
1163
|
+
}
|
|
1027
1164
|
} catch (err) {
|
|
1028
1165
|
error = err;
|
|
1029
1166
|
done = true;
|
|
@@ -1036,56 +1173,44 @@ async function* callSdk(mujian, content, type = 'generate', signal) {
|
|
|
1036
1173
|
});
|
|
1037
1174
|
}
|
|
1038
1175
|
const NOT_SAVED_MSG_ID_PREFIX = 'not_saved';
|
|
1039
|
-
const
|
|
1040
|
-
哎呀,AI线路好像抽风了,重说一下试试吧~`;
|
|
1041
|
-
const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
1176
|
+
const useChatStreaming = ({ common, setError, setMessages, getMessages, setInput, mujian, conversationVersion: conversationVersionRef })=>{
|
|
1042
1177
|
const { body } = common;
|
|
1043
1178
|
const [isStreaming, setIsStreaming] = useState(false);
|
|
1044
|
-
const chatStreaming = useCallback(async ({ query, regenerate, is_continue,
|
|
1179
|
+
const chatStreaming = useCallback(async ({ query, regenerate, is_continue, conversationVersion })=>{
|
|
1045
1180
|
try {
|
|
1046
1181
|
setError(void 0);
|
|
1047
1182
|
setIsStreaming(true);
|
|
1183
|
+
const backupMessages = getMessages();
|
|
1048
1184
|
const userMessage = {
|
|
1049
1185
|
id: `${NOT_SAVED_MSG_ID_PREFIX}_user_${Date.now()}`,
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1186
|
+
isUser: true,
|
|
1187
|
+
swipes: [
|
|
1188
|
+
{
|
|
1189
|
+
content: query ?? ''
|
|
1190
|
+
}
|
|
1191
|
+
],
|
|
1053
1192
|
activeSwipeId: 0,
|
|
1054
|
-
|
|
1055
|
-
sendAt: new Date(),
|
|
1056
|
-
swipeInfo: []
|
|
1193
|
+
isGenerating: false
|
|
1057
1194
|
};
|
|
1058
1195
|
const aiMessage = {
|
|
1059
1196
|
id: `${NOT_SAVED_MSG_ID_PREFIX}_assistant_${Date.now()}`,
|
|
1060
|
-
|
|
1061
|
-
role: 'assistant',
|
|
1197
|
+
isUser: false,
|
|
1062
1198
|
swipes: [
|
|
1063
|
-
|
|
1199
|
+
{
|
|
1200
|
+
content: ''
|
|
1201
|
+
}
|
|
1064
1202
|
],
|
|
1065
1203
|
activeSwipeId: 0,
|
|
1066
|
-
|
|
1067
|
-
sendAt: new Date(),
|
|
1068
|
-
swipeInfo: [
|
|
1069
|
-
{}
|
|
1070
|
-
]
|
|
1204
|
+
isGenerating: true
|
|
1071
1205
|
};
|
|
1072
|
-
if (regenerate) setMessages((
|
|
1073
|
-
const
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
swipes: [
|
|
1081
|
-
...lastMessage.swipes,
|
|
1082
|
-
''
|
|
1083
|
-
],
|
|
1084
|
-
content: '',
|
|
1085
|
-
isStreaming: true
|
|
1086
|
-
};
|
|
1087
|
-
return newMessages;
|
|
1088
|
-
});
|
|
1206
|
+
if (regenerate) setMessages(produce((draft)=>{
|
|
1207
|
+
const lastMessage = draft[draft.length - 1];
|
|
1208
|
+
lastMessage.activeSwipeId = lastMessage.swipes.length;
|
|
1209
|
+
lastMessage.swipes.push({
|
|
1210
|
+
content: ''
|
|
1211
|
+
});
|
|
1212
|
+
lastMessage.isGenerating = true;
|
|
1213
|
+
}));
|
|
1089
1214
|
else is_continue ? setMessages((prev)=>[
|
|
1090
1215
|
...prev,
|
|
1091
1216
|
aiMessage
|
|
@@ -1094,111 +1219,45 @@ const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
|
1094
1219
|
userMessage,
|
|
1095
1220
|
aiMessage
|
|
1096
1221
|
]);
|
|
1097
|
-
const stream = callSdk(mujian, query || '', is_continue ? 'continue' : regenerate ? 'regenerate' : 'generate',
|
|
1098
|
-
let buffer = '';
|
|
1099
|
-
let content = '';
|
|
1222
|
+
const stream = callSdk(mujian, query || '', is_continue ? 'continue' : regenerate ? 'regenerate' : 'generate', conversationVersion);
|
|
1100
1223
|
try {
|
|
1101
1224
|
for await (const chunk of stream){
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
const parsedData = JSON.parse(data);
|
|
1109
|
-
if (regenerate || 'meta' !== parsedData.type) {
|
|
1110
|
-
if ('stream' === parsedData.type) {
|
|
1111
|
-
const partialContent = parsedData.choices[0].delta.content;
|
|
1112
|
-
parsedData.choices[0].delta.reasoning;
|
|
1113
|
-
content += partialContent;
|
|
1114
|
-
if (content || '' === content) {
|
|
1115
|
-
setMessages((prev)=>{
|
|
1116
|
-
const newMessages = [
|
|
1117
|
-
...prev
|
|
1118
|
-
];
|
|
1119
|
-
const lastMessage = newMessages[newMessages.length - 1];
|
|
1120
|
-
lastMessage.swipes[lastMessage.activeSwipeId] = content;
|
|
1121
|
-
newMessages[newMessages.length - 1] = {
|
|
1122
|
-
...lastMessage,
|
|
1123
|
-
content: content,
|
|
1124
|
-
isStreaming: true
|
|
1125
|
-
};
|
|
1126
|
-
return newMessages;
|
|
1127
|
-
});
|
|
1128
|
-
await new Promise((resolve)=>setTimeout(resolve, 10));
|
|
1129
|
-
} else {
|
|
1130
|
-
console.error('data', data);
|
|
1131
|
-
setError(new InvalidDeltaContentError(data));
|
|
1132
|
-
}
|
|
1133
|
-
} else if ('mjv' === parsedData.type) {
|
|
1134
|
-
const { value, delta, schema } = parsedData;
|
|
1135
|
-
setMessages((prev)=>{
|
|
1136
|
-
const newMessages = [
|
|
1137
|
-
...prev
|
|
1138
|
-
];
|
|
1139
|
-
const lastMessage = newMessages[newMessages.length - 1];
|
|
1140
|
-
const mjv = {
|
|
1141
|
-
value,
|
|
1142
|
-
delta,
|
|
1143
|
-
schema
|
|
1144
|
-
};
|
|
1145
|
-
const newSwipeInfo = lastMessage.swipeInfo;
|
|
1146
|
-
if (newSwipeInfo[lastMessage.activeSwipeId]) newSwipeInfo[lastMessage.activeSwipeId].mjv = mjv;
|
|
1147
|
-
else newSwipeInfo[lastMessage.activeSwipeId] = {
|
|
1148
|
-
mjv
|
|
1149
|
-
};
|
|
1150
|
-
newMessages[newMessages.length - 1] = {
|
|
1151
|
-
...lastMessage,
|
|
1152
|
-
swipeInfo: newSwipeInfo,
|
|
1153
|
-
mjv
|
|
1154
|
-
};
|
|
1155
|
-
return newMessages;
|
|
1156
|
-
});
|
|
1157
|
-
}
|
|
1158
|
-
} else {
|
|
1159
|
-
const { question_id, reply_id } = parsedData;
|
|
1160
|
-
setMessages((prev)=>{
|
|
1161
|
-
const newMessages = [
|
|
1162
|
-
...prev
|
|
1163
|
-
];
|
|
1164
|
-
if (question_id && !is_continue) newMessages[newMessages.length - 2].id = question_id;
|
|
1165
|
-
const lastMessage = newMessages[newMessages.length - 1];
|
|
1166
|
-
newMessages[newMessages.length - 1] = {
|
|
1167
|
-
...lastMessage,
|
|
1168
|
-
id: reply_id
|
|
1169
|
-
};
|
|
1170
|
-
return newMessages;
|
|
1171
|
-
});
|
|
1172
|
-
continue;
|
|
1225
|
+
if (!chunk) return;
|
|
1226
|
+
if ('meta' === chunk.type) {
|
|
1227
|
+
if (!regenerate) setMessages(produce((draft)=>{
|
|
1228
|
+
if (!is_continue) {
|
|
1229
|
+
const userMsg = draft[draft.length - 2];
|
|
1230
|
+
userMsg.id = chunk.userMsgId;
|
|
1173
1231
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1232
|
+
const lastMessage = draft[draft.length - 1];
|
|
1233
|
+
lastMessage.id = chunk.assisMsgId;
|
|
1234
|
+
}));
|
|
1235
|
+
conversationVersionRef.current = chunk.newConversationVersion;
|
|
1236
|
+
} else if ('data' === chunk.type) {
|
|
1237
|
+
setMessages(produce((draft)=>{
|
|
1238
|
+
const lastMessage = draft[draft.length - 1];
|
|
1239
|
+
lastMessage.swipes[lastMessage.activeSwipeId] = {
|
|
1240
|
+
content: chunk.content,
|
|
1241
|
+
mjv: chunk.mjv
|
|
1242
|
+
};
|
|
1243
|
+
if (chunk.finishReason) lastMessage.finishReason = chunk.finishReason;
|
|
1244
|
+
if (chunk.error) lastMessage.error = chunk.error;
|
|
1245
|
+
}));
|
|
1246
|
+
await new Promise((resolve)=>setTimeout(resolve, 10));
|
|
1180
1247
|
}
|
|
1181
1248
|
}
|
|
1182
1249
|
} catch (error) {
|
|
1183
1250
|
Log.e('Stream error', error);
|
|
1184
|
-
'object' == typeof error && error && 'message' in error && 'string' == typeof error.message
|
|
1251
|
+
if ('object' == typeof error && error && 'message' in error && 'string' == typeof error.message) if ('code' in error && 2011030001 === error.code) {
|
|
1252
|
+
setMessages(backupMessages);
|
|
1253
|
+
if (!regenerate && !is_continue && query) setInput(query);
|
|
1254
|
+
} else isNetworkError(error.message) ? setError(new SendMessageError('E_NETWORK_ERROR')) : setError(new SendMessageError(error.message));
|
|
1255
|
+
else setError(error);
|
|
1185
1256
|
} finally{
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
];
|
|
1191
|
-
const lastMessage = {
|
|
1192
|
-
...newMessages[newMessages.length - 1],
|
|
1193
|
-
isStreaming: false
|
|
1194
|
-
};
|
|
1195
|
-
if (!lastMessage.swipes[lastMessage.activeSwipeId]) {
|
|
1196
|
-
lastMessage.swipes[lastMessage.activeSwipeId] = FALLBACK_MESSAGE;
|
|
1197
|
-
lastMessage.content = FALLBACK_MESSAGE;
|
|
1198
|
-
}
|
|
1199
|
-
newMessages[newMessages.length - 1] = lastMessage;
|
|
1200
|
-
return newMessages;
|
|
1201
|
-
});
|
|
1257
|
+
setMessages(produce((draft)=>{
|
|
1258
|
+
const lastMessage = draft[draft.length - 1];
|
|
1259
|
+
lastMessage.isGenerating = false;
|
|
1260
|
+
}));
|
|
1202
1261
|
}
|
|
1203
1262
|
} catch (error) {
|
|
1204
1263
|
console.error('Error:', error);
|
|
@@ -1211,15 +1270,46 @@ const useChatStreaming = ({ common, setError, setMessages, mujian })=>{
|
|
|
1211
1270
|
body,
|
|
1212
1271
|
mujian
|
|
1213
1272
|
]);
|
|
1273
|
+
const recoverStreaming = useCallback(async (messageId, conversationVersion)=>{
|
|
1274
|
+
const stream = callSdk(mujian, '', 'recover', conversationVersion, messageId);
|
|
1275
|
+
try {
|
|
1276
|
+
for await (const chunk of stream){
|
|
1277
|
+
if (!chunk) return;
|
|
1278
|
+
if ('data' === chunk.type) setMessages(produce((draft)=>{
|
|
1279
|
+
const msg = draft.find((m)=>m.id === messageId);
|
|
1280
|
+
if (!msg) return;
|
|
1281
|
+
msg.swipes[msg.activeSwipeId] = {
|
|
1282
|
+
content: chunk.content,
|
|
1283
|
+
mjv: chunk.mjv
|
|
1284
|
+
};
|
|
1285
|
+
if (chunk.finishReason) msg.finishReason = chunk.finishReason;
|
|
1286
|
+
if (chunk.error) msg.error = chunk.error;
|
|
1287
|
+
}));
|
|
1288
|
+
}
|
|
1289
|
+
} catch (error) {
|
|
1290
|
+
Log.e('Stream error', error);
|
|
1291
|
+
if ('object' == typeof error && error && 'message' in error && 'string' == typeof error.message) isNetworkError(error.message) ? setError(new SendMessageError('E_NETWORK_ERROR')) : setError(new SendMessageError(error.message));
|
|
1292
|
+
else setError(error);
|
|
1293
|
+
} finally{
|
|
1294
|
+
setMessages(produce((draft)=>{
|
|
1295
|
+
const msg = draft.find((m)=>m.id === messageId);
|
|
1296
|
+
if (!msg) return;
|
|
1297
|
+
msg.isGenerating = false;
|
|
1298
|
+
}));
|
|
1299
|
+
}
|
|
1300
|
+
}, [
|
|
1301
|
+
mujian
|
|
1302
|
+
]);
|
|
1214
1303
|
return {
|
|
1215
1304
|
chatStreaming,
|
|
1216
|
-
isStreaming
|
|
1305
|
+
isStreaming,
|
|
1306
|
+
recoverStreaming
|
|
1217
1307
|
};
|
|
1218
1308
|
};
|
|
1219
|
-
const useChat = ({ body, onError, onFinish, pageSize })=>{
|
|
1309
|
+
const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
|
|
1220
1310
|
const [error, _setError] = useState();
|
|
1221
1311
|
const [input, setInput] = useState('');
|
|
1222
|
-
const
|
|
1312
|
+
const conversationVersion = useRef(0);
|
|
1223
1313
|
const mujian = useMujian();
|
|
1224
1314
|
const setError = (error)=>{
|
|
1225
1315
|
_setError(error);
|
|
@@ -1234,12 +1324,12 @@ const useChat = ({ body, onError, onFinish, pageSize })=>{
|
|
|
1234
1324
|
};
|
|
1235
1325
|
try {
|
|
1236
1326
|
const resp = await mujian.ai.chat.message.getPage(current?.cursor, pageSize);
|
|
1327
|
+
conversationVersion.current = resp.conversationVersion;
|
|
1328
|
+
const lastMessage = resp.messages.at(-1);
|
|
1329
|
+
if (lastMessage?.isGenerating) recoverStreaming(lastMessage.id, conversationVersion.current);
|
|
1237
1330
|
return {
|
|
1238
1331
|
cursor: resp.nextCursor,
|
|
1239
|
-
list: resp.messages
|
|
1240
|
-
...m,
|
|
1241
|
-
mjv: m.swipeInfo[m.activeSwipeId]?.mjv
|
|
1242
|
-
})),
|
|
1332
|
+
list: resp.messages,
|
|
1243
1333
|
noMore: !resp.nextCursor
|
|
1244
1334
|
};
|
|
1245
1335
|
} finally{
|
|
@@ -1270,13 +1360,19 @@ const useChat = ({ body, onError, onFinish, pageSize })=>{
|
|
|
1270
1360
|
list: newList
|
|
1271
1361
|
});
|
|
1272
1362
|
};
|
|
1273
|
-
const
|
|
1363
|
+
const getMessages = useCallback(()=>latestListRef.current, [
|
|
1364
|
+
latestListRef
|
|
1365
|
+
]);
|
|
1366
|
+
const { chatStreaming, isStreaming, recoverStreaming } = useChatStreaming({
|
|
1274
1367
|
common: {
|
|
1275
1368
|
body
|
|
1276
1369
|
},
|
|
1277
1370
|
setError,
|
|
1278
1371
|
setMessages,
|
|
1279
|
-
|
|
1372
|
+
getMessages,
|
|
1373
|
+
setInput,
|
|
1374
|
+
mujian,
|
|
1375
|
+
conversationVersion
|
|
1280
1376
|
});
|
|
1281
1377
|
useUpdateEffect(()=>{
|
|
1282
1378
|
if (!isStreaming) {
|
|
@@ -1288,18 +1384,14 @@ const useChat = ({ body, onError, onFinish, pageSize })=>{
|
|
|
1288
1384
|
]);
|
|
1289
1385
|
const append = useCallback(async (query)=>{
|
|
1290
1386
|
if (isStreaming) throw new Error('useChat is streaming already.');
|
|
1291
|
-
const controller = new AbortController();
|
|
1292
|
-
setAbortController(controller);
|
|
1293
1387
|
try {
|
|
1294
1388
|
await chatStreaming({
|
|
1295
1389
|
query,
|
|
1296
|
-
|
|
1390
|
+
conversationVersion: conversationVersion.current
|
|
1297
1391
|
});
|
|
1298
1392
|
} catch (e) {
|
|
1299
1393
|
setError(e);
|
|
1300
1394
|
throw e;
|
|
1301
|
-
} finally{
|
|
1302
|
-
setAbortController(void 0);
|
|
1303
1395
|
}
|
|
1304
1396
|
}, [
|
|
1305
1397
|
isStreaming,
|
|
@@ -1307,20 +1399,17 @@ const useChat = ({ body, onError, onFinish, pageSize })=>{
|
|
|
1307
1399
|
]);
|
|
1308
1400
|
const regenerate = useCallback(async ()=>{
|
|
1309
1401
|
if (isStreaming) throw new Error('useChat is streaming already.');
|
|
1310
|
-
const
|
|
1311
|
-
setAbortController(controller);
|
|
1312
|
-
const lastMessage = messages.findLast((message)=>'user' === message.role);
|
|
1402
|
+
const lastMessage = messages.findLast((message)=>message.isUser);
|
|
1313
1403
|
try {
|
|
1404
|
+
const query = lastMessage ? lastMessage.swipes[lastMessage.activeSwipeId].content : '';
|
|
1314
1405
|
await chatStreaming({
|
|
1315
|
-
query
|
|
1406
|
+
query,
|
|
1316
1407
|
regenerate: true,
|
|
1317
|
-
|
|
1408
|
+
conversationVersion: conversationVersion.current
|
|
1318
1409
|
});
|
|
1319
1410
|
} catch (e) {
|
|
1320
1411
|
setError(e);
|
|
1321
1412
|
throw e;
|
|
1322
|
-
} finally{
|
|
1323
|
-
setAbortController(void 0);
|
|
1324
1413
|
}
|
|
1325
1414
|
}, [
|
|
1326
1415
|
isStreaming,
|
|
@@ -1329,49 +1418,55 @@ const useChat = ({ body, onError, onFinish, pageSize })=>{
|
|
|
1329
1418
|
]);
|
|
1330
1419
|
const continueGenerate = useCallback(async ()=>{
|
|
1331
1420
|
if (isStreaming) throw new Error('useChat is streaming already.');
|
|
1332
|
-
const controller = new AbortController();
|
|
1333
|
-
setAbortController(controller);
|
|
1334
1421
|
try {
|
|
1335
1422
|
await chatStreaming({
|
|
1336
1423
|
query: '',
|
|
1337
1424
|
is_continue: true,
|
|
1338
|
-
|
|
1425
|
+
conversationVersion: conversationVersion.current
|
|
1339
1426
|
});
|
|
1340
1427
|
} catch (e) {
|
|
1341
1428
|
setError(e);
|
|
1342
1429
|
throw e;
|
|
1343
|
-
} finally{
|
|
1344
|
-
setAbortController(void 0);
|
|
1345
1430
|
}
|
|
1346
1431
|
}, [
|
|
1347
1432
|
isStreaming,
|
|
1348
1433
|
chatStreaming
|
|
1349
1434
|
]);
|
|
1350
1435
|
const stop = ()=>{
|
|
1351
|
-
|
|
1436
|
+
const assisMsgId = messages.at(-1)?.id;
|
|
1437
|
+
if (!assisMsgId) return;
|
|
1438
|
+
mujian.ai.chat.stop(conversationVersion.current, assisMsgId);
|
|
1352
1439
|
};
|
|
1353
1440
|
const setSwipe = async (messageId, swipeId)=>{
|
|
1354
1441
|
if (swipeId < 0) return;
|
|
1355
1442
|
setMessages((prev)=>prev.map((msg)=>msg.id === messageId && swipeId < msg.swipes.length ? {
|
|
1356
1443
|
...msg,
|
|
1357
|
-
activeSwipeId: swipeId
|
|
1358
|
-
content: msg.swipes[swipeId],
|
|
1359
|
-
mjv: msg.swipeInfo[swipeId]?.mjv
|
|
1444
|
+
activeSwipeId: swipeId
|
|
1360
1445
|
} : msg));
|
|
1361
|
-
await mujian.ai.chat.message.swipe(messageId, swipeId);
|
|
1446
|
+
const resp = await mujian.ai.chat.message.swipe(messageId, swipeId);
|
|
1447
|
+
const schema = z.object({
|
|
1448
|
+
newConversationVersion: z.number()
|
|
1449
|
+
});
|
|
1450
|
+
const { data, success } = schema.safeParse(resp);
|
|
1451
|
+
if (success && data.newConversationVersion) conversationVersion.current = data.newConversationVersion;
|
|
1362
1452
|
};
|
|
1363
1453
|
const editMessage = async (messageId, content)=>{
|
|
1364
|
-
await mujian.ai.chat.message.editOne(messageId, content);
|
|
1454
|
+
const resp = await mujian.ai.chat.message.editOne(messageId, content);
|
|
1455
|
+
const schema = z.object({
|
|
1456
|
+
newConversationVersion: z.number()
|
|
1457
|
+
});
|
|
1458
|
+
const { data, success } = schema.safeParse(resp);
|
|
1459
|
+
if (success && data.newConversationVersion) conversationVersion.current = data.newConversationVersion;
|
|
1365
1460
|
const patchMessage = (msg)=>{
|
|
1366
1461
|
const newMsg = {
|
|
1367
1462
|
...msg,
|
|
1368
1463
|
content
|
|
1369
1464
|
};
|
|
1370
|
-
if (
|
|
1465
|
+
if (!newMsg.isUser) {
|
|
1371
1466
|
newMsg.swipes = [
|
|
1372
1467
|
...newMsg.swipes
|
|
1373
1468
|
];
|
|
1374
|
-
newMsg.swipes[newMsg.activeSwipeId] = content;
|
|
1469
|
+
newMsg.swipes[newMsg.activeSwipeId].content = content;
|
|
1375
1470
|
}
|
|
1376
1471
|
return newMsg;
|
|
1377
1472
|
};
|
|
@@ -1379,7 +1474,12 @@ const useChat = ({ body, onError, onFinish, pageSize })=>{
|
|
|
1379
1474
|
};
|
|
1380
1475
|
const deleteMessage = async (messageId)=>{
|
|
1381
1476
|
if (!messageId.startsWith(NOT_SAVED_MSG_ID_PREFIX)) try {
|
|
1382
|
-
await mujian.ai.chat.message.deleteOne(messageId);
|
|
1477
|
+
const resp = await mujian.ai.chat.message.deleteOne(messageId);
|
|
1478
|
+
const schema = z.object({
|
|
1479
|
+
newConversationVersion: z.number()
|
|
1480
|
+
});
|
|
1481
|
+
const { data, success } = schema.safeParse(resp);
|
|
1482
|
+
if (success && data.newConversationVersion) conversationVersion.current = data.newConversationVersion;
|
|
1383
1483
|
} catch (e) {
|
|
1384
1484
|
if (e?.code !== 2011030004) throw e;
|
|
1385
1485
|
}
|
|
@@ -1410,4 +1510,4 @@ const useChat = ({ body, onError, onFinish, pageSize })=>{
|
|
|
1410
1510
|
messagesStatus: messageLoadError ? 'error' : loadingMore || loading ? 'loading' : data?.noMore ? 'all-loaded' : 'has-more'
|
|
1411
1511
|
};
|
|
1412
1512
|
};
|
|
1413
|
-
export { MdRenderer, MujianProvider, MujianSpinner, Thread, useChat, useMujian };
|
|
1513
|
+
export { MdRenderer, MujianProvider, MujianSpinner, Thread, useChat, useChatContext, useMjEngine, useMujian };
|