fix: remove monorepo

This commit is contained in:
Sam Denty
2024-09-25 19:54:09 +01:00
parent d364a6f774
commit 6fb59d2bc5
137 changed files with 194 additions and 1229 deletions

4
app/lib/hooks/index.ts Normal file
View File

@@ -0,0 +1,4 @@
export * from './useMessageParser';
export * from './usePromptEnhancer';
export * from './useShortcuts';
export * from './useSnapScroll';

View File

@@ -0,0 +1,66 @@
import type { Message } from 'ai';
import { useCallback, useState } from 'react';
import { StreamingMessageParser } from '~/lib/runtime/message-parser';
import { workbenchStore } from '~/lib/stores/workbench';
import { createScopedLogger } from '~/utils/logger';
const logger = createScopedLogger('useMessageParser');
const messageParser = new StreamingMessageParser({
callbacks: {
onArtifactOpen: (data) => {
logger.trace('onArtifactOpen', data);
workbenchStore.showWorkbench.set(true);
workbenchStore.addArtifact(data);
},
onArtifactClose: (data) => {
logger.trace('onArtifactClose');
workbenchStore.updateArtifact(data, { closed: true });
},
onActionOpen: (data) => {
logger.trace('onActionOpen', data.action);
// we only add shell actions when when the close tag got parsed because only then we have the content
if (data.action.type !== 'shell') {
workbenchStore.addAction(data);
}
},
onActionClose: (data) => {
logger.trace('onActionClose', data.action);
if (data.action.type === 'shell') {
workbenchStore.addAction(data);
}
workbenchStore.runAction(data);
},
},
});
export function useMessageParser() {
const [parsedMessages, setParsedMessages] = useState<{ [key: number]: string }>({});
const parseMessages = useCallback((messages: Message[], isLoading: boolean) => {
let reset = false;
if (import.meta.env.DEV && !isLoading) {
reset = true;
messageParser.reset();
}
for (const [index, message] of messages.entries()) {
if (message.role === 'assistant') {
const newParsedContent = messageParser.parse(message.id, message.content);
setParsedMessages((prevParsed) => ({
...prevParsed,
[index]: !reset ? (prevParsed[index] || '') + newParsedContent : newParsedContent,
}));
}
}
}, []);
return { parsedMessages, parseMessages };
}

View File

@@ -0,0 +1,71 @@
import { useState } from 'react';
import { createScopedLogger } from '~/utils/logger';
const logger = createScopedLogger('usePromptEnhancement');
export function usePromptEnhancer() {
const [enhancingPrompt, setEnhancingPrompt] = useState(false);
const [promptEnhanced, setPromptEnhanced] = useState(false);
const resetEnhancer = () => {
setEnhancingPrompt(false);
setPromptEnhanced(false);
};
const enhancePrompt = async (input: string, setInput: (value: string) => void) => {
setEnhancingPrompt(true);
setPromptEnhanced(false);
const response = await fetch('/api/enhancer', {
method: 'POST',
body: JSON.stringify({
message: input,
}),
});
const reader = response.body?.getReader();
const originalInput = input;
if (reader) {
const decoder = new TextDecoder();
let _input = '';
let _error;
try {
setInput('');
while (true) {
const { value, done } = await reader.read();
if (done) {
break;
}
_input += decoder.decode(value);
logger.trace('Set input', _input);
setInput(_input);
}
} catch (error) {
_error = error;
setInput(originalInput);
} finally {
if (_error) {
logger.error(_error);
}
setEnhancingPrompt(false);
setPromptEnhanced(true);
setTimeout(() => {
setInput(_input);
});
}
}
};
return { enhancingPrompt, promptEnhanced, enhancePrompt, resetEnhancer };
}

View File

@@ -0,0 +1,59 @@
import { useStore } from '@nanostores/react';
import { useEffect } from 'react';
import { shortcutsStore, type Shortcuts } from '~/lib/stores/settings';
class ShortcutEventEmitter {
#emitter = new EventTarget();
dispatch(type: keyof Shortcuts) {
this.#emitter.dispatchEvent(new Event(type));
}
on(type: keyof Shortcuts, cb: VoidFunction) {
this.#emitter.addEventListener(type, cb);
return () => {
this.#emitter.removeEventListener(type, cb);
};
}
}
export const shortcutEventEmitter = new ShortcutEventEmitter();
export function useShortcuts(): void {
const shortcuts = useStore(shortcutsStore);
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent): void => {
const { key, ctrlKey, shiftKey, altKey, metaKey } = event;
for (const name in shortcuts) {
const shortcut = shortcuts[name as keyof Shortcuts];
if (
shortcut.key.toLowerCase() === key.toLowerCase() &&
(shortcut.ctrlOrMetaKey
? ctrlKey || metaKey
: (shortcut.ctrlKey === undefined || shortcut.ctrlKey === ctrlKey) &&
(shortcut.metaKey === undefined || shortcut.metaKey === metaKey)) &&
(shortcut.shiftKey === undefined || shortcut.shiftKey === shiftKey) &&
(shortcut.altKey === undefined || shortcut.altKey === altKey)
) {
shortcutEventEmitter.dispatch(name as keyof Shortcuts);
event.preventDefault();
event.stopPropagation();
shortcut.action();
break;
}
}
};
window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, [shortcuts]);
}

View File

@@ -0,0 +1,52 @@
import { useRef, useCallback } from 'react';
export function useSnapScroll() {
const autoScrollRef = useRef(true);
const scrollNodeRef = useRef<HTMLDivElement>();
const onScrollRef = useRef<() => void>();
const observerRef = useRef<ResizeObserver>();
const messageRef = useCallback((node: HTMLDivElement | null) => {
if (node) {
const observer = new ResizeObserver(() => {
if (autoScrollRef.current && scrollNodeRef.current) {
const { scrollHeight, clientHeight } = scrollNodeRef.current;
const scrollTarget = scrollHeight - clientHeight;
scrollNodeRef.current.scrollTo({
top: scrollTarget,
});
}
});
observer.observe(node);
} else {
observerRef.current?.disconnect();
observerRef.current = undefined;
}
}, []);
const scrollRef = useCallback((node: HTMLDivElement | null) => {
if (node) {
onScrollRef.current = () => {
const { scrollTop, scrollHeight, clientHeight } = node;
const scrollTarget = scrollHeight - clientHeight;
autoScrollRef.current = Math.abs(scrollTop - scrollTarget) <= 10;
};
node.addEventListener('scroll', onScrollRef.current);
scrollNodeRef.current = node;
} else {
if (onScrollRef.current) {
scrollNodeRef.current?.removeEventListener('scroll', onScrollRef.current);
}
scrollNodeRef.current = undefined;
onScrollRef.current = undefined;
}
}, []);
return [messageRef, scrollRef];
}