feat: add settings and search features
This commit is contained in:
parent
aa2d6e97f0
commit
c50cf1b096
30 changed files with 1374 additions and 1094 deletions
1175
cognee-frontend/package-lock.json
generated
1175
cognee-frontend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -11,7 +11,7 @@
|
|||
"dependencies": {
|
||||
"classnames": "^2.5.1",
|
||||
"next": "14.2.3",
|
||||
"ohmy-ui": "^0.0.1",
|
||||
"ohmy-ui": "^0.0.2",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"uuid": "^9.0.1"
|
||||
|
|
|
|||
|
|
@ -1,14 +1,20 @@
|
|||
.main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-direction: column;
|
||||
padding: 32px;
|
||||
min-height: 100vh;
|
||||
gap: 32px;
|
||||
}
|
||||
.main.noData {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.data {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
.datasetsView {
|
||||
width: 50%;
|
||||
transition: width 0.3s ease-in-out;
|
||||
|
|
@ -33,19 +39,3 @@
|
|||
width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
.noDataWizardContainer {
|
||||
width: 100%;
|
||||
margin-top: 96px;
|
||||
}
|
||||
|
||||
.wizardDataset {
|
||||
border: 2px solid white;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 24px;
|
||||
min-width: 350px;
|
||||
}
|
||||
|
||||
.fileSize {
|
||||
display: block;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
'use client';
|
||||
|
||||
import { Fragment, useCallback, useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import styles from "./page.module.css";
|
||||
import { CTAButton, H1, Notification, NotificationContainer, Stack, Text, UploadInput, useBoolean, useNotifications } from 'ohmy-ui';
|
||||
import { Notification, NotificationContainer, Text, useNotifications } from 'ohmy-ui';
|
||||
import useDatasets from '@/modules/ingestion/useDatasets';
|
||||
import DataView, { Data } from '@/modules/ingestion/DataView';
|
||||
import DatasetsView from '@/modules/ingestion/DatasetsView';
|
||||
import classNames from 'classnames';
|
||||
import { TextLogo, LoadingIndicator } from '@/modules/app';
|
||||
import { IFrameView } from '@/ui';
|
||||
import addData from '@/modules/ingestion/addData';
|
||||
import cognifyDataset from '@/modules/datasets/cognifyDataset';
|
||||
import deleteDataset from '@/modules/datasets/deleteDataset';
|
||||
import getDatasetData from '@/modules/datasets/getDatasetData';
|
||||
import getExplorationGraphUrl from '@/modules/exploration/getExplorationGraphUrl';
|
||||
import { Footer } from '@/ui/Partials';
|
||||
|
||||
export default function Home() {
|
||||
const {
|
||||
|
|
@ -19,26 +23,12 @@ export default function Home() {
|
|||
const [datasetData, setDatasetData] = useState<Data[]>([]);
|
||||
const [selectedDataset, setSelectedDataset] = useState<string | null>(null);
|
||||
|
||||
const {
|
||||
value: isWizardShown,
|
||||
setFalse: hideWizard,
|
||||
} = useBoolean(true);
|
||||
const [wizardStep, setWizardStep] = useState<'add' | 'upload' | 'cognify' | 'explore'>('add');
|
||||
const [wizardData, setWizardData] = useState<File[] | null>(null);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (datasets.length > 0) {
|
||||
// hideWizard();
|
||||
// }
|
||||
// }, [datasets, hideWizard]);
|
||||
|
||||
useEffect(() => {
|
||||
refreshDatasets();
|
||||
}, [refreshDatasets]);
|
||||
|
||||
const openDatasetData = (dataset: { id: string }) => {
|
||||
fetch(`http://0.0.0.0:8000/datasets/${dataset.id}/data`)
|
||||
.then((response) => response.json())
|
||||
getDatasetData(dataset)
|
||||
.then(setDatasetData)
|
||||
.then(() => setSelectedDataset(dataset.id));
|
||||
};
|
||||
|
|
@ -50,232 +40,67 @@ export default function Home() {
|
|||
|
||||
const { notifications, showNotification } = useNotifications();
|
||||
|
||||
const handleDataAdd = useCallback((dataset: { id: string }, files: File[]) => {
|
||||
const formData = new FormData();
|
||||
formData.append('datasetId', dataset.id);
|
||||
const file = files[0];
|
||||
formData.append('data', file, file.name);
|
||||
|
||||
return fetch('http://0.0.0.0:8000/add', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
})
|
||||
const onDataAdd = useCallback((dataset: { id: string }, files: File[]) => {
|
||||
return addData(dataset, files)
|
||||
.then(() => {
|
||||
showNotification("Data added successfully.", 5000);
|
||||
openDatasetData(dataset);
|
||||
});
|
||||
}, [showNotification])
|
||||
|
||||
const addWizardData = useCallback((files: File[]) => {
|
||||
setWizardData(files);
|
||||
setWizardStep('upload');
|
||||
}, []);
|
||||
|
||||
const {
|
||||
value: isUploadRunning,
|
||||
setTrue: disableUploadRun,
|
||||
setFalse: enableUploadRun,
|
||||
} = useBoolean(false);
|
||||
const uploadWizardData = useCallback(() => {
|
||||
disableUploadRun()
|
||||
handleDataAdd({ id: 'main' }, wizardData!)
|
||||
.then(() => {
|
||||
setWizardStep('cognify')
|
||||
})
|
||||
.finally(() => enableUploadRun());
|
||||
}, [disableUploadRun, enableUploadRun, handleDataAdd, wizardData]);
|
||||
|
||||
const cognifyDataset = useCallback((dataset: { id: string }) => {
|
||||
const onDatasetCognify = useCallback((dataset: { id: string }) => {
|
||||
showNotification(`Cognification started for dataset "${dataset.id}".`, 5000);
|
||||
|
||||
return fetch('http://0.0.0.0:8000/cognify', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
datasets: [dataset.id],
|
||||
}),
|
||||
})
|
||||
return cognifyDataset(dataset)
|
||||
.then(() => {
|
||||
showNotification(`Dataset "${dataset.id}" cognified.`, 5000);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
.catch(() => {
|
||||
showNotification(`Dataset "${dataset.id}" cognification failed. Please try again.`, 5000);
|
||||
});
|
||||
}, [showNotification]);
|
||||
|
||||
const {
|
||||
value: isCognifyRunning,
|
||||
setTrue: disableCognifyRun,
|
||||
setFalse: enableCognifyRun,
|
||||
} = useBoolean(false);
|
||||
const cognifyWizardData = useCallback(() => {
|
||||
disableCognifyRun();
|
||||
cognifyDataset({ id: 'main' })
|
||||
.then(() => {
|
||||
setWizardStep('explore');
|
||||
})
|
||||
.finally(() => enableCognifyRun());
|
||||
}, [cognifyDataset, disableCognifyRun, enableCognifyRun]);
|
||||
|
||||
const deleteDataset = useCallback((dataset: { id: string }) => {
|
||||
fetch(`http://0.0.0.0:8000/datasets/${dataset.id}`, {
|
||||
method: 'DELETE',
|
||||
})
|
||||
const onDatasetDelete = useCallback((dataset: { id: string }) => {
|
||||
deleteDataset(dataset)
|
||||
.then(() => {
|
||||
showNotification(`Dataset "${dataset.id}" deleted.`, 5000);
|
||||
refreshDatasets();
|
||||
})
|
||||
}, [refreshDatasets, showNotification]);
|
||||
|
||||
interface ExplorationWindowProps {
|
||||
url: string;
|
||||
title: string;
|
||||
}
|
||||
const [explorationWindowProps, setExplorationWindowProps] = useState<ExplorationWindowProps | null>(null);
|
||||
const {
|
||||
value: isExplorationWindowShown,
|
||||
setTrue: showExplorationWindow,
|
||||
setFalse: hideExplorationWindow,
|
||||
} = useBoolean(false);
|
||||
|
||||
const openExplorationWindow = useCallback((explorationWindowProps: ExplorationWindowProps) => {
|
||||
setExplorationWindowProps(explorationWindowProps);
|
||||
showExplorationWindow();
|
||||
}, [showExplorationWindow]);
|
||||
|
||||
const exploreDataset = useCallback((dataset: { id: string }) => {
|
||||
fetch(`http://0.0.0.0:8000/datasets/${dataset.id}/graph`)
|
||||
.then((response) => response.text())
|
||||
.then((text) => text.replace('"', ''))
|
||||
.then((graphUrl: string) => {
|
||||
openExplorationWindow({
|
||||
url: graphUrl,
|
||||
title: dataset.id,
|
||||
});
|
||||
});
|
||||
}, [openExplorationWindow]);
|
||||
|
||||
const exploreWizardData = useCallback(() => {
|
||||
exploreDataset({ id: 'main' });
|
||||
}, [exploreDataset]);
|
||||
|
||||
const closeWizard = useCallback(() => {
|
||||
hideExplorationWindow();
|
||||
hideWizard();
|
||||
}, [hideExplorationWindow, hideWizard]);
|
||||
|
||||
if (isWizardShown) {
|
||||
return (
|
||||
<main className={classNames(styles.main, styles.noData)}>
|
||||
<TextLogo />
|
||||
<Stack gap="4" orientation="vertical" align="center/center" className={styles.noDataWizardContainer}>
|
||||
<H1>Add Knowledge</H1>
|
||||
<Stack gap="4" orientation="vertical" align="center/center">
|
||||
{wizardStep === 'upload' && wizardData && (
|
||||
<div className={styles.wizardDataset}>
|
||||
{wizardData.map((file, index) => (
|
||||
<Fragment key={index}>
|
||||
<Text bold>{file.name}</Text>
|
||||
<Text className={styles.fileSize} size="small">
|
||||
{getBiggestUnitSize(file.size)}
|
||||
</Text>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{(wizardStep === 'add' || wizardStep === 'upload') && (
|
||||
<Text>No data in the system. Let's add your data.</Text>
|
||||
)}
|
||||
{wizardStep === 'cognify' && (
|
||||
<Text>Process data and make it explorable.</Text>
|
||||
)}
|
||||
{wizardStep === 'add' && (
|
||||
<UploadInput onChange={addWizardData}>
|
||||
<Text>Add data</Text>
|
||||
</UploadInput>
|
||||
)}
|
||||
{wizardStep === 'upload' && (
|
||||
<CTAButton disabled={isUploadRunning} onClick={uploadWizardData}>
|
||||
<Stack gap="2" orientation="horizontal" align="center/center">
|
||||
<Text>Upload</Text>
|
||||
{isUploadRunning && (
|
||||
<LoadingIndicator />
|
||||
)}
|
||||
</Stack>
|
||||
</CTAButton>
|
||||
)}
|
||||
{wizardStep === 'cognify' && (
|
||||
<>
|
||||
{isCognifyRunning && (
|
||||
<Text>Processing may take a minute, depending on data size.</Text>
|
||||
)}
|
||||
<CTAButton disabled={isCognifyRunning} onClick={cognifyWizardData}>
|
||||
<Stack gap="2" orientation="horizontal" align="center/center">
|
||||
<Text>Cognify</Text>
|
||||
{isCognifyRunning && (
|
||||
<LoadingIndicator />
|
||||
)}
|
||||
</Stack>
|
||||
</CTAButton>
|
||||
</>
|
||||
)}
|
||||
{wizardStep === 'explore' && (
|
||||
<>
|
||||
{!isExplorationWindowShown && (
|
||||
<CTAButton onClick={exploreWizardData}>
|
||||
<Text>Start exploring the data</Text>
|
||||
</CTAButton>
|
||||
)}
|
||||
{isExplorationWindowShown && (
|
||||
<IFrameView
|
||||
src={explorationWindowProps!.url}
|
||||
title={explorationWindowProps!.title}
|
||||
onClose={closeWizard}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
const onDatasetExplore = useCallback((dataset: { id: string }) => {
|
||||
return getExplorationGraphUrl(dataset);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<main className={styles.main}>
|
||||
<div className={classNames(styles.datasetsView, {
|
||||
[styles.openDatasetData]: datasetData.length > 0,
|
||||
})}>
|
||||
<DatasetsView
|
||||
datasets={datasets}
|
||||
onDataAdd={handleDataAdd}
|
||||
onDatasetClick={openDatasetData}
|
||||
onDatasetCognify={cognifyDataset}
|
||||
onDatasetDelete={deleteDataset}
|
||||
onDatasetExplore={exploreDataset}
|
||||
/>
|
||||
{isExplorationWindowShown && (
|
||||
<IFrameView
|
||||
src={explorationWindowProps!.url}
|
||||
title={explorationWindowProps!.title}
|
||||
onClose={hideExplorationWindow}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{datasetData.length > 0 && selectedDataset && (
|
||||
<div className={styles.dataView}>
|
||||
<DataView
|
||||
data={datasetData}
|
||||
datasetId={selectedDataset}
|
||||
onClose={closeDatasetData}
|
||||
onDataAdd={handleDataAdd}
|
||||
<div className={styles.data}>
|
||||
<div className={classNames(styles.datasetsView, {
|
||||
[styles.openDatasetData]: datasetData.length > 0,
|
||||
})}>
|
||||
<DatasetsView
|
||||
datasets={datasets}
|
||||
onDataAdd={onDataAdd}
|
||||
onDatasetClick={openDatasetData}
|
||||
onDatasetCognify={onDatasetCognify}
|
||||
onDatasetDelete={onDatasetDelete}
|
||||
onDatasetExplore={onDatasetExplore}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{datasetData.length > 0 && selectedDataset && (
|
||||
<div className={styles.dataView}>
|
||||
<DataView
|
||||
data={datasetData}
|
||||
datasetId={selectedDataset}
|
||||
onClose={closeDatasetData}
|
||||
onDataAdd={onDataAdd}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Footer />
|
||||
<NotificationContainer gap="1" bottom right>
|
||||
{notifications.map((notification, index) => (
|
||||
{notifications.map((notification, index: number) => (
|
||||
<Notification
|
||||
key={notification.id}
|
||||
isOpen={notification.isOpen}
|
||||
|
|
@ -290,14 +115,3 @@ export default function Home() {
|
|||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
function getBiggestUnitSize(sizeInBytes: number): string {
|
||||
const units = ['B', 'KB', 'MB', 'GB'];
|
||||
|
||||
let i = 0;
|
||||
while (sizeInBytes >= 1024 && i < units.length - 1) {
|
||||
sizeInBytes /= 1024;
|
||||
i++;
|
||||
}
|
||||
return `${sizeInBytes.toFixed(2)} ${units[i]}`;
|
||||
}
|
||||
|
|
|
|||
24
cognee-frontend/src/app/wizard/WizardPage.module.css
Normal file
24
cognee-frontend/src/app/wizard/WizardPage.module.css
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
.main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-direction: column;
|
||||
padding: 32px;
|
||||
min-height: 100vh;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
.wizardContainer {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wizardDataset {
|
||||
border: 2px solid white;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 24px;
|
||||
min-width: 350px;
|
||||
}
|
||||
|
||||
.fileSize {
|
||||
display: block;
|
||||
}
|
||||
198
cognee-frontend/src/app/wizard/WizardPage.tsx
Normal file
198
cognee-frontend/src/app/wizard/WizardPage.tsx
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
import { useCallback, useState } from 'react';
|
||||
import { IFrameView } from '@/ui';
|
||||
import { SettingsIcon } from '@/ui/Icons';
|
||||
import { LoadingIndicator, TextLogo } from '@/modules/app';
|
||||
import { CTAButton, GhostButton, H1, Stack, Text, UploadInput, useBoolean } from 'ohmy-ui';
|
||||
import { Footer, SettingsModal } from '@/ui/Partials';
|
||||
|
||||
import styles from './WizardPage.module.css';
|
||||
|
||||
interface ExplorationWindowConfig {
|
||||
url: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
interface WizardPageProps {
|
||||
onDataAdd: (dataset: { id: string }, files: File[]) => Promise<void>;
|
||||
onDataCognify: (dataset: { id: string }) => Promise<void>;
|
||||
onDataExplore: (dataset: { id: string }) => Promise<ExplorationWindowConfig>;
|
||||
onFinish: () => void;
|
||||
}
|
||||
|
||||
export default function WizardPage({
|
||||
onDataAdd,
|
||||
onDataCognify,
|
||||
onDataExplore,
|
||||
onFinish,
|
||||
}: WizardPageProps) {
|
||||
const [wizardStep, setWizardStep] = useState<'add' | 'upload' | 'cognify' | 'explore'>('add');
|
||||
const [wizardData, setWizardData] = useState<File[] | null>(null);
|
||||
|
||||
const addWizardData = useCallback((files: File[]) => {
|
||||
setWizardData(files);
|
||||
setWizardStep('upload');
|
||||
}, []);
|
||||
|
||||
const {
|
||||
value: isUploadRunning,
|
||||
setTrue: disableUploadRun,
|
||||
setFalse: enableUploadRun,
|
||||
} = useBoolean(false);
|
||||
const uploadWizardData = useCallback(() => {
|
||||
disableUploadRun()
|
||||
onDataAdd({ id: 'main' }, wizardData!)
|
||||
.then(() => {
|
||||
setWizardStep('cognify')
|
||||
})
|
||||
.finally(() => enableUploadRun());
|
||||
}, [disableUploadRun, enableUploadRun, onDataAdd, wizardData]);
|
||||
|
||||
const {
|
||||
value: isCognifyRunning,
|
||||
setTrue: disableCognifyRun,
|
||||
setFalse: enableCognifyRun,
|
||||
} = useBoolean(false);
|
||||
const cognifyWizardData = useCallback(() => {
|
||||
disableCognifyRun();
|
||||
onDataCognify({ id: 'main' })
|
||||
.then(() => {
|
||||
setWizardStep('explore');
|
||||
})
|
||||
.finally(() => enableCognifyRun());
|
||||
}, [onDataCognify, disableCognifyRun, enableCognifyRun]);
|
||||
|
||||
const {
|
||||
value: isExploreLoading,
|
||||
setTrue: startLoadingExplore,
|
||||
setFalse: finishLoadingExplore,
|
||||
} = useBoolean(false);
|
||||
|
||||
const [explorationWindowProps, setExplorationWindowProps] = useState<ExplorationWindowConfig | null>(null);
|
||||
|
||||
const {
|
||||
value: isExplorationWindowShown,
|
||||
setTrue: showExplorationWindow,
|
||||
} = useBoolean(false);
|
||||
|
||||
const openExplorationWindow = useCallback((explorationWindowProps: ExplorationWindowConfig) => {
|
||||
setExplorationWindowProps(explorationWindowProps);
|
||||
showExplorationWindow();
|
||||
}, [showExplorationWindow]);
|
||||
|
||||
const exploreWizardData = useCallback(() => {
|
||||
startLoadingExplore();
|
||||
onDataExplore({ id: 'main' })
|
||||
.then((exploreWindowConfig) => {
|
||||
openExplorationWindow(exploreWindowConfig);
|
||||
})
|
||||
.finally(() => {
|
||||
finishLoadingExplore();
|
||||
});
|
||||
}, [finishLoadingExplore, onDataExplore, openExplorationWindow, startLoadingExplore]);
|
||||
|
||||
const {
|
||||
value: isSettingsModalOpen,
|
||||
setTrue: openSettingsModal,
|
||||
setFalse: closeSettingsModal,
|
||||
} = useBoolean(false);
|
||||
|
||||
return (
|
||||
<main className={styles.main}>
|
||||
<Stack orientation="horizontal" gap="between" align="center">
|
||||
<TextLogo />
|
||||
<GhostButton onClick={openSettingsModal}>
|
||||
<SettingsIcon />
|
||||
</GhostButton>
|
||||
</Stack>
|
||||
<SettingsModal isOpen={isSettingsModalOpen} onClose={closeSettingsModal} />
|
||||
<Stack gap="4" orientation="vertical" align="center/center" className={styles.wizardContainer}>
|
||||
{wizardStep === 'explore'
|
||||
? (<H1>Explore the Knowledge</H1>)
|
||||
: (<H1>Add Knowledge</H1>)}
|
||||
<Stack gap="4" orientation="vertical" align="center/center">
|
||||
{wizardStep === 'upload' && wizardData && (
|
||||
<Stack gap="4" className={styles.wizardDataset}>
|
||||
{wizardData.map((file, index) => (
|
||||
<div key={index}>
|
||||
<Text bold>{file.name}</Text>
|
||||
<Text className={styles.fileSize} size="small">
|
||||
{getBiggestUnitSize(file.size)}
|
||||
</Text>
|
||||
</div>
|
||||
))}
|
||||
</Stack>
|
||||
)}
|
||||
{(wizardStep === 'add' || wizardStep === 'upload') && (
|
||||
<Text>No data in the system. Let's add your data.</Text>
|
||||
)}
|
||||
{wizardStep === 'cognify' && (
|
||||
<Text>Process data and make it explorable.</Text>
|
||||
)}
|
||||
{wizardStep === 'add' && (
|
||||
<UploadInput onChange={addWizardData}>
|
||||
<Text>Add data</Text>
|
||||
</UploadInput>
|
||||
)}
|
||||
{wizardStep === 'upload' && (
|
||||
<CTAButton disabled={isUploadRunning} onClick={uploadWizardData}>
|
||||
<Stack gap="2" orientation="horizontal" align="center/center">
|
||||
<Text>Upload</Text>
|
||||
{isUploadRunning && (
|
||||
<LoadingIndicator />
|
||||
)}
|
||||
</Stack>
|
||||
</CTAButton>
|
||||
)}
|
||||
{wizardStep === 'cognify' && (
|
||||
<>
|
||||
{isCognifyRunning && (
|
||||
<Text>Processing may take a minute, depending on data size.</Text>
|
||||
)}
|
||||
<CTAButton disabled={isCognifyRunning} onClick={cognifyWizardData}>
|
||||
<Stack gap="2" orientation="horizontal" align="center/center">
|
||||
<Text>Cognify</Text>
|
||||
{isCognifyRunning && (
|
||||
<LoadingIndicator />
|
||||
)}
|
||||
</Stack>
|
||||
</CTAButton>
|
||||
</>
|
||||
)}
|
||||
{wizardStep === 'explore' && (
|
||||
<>
|
||||
{!isExplorationWindowShown && (
|
||||
<CTAButton onClick={exploreWizardData}>
|
||||
<Stack gap="2" orientation="horizontal" align="center/center">
|
||||
<Text>Start exploring</Text>
|
||||
{isExploreLoading && (
|
||||
<LoadingIndicator />
|
||||
)}
|
||||
</Stack>
|
||||
</CTAButton>
|
||||
)}
|
||||
{isExplorationWindowShown && (
|
||||
<IFrameView
|
||||
src={explorationWindowProps!.url}
|
||||
title={explorationWindowProps!.title}
|
||||
onClose={onFinish}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Footer />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
function getBiggestUnitSize(sizeInBytes: number): string {
|
||||
const units = ['B', 'KB', 'MB', 'GB'];
|
||||
|
||||
let i = 0;
|
||||
while (sizeInBytes >= 1024 && i < units.length - 1) {
|
||||
sizeInBytes /= 1024;
|
||||
i++;
|
||||
}
|
||||
return `${sizeInBytes.toFixed(2)} ${units[i]}`;
|
||||
}
|
||||
32
cognee-frontend/src/app/wizard/page.tsx
Normal file
32
cognee-frontend/src/app/wizard/page.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
'use client';
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import WizardPage from './WizardPage';
|
||||
import addData from '@/modules/ingestion/addData';
|
||||
import cognifyDataset from '@/modules/datasets/cognifyDataset';
|
||||
import getExplorationGraphUrl from '@/modules/exploration/getExplorationGraphUrl';
|
||||
|
||||
export default function Page() {
|
||||
const onDataExplore = useCallback((dataset: { id: string }) => {
|
||||
return getExplorationGraphUrl(dataset)
|
||||
.then((explorationWindowUrl) => {
|
||||
return {
|
||||
url: explorationWindowUrl,
|
||||
title: dataset.id,
|
||||
};
|
||||
});
|
||||
}, []);
|
||||
|
||||
const finishWizard = useCallback(() => {
|
||||
window.location.href = '/';
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<WizardPage
|
||||
onDataAdd={addData}
|
||||
onDataCognify={cognifyDataset}
|
||||
onDataExplore={onDataExplore}
|
||||
onFinish={finishWizard}
|
||||
/>
|
||||
);
|
||||
}
|
||||
11
cognee-frontend/src/modules/datasets/cognifyDataset.ts
Normal file
11
cognee-frontend/src/modules/datasets/cognifyDataset.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
export default function cognifyDataset(dataset: { id: string }) {
|
||||
return fetch('http://0.0.0.0:8000/cognify', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
datasets: [dataset.id],
|
||||
}),
|
||||
}).then((response) => response.json());
|
||||
}
|
||||
5
cognee-frontend/src/modules/datasets/deleteDataset.ts
Normal file
5
cognee-frontend/src/modules/datasets/deleteDataset.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export default function deleteDataset(dataset: { id: string }) {
|
||||
return fetch(`http://0.0.0.0:8000/datasets/${dataset.id}`, {
|
||||
method: 'DELETE',
|
||||
})
|
||||
}
|
||||
4
cognee-frontend/src/modules/datasets/getDatasetData.ts
Normal file
4
cognee-frontend/src/modules/datasets/getDatasetData.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export default function getDatasetData(dataset: { id: string }) {
|
||||
return fetch(`http://0.0.0.0:8000/datasets/${dataset.id}/data`)
|
||||
.then((response) => response.json());
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
export default function getExplorationGraphUrl(dataset: { id: string }) {
|
||||
return fetch(`http://0.0.0.0:8000/datasets/${dataset.id}/graph`)
|
||||
.then((response) => response.text())
|
||||
.then((text) => text.replace('"', ''));
|
||||
}
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
import { DropdownMenu, GhostButton, Stack, Text, UploadInput, CTAButton } from "ohmy-ui";
|
||||
import styles from "./DatasetsView.module.css";
|
||||
import { useCallback, useState } from 'react';
|
||||
import { IFrameView } from '@/ui';
|
||||
import StatusIcon from './StatusIcon';
|
||||
import { LoadingIndicator } from '@/modules/app';
|
||||
import { DropdownMenu, GhostButton, Stack, Text, UploadInput, CTAButton, useBoolean, NeutralButton } from "ohmy-ui";
|
||||
import styles from "./DatasetsView.module.css";
|
||||
import { SearchView } from '@/ui/Partials';
|
||||
|
||||
interface Dataset {
|
||||
id: string;
|
||||
|
|
@ -10,13 +14,18 @@ interface Dataset {
|
|||
|
||||
const DatasetItem = GhostButton.mixClassName()("div")
|
||||
|
||||
interface ExplorationWindowConfig {
|
||||
url: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
interface DatasetsViewProps {
|
||||
datasets: Dataset[];
|
||||
onDataAdd: (dataset: Dataset, files: File[]) => void;
|
||||
onDatasetClick: (dataset: Dataset) => void;
|
||||
onDatasetDelete: (dataset: Dataset) => void;
|
||||
onDatasetCognify: (dataset: Dataset) => void;
|
||||
onDatasetExplore: (dataset: Dataset) => void;
|
||||
onDatasetCognify: (dataset: Dataset) => Promise<void>;
|
||||
onDatasetExplore: (dataset: Dataset) => Promise<string>;
|
||||
}
|
||||
|
||||
export default function DatasetsView({
|
||||
|
|
@ -27,9 +36,19 @@ export default function DatasetsView({
|
|||
onDatasetDelete,
|
||||
onDatasetExplore,
|
||||
}: DatasetsViewProps) {
|
||||
const {
|
||||
value: isCognifyRunning,
|
||||
setTrue: disableCognifyRun,
|
||||
setFalse: enableCognifyRun,
|
||||
} = useBoolean(false);
|
||||
|
||||
const handleCognifyDataset = (event: React.MouseEvent<HTMLButtonElement>, dataset: Dataset) => {
|
||||
event.stopPropagation();
|
||||
onDatasetCognify(dataset);
|
||||
|
||||
disableCognifyRun();
|
||||
|
||||
onDatasetCognify(dataset)
|
||||
.finally(() => enableCognifyRun());
|
||||
}
|
||||
|
||||
// const handleDatasetDelete = (event: React.MouseEvent<HTMLButtonElement>, dataset: Dataset) => {
|
||||
|
|
@ -37,52 +56,118 @@ export default function DatasetsView({
|
|||
// onDatasetDelete(dataset);
|
||||
// }
|
||||
|
||||
const [explorationWindowProps, setExplorationWindowProps] = useState<ExplorationWindowConfig | null>(null);
|
||||
const {
|
||||
value: isExplorationWindowShown,
|
||||
setTrue: showExplorationWindow,
|
||||
setFalse: hideExplorationWindow,
|
||||
} = useBoolean(false);
|
||||
|
||||
const openExplorationWindow = useCallback((explorationWindowProps: ExplorationWindowConfig) => {
|
||||
setExplorationWindowProps(explorationWindowProps);
|
||||
showExplorationWindow();
|
||||
}, [showExplorationWindow]);
|
||||
|
||||
const {
|
||||
value: isExploreLoading,
|
||||
setTrue: startLoadingExplore,
|
||||
setFalse: finishLoadingExplore,
|
||||
} = useBoolean(false);
|
||||
const handleExploreDataset = (event: React.MouseEvent<HTMLButtonElement>, dataset: Dataset) => {
|
||||
event.stopPropagation();
|
||||
onDatasetExplore(dataset);
|
||||
|
||||
startLoadingExplore();
|
||||
onDatasetExplore(dataset)
|
||||
.then((explorationWindowUrl) => {
|
||||
openExplorationWindow({
|
||||
url: explorationWindowUrl,
|
||||
title: dataset.id,
|
||||
});
|
||||
})
|
||||
.finally(() => finishLoadingExplore());
|
||||
}
|
||||
|
||||
const handleDataAdd = (dataset: Dataset, files: File[]) => {
|
||||
onDataAdd(dataset, files);
|
||||
}
|
||||
|
||||
const {
|
||||
value: isSearchWindowOpen,
|
||||
setTrue: openSearchWindow,
|
||||
setFalse: closeSearchWindow,
|
||||
} = useBoolean(false);
|
||||
|
||||
const handleSearchDataset = (event: React.MouseEvent<HTMLButtonElement>, dataset: Dataset) => {
|
||||
event.stopPropagation();
|
||||
openSearchWindow();
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack orientation="vertical" gap="4">
|
||||
{datasets.map((dataset) => (
|
||||
<DatasetItem key={dataset.id} onClick={() => onDatasetClick(dataset)}>
|
||||
<Stack orientation="horizontal" gap="between" align="start/center">
|
||||
<Text>{dataset.name}</Text>
|
||||
<Stack orientation="horizontal" gap="2" align="center">
|
||||
<StatusIcon status={dataset.status} />
|
||||
<DropdownMenu>
|
||||
<Stack gap="1" className={styles.datasetMenu} orientation="vertical">
|
||||
{dataset.status === 'DATASET_PROCESSING_FINISHED' ? (
|
||||
<CTAButton
|
||||
onClick={(event: React.MouseEvent<HTMLButtonElement>) => handleExploreDataset(event, dataset)}
|
||||
<>
|
||||
<Stack orientation="vertical" gap="4">
|
||||
{datasets.map((dataset) => (
|
||||
<DatasetItem key={dataset.id} onClick={() => onDatasetClick(dataset)}>
|
||||
<Stack orientation="horizontal" gap="between" align="start/center">
|
||||
<Text>{dataset.name}</Text>
|
||||
<Stack orientation="horizontal" gap="2" align="center">
|
||||
<StatusIcon status={dataset.status} />
|
||||
<DropdownMenu>
|
||||
<Stack gap="1" className={styles.datasetMenu} orientation="vertical">
|
||||
{dataset.status === 'DATASET_PROCESSING_FINISHED' ? (
|
||||
<>
|
||||
<CTAButton
|
||||
onClick={(event: React.MouseEvent<HTMLButtonElement>) => handleExploreDataset(event, dataset)}
|
||||
>
|
||||
<Stack gap="2" orientation="horizontal" align="center/center">
|
||||
<Text>Explore</Text>
|
||||
{isExploreLoading && (
|
||||
<LoadingIndicator />
|
||||
)}
|
||||
</Stack>
|
||||
</CTAButton>
|
||||
<NeutralButton
|
||||
onClick={(event: React.MouseEvent<HTMLButtonElement>) => handleSearchDataset(event, dataset)}
|
||||
>
|
||||
<Text>Search</Text>
|
||||
</NeutralButton>
|
||||
</>
|
||||
) : (
|
||||
<CTAButton
|
||||
onClick={(event: React.MouseEvent<HTMLButtonElement>) => handleCognifyDataset(event, dataset)}
|
||||
>
|
||||
<Stack gap="2" orientation="horizontal" align="center/center">
|
||||
<Text>Cognify</Text>
|
||||
{isCognifyRunning && (
|
||||
<LoadingIndicator />
|
||||
)}
|
||||
</Stack>
|
||||
</CTAButton>
|
||||
)}
|
||||
<UploadInput as={GhostButton} onChange={(files: File[]) => handleDataAdd(dataset, files)}>
|
||||
<Text>Add data</Text>
|
||||
</UploadInput>
|
||||
{/* <NegativeButton
|
||||
onClick={(event: React.MouseEvent<HTMLButtonElement>) => handleDatasetDelete(event, dataset)}
|
||||
>
|
||||
<Text>Explore</Text>
|
||||
</CTAButton>
|
||||
) : (
|
||||
<CTAButton
|
||||
onClick={(event: React.MouseEvent<HTMLButtonElement>) => handleCognifyDataset(event, dataset)}
|
||||
>
|
||||
<Text>Cognify</Text>
|
||||
</CTAButton>
|
||||
)}
|
||||
<UploadInput as={GhostButton} onChange={(files: File[]) => handleDataAdd(dataset, files)}>
|
||||
<Text>Add data</Text>
|
||||
</UploadInput>
|
||||
{/* <NegativeButton
|
||||
onClick={(event: React.MouseEvent<HTMLButtonElement>) => handleDatasetDelete(event, dataset)}
|
||||
>
|
||||
<Text>Delete</Text>
|
||||
</NegativeButton> */}
|
||||
</Stack>
|
||||
</DropdownMenu>
|
||||
<Text>Delete</Text>
|
||||
</NegativeButton> */}
|
||||
</Stack>
|
||||
</DropdownMenu>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</DatasetItem>
|
||||
))}
|
||||
</Stack>
|
||||
</DatasetItem>
|
||||
))}
|
||||
</Stack>
|
||||
{isSearchWindowOpen && (
|
||||
<SearchView onClose={closeSearchWindow} />
|
||||
)}
|
||||
{isExplorationWindowShown && (
|
||||
<IFrameView
|
||||
src={explorationWindowProps!.url}
|
||||
title={explorationWindowProps!.title}
|
||||
onClose={hideExplorationWindow}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
11
cognee-frontend/src/modules/ingestion/addData.ts
Normal file
11
cognee-frontend/src/modules/ingestion/addData.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
export default function addData(dataset: { id: string }, files: File[]) {
|
||||
const formData = new FormData();
|
||||
formData.append('datasetId', dataset.id);
|
||||
const file = files[0];
|
||||
formData.append('data', file, file.name);
|
||||
|
||||
return fetch('http://0.0.0.0:8000/add', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
}).then((response) => response.json());
|
||||
}
|
||||
|
|
@ -70,7 +70,10 @@ function useDatasets() {
|
|||
.then((datasets) => datasets.map((dataset: string) => ({ id: dataset, name: dataset })))
|
||||
.then((datasets) => {
|
||||
setDatasets(datasets);
|
||||
checkDatasetStatuses(datasets);
|
||||
|
||||
if (datasets.length > 0) {
|
||||
checkDatasetStatuses(datasets);
|
||||
}
|
||||
});
|
||||
}, [checkDatasetStatuses]);
|
||||
|
||||
|
|
|
|||
7
cognee-frontend/src/ui/Icons/DiscordIcon.tsx
Normal file
7
cognee-frontend/src/ui/Icons/DiscordIcon.tsx
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
export default function DiscordIcon({ width = 26, height = 20, color = 'currentColor', className = '' }) {
|
||||
return (
|
||||
<svg width={width} height={height} viewBox="0 0 26 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
|
||||
<path d="M21.8932 1.67459C20.1988 0.882007 18.4062 0.31885 16.5629 0C16.3116 0.460879 16.0836 0.934131 15.8798 1.41796C13.9218 1.11898 11.9297 1.11898 9.97166 1.41796C9.76656 0.933656 9.53639 0.460364 9.28207 0C7.43679 0.319052 5.64255 0.883808 3.9472 1.67921C0.93192 6.05499 -0.425956 11.3618 0.117059 16.6481C2.08567 18.1347 4.29746 19.2682 6.65387 19.9982C7.18384 19.269 7.65226 18.4971 8.05428 17.6903C7.28899 17.3987 6.55124 17.0394 5.84981 16.6167C6.03444 16.48 6.21907 16.3397 6.39077 16.1892C8.42961 17.1708 10.6634 17.6806 12.9262 17.6806C15.189 17.6806 17.4228 17.1708 19.4616 16.1892C19.6389 16.3369 19.8189 16.48 20.0026 16.6167C19.2998 17.0404 18.5605 17.4004 17.7935 17.6921C18.1952 18.4991 18.6637 19.271 19.1939 20C21.5524 19.2708 23.7659 18.1365 25.7353 16.6481C26.278 11.3587 24.9156 6.04922 21.8932 1.67459ZM8.6331 13.634C7.97676 13.5863 7.36544 13.2826 6.93095 12.7884C6.49646 12.2942 6.27361 11.649 6.31046 10.9919C6.26895 10.3336 6.4901 9.68562 6.92546 9.19004C7.36083 8.69446 7.97489 8.39167 8.6331 8.34803C8.95965 8.36785 9.27905 8.45212 9.57288 8.59599C9.8667 8.73985 10.1291 8.94046 10.3451 9.18624C10.561 9.43202 10.7261 9.71812 10.8309 10.028C10.9357 10.3379 10.9781 10.6655 10.9557 10.9919C10.9967 11.65 10.7754 12.2974 10.34 12.7926C9.90474 13.2878 9.29097 13.5903 8.6331 13.634ZM17.2184 13.634C16.562 13.5863 15.9507 13.2826 15.5162 12.7884C15.0817 12.2942 14.8589 11.649 14.8957 10.9919C14.8542 10.3336 15.0754 9.68562 15.5107 9.19004C15.9461 8.69446 16.5602 8.39167 17.2184 8.34803C17.5449 8.36785 17.8643 8.45212 18.1582 8.59599C18.452 8.73985 18.7144 8.94046 18.9303 9.18624C19.1463 9.43202 19.3114 9.71812 19.4162 10.028C19.521 10.3379 19.5634 10.6655 19.541 10.9919C19.582 11.6501 19.3605 12.2977 18.925 12.7929C18.4895 13.2881 17.8764 13.5906 17.2184 13.634Z" fill={color} />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
10
cognee-frontend/src/ui/Icons/GitHubIcon.tsx
Normal file
10
cognee-frontend/src/ui/Icons/GitHubIcon.tsx
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export default function GitHubIcon({ width = 24, height = 24, color = 'currentColor', className = '' }) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width={width} height={height} viewBox="0 0 28 28" className={className}>
|
||||
<g transform="translate(-1477 -38)">
|
||||
<rect width="28" height="28" transform="translate(1477 38)" fill={color} opacity="0" />
|
||||
<path d="M16.142,1.9A13.854,13.854,0,0,0,11.78,28.966c.641.128,1.155-.577,1.155-1.154v-1.86c-3.848.834-5.067-1.86-5.067-1.86a4.169,4.169,0,0,0-1.411-2.052c-1.283-.9.064-.834.064-.834a2.758,2.758,0,0,1,2.117,1.283c1.09,1.86,3.528,1.668,4.3,1.347a3.463,3.463,0,0,1,.321-1.86c-4.361-.77-6.735-3.335-6.735-6.8A6.863,6.863,0,0,1,8.381,10.3a3.977,3.977,0,0,1,.192-4.1,5.708,5.708,0,0,1,4.1,1.86,9.685,9.685,0,0,1,3.463-.513,10.968,10.968,0,0,1,3.463.449,5.773,5.773,0,0,1,4.1-1.8,4.169,4.169,0,0,1,.257,4.1,6.863,6.863,0,0,1,1.8,4.875c0,3.463-2.373,6.029-6.735,6.8a3.464,3.464,0,0,1,.321,1.86v3.977a1.155,1.155,0,0,0,1.219,1.155A13.918,13.918,0,0,0,16.142,1.9Z" transform="translate(1474.913 36.102)" fill="#fdfdfd"/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
66
cognee-frontend/src/ui/Icons/SettingsIcon.tsx
Normal file
66
cognee-frontend/src/ui/Icons/SettingsIcon.tsx
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
export default function SettingsIcon({ width = "32px", height = "32px", color = "white" }) {
|
||||
return (
|
||||
<svg fill={color} height={height} width={width} version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 397.516 397.516" xmlSpace="preserve">
|
||||
<g>
|
||||
<path d="M126.32,156.454c-37.993,0-68.901,30.911-68.901,68.905c0,37.991,30.909,68.9,68.901,68.9s68.9-30.909,68.9-68.9
|
||||
C195.22,187.365,164.311,156.454,126.32,156.454z M126.32,279.641c-29.932,0-54.283-24.351-54.283-54.281
|
||||
c0-29.934,24.352-54.286,54.283-54.286s54.282,24.353,54.282,54.286C180.602,255.29,156.251,279.641,126.32,279.641z"/>
|
||||
<path d="M241.133,193.697l-9.568-2.638c-1.085-0.299-2.955-2.038-3.333-3.102l-2.717-6.683l-0.152-0.346
|
||||
c-0.483-1.028-0.382-3.607,0.179-4.597l4.819-8.491c3.36-5.921,2.264-14.015-2.549-18.824l-23.776-23.779
|
||||
c-2.852-2.848-6.952-4.482-11.248-4.482c-2.723,0-5.341,0.669-7.57,1.935l-8.038,4.561c-0.324,0.184-1.251,0.458-2.478,0.458
|
||||
c-1.061,0-1.766-0.207-1.991-0.316l-8.275-3.484l-0.348-0.136c-1.068-0.385-2.818-2.276-3.121-3.375l-2.719-9.851
|
||||
c-1.81-6.563-8.307-11.511-15.113-11.511h-33.629c-6.807,0-13.303,4.949-15.11,11.508l-2.723,9.855
|
||||
c-0.303,1.101-2.06,3.003-3.132,3.393l-8.905,3.768l-0.378,0.173c-0.223,0.11-0.926,0.318-1.988,0.318
|
||||
c-1.202,0.001-2.109-0.267-2.429-0.448l-7.565-4.295c-2.231-1.266-4.851-1.936-7.575-1.936c-4.3,0-8.4,1.636-11.247,4.484
|
||||
l-23.782,23.778c-4.812,4.813-5.906,12.904-2.546,18.822l4.736,8.343c0.565,0.998,0.677,3.584,0.198,4.613
|
||||
c-1.323,2.844-4.967,8.298-6.713,9.848l-8.841,2.438C4.946,195.509,0,202.006,0,208.812v33.626c0,6.803,4.946,13.3,11.506,15.112
|
||||
l9.568,2.641c1.088,0.3,2.96,2.038,3.338,3.101l2.945,7.17l0.149,0.338c0.484,1.024,0.39,3.586-0.169,4.568l-4.362,7.68
|
||||
c-3.356,5.916-2.261,14.006,2.55,18.822l23.78,23.777c2.85,2.85,6.95,4.484,11.248,4.484l0,0c2.723,0,5.342-0.669,7.576-1.936
|
||||
l7.361-4.177c0.327-0.186,1.26-0.461,2.492-0.461c1.062,0,1.769,0.206,1.995,0.315l8.39,3.522l0.357,0.139
|
||||
c1.065,0.382,2.81,2.264,3.112,3.358l2.56,9.276c1.808,6.561,8.305,11.511,15.111,11.511h33.629
|
||||
c6.806,0,13.303-4.948,15.113-11.511l2.558-9.279c0.3-1.087,2.038-2.957,3.099-3.335l7.735-3.188l0.355-0.158
|
||||
c0.225-0.107,0.931-0.311,1.99-0.311c1.259,0,2.214,0.282,2.548,0.472l7.823,4.443c2.232,1.267,4.851,1.936,7.576,1.936
|
||||
c4.3,0,8.4-1.636,11.248-4.485l23.778-23.777c4.814-4.812,5.91-12.904,2.549-18.825l-4.441-7.82
|
||||
c-0.556-0.979-0.647-3.525-0.163-4.541l3.188-7.659l0.134-0.347c0.379-1.064,2.253-2.805,3.343-3.105l9.57-2.64
|
||||
c6.559-1.812,11.505-8.309,11.505-15.112v-33.623C252.641,202.006,247.695,195.508,241.133,193.697z M237.247,243.459
|
||||
l-9.568,2.64c-5.615,1.549-11.11,6.61-13.151,12.086l-2.914,7.023c-2.439,5.314-2.139,12.778,0.738,17.851l4.422,7.782
|
||||
c0.124,0.31,0.021,1.075-0.152,1.31L192.875,315.9c-0.096,0.073-0.467,0.233-0.944,0.233c-0.22,0-0.366-0.046-0.357-0.03
|
||||
l-7.824-4.443c-2.702-1.534-6.17-2.379-9.766-2.379c-2.072,0-5.137,0.288-8.082,1.641l-7.098,2.934
|
||||
c-5.479,2.037-10.544,7.533-12.093,13.151l-2.544,9.234c-0.13,0.305-0.73,0.766-1.066,0.82l-33.553,0.002
|
||||
c-0.331-0.045-0.946-0.513-1.064-0.78l-2.56-9.276c-1.546-5.609-6.598-11.106-12.064-13.157l-7.725-3.232
|
||||
c-2.97-1.383-6.063-1.678-8.155-1.678c-3.572,0-7.02,0.841-9.707,2.366l-7.32,4.155c-0.036,0.015-0.178,0.053-0.402,0.053
|
||||
c-0.478,0-0.85-0.161-0.913-0.204l-23.747-23.741c-0.204-0.268-0.309-1.036-0.206-1.304l4.36-7.676
|
||||
c2.873-5.058,3.185-12.52,0.766-17.839l-2.701-6.555c-2.037-5.48-7.535-10.548-13.153-12.097l-9.521-2.625
|
||||
c-0.309-0.132-0.778-0.748-0.822-1.035l-0.002-33.581c0.045-0.333,0.514-0.949,0.777-1.067l9.563-2.637
|
||||
c8.015-2.207,15.287-17.422,15.357-17.572c2.473-5.313,2.164-12.878-0.737-17.994l-4.718-8.307
|
||||
c-0.124-0.312-0.021-1.076,0.15-1.309l23.749-23.748c0.096-0.073,0.467-0.232,0.943-0.232c0.222,0,0.363,0.041,0.359,0.03
|
||||
l7.562,4.292c2.674,1.52,6.101,2.357,9.649,2.357c2.116,0,5.241-0.303,8.236-1.722l8.238-3.494
|
||||
c5.445-2.071,10.479-7.573,12.021-13.166l2.709-9.813c0.131-0.308,0.746-0.776,1.032-0.819l33.584-0.002
|
||||
c0.333,0.045,0.948,0.514,1.066,0.781l2.719,9.85c1.545,5.604,6.591,11.105,12.048,13.164l7.61,3.193
|
||||
c2.975,1.39,6.073,1.686,8.17,1.686c3.568,0,7.012-0.84,9.694-2.363l7.995-4.538c0.036-0.015,0.176-0.051,0.396-0.051
|
||||
c0.48,0,0.853,0.161,0.914,0.202l23.744,23.744c0.203,0.267,0.306,1.032,0.201,1.304l-4.819,8.493
|
||||
c-2.868,5.056-3.189,12.511-0.79,17.823l2.489,6.102c2.034,5.487,7.535,10.562,13.154,12.11l9.523,2.623
|
||||
c0.309,0.132,0.777,0.748,0.82,1.036l0.002,33.581C237.98,242.726,237.511,243.342,237.247,243.459z"/>
|
||||
<path d="M393.377,112.81l-6.573-1.953c-2.321-0.688-4.846-3.132-5.611-5.428l-1.713-4.439c-0.983-2.211-0.778-5.725,0.459-7.805
|
||||
l3.443-5.806c1.236-2.08,0.875-5.212-0.8-6.958L366.48,63.675c-1.679-1.746-4.794-2.232-6.922-1.076l-5.609,3.038
|
||||
c-2.13,1.154-5.636,1.198-7.793,0.097l-5.418-2.399c-2.262-0.866-4.599-3.496-5.199-5.843l-1.745-6.844
|
||||
c-0.598-2.345-3.066-4.304-5.487-4.352l-23.232-0.457c-2.42-0.048-4.965,1.814-5.654,4.133l-2.013,6.77
|
||||
c-0.691,2.321-3.129,4.861-5.42,5.645l-5.954,2.389c-2.19,1.027-5.692,0.856-7.772-0.38l-5.166-3.07
|
||||
c-2.083-1.237-5.215-0.876-6.96,0.805l-16.751,16.1c-1.742,1.676-2.226,4.793-1.073,6.921l3.159,5.831
|
||||
c1.153,2.13,1.23,5.645,0.169,7.813c-1.061,2.167-5.21,8.66-7.557,9.256l-6.643,1.693c-2.345,0.599-4.305,3.07-4.353,5.49
|
||||
l-0.456,23.228c-0.047,2.422,1.814,4.965,4.134,5.655l6.573,1.954c2.322,0.688,4.849,3.132,5.616,5.43l1.852,4.759
|
||||
c0.992,2.211,0.795,5.721-0.444,7.802l-3.113,5.241c-1.238,2.084-0.875,5.215,0.803,6.961l16.104,16.746
|
||||
c1.678,1.747,4.793,2.232,6.924,1.078l5.14-2.785c2.128-1.155,5.638-1.197,7.796-0.101l5.501,2.428
|
||||
c2.261,0.864,4.605,3.488,5.2,5.837l1.642,6.442c0.598,2.348,3.067,4.307,5.488,4.354l23.231,0.455
|
||||
c2.422,0.049,4.964-1.811,5.654-4.133l1.894-6.373c0.687-2.323,3.131-4.851,5.43-5.617l5.146-2.013
|
||||
c2.207-0.997,5.719-0.802,7.798,0.436l5.342,3.172c2.082,1.238,5.215,0.876,6.958-0.804l16.751-16.1
|
||||
c1.744-1.68,2.229-4.794,1.074-6.921l-2.962-5.467c-1.152-2.129-1.21-5.644-0.123-7.808l2.192-5.01
|
||||
c0.86-2.266,3.482-4.609,5.829-5.206l6.645-1.693c2.343-0.599,4.305-3.066,4.352-5.488l0.457-23.229
|
||||
C397.557,116.047,395.695,113.5,393.377,112.81z M314.236,170.826c-23.495-0.462-42.171-19.886-41.709-43.381
|
||||
c0.462-23.5,19.886-42.176,43.381-41.715c23.497,0.463,42.172,19.889,41.71,43.387
|
||||
C357.156,152.614,337.733,171.288,314.236,170.826z"/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
3
cognee-frontend/src/ui/Icons/index.ts
Normal file
3
cognee-frontend/src/ui/Icons/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export { default as GithubIcon } from './GitHubIcon';
|
||||
export { default as DiscordIcon } from './DiscordIcon';
|
||||
export { default as SettingsIcon } from './SettingsIcon';
|
||||
16
cognee-frontend/src/ui/Partials/Footer/Footer.module.css
Normal file
16
cognee-frontend/src/ui/Partials/Footer/Footer.module.css
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
.footer {
|
||||
padding: 24px 0;
|
||||
}
|
||||
|
||||
.leftSide {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.rightSide {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
}
|
||||
25
cognee-frontend/src/ui/Partials/Footer/Footer.tsx
Normal file
25
cognee-frontend/src/ui/Partials/Footer/Footer.tsx
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import Link from 'next/link';
|
||||
import { Stack } from 'ohmy-ui';
|
||||
import { DiscordIcon, GithubIcon } from '@/ui/Icons';
|
||||
import { TextLogo } from '@/modules/app';
|
||||
import styles from './Footer.module.css';
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className={styles.footer}>
|
||||
<Stack orientation="horizontal" gap="between">
|
||||
<div className={styles.leftSide}>
|
||||
<TextLogo width={92} height={24} />
|
||||
</div>
|
||||
<div className={styles.rightSide}>
|
||||
<Link target="_blank" href="https://github.com/topoteretes/cognee">
|
||||
<GithubIcon />
|
||||
</Link>
|
||||
<Link target="_blank" href="https://discord.gg/m63hxKsp4p">
|
||||
<DiscordIcon />
|
||||
</Link>
|
||||
</div>
|
||||
</Stack>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
.searchViewContainer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 30%;
|
||||
background: var(--global-background-default);
|
||||
border-radius: var(--border-radius);
|
||||
border: 1px solid white;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.searchContainer {
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
border-top: 2px solid white;
|
||||
}
|
||||
|
||||
.messages {
|
||||
flex: 1;
|
||||
padding-top: 24px;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 16px;
|
||||
border-radius: var(--border-radius);
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.userMessage {
|
||||
align-self: flex-end;
|
||||
background-color: #5858ff;
|
||||
}
|
||||
95
cognee-frontend/src/ui/Partials/SearchView/SearchView.tsx
Normal file
95
cognee-frontend/src/ui/Partials/SearchView/SearchView.tsx
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import { CTAButton, CloseIcon, GhostButton, Input, Spacer, Stack, Text } from 'ohmy-ui';
|
||||
import styles from './SearchView.module.css';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { v4 } from 'uuid';
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface SearchViewProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
interface Message {
|
||||
id: string;
|
||||
user: 'user' | 'system';
|
||||
text: string;
|
||||
}
|
||||
|
||||
export default function SearchView({ onClose }: SearchViewProps) {
|
||||
const [messages, setMessages] = useState<Message[]>([]);
|
||||
const [inputValue, setInputValue] = useState<string>("");
|
||||
|
||||
const handleInputChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setInputValue(event.target.value);
|
||||
}, []);
|
||||
|
||||
const handleSearchSubmit = useCallback((event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
|
||||
|
||||
setMessages((currentMessages) => [
|
||||
...currentMessages,
|
||||
{
|
||||
id: v4(),
|
||||
user: 'user',
|
||||
text: inputValue,
|
||||
},
|
||||
]);
|
||||
|
||||
fetch('http://localhost:8000/search', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query_params: {
|
||||
query: inputValue,
|
||||
},
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((systemMessage) => {
|
||||
setMessages((currentMessages) => [
|
||||
...currentMessages,
|
||||
{
|
||||
id: v4(),
|
||||
user: 'system',
|
||||
text: systemMessage,
|
||||
},
|
||||
]);
|
||||
setInputValue('');
|
||||
})
|
||||
}, [inputValue]);
|
||||
|
||||
return (
|
||||
<Stack className={styles.searchViewContainer}>
|
||||
<Stack gap="between" align="center/" orientation="horizontal">
|
||||
<Spacer horizontal="2">
|
||||
<Text>Search</Text>
|
||||
</Spacer>
|
||||
<GhostButton onClick={onClose}>
|
||||
<CloseIcon />
|
||||
</GhostButton>
|
||||
</Stack>
|
||||
<Stack className={styles.searchContainer}>
|
||||
<Stack gap="2" className={styles.messages} align="end">
|
||||
{messages.map((message) => (
|
||||
<Text
|
||||
key={message.id}
|
||||
className={classNames(styles.message, {
|
||||
[styles.userMessage]: message.user === "user",
|
||||
})}
|
||||
>
|
||||
{message.text}
|
||||
</Text>
|
||||
))}
|
||||
</Stack>
|
||||
<form onSubmit={handleSearchSubmit}>
|
||||
<Stack orientation="horizontal" gap="2">
|
||||
<Input value={inputValue} onChange={handleInputChange} name="searchInput" placeholder="Search" />
|
||||
<CTAButton type="submit">Search</CTAButton>
|
||||
</Stack>
|
||||
</form>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
122
cognee-frontend/src/ui/Partials/SettingsModal/SettingsModal.tsx
Normal file
122
cognee-frontend/src/ui/Partials/SettingsModal/SettingsModal.tsx
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
import { CTAButton, DropdownSelect, FormGroup, FormInput, FormLabel, H2, H3, Input, Modal, Spacer, Stack, useBoolean } from 'ohmy-ui';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
interface SelectOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export default function SettingsModal({ isOpen = false, onClose = () => {} }) {
|
||||
const [llmConfig, setLLMConfig] = useState<{ openAIApiKey: string }>();
|
||||
const [vectorDBConfig, setVectorDBConfig] = useState<{
|
||||
choice: SelectOption;
|
||||
options: SelectOption[];
|
||||
url: string;
|
||||
apiKey: string;
|
||||
}>();
|
||||
|
||||
const {
|
||||
value: isSaving,
|
||||
setTrue: startSaving,
|
||||
setFalse: stopSaving,
|
||||
} = useBoolean(false);
|
||||
|
||||
const saveConfig = (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
const newOpenAIApiKey = event.target.openAIApiKey.value;
|
||||
const newVectorDBChoice = vectorDBConfig?.choice.value;
|
||||
const newVectorDBUrl = event.target.vectorDBUrl.value;
|
||||
const newVectorDBApiKey = event.target.vectorDBApiKey.value;
|
||||
|
||||
startSaving();
|
||||
|
||||
fetch('http://0.0.0.0:8000/settings', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
llm: {
|
||||
openAIApiKey: newOpenAIApiKey,
|
||||
},
|
||||
vectorDB: {
|
||||
choice: newVectorDBChoice,
|
||||
url: newVectorDBUrl,
|
||||
apiKey: newVectorDBApiKey,
|
||||
},
|
||||
}),
|
||||
})
|
||||
.then(() => {
|
||||
onClose();
|
||||
})
|
||||
.finally(() => stopSaving());
|
||||
};
|
||||
|
||||
const handleVectorDBChange = useCallback((newChoice: SelectOption) => {
|
||||
setVectorDBConfig((config) => {
|
||||
if (config?.choice !== newChoice) {
|
||||
return {
|
||||
...config,
|
||||
choice: newChoice,
|
||||
url: '',
|
||||
apiKey: '',
|
||||
};
|
||||
}
|
||||
return config;
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchVectorDBChoices = async () => {
|
||||
const response = await fetch('http://0.0.0.0:8000/settings');
|
||||
const settings = await response.json();
|
||||
|
||||
setLLMConfig(settings.llm);
|
||||
setVectorDBConfig(settings.vectorDB);
|
||||
};
|
||||
isOpen && fetchVectorDBChoices();
|
||||
}, [isOpen]);
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<Stack gap="4" orientation="vertical" align="center/">
|
||||
<H2>Settings</H2>
|
||||
<form onSubmit={saveConfig} style={{ width: '100%' }}>
|
||||
<Stack gap="2" orientation="vertical">
|
||||
<H3>LLM Config</H3>
|
||||
<FormGroup orientation="vertical" align="center/" gap="1">
|
||||
<FormLabel>OpenAI API Key</FormLabel>
|
||||
<FormInput>
|
||||
<Input defaultValue={llmConfig?.openAIApiKey} name="openAIApiKey" placeholder="OpenAI API Key" />
|
||||
</FormInput>
|
||||
</FormGroup>
|
||||
|
||||
<H3>Vector Database Config</H3>
|
||||
<DropdownSelect
|
||||
value={vectorDBConfig?.choice}
|
||||
options={vectorDBConfig?.options}
|
||||
onChange={handleVectorDBChange}
|
||||
/>
|
||||
<FormGroup orientation="vertical" align="center/" gap="1">
|
||||
<FormLabel>Vector DB url</FormLabel>
|
||||
<FormInput>
|
||||
<Input defaultValue={vectorDBConfig?.url} name="vectorDBUrl" placeholder="Vector DB API url" />
|
||||
</FormInput>
|
||||
</FormGroup>
|
||||
<FormGroup orientation="vertical" align="center/" gap="1">
|
||||
<FormLabel>Vector DB API key</FormLabel>
|
||||
<FormInput>
|
||||
<Input defaultValue={vectorDBConfig?.apiKey} name="vectorDBApiKey" placeholder="Vector DB API key" />
|
||||
</FormInput>
|
||||
</FormGroup>
|
||||
<Stack align="/end">
|
||||
<Spacer top="2">
|
||||
<CTAButton type="submit">Save</CTAButton>
|
||||
</Spacer>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</form>
|
||||
</Stack>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
3
cognee-frontend/src/ui/Partials/index.ts
Normal file
3
cognee-frontend/src/ui/Partials/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export { default as Footer } from './Footer/Footer';
|
||||
export { default as SettingsModal } from './SettingsModal/SettingsModal';
|
||||
export { default as SearchView } from './SearchView/SearchView';
|
||||
|
|
@ -16,7 +16,7 @@ from cognee.config import Config
|
|||
config = Config()
|
||||
config.load()
|
||||
|
||||
from typing import Dict, Any, List, Union, Annotated
|
||||
from typing import Dict, Any, List, Union, Annotated, Literal
|
||||
from fastapi import FastAPI, HTTPException, Form, File, UploadFile, Query
|
||||
from fastapi.responses import JSONResponse, FileResponse
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
|
@ -229,6 +229,38 @@ async def search(payload: SearchPayload):
|
|||
)
|
||||
|
||||
|
||||
@app.get("/settings", response_model=dict)
|
||||
async def get_settings():
|
||||
from cognee.modules.settings import get_settings
|
||||
return get_settings()
|
||||
|
||||
|
||||
class LLMConfig(BaseModel):
|
||||
openAIApiKey: str
|
||||
|
||||
class VectorDBConfig(BaseModel):
|
||||
choice: Union[Literal["lancedb"], Literal["qdrant"], Literal["weaviate"]]
|
||||
url: str
|
||||
apiKey: str
|
||||
|
||||
class SettingsPayload(BaseModel):
|
||||
llm: LLMConfig | None = None
|
||||
vectorDB: VectorDBConfig | None = None
|
||||
|
||||
@app.post("/settings", response_model=dict)
|
||||
async def save_config(new_settings: SettingsPayload):
|
||||
from cognee.modules.settings import save_llm_config, save_vector_db_config
|
||||
|
||||
if hasattr(new_settings, "llm"):
|
||||
await save_llm_config(new_settings.llm)
|
||||
|
||||
if hasattr(new_settings, "vectorDB"):
|
||||
await save_vector_db_config(new_settings.vectorDB)
|
||||
|
||||
return JSONResponse(
|
||||
status_code = 200,
|
||||
content = "OK",
|
||||
)
|
||||
|
||||
def start_api_server(host: str = "0.0.0.0", port: int = 8000):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class InfrastructureConfig():
|
|||
llm_provider: str = config.llm_provider
|
||||
database_engine: DatabaseEngine = None
|
||||
vector_engine: VectorDBInterface = None
|
||||
vector_engine_choice: str = None
|
||||
graph_engine: GraphDBType = None
|
||||
llm_engine: LLMInterface = None
|
||||
classification_model = None
|
||||
|
|
@ -89,6 +90,7 @@ class InfrastructureConfig():
|
|||
if (config_entity is None or config_entity == "vector_engine") and self.vector_engine is None:
|
||||
try:
|
||||
from .databases.vector.weaviate_db import WeaviateAdapter
|
||||
config.load()
|
||||
|
||||
if config.weaviate_url is None and config.weaviate_api_key is None:
|
||||
raise EnvironmentError("Weaviate is not configured!")
|
||||
|
|
@ -98,7 +100,10 @@ class InfrastructureConfig():
|
|||
config.weaviate_api_key,
|
||||
embedding_engine = self.embedding_engine
|
||||
)
|
||||
self.vector_engine_choice = "weaviate"
|
||||
except (EnvironmentError, ModuleNotFoundError):
|
||||
config.load()
|
||||
|
||||
if config.qdrant_url and config.qdrant_api_key:
|
||||
from .databases.vector.qdrant.QDrantAdapter import QDrantAdapter
|
||||
|
||||
|
|
@ -107,8 +112,10 @@ class InfrastructureConfig():
|
|||
qdrant_api_key = config.qdrant_api_key,
|
||||
embedding_engine = self.embedding_engine
|
||||
)
|
||||
self.vector_engine_choice = "qdrant"
|
||||
else:
|
||||
from .databases.vector.lancedb.LanceDBAdapter import LanceDBAdapter
|
||||
config.load()
|
||||
lance_db_path = self.database_directory_path + "/cognee.lancedb"
|
||||
LocalStorage.ensure_directory_exists(lance_db_path)
|
||||
|
||||
|
|
@ -117,6 +124,8 @@ class InfrastructureConfig():
|
|||
api_key = None,
|
||||
embedding_engine = self.embedding_engine,
|
||||
)
|
||||
self.lance_db_path = lance_db_path
|
||||
self.vector_engine_choice = "lancedb"
|
||||
|
||||
if config_entity is not None:
|
||||
return getattr(self, config_entity)
|
||||
|
|
@ -124,6 +133,7 @@ class InfrastructureConfig():
|
|||
return {
|
||||
"llm_engine": self.llm_engine,
|
||||
"vector_engine": self.vector_engine,
|
||||
"vector_engine_choice": self.vector_engine_choice,
|
||||
"database_engine": self.database_engine,
|
||||
"system_root_directory": self.system_root_directory,
|
||||
"data_root_directory": self.data_root_directory,
|
||||
|
|
|
|||
3
cognee/modules/settings/__init__.py
Normal file
3
cognee/modules/settings/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from .get_settings import get_settings
|
||||
from .save_llm_config import save_llm_config
|
||||
from .save_vector_db_config import save_vector_db_config
|
||||
41
cognee/modules/settings/get_settings.py
Normal file
41
cognee/modules/settings/get_settings.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
from cognee.config import Config
|
||||
from cognee.infrastructure import infrastructure_config
|
||||
|
||||
config = Config()
|
||||
config.load()
|
||||
|
||||
def get_settings():
|
||||
vector_engine_choice = infrastructure_config.get_config()["vector_engine_choice"]
|
||||
vector_db_options = [{
|
||||
"value": "weaviate",
|
||||
"label": "Weaviate",
|
||||
}, {
|
||||
"value": "qdrant",
|
||||
"label": "Qdrant",
|
||||
}, {
|
||||
"value": "lancedb",
|
||||
"label": "LanceDB",
|
||||
}]
|
||||
|
||||
vector_db_config = dict(
|
||||
url = config.weaviate_url,
|
||||
apiKey = config.weaviate_api_key,
|
||||
choice = vector_db_options[0],
|
||||
options = vector_db_options,
|
||||
) if vector_engine_choice == "weaviate" else dict(
|
||||
url = config.qdrant_url,
|
||||
apiKey = config.qdrant_api_key,
|
||||
choice = vector_db_options[1],
|
||||
options = vector_db_options,
|
||||
) if vector_engine_choice == "qdrant" else dict(
|
||||
url = infrastructure_config.get_config("lance_db_path"),
|
||||
choice = vector_db_options[2],
|
||||
options = vector_db_options,
|
||||
)
|
||||
|
||||
return dict(
|
||||
llm = dict(
|
||||
openAIApiKey = config.openai_key[:-10] + "**********",
|
||||
),
|
||||
vectorDB = vector_db_config,
|
||||
)
|
||||
15
cognee/modules/settings/save_llm_config.py
Normal file
15
cognee/modules/settings/save_llm_config.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import os
|
||||
from pydantic import BaseModel
|
||||
from cognee.config import Config
|
||||
|
||||
config = Config()
|
||||
|
||||
class LLMConfig(BaseModel):
|
||||
openAIApiKey: str
|
||||
|
||||
async def save_llm_config(llm_config: LLMConfig):
|
||||
if "*" in llm_config.openAIApiKey:
|
||||
return
|
||||
|
||||
os.environ["OPENAI_API_KEY"] = llm_config.openAIApiKey
|
||||
config.load()
|
||||
44
cognee/modules/settings/save_vector_db_config.py
Normal file
44
cognee/modules/settings/save_vector_db_config.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import os
|
||||
from typing import Union, Literal
|
||||
from pydantic import BaseModel
|
||||
from cognee.config import Config
|
||||
from cognee.infrastructure import infrastructure_config
|
||||
|
||||
config = Config()
|
||||
|
||||
class VectorDBConfig(BaseModel):
|
||||
choice: Union[Literal["lancedb"], Literal["qdrant"], Literal["weaviate"]]
|
||||
url: str
|
||||
apiKey: str
|
||||
|
||||
async def save_vector_db_config(vector_db_config: VectorDBConfig):
|
||||
if vector_db_config.choice == "weaviate":
|
||||
os.environ["WEAVIATE_URL"] = vector_db_config.url
|
||||
os.environ["WEAVIATE_API_KEY"] = vector_db_config.apiKey
|
||||
|
||||
remove_qdrant_config()
|
||||
|
||||
if vector_db_config.choice == "qdrant":
|
||||
os.environ["QDRANT_URL"] = vector_db_config.url
|
||||
os.environ["QDRANT_API_KEY"] = vector_db_config.apiKey
|
||||
|
||||
remove_weaviate_config()
|
||||
|
||||
if vector_db_config.choice == "lancedb":
|
||||
remove_qdrant_config()
|
||||
remove_weaviate_config()
|
||||
|
||||
config.load()
|
||||
infrastructure_config.vector_engine = None
|
||||
|
||||
def remove_weaviate_config():
|
||||
if "WEAVIATE_URL" in os.environ:
|
||||
del os.environ["WEAVIATE_URL"]
|
||||
if "WEAVIATE_API_KEY" in os.environ:
|
||||
del os.environ["WEAVIATE_API_KEY"]
|
||||
|
||||
def remove_qdrant_config():
|
||||
if "QDRANT_URL" in os.environ:
|
||||
del os.environ["QDRANT_URL"]
|
||||
if "QDRANT_API_KEY" in os.environ:
|
||||
del os.environ["QDRANT_API_KEY"]
|
||||
Loading…
Add table
Reference in a new issue