Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions actions/scripts/fetch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ const external = (file: string): boolean => {
};

export const path = async (file: string): Promise<string> => {
if (!external(file)) return `${SCRIPTS_PATH}/${file}.gpt`;
if (!external(file)) return `${SCRIPTS_PATH()}/${file}.gpt`;
return file;
};

export const fetchFullScript = async (file: string): Promise<Block[]> => {
if (!external(file)) file = `${SCRIPTS_PATH}/${file}.gpt`;
if (!external(file)) file = `${SCRIPTS_PATH()}/${file}.gpt`;

const gptscript = new GPTScript();
try {
Expand All @@ -24,7 +24,7 @@ export const fetchFullScript = async (file: string): Promise<Block[]> => {
}

export const fetchScript = async (file: string): Promise<Tool> => {
if (!external(file)) file = `${SCRIPTS_PATH}/${file}.gpt`;
if (!external(file)) file = `${SCRIPTS_PATH()}/${file}.gpt`;

const gptscript = new GPTScript();
try {
Expand All @@ -44,15 +44,15 @@ export const fetchScript = async (file: string): Promise<Tool> => {

export const fetchScripts = async (): Promise<Record<string, string>> => {
try {
const files = await fs.readdir(SCRIPTS_PATH);
const files = await fs.readdir(SCRIPTS_PATH());
const gptFiles = files.filter(file => file.endsWith('.gpt'));

if (gptFiles.length === 0) throw new Error('no files found in scripts directory');

const gptscript = new GPTScript();
const scripts: Record<string, string> = {};
for (const file of gptFiles) {
const script = await gptscript.parse(`${SCRIPTS_PATH}/${file}`);
const script = await gptscript.parse(`${SCRIPTS_PATH()}/${file}`);
let description = '';
for (let tool of script) {
if (tool.type === 'text') continue;
Expand All @@ -73,7 +73,7 @@ export const fetchScripts = async (): Promise<Record<string, string>> => {
export const fetchScriptCode = async (file: string): Promise<string> => {
file = file.includes('.gpt') ? file : `${file}.gpt`;
try {
return await fs.readFile(`${SCRIPTS_PATH}/${file}`, 'utf-8');
return await fs.readFile(`${SCRIPTS_PATH()}/${file}`, 'utf-8');
} catch (e) {
throw e;
}
Expand Down
4 changes: 2 additions & 2 deletions actions/scripts/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import fs from 'fs/promises';

export async function newFile(name: string, instructions: string, fileName: string) {
try {
const files = await fs.readdir(SCRIPTS_PATH);
const files = await fs.readdir(SCRIPTS_PATH());
const gptFiles = files.filter(file => file.endsWith('.gpt'));

if(gptFiles.includes(fileName)) throw new Error('file already exists');
if (!fileName.endsWith('.gpt')) {
throw new Error('file cannot be empty and must end with .gpt');
}

await fs.writeFile(`${SCRIPTS_PATH}/${fileName}`, `---\nName: ${name}\nChat: true\n\n${instructions}\n\n`);
await fs.writeFile(`${SCRIPTS_PATH()}/${fileName}`, `---\nName: ${name}\nChat: true\n\n${instructions}\n\n`);
return fileName.replace('.gpt', '')
} catch (e) {
throw e;
Expand Down
4 changes: 2 additions & 2 deletions actions/scripts/update.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const external = (file: string): boolean => {
};

export const path = async (file: string): Promise<string> => {
if (!external(file)) return `${SCRIPTS_PATH}/${file}.gpt`;
if (!external(file)) return `${SCRIPTS_PATH()}/${file}.gpt`;
return file;
};

Expand All @@ -18,7 +18,7 @@ export const updateScript = async (file: string, script: Block[]) => {

const gptscript = new GPTScript();
try {
await fs.writeFile(`${SCRIPTS_PATH}/${file}.gpt`, await gptscript.stringify(script));
await fs.writeFile(`${SCRIPTS_PATH()}/${file}.gpt`, await gptscript.stringify(script));
} catch (e) {
throw e;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export async function uploadFile(formData: FormData) {
const file = formData.get("file") as File;
const arrayBuffer = await file.arrayBuffer();
const buffer = new Uint8Array(arrayBuffer);
await fs.writeFile(path.join(WORKSPACE_DIR,file.name), buffer);
await fs.writeFile(path.join(WORKSPACE_DIR(),file.name), buffer);
revalidatePath("/");
}

Expand All @@ -35,7 +35,7 @@ export async function deleteFile(path: string) {

export async function lsWorkspaceFiles(): Promise<string> {
try {
const dirents = await fs.readdir(WORKSPACE_DIR, { withFileTypes: true });
const dirents = await fs.readdir(WORKSPACE_DIR(), { withFileTypes: true });
const filesOnly = dirents.filter((dirent: Dirent) => !dirent.isDirectory());
return JSON.stringify(filesOnly);
} catch (e) {
Expand Down
6 changes: 6 additions & 0 deletions actions/workspace.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"use server"

import { WORKSPACE_DIR, set_WORKSPACE_DIR } from '@/config/env';

export const getWorkspaceDir = async () => WORKSPACE_DIR();
export const setWorkspaceDir = async (dir: string) => set_WORKSPACE_DIR(dir);
6 changes: 3 additions & 3 deletions app/api/file/[name]/[tool]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ export async function PUT(
try {
const { name, tool } = params as any;

const script = await gptscript.parse(path.join(SCRIPTS_PATH,`${name}.gpt`));
const script = await gptscript.parse(path.join(SCRIPTS_PATH(),`${name}.gpt`));
const updatedScript = updateScript(script, tool, (await req.json()) as Tool);

await fs.writeFile(path.join(SCRIPTS_PATH,`${name}.gpt`), await gptscript.stringify(updatedScript));
return Response.json(await gptscript.parse(path.join(SCRIPTS_PATH,`${name}.gpt`)));
await fs.writeFile(path.join(SCRIPTS_PATH(),`${name}.gpt`), await gptscript.stringify(updatedScript));
return Response.json(await gptscript.parse(path.join(SCRIPTS_PATH(),`${name}.gpt`)));
} catch (e) {
if (`${e}`.includes('no such file')){
return Response.json({ error: '.gpt file not found' }, { status: 404 });
Expand Down
10 changes: 5 additions & 5 deletions app/api/file/[name]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export async function DELETE(
) {
try {
const { name } = params as any;
await fs.unlink(path.join(`${SCRIPTS_PATH}/${name}.gpt`));
await fs.unlink(path.join(`${SCRIPTS_PATH()}/${name}.gpt`));
return Response.json({ success: true });
} catch (e) {
return Response.json({ error: e }, { status: 500 });
Expand All @@ -28,7 +28,7 @@ export async function DELETE(

// export async function PUT(req: Request) {
// try {
// const scriptsPath = process.env.SCRIPTS_PATH || 'gptscripts';
// const scriptsPath = process.env.SCRIPTS_PATH() || 'gptscripts';
// const { name } = req.params as any;
// const content = await req.text();

Expand All @@ -46,7 +46,7 @@ export async function GET(
) {
try {
const { name } = params as any;
const script = await gptscript.parse(path.join(SCRIPTS_PATH,`${name}.gpt`));
const script = await gptscript.parse(path.join(SCRIPTS_PATH(),`${name}.gpt`));
if (req.nextUrl.searchParams.get('nodeify') === 'true') {
const { nodes, edges } = await nodeify(script);
return Response.json({ nodes: nodes, edges: edges });
Expand All @@ -69,8 +69,8 @@ export async function PUT(
const nodes = (await req.json()) as RFNode[];
const script = denodeify(nodes);

await fs.writeFile(path.join(SCRIPTS_PATH,`${name}.gpt`), await gptscript.stringify(script));
return Response.json(await gptscript.parse(path.join(SCRIPTS_PATH,`${name}.gpt`)));
await fs.writeFile(path.join(SCRIPTS_PATH(),`${name}.gpt`), await gptscript.stringify(script));
return Response.json(await gptscript.parse(path.join(SCRIPTS_PATH(),`${name}.gpt`)));
} catch (e) {
if (`${e}`.includes('no such file')){
return Response.json({ error: '.gpt file not found' }, { status: 404 });
Expand Down
10 changes: 5 additions & 5 deletions app/api/file/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ const gptscript = new GPTScript();

export async function GET() {
try {
const files = await fs.readdir(SCRIPTS_PATH);
const files = await fs.readdir(SCRIPTS_PATH());
const gptFiles = files.filter(file => file.endsWith('.gpt'));

if (gptFiles.length === 0)
return Response.json({ error: 'no .gpt files found' }, { status: 404 });

const scripts: Record<string, string> = {};
for (const file of gptFiles) {
const script = await gptscript.parse(`${SCRIPTS_PATH}/${file}`);
const script = await gptscript.parse(`${SCRIPTS_PATH()}/${file}`);
let description = '';
for (let tool of script) {
if (tool.type === 'text') continue;
description = tool.description;
description = tool.description || '';
break;
}
scripts[file] = description || '';
Expand All @@ -38,7 +38,7 @@ export async function GET() {

export async function POST(_req: Request) {
try {
const files = await fs.readdir(SCRIPTS_PATH);
const files = await fs.readdir(SCRIPTS_PATH());
const gptFiles = files.filter(file => file.endsWith('.gpt'));

let id = 0;
Expand All @@ -47,7 +47,7 @@ export async function POST(_req: Request) {
id++;
newFileName = `new-file-${id}.gpt`;
}
await fs.writeFile(`${SCRIPTS_PATH}/${newFileName}`, '---\nname: main');
await fs.writeFile(`${SCRIPTS_PATH()}/${newFileName}`, '---\nname: main');
return Response.json({ file: newFileName });
} catch (e) {
return Response.json({ error: e }, { status: 500 });
Expand Down
8 changes: 7 additions & 1 deletion components/script.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Loading from "@/components/loading";
import useChatSocket from '@/components/script/useChatSocket';
import { Button } from "@nextui-org/react";
import { fetchScript, path } from "@/actions/scripts/fetch";
import { getWorkspaceDir } from "@/actions/workspace";

interface ScriptProps {
file: string;
Expand All @@ -34,7 +35,12 @@ const Script: React.FC<ScriptProps> = ({ file, className, messagesHeight = 'h-fu
useEffect(() => {
if (hasRun || !socket || !connected) return;
if ( !tool.arguments?.properties || Object.keys(tool.arguments.properties).length === 0 ) {
path(file).then((path) => { socket.emit("run", path, tool.name, formValues) });
path(file)
.then(async (path) => {
const workspace = await getWorkspaceDir()
return { path, workspace}
})
.then(({path, workspace}) => { socket.emit("run", path, tool.name, formValues, workspace) });
setHasRun(true);
}
}, [tool, file, formValues]);
Expand Down
2 changes: 1 addition & 1 deletion components/script/chatBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const ChatBar = ({
onPress={onRestart}
/>
</Tooltip>
<Upload />
<Upload onRestart={onRestart}/>
<Textarea
id="chatInput"
autoComplete="off"
Expand Down
21 changes: 13 additions & 8 deletions components/script/chatBar/upload.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useState, useCallback, useRef, useEffect } from 'react';
import { GoPlus, GoUpload, GoFile, GoX } from 'react-icons/go';
import { useState, useRef, useEffect } from 'react';
import { GoFileDirectory, GoUpload, GoFile, GoX } from 'react-icons/go';
import Files from './upload/files';
import { uploadFile, lsWorkspaceFiles } from './upload/actions';
import { uploadFile, lsWorkspaceFiles } from '@/actions/upload';
import { Dirent } from 'fs';
import Workspace from '@/components/script/chatBar/upload/workspace';
import {
Modal,
ModalContent,
Expand All @@ -15,7 +16,11 @@ import {
Divider,
} from '@nextui-org/react';

const UploadModal = () => {
interface UploadModalProps {
onRestart: () => void;
}

const UploadModal = ({onRestart}: UploadModalProps) => {
const [isOpen, setIsOpen] = useState(false);
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [files, setFiles] = useState<Dirent[]>([]);
Expand All @@ -30,7 +35,6 @@ const UploadModal = () => {
.catch((error) => console.error('Error fetching files:', error));
}


const handleOpen = () => setIsOpen(true)
const handleClose = () => setIsOpen(false);
const handleCancel = () => setSelectedFile(null);
Expand All @@ -54,12 +58,12 @@ const UploadModal = () => {

return (
<>
<Tooltip content="Add files to your workspace" closeDelay={0.5} placement="top">
<Tooltip content="View and manage your workspace" closeDelay={0.5} placement="top">
<Button
startContent={<GoPlus />}
startContent={<GoFileDirectory />}
isIconOnly
radius="full"
className="mr-2 my-auto text-2xl"
className="mr-2 my-auto text-xl"
color="primary"
onPress={handleOpen}
/>
Expand All @@ -76,6 +80,7 @@ const UploadModal = () => {
<h1>Your workspace</h1>
</ModalHeader>
<ModalBody className="max-h-[900px] overflow-y-scroll">
<Workspace onRestart={onRestart}/>
<ScrollShadow>
<Files files={files} setFiles={setFiles} />
</ScrollShadow>
Expand Down
2 changes: 1 addition & 1 deletion components/script/chatBar/upload/files.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect } from 'react';
import { GoTrash, GoFile } from 'react-icons/go';
import { Table, TableBody, TableHeader, TableRow, TableCell, TableColumn, Button } from '@nextui-org/react'; // Replace 'next-ui' with the actual package name
import { deleteFile, lsWorkspaceFiles } from './actions';
import { deleteFile, lsWorkspaceFiles } from '@/actions/upload';
import { Dirent } from 'fs';
import path from 'path';

Expand Down
88 changes: 88 additions & 0 deletions components/script/chatBar/upload/workspace.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { useState, useCallback, useRef, useEffect } from 'react';
import { getWorkspaceDir, setWorkspaceDir } from '@/actions/workspace';
import {
Modal,
ModalContent,
ModalHeader,
ModalBody,
ModalFooter,
Button,
Input,
} from '@nextui-org/react';

interface WorkspaceProps {
onRestart: () => void;
}

const Workspace = ({onRestart}: WorkspaceProps) => {
const [isOpen, setIsOpen] = useState(false);
const [workspace, setWorkspace] = useState<string>('');
const [actingWorkspace, setActingWorkspace] = useState<string>('');

useEffect(() => { getWorkspaceDir().then((wd) => setActingWorkspace(wd)) }, []);
useEffect(() => { setWorkspace(actingWorkspace) }, [actingWorkspace]);

const handleOpen = () => setIsOpen(true)
const handleClose = () => setIsOpen(false);
const handleConfirm = useCallback(() => {
setWorkspaceDir(workspace);
setIsOpen(false);
onRestart();
}, [workspace]);

return (
<div className="flex w-full space-x-4">
<Input
variant="bordered"
placeholder="Set your workspace folder..."
label="Workspace folder"
value={workspace}
onKeyDown={(event) => event.key === 'Enter' && actingWorkspace != workspace && handleConfirm()}
onChange={(event) => setWorkspace(event.target.value) }
/>
{ workspace != actingWorkspace &&
<Button
className="absolute right-8 mt-2"
color="danger"
onPress={handleOpen}
>
Update
</Button>
}
<Modal
isOpen={isOpen}
onClose={handleClose}
backdrop='blur'
title="Upload Modal"
size="xl"
>
<ModalContent>
<ModalHeader>
<h1>Are you sure?</h1>
</ModalHeader>
<ModalBody className="max-h-[900px] overflow-y-scroll">
<p>Changing the workspace for this script requires it to restart.</p>
</ModalBody>
<ModalFooter className="flex justify-between">
<Button
color="danger"
className="w-1/2"
onPress={handleConfirm}
>
Confirm and restart
</Button>
<Button
color="primary"
className="w-1/2"
onPress={handleClose}
>
Cancel
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</div>
);
};

export default Workspace;
Loading