feat: initial commit

This commit is contained in:
Dominic Elm
2024-07-10 18:44:39 +02:00
commit 6927c07451
64 changed files with 12330 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
export * from './useMessageParser';
export * from './usePromptEnhancer';

View File

@@ -0,0 +1,57 @@
import type { Message } from 'ai';
import { useCallback, useState } from 'react';
import { StreamingMessageParser } from '~/lib/runtime/message-parser';
import { workspaceStore } from '~/lib/stores/workspace';
import { createScopedLogger } from '~/utils/logger';
const logger = createScopedLogger('useMessageParser');
const messageParser = new StreamingMessageParser({
callbacks: {
onArtifactOpen: (messageId, { title }) => {
logger.debug('onArtifactOpen', title);
workspaceStore.updateArtifact(messageId, { title, closed: false });
},
onArtifactClose: (messageId) => {
logger.debug('onArtifactClose');
workspaceStore.updateArtifact(messageId, { closed: true });
},
onAction: (messageId, { type, path, content }) => {
console.log('ACTION', messageId, { type, path, content });
},
},
});
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') {
/**
* In production, we only parse the last assistant message since previous messages can't change.
* During development they can change, e.g., if the parser gets modified.
*/
if (import.meta.env.PROD && index < messages.length - 1) {
continue;
}
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 };
}