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
55 changes: 23 additions & 32 deletions actions/knowledge/knowledge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,25 @@ export async function deleteDataset(datasetID: string): Promise<void> {
return;
}

export async function firstIngestion(
scriptId: string,
files: string[]
): Promise<boolean> {
const dir = path.join(KNOWLEDGE_DIR(), 'script_data', scriptId, 'data');
return !fs.existsSync(dir) && files.length > 0;
}

export async function ensureFilesIngested(
files: string[],
scriptId: string,
token: string
) {
): Promise<string> {
const dir = path.join(KNOWLEDGE_DIR(), 'script_data', scriptId, 'data');
if (!fs.existsSync(dir) && files.length > 0) {
fs.mkdirSync(dir, { recursive: true });
} else if (!fs.existsSync(dir) && files.length === 0) {
// if there are no files in the directory and no dropped files, do nothing
return;
return '';
}

for (const file of files) {
Expand All @@ -57,8 +65,7 @@ export async function ensureFilesIngested(
await fs.promises.copyFile(file, filePath);
}
} catch (error) {
console.error(`Error copying file ${file}:`, error);
throw error;
return `Error copying file ${file}: ${error}`;
}
}

Expand All @@ -74,8 +81,7 @@ export async function ensureFilesIngested(
}
}
} catch (error) {
console.error('Error during cleanup of removed files:', error);
throw error;
return `Error deleting files: ${error}`;
}

try {
Expand All @@ -85,37 +91,27 @@ export async function ensureFilesIngested(
token
);
} catch (error) {
console.error('Error during ingestion:', error);
throw error;
return `Error running knowledge ingestion: ${error}`;
}

return;
return '';
}

async function runKnowledgeIngest(
id: string,
knowledgePath: string,
token: string
): Promise<void> {
try {
// Start the ingestion process in the background
await execPromise(
`${process.env.KNOWLEDGE_BIN} ingest --prune --dataset ${id} ./data`,
{
cwd: knowledgePath,
env: { ...process.env, GPTSCRIPT_GATEWAY_API_KEY: token },
}
);

const errorFilePath = path.join(knowledgePath, 'error.log');
if (fs.existsSync(errorFilePath)) {
await fs.promises.rm(errorFilePath);
// Start the ingestion process in the background
await execPromise(
`${process.env.KNOWLEDGE_BIN} ingest --prune --dataset ${id} ./data`,
{
cwd: knowledgePath,
env: { ...process.env, GPTSCRIPT_GATEWAY_API_KEY: token },
}
} catch (error) {
console.log(error);
handleError(knowledgePath, error as Error);
throw error;
}
);

return;
}

export async function getFiles(scriptId: string): Promise<string[]> {
Expand All @@ -135,8 +131,3 @@ export async function datasetExists(scriptId: string): Promise<boolean> {
export async function getKnowledgeBinaryPath(): Promise<string> {
return process.env.KNOWLEDGE_BIN || 'knowledge';
}

function handleError(dir: string, error: Error): void {
const errorFilePath = path.join(dir, 'error.log');
fs.writeFileSync(errorFilePath, error.message);
}
130 changes: 92 additions & 38 deletions components/edit/configure.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Models from '@/components/edit/configure/models';
import Visibility from '@/components/edit/configure/visibility';
import Code from '@/components/edit/configure/code';
import { EditContext, KNOWLEDGE_NAME } from '@/contexts/edit';
import { GoLightBulb } from 'react-icons/go';
import { GoLightBulb, GoTrash } from 'react-icons/go';
import { HiCog } from 'react-icons/hi2';
import { LuCircuitBoard } from 'react-icons/lu';
import {
Expand All @@ -24,11 +24,11 @@ import AssistantNotFound from '@/components/assistant-not-found';
import { useRouter } from 'next/navigation';
import { ChatContext } from '@/contexts/chat';
import Chat from '@/components/chat';
import { GoDatabase } from 'react-icons/go';
import { IoSettingsOutline } from 'react-icons/io5';
import { IoMdAdd } from 'react-icons/io';
import { IoMdAdd, IoMdRefresh } from 'react-icons/io';
import { RiFileSearchLine } from 'react-icons/ri';
import KnowledgeModals from '@/components/knowledge/KnowledgeModals';
import FileSettingModals from '@/components/knowledge/KnowledgeModals';
import { RiFoldersLine } from 'react-icons/ri';

interface ConfigureProps {
collapsed?: boolean;
Expand All @@ -51,12 +51,14 @@ const Configure: React.FC<ConfigureProps> = ({ collapsed }) => {
setDependencies,
setDroppedFiles,
droppedFileDetails,
setDroppedFileDetails,
ingesting,
ingest,
updated,
setUpdated,
ingestionError,
} = useContext(EditContext);
const { restartScript } = useContext(ChatContext);
const fileTableModal = useDisclosure();
const fileSettingModal = useDisclosure();

const abbreviate = (name: string) => {
Expand Down Expand Up @@ -212,40 +214,95 @@ const Configure: React.FC<ConfigureProps> = ({ collapsed }) => {
aria-label="files"
title={<h1>Files</h1>}
startContent={<RiFileSearchLine />}
classNames={{ content: 'pt-1 pb-3' }}
classNames={{ content: collapsed ? 'pt-6 pb-10' : 'p-10 pt-6' }}
>
<div className="flex justify-between items-center">
<Button
isIconOnly
size="sm"
startContent={<GoDatabase />}
onClick={fileTableModal.onOpen}
/>

{droppedFileDetails?.size > 0 && !ingesting && (
<p className="text-sm text-zinc-500 ml-2">{`${droppedFileDetails.size} ${droppedFileDetails.size === 1 ? 'file' : 'files'}, ${Array.from(
droppedFileDetails.values()
<div className="grid grid-cols-1 gap-2 w-full mb-2">
{Array.from(droppedFileDetails.entries()).map(
(fileDetail, i) => (
<div key={i} className="flex space-x-2">
<div className="truncate w-full border-2 dark:border-zinc-700 text-sm pl-2 rounded-lg flex justify-between items-center">
<div className="flex items-center space-x-2">
<RiFileSearchLine />
<p className="capitalize">{fileDetail[1].fileName}</p>
<p className="text-xs text-zinc-400 ml-2">{`${fileDetail[1].size} KB`}</p>
</div>
<Button
variant="light"
isIconOnly
size="sm"
startContent={<GoTrash />}
onPress={() => {
setDroppedFiles((prev) =>
prev.filter((f) => f !== fileDetail[0])
);
const newDetails = new Map(droppedFileDetails);
newDetails.delete(fileDetail[0]);
setDroppedFileDetails(newDetails);
}}
/>
</div>
</div>
)
.reduce((acc, detail) => acc + detail.size, 0)
.toFixed(2)} KB`}</p>
)}
{ingesting && <Spinner size="sm" className="ml-2" />}
<div className="ml-auto flex space-x-2">
<Button
isIconOnly
size="sm"
startContent={<IoSettingsOutline />}
onClick={fileSettingModal.onOpen}
/>
<Button
size="sm"
startContent={<IoMdAdd />}
onClick={handleAddFiles}
>
Files
</Button>
<div className="flex justify-end mt-2">
{droppedFileDetails?.size > 0 &&
!ingesting &&
!ingestionError && (
<div className="flex justify-center">
<RiFoldersLine />
<p className="text-sm text-zinc-500 ml-2">{`${droppedFileDetails.size} ${droppedFileDetails.size === 1 ? 'file' : 'files'}, ${Array.from(
droppedFileDetails.values()
)
.reduce((acc, detail) => acc + detail.size, 0)
.toFixed(2)} KB`}</p>
</div>
)}
{ingesting && !ingestionError && (
<Spinner size="sm" className="ml-2" />
)}
{ingestionError && (
<>
<Button
isIconOnly
variant="flat"
color="primary"
size="sm"
startContent={<IoMdRefresh size={18} />}
onClick={ingest}
></Button>
<p className="text-sm text-red-500 ml-2">
{ingestionError}
</p>
</>
)}
</div>
</div>
<div
className={`flex ${collapsed ? 'flex-col space-y-2' : 'space-x-4'} ${droppedFileDetails.size > 0 ? 'pt-4' : ''}`}
>
<Button
className="w-full"
variant="flat"
color="primary"
isIconOnly
size="sm"
startContent={<IoSettingsOutline className="mr-2" />}
onPress={fileSettingModal.onOpen}
>
Settings
</Button>
<Button
className="w-full"
variant="flat"
color="primary"
isIconOnly
size="sm"
startContent={<IoMdAdd className="mr-2" />}
onPress={handleAddFiles}
>
Add Files
</Button>
</div>
</AccordionItem>
<AccordionItem
aria-label="advanced"
Expand Down Expand Up @@ -308,12 +365,9 @@ const Configure: React.FC<ConfigureProps> = ({ collapsed }) => {
: `Click "Refresh Chat" to chat with the updated version of ${placeholderName()}`
}
/>
<KnowledgeModals
<FileSettingModals
isFileSettingOpen={fileSettingModal.isOpen}
onFileSettingClose={fileSettingModal.onClose}
isFileTableOpen={fileTableModal.isOpen}
onFileTableClose={fileTableModal.onClose}
handleAddFiles={handleAddFiles}
/>
</>
);
Expand Down
77 changes: 1 addition & 76 deletions components/knowledge/KnowledgeModals.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,23 @@
import {
Button,
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader,
Slider,
Table,
TableBody,
TableCell,
TableColumn,
TableHeader,
TableRow,
} from '@nextui-org/react';
import { BiPlus, BiTrash } from 'react-icons/bi';
import { useContext } from 'react';
import { EditContext } from '@/contexts/edit';

interface KnowledgeProps {
isFileSettingOpen: boolean;
onFileSettingClose: () => void;
isFileTableOpen: boolean;
onFileTableClose: () => void;
handleAddFiles: () => void;
}

const KnowledgeModals = ({
isFileSettingOpen,
onFileSettingClose,
isFileTableOpen,
onFileTableClose,
handleAddFiles,
}: KnowledgeProps) => {
const {
topK,
setTopK,
droppedFileDetails,
setDroppedFileDetails,
setDroppedFiles,
} = useContext(EditContext);
const { topK, setTopK } = useContext(EditContext);
return (
<>
<Modal
Expand Down Expand Up @@ -72,60 +51,6 @@ const KnowledgeModals = ({
</ModalBody>
</ModalContent>
</Modal>
<Modal
size="xl"
backdrop="opaque"
isOpen={isFileTableOpen}
onClose={onFileTableClose}
>
<ModalContent>
<ModalHeader>
<h3 id="modal-title">Files</h3>
</ModalHeader>
<ModalBody>
<Table removeWrapper aria-label="File table">
<TableHeader>
<TableColumn>File Name</TableColumn>
<TableColumn>Size</TableColumn>
<TableColumn>{''}</TableColumn>
</TableHeader>
<TableBody>
{Array.from(droppedFileDetails).map((fileDetail, index) => (
<TableRow key={index}>
<TableCell>{fileDetail[1].fileName}</TableCell>
<TableCell>{fileDetail[1].size} KB</TableCell>
<TableCell align="right">
<Button
isIconOnly
size="md"
onClick={() => {
setDroppedFiles((prev) =>
prev.filter((f) => f !== fileDetail[0])
);
const newDetails = new Map(droppedFileDetails);
newDetails.delete(fileDetail[0]);
setDroppedFileDetails(newDetails);
}}
className="bg-white"
startContent={<BiTrash />}
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</ModalBody>
<ModalFooter>
<Button
className="w-full"
onClick={handleAddFiles}
startContent={<BiPlus />}
>
Add files
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
);
};
Expand Down
Loading