Add story cloning, fix storage caching issue
This commit is contained in:
parent
a660ab8161
commit
3f41cea5eb
|
|
@ -55,18 +55,14 @@ export const Header = () => {
|
|||
assistantOpen.setFalse();
|
||||
}, [addSwipe, messages]);
|
||||
|
||||
const handleSetBannedWords = useCallback((e: Event) => {
|
||||
if (e.target instanceof HTMLTextAreaElement) {
|
||||
const words = e.target.value.split('\n');
|
||||
const handleSetBannedWords = useInputCallback((text) => {
|
||||
const words = text.split('\n');
|
||||
setBannedWords(words);
|
||||
}
|
||||
}, [setBannedWords]);
|
||||
|
||||
const handleBlurBannedWords = useCallback((e: Event) => {
|
||||
if (e.target instanceof HTMLTextAreaElement) {
|
||||
const words = e.target.value.toLowerCase().split('\n').sort();
|
||||
const handleBlurBannedWords = useInputCallback((text) => {
|
||||
const words = text.toLowerCase().split('\n').sort();
|
||||
setBannedWords(words);
|
||||
}
|
||||
}, [setBannedWords]);
|
||||
|
||||
const handleSetSummaryEnabled = useCallback((e: Event) => {
|
||||
|
|
@ -76,15 +72,7 @@ export const Header = () => {
|
|||
}, [setSummaryEnabled]);
|
||||
|
||||
const handleChangeStory = useInputCallback((story) => {
|
||||
if (story === '@new') {
|
||||
const id = prompt('Story id');
|
||||
if (id) {
|
||||
createStory(id);
|
||||
setCurrentStory(id);
|
||||
}
|
||||
} else {
|
||||
setCurrentStory(story);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleDeleteStory = useCallback(() => {
|
||||
|
|
@ -93,6 +81,14 @@ export const Header = () => {
|
|||
}
|
||||
}, [currentStory]);
|
||||
|
||||
const handleDuplicateStory = useCallback(() => {
|
||||
const id = prompt('Story id');
|
||||
if (id) {
|
||||
createStory(id, currentStory);
|
||||
setCurrentStory(id);
|
||||
}
|
||||
}, [currentStory]);
|
||||
|
||||
return (
|
||||
<div class={styles.header}>
|
||||
<div class={styles.inputs}>
|
||||
|
|
@ -137,8 +133,10 @@ export const Header = () => {
|
|||
{Object.keys(stories).map((story) => (
|
||||
<option key={story} value={story}>{story}</option>
|
||||
))}
|
||||
<option value='@new'>New Story...</option>
|
||||
</select>
|
||||
<button class='icon' onClick={handleDuplicateStory}>
|
||||
➕
|
||||
</button>
|
||||
{currentStory !== DEFAULT_STORY
|
||||
? <button class='icon' onClick={handleDeleteStory}>
|
||||
🗑️
|
||||
|
|
|
|||
|
|
@ -101,9 +101,9 @@ export const LLMContextProvider = ({ children }: { children?: any }) => {
|
|||
let content = swipe?.content ?? '';
|
||||
if (role === 'user' && usersRemaining > keepUsers) {
|
||||
usersRemaining--;
|
||||
} else if (role === 'assistant' && templateMessages.at(-1).role === 'assistant') {
|
||||
} else if (role === 'assistant' && templateMessages.at(-1)!.role === 'assistant') {
|
||||
wasStory = true;
|
||||
templateMessages.at(-1).content += '\n\n' + content;
|
||||
templateMessages.at(-1)!.content += '\n\n' + content;
|
||||
} else if (role === 'user' && !message.technical) {
|
||||
templateMessages.push({
|
||||
role: message.role,
|
||||
|
|
|
|||
|
|
@ -35,13 +35,13 @@ interface StoryActionSetLore {
|
|||
interface StoryActionWithId {
|
||||
action: 'create' | 'delete';
|
||||
id: string;
|
||||
fromId?: string;
|
||||
}
|
||||
|
||||
type StoryAction = StoryActionSetCurrent | StoryActionSetLore | StoryActionSetMessages | StoryActionWithId;
|
||||
|
||||
interface IContext {
|
||||
currentConnection: number;
|
||||
availableConnections: IConnection[];
|
||||
connection: IConnection;
|
||||
input: string;
|
||||
systemPrompt: string;
|
||||
userPrompt: string;
|
||||
|
|
@ -57,15 +57,12 @@ interface IContext {
|
|||
}
|
||||
|
||||
interface IComputableContext {
|
||||
connection: IConnection;
|
||||
lore: string;
|
||||
messages: IMessage[];
|
||||
}
|
||||
|
||||
interface IActions {
|
||||
setConnection: (connection: IConnection) => void;
|
||||
setAvailableConnections: (connections: IConnection[]) => void;
|
||||
setCurrentConnection: (connection: number) => void;
|
||||
setInput: (url: string | Event) => void;
|
||||
setInstruct: (template: string | Event) => void;
|
||||
setLore: (lore: string | Event) => void;
|
||||
|
|
@ -90,7 +87,7 @@ interface IActions {
|
|||
continueMessage: (continueLast?: boolean) => void;
|
||||
|
||||
setCurrentStory: (id: string) => void;
|
||||
createStory: (id: string) => void;
|
||||
createStory: (id: string, fromId?: string) => void;
|
||||
deleteStory: (id: string) => void;
|
||||
}
|
||||
|
||||
|
|
@ -119,12 +116,11 @@ export const INSTRUCTS = {
|
|||
}
|
||||
|
||||
const DEFAULT_CONTEXT: IContext = {
|
||||
currentConnection: 0,
|
||||
availableConnections: [{
|
||||
connection: {
|
||||
type: 'kobold',
|
||||
url: 'http://localhost:5001',
|
||||
instruct: INSTRUCT_MISTRAL,
|
||||
}],
|
||||
},
|
||||
input: '',
|
||||
systemPrompt: 'You are a creative writer. Write a story based on the world description below. Story should be adult and mature; and could include swearing, violence and unfairness. Portray characters realistically and stay in the lore.',
|
||||
stories: {},
|
||||
|
|
@ -155,7 +151,6 @@ const EMPTY_STORY: IStory = {
|
|||
|
||||
const saveContext = throttle(async (context: IContext & IComputableContext) => {
|
||||
const contextToSave: Partial<IContext & IComputableContext> = { ...context };
|
||||
delete contextToSave.connection;
|
||||
delete contextToSave.triggerNext;
|
||||
delete contextToSave.continueLast;
|
||||
delete contextToSave.lore;
|
||||
|
|
@ -176,7 +171,10 @@ const storyReducer = (state: StoriesState, action: StoryAction): StoriesState =>
|
|||
if ('id' in action) {
|
||||
switch (action.action) {
|
||||
case 'create':
|
||||
stories[action.id] = EMPTY_STORY;
|
||||
stories[action.id] = {
|
||||
...EMPTY_STORY,
|
||||
lore: (action.fromId && stories[action.fromId]?.lore) ?? EMPTY_STORY.lore,
|
||||
};
|
||||
break;
|
||||
case 'delete':
|
||||
if (action.id !== DEFAULT_STORY) {
|
||||
|
|
@ -204,8 +202,7 @@ const storyReducer = (state: StoriesState, action: StoryAction): StoriesState =>
|
|||
};
|
||||
|
||||
export const StateContextProvider = ({ children }: { children?: any }) => {
|
||||
const [currentConnection, setCurrentConnection] = useState<number>(loadedContext.currentConnection);
|
||||
const [availableConnections, setAvailableConnections] = useState<IConnection[]>(loadedContext.availableConnections);
|
||||
const [connection, setConnection] = useState<IConnection>(loadedContext.connection);
|
||||
const [input, setInput] = useInputState(loadedContext.input);
|
||||
const [systemPrompt, setSystemPrompt] = useInputState(loadedContext.systemPrompt);
|
||||
const [userPrompt, setUserPrompt] = useInputState(loadedContext.userPrompt);
|
||||
|
|
@ -221,22 +218,10 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
|
|||
messages: loadedContext.stories[loadedContext.currentStory]?.messages ?? [],
|
||||
});
|
||||
|
||||
const connection = availableConnections[currentConnection] ?? DEFAULT_CONTEXT.availableConnections[0];
|
||||
|
||||
const [triggerNext, setTriggerNext] = useState(false);
|
||||
const [continueLast, setContinueLast] = useState(false);
|
||||
const [instruct, setInstruct] = useInputState(connection.instruct);
|
||||
|
||||
const setConnection = useCallback((c: IConnection) => {
|
||||
setAvailableConnections(availableConnections.map((ac, ai) => {
|
||||
if (ai === currentConnection) {
|
||||
return c;
|
||||
} else {
|
||||
return ac;
|
||||
}
|
||||
}));
|
||||
}, [availableConnections, currentConnection]);
|
||||
|
||||
useEffect(() => setConnection({ ...connection, instruct }), [instruct]);
|
||||
|
||||
const setLore = useInputCallback((lore) => {
|
||||
|
|
@ -253,7 +238,6 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
|
|||
|
||||
const actions: IActions = useMemo(() => ({
|
||||
setConnection,
|
||||
setCurrentConnection,
|
||||
setInput,
|
||||
setInstruct,
|
||||
setSystemPrompt,
|
||||
|
|
@ -268,7 +252,6 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
|
|||
setCurrentStory,
|
||||
|
||||
setBannedWords: (words) => setBannedWords(words.slice()),
|
||||
setAvailableConnections: (connections) => setAvailableConnections(connections.slice()),
|
||||
|
||||
setMessages: (newMessages) => setMessages(newMessages.slice()),
|
||||
addMessage: (content, role, triggerNext = false) => {
|
||||
|
|
@ -297,7 +280,7 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
|
|||
const swipes = message.swipes.slice();
|
||||
const latestSwipe = swipes.at(-1);
|
||||
if (currentSwipe >= swipes.length) {
|
||||
if (latestSwipe.content.length > 0) {
|
||||
if (latestSwipe && latestSwipe.content.length > 0) {
|
||||
currentSwipe = swipes.length;
|
||||
swipes.push({ content: '', cost: 0 });
|
||||
} else {
|
||||
|
|
@ -340,8 +323,8 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
|
|||
setTriggerNext(true);
|
||||
setContinueLast(c);
|
||||
},
|
||||
createStory: (id: string) => {
|
||||
storyDispatch({ id, action: 'create' });
|
||||
createStory: (id: string, fromId?: string) => {
|
||||
storyDispatch({ id, action: 'create', fromId });
|
||||
},
|
||||
deleteStory: (id: string) => {
|
||||
storyDispatch({ id, action: 'delete' });
|
||||
|
|
@ -350,8 +333,6 @@ export const StateContextProvider = ({ children }: { children?: any }) => {
|
|||
|
||||
const rawContext: IContext & IComputableContext = {
|
||||
connection,
|
||||
currentConnection,
|
||||
availableConnections,
|
||||
input,
|
||||
systemPrompt,
|
||||
userPrompt,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export const loadObject = async <T>(key: string, defaultObject: T): Promise<T> =
|
|||
|
||||
let remoteObject: Partial<T> = {};
|
||||
try {
|
||||
const response = await fetch(`https://demo.pabloader.ru/storage/${key}`);
|
||||
const response = await fetch(`https://demo.pabloader.ru/storage/${key}?_=${Math.random()}`);
|
||||
if (response.ok) {
|
||||
const compressedData = await response.blob();
|
||||
const decompressedData = await decompressBlob(compressedData);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,6 @@
|
|||
"@common/*": ["./src/common/*"]
|
||||
}
|
||||
},
|
||||
"include": ["./**/*.ts", "./**/*.tsx", "./**/*.js", "./**/*.jsx", "./node_modules/assemblyscript/std/portable/index.d.ts"],
|
||||
"include": ["./**/*.ts", "./**/*.tsx", "./**/*.js", "./**/*.jsx"],
|
||||
"exclude": ["./dist/**/*"]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue