Skip to content

Commit

Permalink
Add messages for platform iframe
Browse files Browse the repository at this point in the history
  • Loading branch information
miku448 committed Oct 18, 2023
1 parent 4556bfd commit e737eb6
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 116 deletions.
1 change: 1 addition & 0 deletions apps/browser-chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9",
"@types/react-toastify": "^4.1.0",
"@types/uuid": "^9.0.1",
"@vitejs/plugin-react": "^3.0.0",
"autoprefixer": "^10.4.13",
"postcss": "^8.4.21",
Expand Down
23 changes: 17 additions & 6 deletions apps/browser-chat/src/components/chat-history/chat-history.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import "./chat-history.css";
import trim from "lodash.trim";
import platformAPI from "../../libs/platformAPI";
import { getAphroditeConfig } from "../../App";
import { updateChat } from "../../libs/postMessage";
import { responsesStore } from "../../libs/responsesStore";

export const HistoryManagementButtons = ({
onLoad,
Expand Down Expand Up @@ -249,23 +251,32 @@ export const HistoryConsole = () => {
}
const aphrodite = getAphroditeConfig();
if (!trim(editedText)) {
if (aphrodite.enabled && lines[editedIndex].id) {
platformAPI.deleteChatMessage(aphrodite.chatId, lines[editedIndex].id || '')
}
lines.splice(editedIndex, 1);
} else {
lines[editedIndex] = {
...lines[editedIndex],
text: editedText,
};
if (aphrodite.enabled && lines[editedIndex].id) {
platformAPI.editChatMessage(aphrodite.chatId, lines[editedIndex].id || '', editedText)
}
}
memory?.clearMemories();
lines.forEach((line) => {
memory?.pushMemory(line);
});
if (aphrodite.enabled) {
updateChat(aphrodite.chatId, lines.map((line) => {
const response = responsesStore.get(line.id || '');
return {
id: line.id,
text: line.text,
subject: line.subject,
type: line.type,
emotionId: response?.emotion || '',
isBot: !!response,
sceneId: response?.scene || '',
audioId: response?.audio || '',
};
}), false)
}
setEditedIndex(-1);
forceUpdate();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { getAphroditeConfig } from "../../../App";
import { PromptCompleterEndpointType } from "../../../libs/botSettingsUtils";
import MusicPlayer from "../../music/MusicPlayer";
import SettingsModal, { SettingsState } from "../../settings/SettingsModal";
import { updateChat } from "../../../libs/postMessage";

export type BotSettings = {
promptStrategy: string;
Expand Down Expand Up @@ -265,15 +266,6 @@ export const BotDisplay = () => {
responseIds.shift();
return responseIds;
});
const aphrodite = getAphroditeConfig();

if (aphrodite.enabled && lastMemoryLine.id) {
const lastCommandId = platformAPI.getLastMessageId();
if (lastCommandId) {
platformAPI.deleteChatMessage(aphrodite.chatId, lastCommandId || '');
platformAPI.deleteChatMessage(aphrodite.chatId, lastMemoryLine?.id || '');
}
}

const result = botFactory
.getInstance()
Expand All @@ -300,14 +292,6 @@ export const BotDisplay = () => {
const memoryLines = shortTermMemory?.getMemory();

const text = responsesStore.get(responseId)?.text;
const aphrodite = getAphroditeConfig();
if (aphrodite.enabled && memoryLines?.length) {
const lastCommandId = platformAPI.getLastMessageId();
const newresponse = responsesStore.get(responseId);
if (lastCommandId) {
platformAPI.editChatMessage(aphrodite.chatId, lastCommandId, newresponse?.text || '');
}
}

if (shortTermMemory && memoryLines && memoryLines.length >= 2) {
shortTermMemory.clearMemories();
Expand All @@ -325,6 +309,23 @@ export const BotDisplay = () => {
});
}
}
const aphrodite = getAphroditeConfig();
const updatedMemoryLines = shortTermMemory?.getMemory();
if (aphrodite.enabled && updatedMemoryLines?.length) {
updateChat(aphrodite.chatId, updatedMemoryLines.map((line) => {
const response = responsesStore.get(line.id || '');
return {
id: line.id,
text: line.text,
subject: line.subject,
type: line.type,
emotionId: response?.emotion || '',
isBot: !!response,
sceneId: response?.scene || '',
audioId: response?.audio || '',
};
}), false)
}
};

const profileImage = card?.data.extensions?.mikugg?.profile_pic || '';
Expand Down
64 changes: 41 additions & 23 deletions apps/browser-chat/src/libs/botFactory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { CustomEndpoints, getBotDataFromURL, setBotDataInURL } from "./botLoader
import platformAPI from "./platformAPI";
import { getAphroditeConfig } from "../App";
import { AphroditeSettings, PromptCompleterEndpointType } from "./botSettingsUtils";
import { ChatMessageInput, newChat, updateChat } from "./postMessage";
import { v4 as uuidv4 } from 'uuid';
import { responsesStore } from "./responsesStore";

const MOCK_PRIVATE_KEY =
"2658e4257eaaf9f72295ce012fa8f8cc4a600cdaf4051884d2c02593c717c173";
Expand Down Expand Up @@ -195,11 +198,28 @@ class BotFactory {
const aphrodite = getAphroditeConfig();
if (aphrodite.enabled) {
const memoryLines = memory.getMemory();
const lastSentMessage = memoryLines[memoryLines.length - 2];
const firstMessage: ChatMessageInput = {
text: lastSentMessage.text,
isBot: false,
emotionId: output.emotion,
sceneId: output.nextContextId,
audioId: '',
};
const secondMessage: ChatMessageInput = {
text: output.text,
isBot: true,
emotionId: output.emotion,
sceneId: output.nextContextId,
audioId: '',
}
let chatId = aphrodite.chatId;
if (!chatId) {
const chat = await platformAPI.createChat(aphrodite.botId);
chatId = chat.data.id;
window?.parent?.postMessage({ type: 'chatId', payload: chatId }, '*');
chatId = uuidv4();
newChat(aphrodite.botId, chatId, [
firstMessage,
secondMessage
]);
const botData = getBotDataFromURL();
setBotDataInURL({
...botData,
Expand All @@ -214,27 +234,25 @@ class BotFactory {
}
}
})
} else {
updateChat(chatId, [
...memoryLines.slice(0, memoryLines.length - 2).map((line) => {
const response = responsesStore.get(line.id || '');
return {
id: line.id,
text: line.text,
subject: line.subject,
type: line.type,
emotionId: response?.emotion || '',
isBot: !!response,
sceneId: response?.scene || '',
audioId: response?.audio || '',
};
}),
firstMessage,
secondMessage
], true);
}
const lastSentMessage = memoryLines[memoryLines.length - 2];
const firstMessage = {
text: lastSentMessage.text,
isBot: false,
emotionId: output.emotion,
sceneId: output.nextContextId,
};
const secondMessage = {
text: output.text,
isBot: true,
emotionId: output.emotion,
sceneId: output.nextContextId,
}
const results = await platformAPI.createChatMessages(
chatId,
firstMessage,
secondMessage
);
memoryLines[memoryLines.length - 2].id = results?.data?.firstMessage?.id;
memoryLines[memoryLines.length - 1].id = results?.data?.secondMessage?.id;
}
})
break;
Expand Down
7 changes: 4 additions & 3 deletions apps/browser-chat/src/libs/botLoader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as MikuExtensions from "@mikugg/extensions";
import platformAPI from "./platformAPI";
import { fillResponse } from "./responsesStore";
import debounce from "lodash.debounce";
import { getChat } from "./postMessage";

export interface BotLoaderProps {
assetLinkLoader: (asset: string, format?: string) => string;
Expand Down Expand Up @@ -336,14 +337,14 @@ export function useBot(): {
_botData.settings.promptCompleterEndpoint.type === PromptCompleterEndpointType.APHRODITE &&
_botData.settings.promptCompleterEndpoint.genSettings.chatId
) {
const chat = await platformAPI.getChat(_botData.settings.promptCompleterEndpoint.genSettings.chatId);
memoryLines = chat.data.chatMessages.map((message) => ({
const narration = await getChat();
memoryLines = narration.narrationMessages.map((message) => ({
id: message.id,
type: MikuCore.Commands.CommandType.DIALOG,
subject: message.isBot ? decoratedConfig.bot_name : _botData.settings.text.name,
text: message.text,
}));
const botMessages = chat.data.chatMessages.filter(message => message.isBot).map((message) => {
const botMessages = narration.narrationMessages.filter(message => message.isBot).map((message) => {
const firstScenario = res.card?.data.extensions.mikugg.scenarios.find(_scenario => message.sceneId === _scenario.id);
const firstEmotionGroup = res.card?.data.extensions.mikugg.emotion_groups.find(emotion_group => firstScenario?.emotion_group === emotion_group.id);
let firstImage = firstEmotionGroup?.emotions?.find(emotion => emotion?.id === message.emotionId)?.source[0] || firstEmotionGroup?.emotions[0].source[0];
Expand Down
65 changes: 0 additions & 65 deletions apps/browser-chat/src/libs/platformAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,8 @@ export interface APIResponse<T> {
status: number;
}

export interface ChatMessage {
id: string,
text: string,
isBot: string,
emotionId: string,
sceneId: string,
createdAt: string,
updatedAt: string,
}

export interface Chat {
id: string,
userId: string,
createdAt: string,
updatedAt: string,
lastMemoryTimeStamp: string,
bot: {
config: string,
id: string,
},
chatMessages: ChatMessage[],
}

export interface ChatMessageInput {
text: string,
isBot: boolean,
emotionId: string,
sceneId: string,
}

class PlatformAPIClient {
private readonly client: AxiosInstance;
private lastMessageId: string | null = null;

constructor(token?: string) {
this.client = axios.create({ baseURL: import.meta.env.VITE_PLATFORM_API || '', withCredentials: true });
Expand All @@ -52,40 +21,6 @@ class PlatformAPIClient {
const response: AxiosResponse<MikuCard> = await this.client.get(`/bot/config/${configHash}`);
return response;
}

async getChat(chatId: string): Promise<APIResponse<Chat>> {
const response: AxiosResponse<Chat> = await this.client.get(`/chat/${chatId}`);
if (response.data.chatMessages.length) {
this.lastMessageId = response.data.chatMessages[response.data.chatMessages.length - 1].id;
}
return response;
}

async createChat(botId: string): Promise<APIResponse<Chat>> {
const response: AxiosResponse<Chat> = await this.client.post(`/chat`, { botId });
return response;
}

async createChatMessages(chatId: string, firstMessage: ChatMessageInput, secondMessage: ChatMessageInput): Promise<APIResponse<{
firstMessage: ChatMessage,
secondMessage: ChatMessage,
}>> {
const response = await this.client.post(`/chat/${chatId}/messages`, { firstMessage, secondMessage });
this.lastMessageId = response.data.secondMessage.id;
return response;
}

async editChatMessage(chatId: string, messageId: string, text: string): Promise<APIResponse<ChatMessage>> {
return await this.client.put(`/chat/${chatId}/message/${messageId}`, { text });
}

async deleteChatMessage(chatId: string, messageId: string): Promise<APIResponse<ChatMessage>> {
return await this.client.delete(`/chat/${chatId}/message/${messageId}`);
}

getLastMessageId(): string | null {
return this.lastMessageId;
}
}

export default new PlatformAPIClient();
63 changes: 63 additions & 0 deletions apps/browser-chat/src/libs/postMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
export interface NarrationMessage {
id: string;
text: string;
isBot: boolean;
emotionId: string;
audioId: string;
sceneId: string;
narrationId: string;
}

export interface Narration {
id: string;
botId: string;
userId: string;
createdAt: Date;
updatedAt: Date;
narrationIndex: number;
narrationMessages: NarrationMessage[];
}


export interface ChatMessageInput {
text: string,
isBot: boolean,
emotionId: string,
sceneId: string,
audioId: string,
}

enum IframeEventTypes {
NEW_CHAT = 'NEW_CHAT',
UPDATE_CHAT = 'UPDATE_CHAT',
}

interface IframeEvent {
type: IframeEventTypes;
payload: any;
}

const postMessage = (type: IframeEventTypes, payload: any) => {
window.parent.postMessage({ type, payload }, '*');
};

export const newChat = (botId: string, chatId: string, chatMessages: ChatMessageInput[]) => {
postMessage(IframeEventTypes.NEW_CHAT, { botId, chatId, chatMessages });
}

export const updateChat = (chatId: string, chatMessages: ChatMessageInput[], isNewGeneration: boolean) => {
postMessage(IframeEventTypes.UPDATE_CHAT, { chatId, chatMessages, isNewGeneration });
}

let chatData: Promise<Narration> = new Promise((resolve, reject) => {
window.addEventListener('message', (event) => {
const { type, payload } = event.data;
if (type === 'CHAT_DATA') {
resolve(payload as Narration);
}
});
});

export const getChat = (): Promise<Narration> => {
return chatData;
}
Loading

0 comments on commit e737eb6

Please sign in to comment.