mirror of
https://github.com/NovaOSS/nova-betterchat.git
synced 2024-11-25 21:34:00 +01:00
feat: auto generate title
This commit is contained in:
parent
68562b699f
commit
b080c185f4
|
@ -4,7 +4,7 @@ import useStore from '@store/store';
|
||||||
import PlusIcon from '@icon/PlusIcon';
|
import PlusIcon from '@icon/PlusIcon';
|
||||||
|
|
||||||
import { ChatInterface } from '@type/chat';
|
import { ChatInterface } from '@type/chat';
|
||||||
import { defaultChatConfig, defaultSystemMessage } from '@constants/chat';
|
import { generateDefaultChat } from '@constants/chat';
|
||||||
|
|
||||||
const NewMessageButton = React.memo(
|
const NewMessageButton = React.memo(
|
||||||
({ messageIndex }: { messageIndex: number }) => {
|
({ messageIndex }: { messageIndex: number }) => {
|
||||||
|
@ -24,16 +24,7 @@ const NewMessageButton = React.memo(
|
||||||
title = `New Chat ${titleIndex}`;
|
title = `New Chat ${titleIndex}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedChats.unshift({
|
updatedChats.unshift(generateDefaultChat(title));
|
||||||
title,
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: 'system',
|
|
||||||
content: defaultSystemMessage,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
config: { ...defaultChatConfig },
|
|
||||||
});
|
|
||||||
setChats(updatedChats);
|
setChats(updatedChats);
|
||||||
setCurrentChatIndex(0);
|
setCurrentChatIndex(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ConfigInterface } from '@type/chat';
|
import { ChatInterface, ConfigInterface } from '@type/chat';
|
||||||
|
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
const dateString =
|
const dateString =
|
||||||
|
@ -17,3 +17,10 @@ export const defaultChatConfig: ConfigInterface = {
|
||||||
temperature: 1,
|
temperature: 1,
|
||||||
presence_penalty: 0,
|
presence_penalty: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const generateDefaultChat = (title?: string): ChatInterface => ({
|
||||||
|
title: title ? title : 'New Chat',
|
||||||
|
messages: [{ role: 'system', content: defaultSystemMessage }],
|
||||||
|
config: { ...defaultChatConfig },
|
||||||
|
titleSet: false,
|
||||||
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import useStore from '@store/store';
|
import useStore from '@store/store';
|
||||||
import { defaultChatConfig, defaultSystemMessage } from '@constants/chat';
|
import { generateDefaultChat } from '@constants/chat';
|
||||||
import { ChatInterface } from '@type/chat';
|
import { ChatInterface } from '@type/chat';
|
||||||
|
|
||||||
const useAddChat = () => {
|
const useAddChat = () => {
|
||||||
|
@ -19,11 +19,7 @@ const useAddChat = () => {
|
||||||
title = `New Chat ${titleIndex}`;
|
title = `New Chat ${titleIndex}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedChats.unshift({
|
updatedChats.unshift(generateDefaultChat(title));
|
||||||
title,
|
|
||||||
messages: [{ role: 'system', content: defaultSystemMessage }],
|
|
||||||
config: { ...defaultChatConfig },
|
|
||||||
});
|
|
||||||
setChats(updatedChats);
|
setChats(updatedChats);
|
||||||
setCurrentChatIndex(0);
|
setCurrentChatIndex(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,14 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import useStore from '@store/store';
|
import useStore from '@store/store';
|
||||||
import { MessageInterface } from '@type/chat';
|
import { MessageInterface } from '@type/chat';
|
||||||
import { defaultChatConfig, defaultSystemMessage } from '@constants/chat';
|
import { generateDefaultChat } from '@constants/chat';
|
||||||
|
|
||||||
const useInitialiseNewChat = () => {
|
const useInitialiseNewChat = () => {
|
||||||
const setChats = useStore((state) => state.setChats);
|
const setChats = useStore((state) => state.setChats);
|
||||||
const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex);
|
const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex);
|
||||||
|
|
||||||
const initialiseNewChat = () => {
|
const initialiseNewChat = () => {
|
||||||
const message: MessageInterface = {
|
setChats([generateDefaultChat()]);
|
||||||
role: 'system',
|
|
||||||
content: defaultSystemMessage,
|
|
||||||
};
|
|
||||||
setChats([
|
|
||||||
{
|
|
||||||
title: 'New Chat',
|
|
||||||
messages: [message],
|
|
||||||
config: { ...defaultChatConfig },
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
setCurrentChatIndex(0);
|
setCurrentChatIndex(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import useStore from '@store/store';
|
import useStore from '@store/store';
|
||||||
import { ChatInterface } from '@type/chat';
|
import { ChatInterface, MessageInterface } from '@type/chat';
|
||||||
import { getChatCompletionStream as getChatCompletionStreamFree } from '@api/freeApi';
|
import {
|
||||||
import { getChatCompletionStream as getChatCompletionStreamCustom } from '@api/customApi';
|
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 { parseEventSource } from '@api/helper';
|
||||||
import { limitMessageTokens } from '@utils/messageUtils';
|
import { limitMessageTokens } from '@utils/messageUtils';
|
||||||
|
import { defaultChatConfig } from '@constants/chat';
|
||||||
|
|
||||||
const useSubmit = () => {
|
const useSubmit = () => {
|
||||||
const error = useStore((state) => state.error);
|
const error = useStore((state) => state.error);
|
||||||
|
@ -16,6 +23,22 @@ const useSubmit = () => {
|
||||||
const currentChatIndex = useStore((state) => state.currentChatIndex);
|
const currentChatIndex = useStore((state) => state.currentChatIndex);
|
||||||
const setChats = useStore((state) => state.setChats);
|
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 handleSubmit = async () => {
|
||||||
const chats = useStore.getState().chats;
|
const chats = useStore.getState().chats;
|
||||||
if (generating || !chats) return;
|
if (generating || !chats) return;
|
||||||
|
@ -94,6 +117,34 @@ const useSubmit = () => {
|
||||||
reader.releaseLock();
|
reader.releaseLock();
|
||||||
stream.cancel();
|
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) {
|
} catch (e: unknown) {
|
||||||
const err = (e as Error).message;
|
const err = (e as Error).message;
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
|
5
src/store/migrate.ts
Normal file
5
src/store/migrate.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { LocalStorageInterface } from '@type/chat';
|
||||||
|
|
||||||
|
export const migrateV0 = (persistedState: LocalStorageInterface) => {
|
||||||
|
persistedState.chats.forEach((chat) => (chat.titleSet = false));
|
||||||
|
};
|
|
@ -4,6 +4,8 @@ import { ChatSlice, createChatSlice } from './chat-slice';
|
||||||
import { InputSlice, createInputSlice } from './input-slice';
|
import { InputSlice, createInputSlice } from './input-slice';
|
||||||
import { AuthSlice, createAuthSlice } from './auth-slice';
|
import { AuthSlice, createAuthSlice } from './auth-slice';
|
||||||
import { ConfigSlice, createConfigSlice } from './config-slice';
|
import { ConfigSlice, createConfigSlice } from './config-slice';
|
||||||
|
import { LocalStorageInterface } from '@type/chat';
|
||||||
|
import { migrateV0 } from './migrate';
|
||||||
|
|
||||||
export type StoreState = ChatSlice & InputSlice & AuthSlice & ConfigSlice;
|
export type StoreState = ChatSlice & InputSlice & AuthSlice & ConfigSlice;
|
||||||
|
|
||||||
|
@ -30,6 +32,15 @@ const useStore = create<StoreState>()(
|
||||||
apiFreeEndpoint: state.apiFreeEndpoint,
|
apiFreeEndpoint: state.apiFreeEndpoint,
|
||||||
theme: state.theme,
|
theme: state.theme,
|
||||||
}),
|
}),
|
||||||
|
version: 1,
|
||||||
|
migrate: (persistedState, version) => {
|
||||||
|
switch (version) {
|
||||||
|
case 0:
|
||||||
|
migrateV0(persistedState as LocalStorageInterface);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return persistedState as StoreState;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { Theme } from './theme';
|
||||||
|
|
||||||
export type Role = 'user' | 'assistant' | 'system';
|
export type Role = 'user' | 'assistant' | 'system';
|
||||||
export const roles: Role[] = ['user', 'assistant', 'system'];
|
export const roles: Role[] = ['user', 'assistant', 'system'];
|
||||||
|
|
||||||
|
@ -10,9 +12,19 @@ export interface ChatInterface {
|
||||||
title: string;
|
title: string;
|
||||||
messages: MessageInterface[];
|
messages: MessageInterface[];
|
||||||
config: ConfigInterface;
|
config: ConfigInterface;
|
||||||
|
titleSet: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConfigInterface {
|
export interface ConfigInterface {
|
||||||
temperature: number;
|
temperature: number;
|
||||||
presence_penalty: number;
|
presence_penalty: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LocalStorageInterface {
|
||||||
|
chats: ChatInterface[];
|
||||||
|
currentChatIndex: number;
|
||||||
|
apiKey: string;
|
||||||
|
apiFree: boolean;
|
||||||
|
apiFreeEndpoint: string;
|
||||||
|
theme: Theme;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue