@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
110 lines (109 loc) • 3.96 kB
JavaScript
import { ObservableReactValue } from '../utils/observers/ObservableReactValue';
import { MessageReasoningModel } from './MessageReasoningModel';
import { randomInt } from '../utils/numberUtils/randomInt';
import { MessageText } from './MessageText';
import { arrayLast } from '../utils/arrayUtils/arrayLast';
import { v4 as uuid } from 'uuid';
import MessageAttachmentsModel from './MessageAttachmentsModel';
export var ChatMessageOwner;
(function (ChatMessageOwner) {
ChatMessageOwner["USER"] = "user";
ChatMessageOwner["ASSISTANT"] = "assistant";
})(ChatMessageOwner || (ChatMessageOwner = {}));
export class MessageModel {
_data;
viewerUniqueKey = uuid();
/**
* Text of message that supports "observation", should you need to update the component immediately upon variable modification, perfect for React.useSyncExternalStore.
*/
texts = new ObservableReactValue([]);
reasoningManager = new MessageReasoningModel();
attachments = new MessageAttachmentsModel();
/**
* An observable flag indicating the start/finish of message typing.
*/
typing = new ObservableReactValue(false);
/**
* An observable waiting-status text for this message.
* `undefined` — never set (UI shows the default "thinking" indicator while typing);
* `''` — cleared (nothing shown); a non-empty string — shown as-is.
*/
status = new ObservableReactValue(undefined);
photoswipeContainerId = 'photoswipe-container-' + randomInt(100, 100000);
constructor(_data) {
this._data = _data;
if (typeof _data.content === 'string') {
this.texts.value = [new MessageText(_data.content)];
}
else {
const content = Array.isArray(_data.content) ? _data.content : [_data.content];
this.texts.value = content.filter(v => v.type === 'text').map((text) => new MessageText(text.text));
this.attachments.init(content.filter(c => c.type !== 'text'));
}
if (_data.role === ChatMessageOwner.ASSISTANT && _data.initialStatus) {
this.status.value = _data.initialStatus;
this.typing.value = true;
}
if (_data.reasoning) {
if (_data.reasoning.title) {
this.reasoningManager.title.value = _data.reasoning.title;
}
if (_data.reasoning.text) {
this.reasoningManager.text.value = _data.reasoning.text;
}
if (_data.reasoning.timeSec) {
this.reasoningManager.timeSec.value = _data.reasoning.timeSec;
}
}
}
get id() {
return this._data.id;
}
get data() {
return this._data;
}
get parentId() {
return this._data.parentId;
}
set parentId(val) {
this._data.parentId = val;
}
get rating() {
return this._data.rating;
}
set rating(value) {
this._data.rating = value;
}
get time() {
return this._data.time;
}
get role() {
return this._data.role;
}
get isUser() {
return this.role === ChatMessageOwner.USER;
}
get isAssistant() {
return this.role === ChatMessageOwner.ASSISTANT;
}
get content() {
let data = this.text;
if (this.attachments.itemsAll.value.length) {
const attachmentContent = this.attachments.itemsAll.value.map((a) => a.contentData);
data = [{ type: 'text', text: this.text }, ...attachmentContent];
}
return data;
}
get text() {
return arrayLast(this.texts.value)?.text ?? '';
}
set text(value) {
const textModel = arrayLast(this.texts.value);
if (textModel) {
textModel.text = value;
}
}
setId = (id) => {
this._data.id = id;
};
}