* redesign is inevitable * ui: change kai design, add sessions to list, swap to new icon * ui: some changes for suggestions in thread
121 lines
2.7 KiB
TypeScript
121 lines
2.7 KiB
TypeScript
import io from 'socket.io-client';
|
|
import { toast } from 'react-toastify';
|
|
import { ISession } from '@/types/session/session';
|
|
|
|
export class ChatManager {
|
|
socket: ReturnType<typeof io>;
|
|
threadId: string | null = null;
|
|
|
|
constructor({
|
|
projectId,
|
|
threadId,
|
|
token,
|
|
}: {
|
|
projectId: string;
|
|
threadId: string;
|
|
token: string;
|
|
}) {
|
|
this.threadId = threadId;
|
|
const urlObject = new URL(window.env.API_EDP || window.location.origin);
|
|
const socket = io(`${urlObject.origin}/kai/chat`, {
|
|
transports: ['websocket'],
|
|
path: '/kai/chat/socket.io',
|
|
autoConnect: true,
|
|
reconnection: true,
|
|
reconnectionAttempts: 5,
|
|
reconnectionDelay: 1000,
|
|
reconnectionDelayMax: 5000,
|
|
withCredentials: true,
|
|
multiplex: true,
|
|
query: {
|
|
project_id: projectId,
|
|
thread_id: threadId,
|
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
},
|
|
auth: {
|
|
token: `Bearer ${token}`,
|
|
},
|
|
});
|
|
socket.on('connect', () => {
|
|
console.log('Connected to server');
|
|
});
|
|
socket.on('disconnect', () => {
|
|
console.log('Disconnected from server');
|
|
});
|
|
socket.on('error', (err) => {
|
|
if (err.message) {
|
|
toast.error(err.message);
|
|
}
|
|
console.error('Socket error:', err);
|
|
});
|
|
|
|
this.socket = socket;
|
|
}
|
|
|
|
reconnect = () => {
|
|
this.socket.connect();
|
|
};
|
|
|
|
sendMessage = (message: string, isReplace = false) => {
|
|
if (!this.socket.connected) {
|
|
this.reconnect();
|
|
setTimeout(() => {
|
|
this.sendMessage(message, isReplace);
|
|
}, 500);
|
|
} else {
|
|
this.socket.emit(
|
|
'message',
|
|
JSON.stringify({
|
|
message,
|
|
threadId: this.threadId,
|
|
replace: isReplace,
|
|
}),
|
|
);
|
|
}
|
|
};
|
|
|
|
setOnMsgHook = ({
|
|
msgCallback,
|
|
titleCallback,
|
|
}: {
|
|
msgCallback: (msg: StateEvent | BotChunk) => void;
|
|
titleCallback: (title: string) => void;
|
|
}) => {
|
|
this.socket.on('chunk', (msg: BotChunk) => {
|
|
msgCallback({ ...msg, type: 'chunk' });
|
|
});
|
|
this.socket.on('title', (msg: { content: string }) => {
|
|
titleCallback(msg.content);
|
|
});
|
|
this.socket.on(
|
|
'state',
|
|
(state: { message: 'idle' | 'running'; start_time: number }) => {
|
|
msgCallback({
|
|
state: state.message,
|
|
type: 'state',
|
|
start_time: state.start_time,
|
|
});
|
|
},
|
|
);
|
|
};
|
|
|
|
disconnect = () => {
|
|
this.socket.disconnect();
|
|
};
|
|
}
|
|
|
|
export interface BotChunk {
|
|
stage: 'start' | 'chart' | 'final' | 'title';
|
|
content: string;
|
|
messageId: string;
|
|
duration: number;
|
|
supports_visualization: boolean;
|
|
sessions?: ISession[];
|
|
type: 'chunk';
|
|
}
|
|
|
|
interface StateEvent {
|
|
state: string;
|
|
start_time?: number;
|
|
type: 'state';
|
|
}
|