feat: auto generate title

This commit is contained in:
Jing Hua 2023-03-09 21:00:29 +08:00
parent 68562b699f
commit b080c185f4
8 changed files with 96 additions and 33 deletions

View file

@ -4,7 +4,7 @@ import useStore from '@store/store';
import PlusIcon from '@icon/PlusIcon';
import { ChatInterface } from '@type/chat';
import { defaultChatConfig, defaultSystemMessage } from '@constants/chat';
import { generateDefaultChat } from '@constants/chat';
const NewMessageButton = React.memo(
({ messageIndex }: { messageIndex: number }) => {
@ -24,16 +24,7 @@ const NewMessageButton = React.memo(
title = `New Chat ${titleIndex}`;
}
updatedChats.unshift({
title,
messages: [
{
role: 'system',
content: defaultSystemMessage,
},
],
config: { ...defaultChatConfig },
});
updatedChats.unshift(generateDefaultChat(title));
setChats(updatedChats);
setCurrentChatIndex(0);
}

View file

@ -1,4 +1,4 @@
import { ConfigInterface } from '@type/chat';
import { ChatInterface, ConfigInterface } from '@type/chat';
const date = new Date();
const dateString =
@ -17,3 +17,10 @@ export const defaultChatConfig: ConfigInterface = {
temperature: 1,
presence_penalty: 0,
};
export const generateDefaultChat = (title?: string): ChatInterface => ({
title: title ? title : 'New Chat',
messages: [{ role: 'system', content: defaultSystemMessage }],
config: { ...defaultChatConfig },
titleSet: false,
});

View file

@ -1,6 +1,6 @@
import React from 'react';
import useStore from '@store/store';
import { defaultChatConfig, defaultSystemMessage } from '@constants/chat';
import { generateDefaultChat } from '@constants/chat';
import { ChatInterface } from '@type/chat';
const useAddChat = () => {
@ -19,11 +19,7 @@ const useAddChat = () => {
title = `New Chat ${titleIndex}`;
}
updatedChats.unshift({
title,
messages: [{ role: 'system', content: defaultSystemMessage }],
config: { ...defaultChatConfig },
});
updatedChats.unshift(generateDefaultChat(title));
setChats(updatedChats);
setCurrentChatIndex(0);
}

View file

@ -1,24 +1,14 @@
import React from 'react';
import useStore from '@store/store';
import { MessageInterface } from '@type/chat';
import { defaultChatConfig, defaultSystemMessage } from '@constants/chat';
import { generateDefaultChat } from '@constants/chat';
const useInitialiseNewChat = () => {
const setChats = useStore((state) => state.setChats);
const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex);
const initialiseNewChat = () => {
const message: MessageInterface = {
role: 'system',
content: defaultSystemMessage,
};
setChats([
{
title: 'New Chat',
messages: [message],
config: { ...defaultChatConfig },
},
]);
setChats([generateDefaultChat()]);
setCurrentChatIndex(0);
};

View file

@ -1,10 +1,17 @@
import React from 'react';
import useStore from '@store/store';
import { ChatInterface } from '@type/chat';
import { getChatCompletionStream as getChatCompletionStreamFree } from '@api/freeApi';
import { getChatCompletionStream as getChatCompletionStreamCustom } from '@api/customApi';
import { ChatInterface, MessageInterface } from '@type/chat';
import {
getChatCompletionStream as getChatCompletionStreamFree,
getChatCompletion as getChatCompletionFree,
} from '@api/freeApi';
import {
getChatCompletionStream as getChatCompletionStreamCustom,
getChatCompletion as getChatCompletionCustom,
} from '@api/customApi';
import { parseEventSource } from '@api/helper';
import { limitMessageTokens } from '@utils/messageUtils';
import { defaultChatConfig } from '@constants/chat';
const useSubmit = () => {
const error = useStore((state) => state.error);
@ -16,6 +23,22 @@ const useSubmit = () => {
const currentChatIndex = useStore((state) => state.currentChatIndex);
const setChats = useStore((state) => state.setChats);
const generateTitle = async (
message: MessageInterface[]
): Promise<string> => {
let data;
if (apiFree) {
data = await getChatCompletionFree(
useStore.getState().apiFreeEndpoint,
message,
defaultChatConfig
);
} else if (apiKey) {
data = await getChatCompletionCustom(apiKey, message, defaultChatConfig);
}
return data.choices[0].message.content;
};
const handleSubmit = async () => {
const chats = useStore.getState().chats;
if (generating || !chats) return;
@ -94,6 +117,34 @@ const useSubmit = () => {
reader.releaseLock();
stream.cancel();
}
// generate title for new chats
const currChats = useStore.getState().chats;
if (currChats && !currChats[currentChatIndex]?.titleSet) {
const messages_length = currChats[currentChatIndex].messages.length;
const assistant_message =
currChats[currentChatIndex].messages[messages_length - 1].content;
const user_message =
currChats[currentChatIndex].messages[messages_length - 2].content;
const message: MessageInterface = {
role: 'user',
content: `Generate a title in less than 6 words for the following message:\nUser: ${user_message}\nAssistant: ${assistant_message}`,
};
let title = await generateTitle([message]);
if (title.startsWith('"') && title.endsWith('"')) {
title = title.slice(1, -1);
}
const updatedChats: ChatInterface[] = JSON.parse(
JSON.stringify(useStore.getState().chats)
);
updatedChats[currentChatIndex].title = title;
updatedChats[currentChatIndex].titleSet = true;
setChats(updatedChats);
console.log(message);
console.log(title);
}
} catch (e: unknown) {
const err = (e as Error).message;
console.log(err);

5
src/store/migrate.ts Normal file
View file

@ -0,0 +1,5 @@
import { LocalStorageInterface } from '@type/chat';
export const migrateV0 = (persistedState: LocalStorageInterface) => {
persistedState.chats.forEach((chat) => (chat.titleSet = false));
};

View file

@ -4,6 +4,8 @@ import { ChatSlice, createChatSlice } from './chat-slice';
import { InputSlice, createInputSlice } from './input-slice';
import { AuthSlice, createAuthSlice } from './auth-slice';
import { ConfigSlice, createConfigSlice } from './config-slice';
import { LocalStorageInterface } from '@type/chat';
import { migrateV0 } from './migrate';
export type StoreState = ChatSlice & InputSlice & AuthSlice & ConfigSlice;
@ -30,6 +32,15 @@ const useStore = create<StoreState>()(
apiFreeEndpoint: state.apiFreeEndpoint,
theme: state.theme,
}),
version: 1,
migrate: (persistedState, version) => {
switch (version) {
case 0:
migrateV0(persistedState as LocalStorageInterface);
break;
}
return persistedState as StoreState;
},
}
)
);

View file

@ -1,3 +1,5 @@
import { Theme } from './theme';
export type Role = 'user' | 'assistant' | 'system';
export const roles: Role[] = ['user', 'assistant', 'system'];
@ -10,9 +12,19 @@ export interface ChatInterface {
title: string;
messages: MessageInterface[];
config: ConfigInterface;
titleSet: boolean;
}
export interface ConfigInterface {
temperature: number;
presence_penalty: number;
}
export interface LocalStorageInterface {
chats: ChatInterface[];
currentChatIndex: number;
apiKey: string;
apiFree: boolean;
apiFreeEndpoint: string;
theme: Theme;
}