Skip to content

Commit

Permalink
chore: sync live with main branch (#684)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremyphilemon authored Jan 8, 2025
1 parent 8b99b9a commit a1bf5cf
Show file tree
Hide file tree
Showing 13 changed files with 308 additions and 125 deletions.
4 changes: 2 additions & 2 deletions app/(chat)/api/chat/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ export async function POST(request: Request) {
if (document.kind === 'text') {
const { fullStream } = streamText({
model: customModel(model.apiIdentifier),
system: updateDocumentPrompt(currentContent),
system: updateDocumentPrompt(currentContent, 'text'),
prompt: description,
experimental_providerMetadata: {
openai: {
Expand Down Expand Up @@ -307,7 +307,7 @@ export async function POST(request: Request) {
} else if (document.kind === 'code') {
const { fullStream } = streamObject({
model: customModel(model.apiIdentifier),
system: updateDocumentPrompt(currentContent),
system: updateDocumentPrompt(currentContent, 'code'),
prompt: description,
schema: z.object({
code: z.string(),
Expand Down
106 changes: 4 additions & 102 deletions components/block-actions.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import { cn, generateUUID } from '@/lib/utils';
import { ClockRewind, CopyIcon, PlayIcon, RedoIcon, UndoIcon } from './icons';
import { cn } from '@/lib/utils';
import { ClockRewind, CopyIcon, RedoIcon, UndoIcon } from './icons';
import { Button } from './ui/button';
import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip';
import { useCopyToClipboard } from 'usehooks-ts';
import { toast } from 'sonner';
import { ConsoleOutput, UIBlock } from './block';
import {
Dispatch,
memo,
SetStateAction,
startTransition,
useCallback,
useState,
} from 'react';
import { Dispatch, memo, SetStateAction } from 'react';
import { RunCodeButton } from './run-code-button';

interface BlockActionsProps {
block: UIBlock;
Expand All @@ -23,98 +17,6 @@ interface BlockActionsProps {
setConsoleOutputs: Dispatch<SetStateAction<Array<ConsoleOutput>>>;
}

export function RunCodeButton({
block,
setConsoleOutputs,
}: {
block: UIBlock;
setConsoleOutputs: Dispatch<SetStateAction<Array<ConsoleOutput>>>;
}) {
const [pyodide, setPyodide] = useState<any>(null);
const isPython = true;
const codeContent = block.content;

const updateConsoleOutput = useCallback(
(runId: string, content: string | null, status: 'completed' | 'failed') => {
setConsoleOutputs((consoleOutputs) => {
const index = consoleOutputs.findIndex((output) => output.id === runId);

if (index === -1) return consoleOutputs;

const updatedOutputs = [...consoleOutputs];
updatedOutputs[index] = {
id: runId,
content,
status,
};

return updatedOutputs;
});
},
[setConsoleOutputs],
);

const loadAndRunPython = useCallback(async () => {
const runId = generateUUID();

setConsoleOutputs((consoleOutputs) => [
...consoleOutputs,
{
id: runId,
content: null,
status: 'in_progress',
},
]);

let currentPyodideInstance = pyodide;

if (isPython) {
if (!currentPyodideInstance) {
// @ts-expect-error - pyodide is not defined
const newPyodideInstance = await loadPyodide({
indexURL: 'https://cdn.jsdelivr.net/pyodide/v0.23.4/full/',
});

setPyodide(newPyodideInstance);
currentPyodideInstance = newPyodideInstance;
}

try {
await currentPyodideInstance.runPythonAsync(`
import sys
import io
sys.stdout = io.StringIO()
`);

await currentPyodideInstance.runPythonAsync(codeContent);

const output: string = await currentPyodideInstance.runPythonAsync(
`sys.stdout.getvalue()`,
);

updateConsoleOutput(runId, output, 'completed');
} catch (error: any) {
updateConsoleOutput(runId, error.message, 'failed');
}
}
}, [pyodide, codeContent, isPython, setConsoleOutputs, updateConsoleOutput]);

return (
<Button
variant="outline"
className="py-1.5 px-2 h-fit dark:hover:bg-zinc-700"
onClick={() => {
startTransition(() => {
loadAndRunPython();
});
}}
disabled={block.status === 'streaming'}
>
<PlayIcon size={18} /> Run
</Button>
);
}

function PureBlockActions({
block,
handleVersionChange,
Expand Down
13 changes: 8 additions & 5 deletions components/block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,15 @@ export interface UIBlock {
};
}

export interface ConsoleOutputContent {
type: 'text' | 'image';
value: string;
}

export interface ConsoleOutput {
id: string;
status: 'in_progress' | 'completed' | 'failed';
content: string | null;
status: 'in_progress' | 'loading_packages' | 'completed' | 'failed';
contents: Array<ConsoleOutputContent>;
}

function PureBlock({
Expand Down Expand Up @@ -431,9 +436,7 @@ function PureBlock({
<BlockCloseButton />

<div className="flex flex-col">
<div className="font-medium">
{document?.title ?? block.title}
</div>
<div className="font-medium">{block.title}</div>

{isContentDirty ? (
<div className="text-sm text-muted-foreground">
Expand Down
3 changes: 3 additions & 0 deletions components/code-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,12 @@ function PureCodeEditor({ content, saveContent, status }: EditorProps) {
}
});

const currentSelection = editorRef.current.state.selection;

const newState = EditorState.create({
doc: editorRef.current.state.doc,
extensions: [basicSetup, python(), oneDark, updateListener],
selection: currentSelection,
});

editorRef.current.setState(newState);
Expand Down
57 changes: 49 additions & 8 deletions components/console.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from 'react';
import { ConsoleOutput } from './block';
import { cn } from '@/lib/utils';
import { useBlockSelector } from '@/hooks/use-block';

interface ConsoleProps {
consoleOutputs: Array<ConsoleOutput>;
Expand All @@ -21,6 +22,8 @@ export function Console({ consoleOutputs, setConsoleOutputs }: ConsoleProps) {
const [isResizing, setIsResizing] = useState(false);
const consoleEndRef = useRef<HTMLDivElement>(null);

const isBlockVisible = useBlockSelector((state) => state.isVisible);

const minHeight = 100;
const maxHeight = 800;

Expand Down Expand Up @@ -57,6 +60,12 @@ export function Console({ consoleOutputs, setConsoleOutputs }: ConsoleProps) {
consoleEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [consoleOutputs]);

useEffect(() => {
if (!isBlockVisible) {
setConsoleOutputs([]);
}
}, [isBlockVisible, setConsoleOutputs]);

return consoleOutputs.length > 0 ? (
<>
<div
Expand All @@ -69,7 +78,7 @@ export function Console({ consoleOutputs, setConsoleOutputs }: ConsoleProps) {

<div
className={cn(
'fixed flex flex-col bottom-0 dark:bg-zinc-900 bg-zinc-50 w-full border-t z-40 overflow-y-scroll dark:border-zinc-700 border-zinc-200',
'fixed flex flex-col bottom-0 dark:bg-zinc-900 bg-zinc-50 w-full border-t z-40 overflow-y-scroll overflow-x-hidden dark:border-zinc-700 border-zinc-200',
{
'select-none': isResizing,
},
Expand Down Expand Up @@ -101,21 +110,53 @@ export function Console({ consoleOutputs, setConsoleOutputs }: ConsoleProps) {
>
<div
className={cn('w-12 shrink-0', {
'text-muted-foreground':
consoleOutput.status === 'in_progress',
'text-muted-foreground': [
'in_progress',
'loading_packages',
].includes(consoleOutput.status),
'text-emerald-500': consoleOutput.status === 'completed',
'text-red-400': consoleOutput.status === 'failed',
})}
>
[{index + 1}]
</div>
{consoleOutput.status === 'in_progress' ? (
<div className="animate-spin size-fit self-center">
<LoaderIcon />
{['in_progress', 'loading_packages'].includes(
consoleOutput.status,
) ? (
<div className="flex flex-row gap-2">
<div className="animate-spin size-fit self-center mb-auto mt-0.5">
<LoaderIcon />
</div>
<div className="text-muted-foreground">
{consoleOutput.status === 'in_progress'
? 'Initializing...'
: consoleOutput.status === 'loading_packages'
? consoleOutput.contents.map((content) =>
content.type === 'text' ? content.value : null,
)
: null}
</div>
</div>
) : (
<div className="dark:text-zinc-50 text-zinc-900 whitespace-pre-line">
{consoleOutput.content}
<div className="dark:text-zinc-50 text-zinc-900 w-full flex flex-col gap-2 overflow-x-scroll">
{consoleOutput.contents.map((content, index) =>
content.type === 'image' ? (
<picture key={`${consoleOutput.id}-${index}`}>
<img
src={content.value}
alt="output"
className="rounded-md max-w-[600px] w-full"
/>
</picture>
) : (
<div
key={`${consoleOutput.id}-${index}`}
className="whitespace-pre-line break-words w-full"
>
{content.value}
</div>
),
)}
</div>
)}
</div>
Expand Down
1 change: 1 addition & 0 deletions components/document-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ const PureHitboxLayer = ({
? { ...block, isVisible: true }
: {
...block,
title: result.title,
documentId: result.id,
kind: result.kind,
isVisible: true,
Expand Down
2 changes: 1 addition & 1 deletion components/messages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export const Messages = memo(PureMessages, (prevProps, nextProps) => {

if (prevProps.isLoading !== nextProps.isLoading) return false;
if (prevProps.isLoading && nextProps.isLoading) return false;
if (!equal(prevProps.messages, nextProps.messages)) return false;
if (prevProps.messages.length !== nextProps.messages.length) return false;
if (!equal(prevProps.votes, nextProps.votes)) return false;

return true;
Expand Down
8 changes: 8 additions & 0 deletions components/multimodal-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ function PureMultimodalInput({
}
};

const resetHeight = () => {
if (textareaRef.current) {
textareaRef.current.style.height = 'auto';
textareaRef.current.style.height = '98px';
}
};

const [localStorageInput, setLocalStorageInput] = useLocalStorage(
'input',
'',
Expand Down Expand Up @@ -126,6 +133,7 @@ function PureMultimodalInput({

setAttachments([]);
setLocalStorageInput('');
resetHeight();

if (width && width > 768) {
textareaRef.current?.focus();
Expand Down
Loading

0 comments on commit a1bf5cf

Please sign in to comment.