@plteam/chat-ui
Version:
CUI Kit is a free and open-source library for creating AI assistant chat interfaces, built with React, Material UI, and TypeScript
131 lines (128 loc) • 4.71 kB
JavaScript
import { MessageModel, ChatMessageOwner } from './MessageModel';
import moment from 'moment';
import { v4 as uuid, v4 as uuidv4 } from 'uuid';
import { ThreadMessages } from './ThreadMessages';
import { ObservableReactValue } from '../utils/observers/ObservableReactValue';
import { randomId } from '../utils/numberUtils/randomInt';
export class ThreadModel {
streamMessage;
/*@observable.shallow
private readonly _messages: ChatMessage[] = [];*/
viewerUniqueKey = uuid();
messages = new ThreadMessages();
observableTitle = new ObservableReactValue('');
isTyping = new ObservableReactValue(false);
isLoadingAttachments = new ObservableReactValue([]);
isEmpty = new ObservableReactValue(false);
tool = new ObservableReactValue(undefined);
aiModel = new ObservableReactValue(undefined);
helloMessage = new MessageModel({
id: 'helloMessage' + randomId(),
content: '',
role: ChatMessageOwner.ASSISTANT,
time: 0
});
/**
* We can pass threads with empty history to improve performance
* When opening such a thread, we need to call the getFullThread method to load the history
*/
isLoadingFullData = new ObservableReactValue(true);
scrollY = -1;
// private _threadCreating?: ApiMethodPromise<{ thread: DD }>;
// диалог уже создан на сервере, но пользователь ещё не отправил ни одного сообщения.
// Установим этот ID сразу после отправки сообщения
// private potentialId?: IdType;
pinnedAt = new ObservableReactValue(null);
timestamp;
_data;
constructor(data, streamMessage) {
this.streamMessage = streamMessage;
this._data = data;
this.observableTitle.value = data.title;
this.aiModel.value = data.aiModel;
this.pinnedAt.value = data.pinnedAt ?? null;
if (data.messages?.find((m) => m.role === ChatMessageOwner.ASSISTANT && m.initialStatus)) {
this.isTyping.value = true;
}
/*if (!_data.messages.find(v => !!v.parentId)) {
const newMessages: DD['messages'] = [];
let parentId: IdType | undefined = undefined;
_data.messages.forEach(v => {
newMessages.push({
...v,
parentId,
});
if (v.role === ChatMessageOwner.USER) {
parentId = v.id;
}
});
_data.messages = newMessages
}*/
this.messages.allMessages.value = data.messages?.map(v => new MessageModel(v)) ?? [];
this.isEmpty.value = !!data.isNew;
if (!!data.messages?.length || data.isNew) {
this.isLoadingFullData.value = false;
}
this.timestamp = new ObservableReactValue(moment(data.date).unix());
}
get id() {
return this._data.id;
}
set id(value) {
this._data.id = value;
}
get time() {
return this.timestamp.value ?? 0;
}
get title() {
return this.observableTitle.value;
}
set title(value) {
this.observableTitle.value = value;
}
get date() {
return this._data.date;
}
get isNew() {
return this._data.isNew;
}
get messagesArray() {
return this.messages.allMessagesArray;
}
get data() {
return this._data;
}
setFullData = (threadData) => {
this.messages.allMessages.value = threadData.messages?.map(v => new MessageModel(v)) ?? [];
this.isLoadingFullData.value = false;
};
static createEmptyData = () => {
return ({
id: 'NEW_THREAD_' + randomId(),
title: 'New thread',
date: (new Date()).toISOString(),
messages: [],
isNew: true,
});
};
_createPair = (content, parentMessage) => {
const userMessage = new MessageModel({
id: uuidv4(),
content,
role: ChatMessageOwner.USER,
time: moment().unix(),
parentId: parentMessage?.id,
});
const assistantMessage = new MessageModel({
id: 'NEW_MESSAGE_' + randomId(),
content: '',
role: ChatMessageOwner.ASSISTANT,
// должно быть больше для правильной сортировки
time: moment().unix() + 1,
parentId: userMessage.id,
});
return {
userMessage, assistantMessage,
};
};
}