@mujian/js-sdk 0.1.0-beta.0 → 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,13 +1301,20 @@ 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
- console.log('finally');
1295
1316
  setMessages(produce((draft)=>{
1296
1317
  const msg = draft.find((m)=>m.id === messageId);
1297
- console.log('finally', msg);
1298
1318
  if (!msg) return;
1299
1319
  msg.isGenerating = false;
1300
1320
  }));
@@ -1308,17 +1328,12 @@ const useChatStreaming = ({ common, setError, setMessages, getMessages, setInput
1308
1328
  recoverStreaming
1309
1329
  };
1310
1330
  };
1311
- const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1312
- const [error, _setError] = useState();
1331
+ const useChat = ({ body, onFinish, pageSize = 10 })=>{
1313
1332
  const [input, setInput] = useState('');
1314
1333
  const conversationVersion = useRef(0);
1315
1334
  const mujian = useMujian();
1316
- const setError = (error)=>{
1317
- _setError(error);
1318
- if (error) onError?.(error);
1319
- };
1320
1335
  const isLoadingMore = useRef(false);
1321
- const { data, loadMoreAsync, loadingMore, loading, mutate, error: messageLoadError } = useInfiniteScroll(async (current)=>{
1336
+ const { data, loadMoreAsync, loadingMore, loading, mutate, error: messageLoadError, reloadAsync } = useInfiniteScroll(async (current)=>{
1322
1337
  isLoadingMore.current = true;
1323
1338
  if (current?.noMore) return {
1324
1339
  noMore: true,
@@ -1328,7 +1343,6 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1328
1343
  const resp = await mujian.ai.chat.message.getPage(current?.cursor, pageSize);
1329
1344
  conversationVersion.current = resp.conversationVersion;
1330
1345
  const lastMessage = resp.messages.at(-1);
1331
- console.log(lastMessage);
1332
1346
  if (lastMessage?.isGenerating) recoverStreaming(lastMessage.id, conversationVersion.current);
1333
1347
  return {
1334
1348
  cursor: resp.nextCursor,
@@ -1341,6 +1355,9 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1341
1355
  }, {
1342
1356
  direction: 'top'
1343
1357
  });
1358
+ const refresh = async ()=>{
1359
+ await reloadAsync();
1360
+ };
1344
1361
  const loadMoreMessage = async ()=>{
1345
1362
  if (isLoadingMore.current) return;
1346
1363
  try {
@@ -1370,7 +1387,6 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1370
1387
  common: {
1371
1388
  body
1372
1389
  },
1373
- setError,
1374
1390
  setMessages,
1375
1391
  getMessages,
1376
1392
  setInput,
@@ -1387,15 +1403,10 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1387
1403
  ]);
1388
1404
  const append = useCallback(async (query)=>{
1389
1405
  if (isStreaming) throw new Error('useChat is streaming already.');
1390
- try {
1391
- await chatStreaming({
1392
- query,
1393
- conversationVersion: conversationVersion.current
1394
- });
1395
- } catch (e) {
1396
- setError(e);
1397
- throw e;
1398
- }
1406
+ await chatStreaming({
1407
+ query,
1408
+ conversationVersion: conversationVersion.current
1409
+ });
1399
1410
  }, [
1400
1411
  isStreaming,
1401
1412
  chatStreaming
@@ -1403,17 +1414,12 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1403
1414
  const regenerate = useCallback(async ()=>{
1404
1415
  if (isStreaming) throw new Error('useChat is streaming already.');
1405
1416
  const lastMessage = messages.findLast((message)=>message.isUser);
1406
- try {
1407
- const query = lastMessage ? lastMessage.swipes[lastMessage.activeSwipeId].content : '';
1408
- await chatStreaming({
1409
- query,
1410
- regenerate: true,
1411
- conversationVersion: conversationVersion.current
1412
- });
1413
- } catch (e) {
1414
- setError(e);
1415
- throw e;
1416
- }
1417
+ const query = lastMessage ? lastMessage.swipes[lastMessage.activeSwipeId].content : '';
1418
+ await chatStreaming({
1419
+ query,
1420
+ regenerate: true,
1421
+ conversationVersion: conversationVersion.current
1422
+ });
1417
1423
  }, [
1418
1424
  isStreaming,
1419
1425
  messages,
@@ -1421,16 +1427,11 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1421
1427
  ]);
1422
1428
  const continueGenerate = useCallback(async ()=>{
1423
1429
  if (isStreaming) throw new Error('useChat is streaming already.');
1424
- try {
1425
- await chatStreaming({
1426
- query: '',
1427
- is_continue: true,
1428
- conversationVersion: conversationVersion.current
1429
- });
1430
- } catch (e) {
1431
- setError(e);
1432
- throw e;
1433
- }
1430
+ await chatStreaming({
1431
+ query: '',
1432
+ is_continue: true,
1433
+ conversationVersion: conversationVersion.current
1434
+ });
1434
1435
  }, [
1435
1436
  isStreaming,
1436
1437
  chatStreaming
@@ -1442,10 +1443,10 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1442
1443
  };
1443
1444
  const setSwipe = async (messageId, swipeId)=>{
1444
1445
  if (swipeId < 0) return;
1445
- setMessages((prev)=>prev.map((msg)=>msg.id === messageId && swipeId < msg.swipes.length ? {
1446
- ...msg,
1447
- activeSwipeId: swipeId
1448
- } : msg));
1446
+ setMessages(produce((draft)=>{
1447
+ const msg = draft.find((m)=>m.id === messageId);
1448
+ if (msg) msg.activeSwipeId = swipeId;
1449
+ }));
1449
1450
  const resp = await mujian.ai.chat.message.swipe(messageId, swipeId);
1450
1451
  const schema = z.object({
1451
1452
  newConversationVersion: z.number()
@@ -1460,20 +1461,10 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1460
1461
  });
1461
1462
  const { data, success } = schema.safeParse(resp);
1462
1463
  if (success && data.newConversationVersion) conversationVersion.current = data.newConversationVersion;
1463
- const patchMessage = (msg)=>{
1464
- const newMsg = {
1465
- ...msg,
1466
- content
1467
- };
1468
- if (!newMsg.isUser) {
1469
- newMsg.swipes = [
1470
- ...newMsg.swipes
1471
- ];
1472
- newMsg.swipes[newMsg.activeSwipeId].content = content;
1473
- }
1474
- return newMsg;
1475
- };
1476
- 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
+ }));
1477
1468
  };
1478
1469
  const deleteMessage = async (messageId)=>{
1479
1470
  if (!messageId.startsWith(NOT_SAVED_MSG_ID_PREFIX)) try {
@@ -1495,11 +1486,9 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1495
1486
  stop,
1496
1487
  messages: messages,
1497
1488
  status: (()=>{
1498
- if (error) return 'error';
1499
1489
  if (isStreaming) return 'streaming';
1500
1490
  return 'ready';
1501
1491
  })(),
1502
- error,
1503
1492
  setMessages: setMessages,
1504
1493
  input,
1505
1494
  setInput,
@@ -1510,7 +1499,8 @@ const useChat = ({ body, onError, onFinish, pageSize = 10 })=>{
1510
1499
  editMessage,
1511
1500
  deleteMessage,
1512
1501
  loadMoreMessage,
1513
- 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
1514
1504
  };
1515
1505
  };
1516
1506
  export { MdRenderer, MujianProvider, MujianSpinner, Thread, useChat, useChatContext, useMjEngine, useMujian };