Skip to content

Commit

Permalink
feat(app): initialization of the user and bot in the chat
Browse files Browse the repository at this point in the history
  • Loading branch information
BroKun committed Jun 30, 2024
1 parent 411f7b9 commit b345981
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 24 deletions.
11 changes: 9 additions & 2 deletions web/app/src/modules/agent-bot/agent-bot-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AgentBotFactory } from './protocol.js';

@singleton()
export class AgentBotManager {
protected cache: Map<number, AgentBot> = new Map<number, AgentBot>();
@inject(AgentBotFactory) botFactory: AgentBotFactory;
@inject(UserManager) userManager: UserManager;
@inject(AxiosClient) axios: AxiosClient;
Expand Down Expand Up @@ -52,7 +53,13 @@ export class AgentBotManager {
return this.botFactory(res.data);
};

getBot = async (options: AgentBotOption): Promise<AgentBot> => {
return this.botFactory(options);
getBot = (option: AgentBotOption): AgentBot => {
const exist = this.cache.get(option.id);
if (exist) {
return exist;
}
const bot = this.botFactory(option);
this.cache.set(bot.id, bot);
return bot;
};
}
11 changes: 9 additions & 2 deletions web/app/src/modules/agent-bot/agent-bot.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { inject, prop, transient } from '@difizen/mana-app';
import { Deferred, inject, prop, transient } from '@difizen/mana-app';

import { AsyncModel } from '../../common/async-model.js';
import { AxiosClient } from '../axios-client/index.js';
Expand All @@ -23,6 +23,12 @@ export class AgentBot extends AsyncModel<AgentBot, AgentBotOption> {
@prop()
draft?: AgentConfig;

protected draftDeferred = new Deferred<AgentConfig>();

get draftReady() {
return this.draftDeferred.promise;
}

option: AgentBotOption;

constructor(
Expand Down Expand Up @@ -52,11 +58,12 @@ export class AgentBot extends AsyncModel<AgentBot, AgentBotOption> {
return this.draft;
}
let draftConfig = option.draft;
if (!this.option.draft) {
if (!draftConfig) {
draftConfig = await this.fetchDraftInfo(option);
}
if (draftConfig) {
this.draft = this.configManager.create(draftConfig);
this.draftDeferred.resolve(this.draft);
}
return this.draft;
}
Expand Down
15 changes: 15 additions & 0 deletions web/app/src/modules/chat/chat-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ import type { Dayjs } from 'dayjs';
import dayjs from 'dayjs';

import { AxiosClient } from '../axios-client/index.js';
import { UserManager } from '../user/user-manager.js';
import type { User } from '../user/user.js';

import type { ChatEventChunk } from './protocol.js';
import { ChatMessageOption, MessageSenderType, MessageType } from './protocol.js';

@transient()
export class ChatMessage {
protected axios: AxiosClient;
protected userManager: UserManager;
option: ChatMessageOption;
senderId: number;
senderType?: MessageSenderType;
Expand All @@ -22,12 +25,17 @@ export class ChatMessage {
@prop()
complete?: boolean = true;

@prop()
sender?: User;

constructor(
@inject(ChatMessageOption) option: ChatMessageOption,
@inject(AxiosClient) axios: AxiosClient,
@inject(UserManager) userManager: UserManager,
) {
this.option = option;
this.axios = axios;
this.userManager = userManager;
const {
senderId,
senderType = MessageSenderType.HUMAN,
Expand All @@ -47,6 +55,13 @@ export class ChatMessage {
if (option.complete !== undefined) {
this.complete = !!option.complete;
}
this.getSender();
}

protected getSender() {
if (this.senderType === MessageSenderType.HUMAN && this.senderId) {
this.sender = this.userManager.getOrCreate({ id: this.senderId.toString() });
}
}

appendChunk(e: ChatEventChunk) {
Expand Down
20 changes: 17 additions & 3 deletions web/app/src/modules/chat/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { EventSourceParserStream } from 'eventsource-parser/stream';
import type { RefObject } from 'react';

import { AsyncModel } from '../../common/async-model.js';
import { AgentBotManager } from '../agent-bot/agent-bot-manager.js';
import type { AgentBot } from '../agent-bot/protocol.js';
import { AxiosClient } from '../axios-client/index.js';
import { UserManager } from '../user/user-manager.js';

Expand Down Expand Up @@ -47,14 +49,18 @@ const msgModelToOption = (msg: ChatMessageModel): ChatMessageOption => {
@transient()
export class Chat extends AsyncModel<Chat, ChatOption> {
@inject(UserManager) userManager: UserManager;
botManager: AgentBotManager;
id?: number;
messageManager: ChatMessageManager;
axios: AxiosClient;
option: ChatOption;
botId: string;
botConfigId?: string;
botId: number;
botConfigId?: number;
createdBy?: string;

@prop()
bot?: AgentBot;

@prop()
messages: ChatMessage[] = [];

Expand All @@ -73,10 +79,12 @@ export class Chat extends AsyncModel<Chat, ChatOption> {
@inject(ChatOption) option: ChatOption,
@inject(AxiosClient) axios: AxiosClient,
@inject(ChatMessageManager) messageManager: ChatMessageManager,
@inject(AgentBotManager) botManager: AgentBotManager,
) {
super();
this.axios = axios;
this.messageManager = messageManager;
this.botManager = botManager;
this.option = option;
this.botId = option.botId;
this.initialize(option);
Expand All @@ -85,6 +93,11 @@ export class Chat extends AsyncModel<Chat, ChatOption> {
override shouldInitFromMeta(option: ChatOption): boolean {
return false;
}

protected getBot = async (botId: number) => {
this.bot = await this.botManager.getBot({ id: botId });
};

override fetchInfo = async (option: ChatOption): Promise<void> => {
const { env = 'debug' } = option;
let url = `api/v1/chats/with_bot/${option.botId}/online`;
Expand All @@ -100,11 +113,12 @@ export class Chat extends AsyncModel<Chat, ChatOption> {
const res = await this.axios.get<ChatModel>(url);
if (res.status === 200) {
const model = res.data;
this.botConfigId = model.bot_config_id.toString();
this.botConfigId = model.bot_config_id;
this.createdBy = model.created_by.toString();
this.messages = model.messages.map(this.getOrCreateMessage);
this.id = model.id;
}
this.getBot(option.botId);
setImmediate(() => this.scrollToBottom(true));
};

Expand Down
17 changes: 9 additions & 8 deletions web/app/src/modules/chat/components/message/message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import classNames from 'classnames';
import type { ReactNode } from 'react';
import { useState } from 'react';

import type { AgentBot } from '../../../agent-bot/protocol.js';
import { BotInstance } from '../../../agent-bot/protocol.js';
import type { ChatMessage } from '../../protocol.js';
import type { Chat, ChatMessage } from '../../protocol.js';
import { ChatInstance, MessageSenderType } from '../../protocol.js';
import Typing from '../typing/index.js';

Expand All @@ -18,15 +16,18 @@ interface MessageProps {
}
export const Message = (props: MessageProps) => {
const message = useObserve(props.message);
const bot = useInject<AgentBot>(BotInstance);
const chat = useInject(ChatInstance);
const chat = useInject<Chat>(ChatInstance);

const [contentHover, setContentHover] = useState<boolean>(false);
let avatarSrc = 'https://api.dicebear.com/7.x/miniavs/svg?seed=1';
let nickName = 'user';
if (message.senderType === MessageSenderType.AI) {
avatarSrc = bot.avatar!;
nickName = 'bot';
if (message.senderType === MessageSenderType.AI && chat.bot?.avatar) {
avatarSrc = chat.bot?.avatar;
nickName = chat.bot?.name;
}
if (message.senderType === MessageSenderType.HUMAN && message.sender?.avatar) {
avatarSrc = message.sender?.avatar;
nickName = message.sender.name;
}

let content: ReactNode = message.content;
Expand Down
4 changes: 2 additions & 2 deletions web/app/src/modules/chat/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ export class ChatManager {
@inject(UserManager) userManager: UserManager;
@inject(AxiosClient) axios: AxiosClient;

getBotDebugChat = async (botId: string): Promise<Chat> => {
getBotDebugChat = async (botId: number): Promise<Chat> => {
const user = await this.userManager.currentReady;
const chat = await this.chatFactory({
botId: botId,
userId: user.id,
userId: parseInt(user.id),
});
return chat;
};
Expand Down
4 changes: 2 additions & 2 deletions web/app/src/modules/chat/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export interface ChatMessageCreate {
}

export interface ChatOption {
botId: string;
userId: string;
botId: number;
userId: number;
env?: 'debug' | 'online';
}
export const ChatOption = Syringe.defineToken('ChatOption');
Expand Down
8 changes: 5 additions & 3 deletions web/app/src/modules/user/user-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class UserManager {

@prop()
current?: User;
protected userMap = new Map<string, User>();
protected cache = new Map<string, User>();

protected initializedDefer = new Deferred<User>();

Expand All @@ -34,7 +34,7 @@ export class UserManager {

getOrCreate(userMeta: UserMeta): User {
if (userMeta.id) {
const exist = this.userMap.get(userMeta.id);
const exist = this.cache.get(userMeta.id);
if (exist) {
return exist;
}
Expand All @@ -43,10 +43,12 @@ export class UserManager {
if (!userMeta.id) {
user.ready
.then(() => {
this.userMap.set(user.id, user);
this.cache.set(user.id, user);
return;
})
.catch(console.error);
} else {
this.cache.set(userMeta.id, user);
}
return user;
}
Expand Down
2 changes: 1 addition & 1 deletion web/app/src/pages/bot/bot-previewer/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class BotPreviewerView extends BaseView {
return;
}
const bot = await this.botProvider.ready;
const chat = await this.chatManager.getBotDebugChat(bot.id.toString());
const chat = await this.chatManager.getBotDebugChat(bot.id);
const context = this.viewManager.getViewContext(this);
const child = context.container.createChild();
child.register({ token: ChatInstance, useValue: chat });
Expand Down
2 changes: 1 addition & 1 deletion web/app/src/pages/bot/model-selector/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const ModelSelectorComponent = forwardRef<HTMLDivElement>(
if (!modelMeta && defaultModel) {
instance.botProvider.ready
.then(async (bot) => {
await bot.ensureDraft();
await bot.draftReady;
if (!bot.draft!.model) {
instance.onSelectChange(defaultModel.key);
}
Expand Down

0 comments on commit b345981

Please sign in to comment.