@mujian/js-sdk 0.1.0-beta.1 → 0.1.0-beta.2

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.
@@ -4,13 +4,11 @@ export type { Message };
4
4
  /**
5
5
  * Use chat
6
6
  * @param {object} body - The body of the chat.
7
- * @param {function} onError - The function to call when an error occurs.
8
7
  * @param {function} onFinish - The function to call when the chat is finished.
9
8
  * @returns {UseChatReturn} The chat.
10
9
  */
11
10
  export type UseChatProps = {
12
11
  body?: object;
13
- onError?: (e: unknown) => void;
14
12
  onFinish?: (message: Message) => void;
15
13
  /** 消息分页大小,不传时不分页 */
16
14
  pageSize?: number;
@@ -37,7 +35,6 @@ export type UseChatProps = {
37
35
  export type UseChatReturn = {
38
36
  messages: Message[];
39
37
  status: 'uninitialized' | 'ready' | 'streaming' | 'error';
40
- error?: unknown;
41
38
  /** 提交用户输入,让AI回答 */
42
39
  append: (query: string) => Promise<void>;
43
40
  /** 重新生成最后一条回答 */
@@ -54,6 +51,7 @@ export type UseChatReturn = {
54
51
  deleteMessage: (messageId: string) => Promise<void>;
55
52
  loadMoreMessage: () => Promise<void>;
56
53
  messagesStatus: 'all-loaded' | 'loading' | 'has-more' | 'error';
54
+ refresh: () => Promise<void>;
57
55
  };
58
56
  /**
59
57
  * Use chat common
@@ -67,7 +65,6 @@ export type UseChatCommon = {
67
65
  * Use chat
68
66
  * @param {UseChatProps} props - The props of the chat.
69
67
  * @param {object} props.body - The body of the chat.
70
- * @param {function} props.onError - The function to call when an error occurs.
71
68
  * @param {function} props.onFinish - The function to call when the chat is finished.
72
69
  * @param {number} props.pageSize - The page size of the chat.
73
70
  * @returns {UseChatReturn} The chat.
@@ -78,4 +75,4 @@ export type UseChatCommon = {
78
75
  * },
79
76
  * });
80
77
  */
81
- export declare const useChat: ({ body, onError, onFinish, pageSize, }: UseChatProps) => UseChatReturn;
78
+ export declare const useChat: ({ body, onFinish, pageSize, }: UseChatProps) => UseChatReturn;
@@ -4,7 +4,6 @@ import type { UseChatCommon } from '..';
4
4
  import type { Message } from '../message';
5
5
  interface ChatStreamingProps {
6
6
  common: UseChatCommon;
7
- setError: (error: unknown) => void;
8
7
  setMessages: Dispatch<SetStateAction<Message[]>>;
9
8
  getMessages: () => Message[];
10
9
  setInput: (input: string) => void;
@@ -12,7 +11,7 @@ interface ChatStreamingProps {
12
11
  conversationVersion: RefObject<number>;
13
12
  }
14
13
  export declare const NOT_SAVED_MSG_ID_PREFIX = "not_saved";
15
- export declare const useChatStreaming: ({ common, setError, setMessages, getMessages, setInput, mujian, conversationVersion: conversationVersionRef, }: ChatStreamingProps) => {
14
+ export declare const useChatStreaming: ({ common, setMessages, getMessages, setInput, mujian, conversationVersion: conversationVersionRef, }: ChatStreamingProps) => {
16
15
  chatStreaming: ({ query, regenerate, is_continue, conversationVersion, }: {
17
16
  /** 用户输入 */
18
17
  query?: string;
package/dist/react.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { useInfiniteScroll, useLatest, useRequest, useUnmount, useUpdateEffect } from "ahooks";
2
2
  import react, { createContext, forwardRef, useCallback, useContext, useEffect, useRef, useState } from "react";
3
+ import { z } from "zod";
3
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
5
  import css_tools from "@adobe/css-tools";
5
6
  import dompurify from "dompurify";
@@ -9,7 +10,6 @@ import postmate from "postmate";
9
10
  import { Virtualizer } from "virtua";
10
11
  import { get } from "lodash-es";
11
12
  import { produce } from "immer";
12
- import { z } from "zod";
13
13
  const adjustIframeHeight = (iframeId)=>`
14
14
  (function () {
15
15
  let scheduled = false;
@@ -1119,13 +1119,6 @@ const errorMessages = [
1119
1119
  function isNetworkError(message) {
1120
1120
  return errorMessages.some((m)=>message.includes(m));
1121
1121
  }
1122
- class SendMessageError extends Error {
1123
- constructor(message, cause){
1124
- super(message);
1125
- this.name = this.constructor.name;
1126
- this.cause = cause;
1127
- }
1128
- }
1129
1122
  async function* callSdk(mujian, content, type = 'generate', conversationVersion, assisMsgId) {
1130
1123
  const queue = [];
1131
1124
  let resolveWait = null;
@@ -1172,15 +1165,21 @@ async function* callSdk(mujian, content, type = 'generate', conversationVersion,
1172
1165
  resolveWait = resolve;
1173
1166
  });
1174
1167
  }
1168
+ const errorSchema = z.object({
1169
+ message: z.string()
1170
+ });
1171
+ function isError(e) {
1172
+ const { success } = errorSchema.safeParse(e);
1173
+ return success;
1174
+ }
1175
1175
  const NOT_SAVED_MSG_ID_PREFIX = 'not_saved';
1176
- const useChatStreaming = ({ common, setError, setMessages, getMessages, setInput, mujian, conversationVersion: conversationVersionRef })=>{
1176
+ const useChatStreaming = ({ common, setMessages, getMessages, setInput, mujian, conversationVersion: conversationVersionRef })=>{
1177
1177
  const { body } = common;
1178
1178
  const [isStreaming, setIsStreaming] = useState(false);
1179
1179
  const chatStreaming = useCallback(async ({ query, regenerate, is_continue, conversationVersion })=>{
1180
+ const backupMessages = getMessages();
1180
1181
  try {
1181
- setError(void 0);
1182
1182
  setIsStreaming(true);
1183
- const backupMessages = getMessages();
1184
1183
  const userMessage = {
1185
1184
  id: `${NOT_SAVED_MSG_ID_PREFIX}_user_${Date.now()}`,
1186
1185
  isUser: true,
@@ -1204,12 +1203,14 @@ const useChatStreaming = ({ common, setError, setMessages, getMessages, setInput
1204
1203
  isGenerating: true
1205
1204
  };
1206
1205
  if (regenerate) setMessages(produce((draft)=>{
1207
- const lastMessage = draft[draft.length - 1];
1206
+ const lastMessage = draft.at(-1);
1208
1207
  lastMessage.activeSwipeId = lastMessage.swipes.length;
1209
1208
  lastMessage.swipes.push({
1210
1209
  content: ''
1211
1210
  });
1212
1211
  lastMessage.isGenerating = true;
1212
+ lastMessage.finishReason = void 0;
1213
+ lastMessage.error = void 0;
1213
1214
  }));
1214
1215
  else is_continue ? setMessages((prev)=>[
1215
1216
  ...prev,
@@ -1220,50 +1221,62 @@ const useChatStreaming = ({ common, setError, setMessages, getMessages, setInput
1220
1221
  aiMessage
1221
1222
  ]);
1222
1223
  const stream = callSdk(mujian, query || '', is_continue ? 'continue' : regenerate ? 'regenerate' : 'generate', conversationVersion);
1223
- try {
1224
- for await (const chunk of stream){
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;
1231
- }
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));
1247
- }
1224
+ for await (const chunk of stream){
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;
1231
+ }
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.at(-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));
1248
1247
  }
1249
- } catch (error) {
1250
- Log.e('Stream error', error);
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);
1256
- } finally{
1257
- setMessages(produce((draft)=>{
1258
- const lastMessage = draft[draft.length - 1];
1259
- lastMessage.isGenerating = false;
1260
- }));
1261
1248
  }
1262
1249
  } catch (error) {
1263
- console.error('Error:', error);
1264
- setError(new SendMessageError('Send message failed', error));
1265
- setMessages((prev)=>prev.slice(0, -1));
1250
+ Log.e('Stream error', error);
1251
+ setMessages(produce((draft)=>{
1252
+ const lastMessage = draft.at(-1);
1253
+ if (isError(error) && isNetworkError(error.message)) lastMessage.error = {
1254
+ code: -10000,
1255
+ message: 'E_NETWORK_ERROR'
1256
+ };
1257
+ else lastMessage.error = {
1258
+ code: 1000000005,
1259
+ message: String(error)
1260
+ };
1261
+ }));
1266
1262
  } finally{
1263
+ setMessages(produce((draft)=>{
1264
+ const lastMessage = draft[draft.length - 1];
1265
+ lastMessage.isGenerating = false;
1266
+ if (lastMessage.error?.code === 2011030009) {
1267
+ const backup = backupMessages.find((m)=>m.id === lastMessage.id);
1268
+ if (backup) {
1269
+ lastMessage.swipes = backup.swipes;
1270
+ lastMessage.activeSwipeId = backup.activeSwipeId;
1271
+ } else {
1272
+ lastMessage.activeSwipeId -= 1;
1273
+ lastMessage.swipes.length = lastMessage.swipes.length - 1;
1274
+ }
1275
+ } else if (lastMessage.error?.code === 2011030001) {
1276
+ setMessages(backupMessages);
1277
+ query && setInput(query);
1278
+ }
1279
+ }));
1267
1280
  setIsStreaming(false);
1268
1281
  }
1269
1282
  }, [
@@ -1288,8 +1301,17 @@ const useChatStreaming = ({ common, setError, setMessages, getMessages, setInput
1288
1301
  }
1289
1302
  } catch (error) {
1290
1303
  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);
1304
+ setMessages(produce((draft)=>{
1305
+ const lastMessage = draft.at(-1);
1306
+ if (isError(error) && isNetworkError(error.message)) lastMessage.error = {
1307
+ code: -10000,
1308
+ message: 'E_NETWORK_ERROR'
1309
+ };
1310
+ else lastMessage.error = {
1311
+ code: 1000000005,
1312
+ message: String(error)
1313
+ };
1314
+ }));
1293
1315
  } finally{
1294
1316
  setMessages(produce((draft)=>{
1295
1317
  const msg = draft.find((m)=>m.id === messageId);
@@ -1306,17 +1328,12 @@ const useChatStreaming = ({ common, setError, setMessages, getMessages, setInput
1306
1328
  recoverStreaming
1307
1329
  };
1308
1330
  };
1309
- const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1310
- const [error, _setError] = useState();
1331
+ const useChat = ({ body, onFinish, pageSize = 10 })=>{
1311
1332
  const [input, setInput] = useState('');
1312
1333
  const conversationVersion = useRef(0);
1313
1334
  const mujian = useMujian();
1314
- const setError = (error)=>{
1315
- _setError(error);
1316
- if (error) onError?.(error);
1317
- };
1318
1335
  const isLoadingMore = useRef(false);
1319
- const { data, loadMoreAsync, loadingMore, loading, mutate, error: messageLoadError } = useInfiniteScroll(async (current)=>{
1336
+ const { data, loadMoreAsync, loadingMore, loading, mutate, error: messageLoadError, reloadAsync } = useInfiniteScroll(async (current)=>{
1320
1337
  isLoadingMore.current = true;
1321
1338
  if (current?.noMore) return {
1322
1339
  noMore: true,
@@ -1338,6 +1355,9 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1338
1355
  }, {
1339
1356
  direction: 'top'
1340
1357
  });
1358
+ const refresh = async ()=>{
1359
+ await reloadAsync();
1360
+ };
1341
1361
  const loadMoreMessage = async ()=>{
1342
1362
  if (isLoadingMore.current) return;
1343
1363
  try {
@@ -1367,7 +1387,6 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1367
1387
  common: {
1368
1388
  body
1369
1389
  },
1370
- setError,
1371
1390
  setMessages,
1372
1391
  getMessages,
1373
1392
  setInput,
@@ -1384,15 +1403,10 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1384
1403
  ]);
1385
1404
  const append = useCallback(async (query)=>{
1386
1405
  if (isStreaming) throw new Error('useChat is streaming already.');
1387
- try {
1388
- await chatStreaming({
1389
- query,
1390
- conversationVersion: conversationVersion.current
1391
- });
1392
- } catch (e) {
1393
- setError(e);
1394
- throw e;
1395
- }
1406
+ await chatStreaming({
1407
+ query,
1408
+ conversationVersion: conversationVersion.current
1409
+ });
1396
1410
  }, [
1397
1411
  isStreaming,
1398
1412
  chatStreaming
@@ -1400,17 +1414,12 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1400
1414
  const regenerate = useCallback(async ()=>{
1401
1415
  if (isStreaming) throw new Error('useChat is streaming already.');
1402
1416
  const lastMessage = messages.findLast((message)=>message.isUser);
1403
- try {
1404
- const query = lastMessage ? lastMessage.swipes[lastMessage.activeSwipeId].content : '';
1405
- await chatStreaming({
1406
- query,
1407
- regenerate: true,
1408
- conversationVersion: conversationVersion.current
1409
- });
1410
- } catch (e) {
1411
- setError(e);
1412
- throw e;
1413
- }
1417
+ const query = lastMessage ? lastMessage.swipes[lastMessage.activeSwipeId].content : '';
1418
+ await chatStreaming({
1419
+ query,
1420
+ regenerate: true,
1421
+ conversationVersion: conversationVersion.current
1422
+ });
1414
1423
  }, [
1415
1424
  isStreaming,
1416
1425
  messages,
@@ -1418,16 +1427,11 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1418
1427
  ]);
1419
1428
  const continueGenerate = useCallback(async ()=>{
1420
1429
  if (isStreaming) throw new Error('useChat is streaming already.');
1421
- try {
1422
- await chatStreaming({
1423
- query: '',
1424
- is_continue: true,
1425
- conversationVersion: conversationVersion.current
1426
- });
1427
- } catch (e) {
1428
- setError(e);
1429
- throw e;
1430
- }
1430
+ await chatStreaming({
1431
+ query: '',
1432
+ is_continue: true,
1433
+ conversationVersion: conversationVersion.current
1434
+ });
1431
1435
  }, [
1432
1436
  isStreaming,
1433
1437
  chatStreaming
@@ -1439,10 +1443,10 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1439
1443
  };
1440
1444
  const setSwipe = async (messageId, swipeId)=>{
1441
1445
  if (swipeId < 0) return;
1442
- setMessages((prev)=>prev.map((msg)=>msg.id === messageId && swipeId < msg.swipes.length ? {
1443
- ...msg,
1444
- activeSwipeId: swipeId
1445
- } : msg));
1446
+ setMessages(produce((draft)=>{
1447
+ const msg = draft.find((m)=>m.id === messageId);
1448
+ if (msg) msg.activeSwipeId = swipeId;
1449
+ }));
1446
1450
  const resp = await mujian.ai.chat.message.swipe(messageId, swipeId);
1447
1451
  const schema = z.object({
1448
1452
  newConversationVersion: z.number()
@@ -1457,20 +1461,10 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1457
1461
  });
1458
1462
  const { data, success } = schema.safeParse(resp);
1459
1463
  if (success && data.newConversationVersion) conversationVersion.current = data.newConversationVersion;
1460
- const patchMessage = (msg)=>{
1461
- const newMsg = {
1462
- ...msg,
1463
- content
1464
- };
1465
- if (!newMsg.isUser) {
1466
- newMsg.swipes = [
1467
- ...newMsg.swipes
1468
- ];
1469
- newMsg.swipes[newMsg.activeSwipeId].content = content;
1470
- }
1471
- return newMsg;
1472
- };
1473
- setMessages((prev)=>prev.map((msg)=>msg.id === messageId ? patchMessage(msg) : msg));
1464
+ setMessages(produce((draft)=>{
1465
+ const msg = draft.find((msg)=>msg.id === messageId);
1466
+ if (msg) msg.swipes[msg.activeSwipeId].content = content;
1467
+ }));
1474
1468
  };
1475
1469
  const deleteMessage = async (messageId)=>{
1476
1470
  if (!messageId.startsWith(NOT_SAVED_MSG_ID_PREFIX)) try {
@@ -1492,11 +1486,9 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1492
1486
  stop,
1493
1487
  messages: messages,
1494
1488
  status: (()=>{
1495
- if (error) return 'error';
1496
1489
  if (isStreaming) return 'streaming';
1497
1490
  return 'ready';
1498
1491
  })(),
1499
- error,
1500
1492
  setMessages: setMessages,
1501
1493
  input,
1502
1494
  setInput,
@@ -1507,7 +1499,8 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1507
1499
  editMessage,
1508
1500
  deleteMessage,
1509
1501
  loadMoreMessage,
1510
- messagesStatus: messageLoadError ? 'error' : loadingMore || loading ? 'loading' : data?.noMore ? 'all-loaded' : 'has-more'
1502
+ messagesStatus: messageLoadError ? 'error' : loadingMore || loading ? 'loading' : data?.noMore ? 'all-loaded' : 'has-more',
1503
+ refresh
1511
1504
  };
1512
1505
  };
1513
1506
  export { MdRenderer, MujianProvider, MujianSpinner, Thread, useChat, useChatContext, useMjEngine, useMujian };