Skip to content

Commit

Permalink
feat(chats): Migration setup
Browse files Browse the repository at this point in the history
  • Loading branch information
RezaRahemtola committed Jul 19, 2024
1 parent a192a07 commit 5aa12ce
Show file tree
Hide file tree
Showing 12 changed files with 118 additions and 57 deletions.
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
"@aleph-sdk/client": "^1.0.6",
"@aleph-sdk/ethereum": "^1.0.3",
"@aleph-sdk/message": "^1.0.7",
"@libertai/libertai-js": "file:../libertai-js/libertai-libertai-js-0.0.8.tgz",
"@libertai/libertai-js": "0.0.8",
"@quasar/extras": "^1.16.12",
"@tanstack/vue-query": "^5.51.9",
"@wagmi/vue": "^0.0.30",
"@wagmi/vue": "^0.0.31",
"axios": "^1.7.2",
"dompurify": "^3.1.6",
"highlight.js": "^11.10.0",
Expand Down
10 changes: 5 additions & 5 deletions src/pages/Chat.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<q-page class="column align-items-center">
<q-page v-if="chatRef" class="column align-items-center">
<div ref="scrollAreaRef" class="col-grow overflow-auto" style="max-height: calc(100vh - 190px)">
<!-- Display message history -->
<q-list class="col-grow q-ma-xl">
Expand Down Expand Up @@ -166,7 +166,7 @@ import { defaultChatTopic, inferChatTopic } from 'src/utils/chat';
import { LlamaCppApiEngine, Message } from '@libertai/libertai-js';
// Local state
import { Chat, UIMessage, useChatsStore } from 'stores/chats';
import { useChatsStore } from 'stores/chats';
import { useModelsStore } from 'stores/models';
import { useKnowledgeStore } from 'stores/knowledge';
import { usePersonasStore } from 'stores/personas';
Expand All @@ -177,6 +177,7 @@ import MessageInput from 'src/components/MessageInput.vue';
import axios from 'axios';
import { getPersonaAvatarUrl } from 'src/utils/personas';
import { useSettingsStore } from 'stores/settings';
import { Chat, UIMessage } from 'src/types/chats';
const $q = useQuasar();
const route = useRoute();
Expand Down Expand Up @@ -327,7 +328,6 @@ async function generatePersonaMessage() {
let searchResults = await knowledgeStore.searchDocuments(lastMessage.content, chatTags);
searchResults.forEach((result) => {
searchResultMessages.push({
author: 'ai', // TODO: maybe another author here
role: 'search-result',
content: result.content,
});
Expand Down Expand Up @@ -483,6 +483,8 @@ async function setChat(chatId: string) {
// TODO: these should already be there ?
loadedChat.messages = loadedChat.messages.map((message) => ({ ...message, stopped: true, error: null }));
chatRef.value = loadedChat;
// Set the selected model for the chat by its URL
const modelApiUrl = loadedChat.model.apiUrl;
modelsStore.setModelByURL(modelApiUrl);
Expand All @@ -493,8 +495,6 @@ async function setChat(chatId: string) {
await setChatName(loadedChat.messages[0].content);
}
chatRef.value = loadedChat;
// Determine if there are messages we need to respond to
// NOTE: this is assuming all chats should be initiated by the user
if (loadedChat.messages.length % 2 === 1) {
Expand Down
10 changes: 5 additions & 5 deletions src/pages/NewChat.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,21 @@ const username = useSettingsStore().username;
const messageInputRef = ref('');
async function sendMessage() {
let message = messageInputRef.value;
const message = messageInputRef.value;
if (message.length === 0) {
return;
}
// Extract the values out of our relevant refs
let title = defaultChatTopic;
const title = defaultChatTopic;
// NOTE: these are refs to the store, so we need to deep clone them
let model = JSON.parse(JSON.stringify(modelsStore.selectedModel));
let persona = JSON.parse(JSON.stringify(personasStore.persona));
const model = JSON.parse(JSON.stringify(modelsStore.selectedModel));
const persona = JSON.parse(JSON.stringify(personasStore.persona));
// Reset the personas now that we have a deep clone of the selected persona
//personasStore.personas = personasClone;
// Creates the new chat
let chat = await chatsStore.createChat(title, username, model, persona);
const chat = await chatsStore.createChat(title, username, model, persona);
// Append the first user message to the chat history
await chatsStore.appendUserMessage(chat.id, message);
Expand Down
6 changes: 3 additions & 3 deletions src/pages/PersonaManagement.vue
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,14 @@ import { usePersonasStore } from 'stores/personas';
import { computed, ref } from 'vue';
import { useRouter } from 'vue-router';
import { v4 as uuidv4 } from 'uuid';
import { getPersonaAvatarUrl, UIPersona } from 'src/utils/personas';
import { getPersonaAvatarUrl } from 'src/utils/personas';
import PersonaDialog from 'src/components/PersonaDialog.vue';
import { useAccountStore } from 'stores/account';
import { exportFile } from 'quasar';
import { getTokenGatingMessage } from 'src/utils/messages';
import { z } from 'zod';
import { BasePersonaDialogProp } from 'components/PersonaDialog.vue';
import { UIPersona } from 'src/types/personas';
const personasStore = usePersonasStore();
const accountStore = useAccountStore();
Expand Down Expand Up @@ -218,9 +219,8 @@ const importPersona = (event: Event) => {
}
const avatar = typeof parsedFile.data.data.avatar === 'string' ? undefined : parsedFile.data.data.avatar;
const personaData = { ...parsedFile.data.data, avatar };
basePersonaCreate.value = personaData;
basePersonaCreate.value = { ...parsedFile.data.data, avatar };
createPersona.value = true;
};
reader.readAsText(file);
Expand Down
55 changes: 36 additions & 19 deletions src/stores/chats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,14 @@ import { defineStore } from 'pinia';
import { defaultModels } from 'src/utils/models';
import { chatTag } from 'src/utils/chat';
import idb from 'src/utils/idb';
import { Message, Model } from '@libertai/libertai-js';
import { UIPersona } from 'src/utils/personas';
import { Model } from '@libertai/libertai-js';
import { chatsMigrations } from 'src/utils/migrations/chats';
import { Chat, ChatMigration, MinimalChat, UIMessage } from 'src/types/chats';
import { UIPersona } from 'src/types/personas';

const CHATS_STORE_NAME = 'chats-store';
const CHATS_STORE_PINIA_KEY = 'chats-store-pinia-key';

// TODO: clean this type and understand the added properties
export type UIMessage = Message & { stopped?: boolean; error?: any; searchResults?: any; attachments?: any[] };

export type Chat = {
id: string;
title: string;
username: string;
tags: string[];

model: Model;
persona: UIPersona;
messages: UIMessage[];
createdAt: Date;
};

type MinimalChat = Pick<Chat, 'id' | 'title' | 'createdAt'> & Partial<Chat>;

/**
* Representation of an attachment:
* interface Attachment {
Expand All @@ -53,23 +38,44 @@ type MinimalChat = Pick<Chat, 'id' | 'title' | 'createdAt'> & Partial<Chat>;
*/

type ChatsStoreState = {
version: number;
chatsStore: ChatsStore;
chats: MinimalChat[];
};

export const useChatsStore = defineStore(CHATS_STORE_PINIA_KEY, {
state: (): ChatsStoreState => ({
// Current version of the migrations
version: 0, // /!\ DO NOT UPDATE /!\, it should be done automatically when running migrations

// Interface for our ChatsStore
chatsStore: new ChatsStore(),
// List of partials chats
chats: [],
}),
persist: {
paths: ['version'],
},
actions: {
async load() {
// Update the models for all chats
await this.chatsStore.updateModels(defaultModels);
// Get the partial chats
this.chats = await this.chatsStore.readChats();

try {
// Running migrations if needed
if (this.version < chatsMigrations.length) {
// Removing migrations already ran
const migrationsToRun = chatsMigrations.slice(this.version);
for (const migration of migrationsToRun) {
await this.chatsStore.runMigration(migration);
}
}
this.version = chatsMigrations.length;
} catch (error) {
console.error(`Chats: Running migrations starting from version ${this.version} failed: ${error}`);
}
},

async readChat(id: string) {
Expand Down Expand Up @@ -140,6 +146,17 @@ class ChatsStore {
this.store = idb.createStore(CHATS_STORE_NAME);
}

async runMigration(migration: ChatMigration) {
const updatedChats: Promise<Chat>[] = [];

await this.store.iterate((currentChat: Chat) => {
const newChat = migration(currentChat);
updatedChats.push(idb.put(currentChat.id, newChat, this.store));
});

await Promise.all(updatedChats);
}

async updateModels(models: Model[]) {
// Create an array for the updates we will resolve
const updatedChats: Promise<Chat>[] = [];
Expand Down
27 changes: 27 additions & 0 deletions src/types/chats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Message, Model } from '@libertai/libertai-js';
import { UIPersona } from 'src/types/personas';

// TODO: clean this type and understand the added properties
export type UIMessage = Message & {
stopped?: boolean;
error?: any;
searchResults?: any;
attachments?: any[];
author: 'user' | 'ai';
};

export type Chat = {
id: string;
title: string;
username: string;
tags: string[];

model: Model;
persona: UIPersona;
messages: UIMessage[];
createdAt: Date;
};
export type MinimalChat = Pick<Chat, 'id' | 'title' | 'createdAt'> & Partial<Chat>;

// eslint-disable-next-line no-unused-vars
export type ChatMigration = (currentChat: Chat) => Chat;
12 changes: 12 additions & 0 deletions src/types/personas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Persona } from '@libertai/libertai-js';

export type UIPersona = Persona & {
id: string;
avatar: {
item_hash: string;
ipfs_hash: string;
};
name: string;
allowEdit: boolean;
hidden: boolean;
};
6 changes: 3 additions & 3 deletions src/utils/chat.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LlamaCppApiEngine } from '@libertai/libertai-js';
import { LlamaCppApiEngine, Message } from '@libertai/libertai-js';

import { modelDefaults, promptFormatDefaults } from './models';

Expand Down Expand Up @@ -28,7 +28,7 @@ const chatTopicPersona = {
'You are a summary function provided with input. Provide an at most 5 word summary of the first sentence of the provided input for the purpose of determining menu item names',
};

const chatTopicExamples = [
const chatTopicExamples: Message[] = [
{
role: 'input',
content: 'Hello, can you please write a short hello world code for me?',
Expand All @@ -49,7 +49,7 @@ const chatTopicExamples = [

export async function inferChatTopic(input: string) {
const engine = new LlamaCppApiEngine();
const message = {
const message: Message = {
role: 'input',
content: input,
};
Expand Down
12 changes: 12 additions & 0 deletions src/utils/migrations/chats/chat_0.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Chat, ChatMigration, UIMessage } from 'src/types/chats';

export const chat_1_add_message_author: ChatMigration = (currentChat: Chat) => {
const messages = currentChat.messages.map((message): UIMessage => {
if (message.role === 'user') {
return { ...message, author: 'user' };
}
return { ...message, author: 'ai' };
});

return { ...currentChat, messages };
};
4 changes: 4 additions & 0 deletions src/utils/migrations/chats/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { ChatMigration } from 'src/types/chats';
import { chat_1_add_message_author } from 'src/utils/migrations/chats/chat_0';

export const chatsMigrations: ChatMigration[] = [chat_1_add_message_author];
15 changes: 2 additions & 13 deletions src/utils/personas.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
// Configuration for base prompts for different types of chatbots
import { Persona } from '@libertai/libertai-js';

export type UIPersona = Persona & {
id: string;
avatar: {
item_hash: string;
ipfs_hash: string;
};
name: string;
allowEdit: boolean;
hidden: boolean;
};
import { UIPersona } from 'src/types/personas';

// Configuration for base prompts for different types of chatbots
export const defaultPersonas: UIPersona[] = [
{
id: '77d15394-d142-4e73-8251-48be48cee016',
Expand Down

0 comments on commit 5aa12ce

Please sign in to comment.