feat: implement cognee ui redesign
This commit is contained in:
parent
8274cf9107
commit
65f1b25413
69 changed files with 998 additions and 719 deletions
46
cognee-frontend/package-lock.json
generated
46
cognee-frontend/package-lock.json
generated
|
|
@ -10,7 +10,7 @@
|
|||
"dependencies": {
|
||||
"classnames": "^2.5.1",
|
||||
"next": "14.2.3",
|
||||
"ohmy-ui": "^0.0.2",
|
||||
"ohmy-ui": "^0.0.3",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"uuid": "^9.0.1"
|
||||
|
|
@ -25,6 +25,45 @@
|
|||
"typescript": "^5"
|
||||
}
|
||||
},
|
||||
"../../../Guerrilla/ohmy-ui": {
|
||||
"version": "0.0.3",
|
||||
"extraneous": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"classnames": "^2.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.0.4",
|
||||
"next": "14.0.4",
|
||||
"postcss": "^8.4.32",
|
||||
"postcss-custom-media": "^10.0.2",
|
||||
"postcss-import": "^15.1.0",
|
||||
"postcss-preset-env": "^9.3.0",
|
||||
"rollup": "^4.17.2",
|
||||
"rollup-plugin-dts": "^6.1.0",
|
||||
"rollup-plugin-peer-deps-external": "^2.2.4",
|
||||
"rollup-plugin-postcss": "^4.0.2",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.24.5",
|
||||
"dev": true,
|
||||
|
|
@ -2853,8 +2892,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/ohmy-ui": {
|
||||
"version": "0.0.2",
|
||||
"license": "MIT",
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/ohmy-ui/-/ohmy-ui-0.0.3.tgz",
|
||||
"integrity": "sha512-GXtTZxbL+sXdlT26+mcSrqvUPUIWNUiZOtKT+0lxK6DglGezB0Y/NVQHBcsoPCzmXHY3wi4UBaCH6//8DjHKXA==",
|
||||
"dependencies": {
|
||||
"classnames": "^2.3.2"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"dependencies": {
|
||||
"classnames": "^2.5.1",
|
||||
"next": "14.2.3",
|
||||
"ohmy-ui": "^0.0.2",
|
||||
"ohmy-ui": "^0.0.3",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"uuid": "^9.0.1"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
:root {
|
||||
--max-width: 1100px;
|
||||
--border-radius: 12px;
|
||||
--border-radius: 2px;
|
||||
--font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono",
|
||||
"Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro",
|
||||
"Fira Mono", "Droid Sans Mono", "Courier New", monospace;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 32px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.main.noData {
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@
|
|||
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import styles from "./page.module.css";
|
||||
import { Notification, NotificationContainer, Text, useNotifications } from 'ohmy-ui';
|
||||
import { GhostButton, Notification, NotificationContainer, Spacer, Stack, Text, useBoolean, 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 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';
|
||||
import { Footer, SettingsModal } from '@/ui/Partials';
|
||||
import { TextLogo } from '@/ui/App';
|
||||
import { SettingsIcon } from '@/ui/Icons';
|
||||
|
||||
export default function Home() {
|
||||
const {
|
||||
|
|
@ -60,45 +60,49 @@ export default function Home() {
|
|||
});
|
||||
}, [showNotification]);
|
||||
|
||||
const onDatasetDelete = useCallback((dataset: { id: string }) => {
|
||||
deleteDataset(dataset)
|
||||
.then(() => {
|
||||
showNotification(`Dataset "${dataset.id}" deleted.`, 5000);
|
||||
refreshDatasets();
|
||||
})
|
||||
}, [refreshDatasets, showNotification]);
|
||||
|
||||
const onDatasetExplore = useCallback((dataset: { id: string }) => {
|
||||
return getExplorationGraphUrl(dataset);
|
||||
}, []);
|
||||
const {
|
||||
value: isSettingsModalOpen,
|
||||
setTrue: openSettingsModal,
|
||||
setFalse: closeSettingsModal,
|
||||
} = useBoolean(false);
|
||||
|
||||
return (
|
||||
<main className={styles.main}>
|
||||
<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}
|
||||
<Spacer inset vertical="1" horizontal="2">
|
||||
<Stack orientation="horizontal" gap="between" align="center">
|
||||
<TextLogo width={225} height={64} />
|
||||
<GhostButton hugContent onClick={openSettingsModal}>
|
||||
<SettingsIcon />
|
||||
</GhostButton>
|
||||
</Stack>
|
||||
</Spacer>
|
||||
<SettingsModal isOpen={isSettingsModalOpen} onClose={closeSettingsModal} />
|
||||
<Spacer inset vertical="1" horizontal="3">
|
||||
<div className={styles.data}>
|
||||
<div className={classNames(styles.datasetsView, {
|
||||
[styles.openDatasetData]: datasetData.length > 0,
|
||||
})}>
|
||||
<DatasetsView
|
||||
datasets={datasets}
|
||||
onDatasetClick={openDatasetData}
|
||||
onDatasetCognify={onDatasetCognify}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Footer />
|
||||
{datasetData.length > 0 && selectedDataset && (
|
||||
<div className={styles.dataView}>
|
||||
<DataView
|
||||
data={datasetData}
|
||||
datasetId={selectedDataset}
|
||||
onClose={closeDatasetData}
|
||||
onDataAdd={onDataAdd}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Spacer>
|
||||
<Spacer inset horizontal="3" wrap>
|
||||
<Footer />
|
||||
</Spacer>
|
||||
<NotificationContainer gap="1" bottom right>
|
||||
{notifications.map((notification, index: number) => (
|
||||
<Notification
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
.files {
|
||||
width: 100%;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.fileSize {
|
||||
display: block;
|
||||
}
|
||||
97
cognee-frontend/src/app/wizard/AddStep/AddStep.tsx
Normal file
97
cognee-frontend/src/app/wizard/AddStep/AddStep.tsx
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import { useCallback, useState } from 'react';
|
||||
import { CTAButton, GhostButton, Stack, Text, TrashIcon, UploadIcon, UploadInput, useBoolean } from 'ohmy-ui';
|
||||
import { Divider } from '@/ui/Layout';
|
||||
import addData from '@/modules/ingestion/addData';
|
||||
import { LoadingIndicator } from '@/ui/App';
|
||||
import styles from './AddStep.module.css';
|
||||
import { WizardHeading } from '@/ui/Partials/Wizard';
|
||||
|
||||
interface ConfigStepProps {
|
||||
onNext: () => void;
|
||||
}
|
||||
|
||||
export default function AddStep({ onNext }: ConfigStepProps) {
|
||||
const [files, setFiles] = useState<File[]>([]);
|
||||
|
||||
const {
|
||||
value: isUploading,
|
||||
setTrue: disableUploading,
|
||||
setFalse: enableUploading,
|
||||
} = useBoolean(false);
|
||||
|
||||
const uploadFiles = useCallback(() => {
|
||||
disableUploading()
|
||||
addData({ id: 'main' }, files)
|
||||
.then(() => {
|
||||
onNext();
|
||||
})
|
||||
.finally(() => enableUploading());
|
||||
}, [disableUploading, enableUploading, files, onNext]);
|
||||
|
||||
const addFiles = useCallback((files: File[]) => {
|
||||
setFiles((existingFiles) => {
|
||||
const newFiles = files.filter((file) => !existingFiles.some((existingFile) => existingFile.name === file.name));
|
||||
|
||||
return [...existingFiles, ...newFiles]
|
||||
});
|
||||
}, []);
|
||||
|
||||
const removeFile = useCallback((file: File) => {
|
||||
setFiles((files) => files.filter((f) => f !== file));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Stack orientation="vertical" gap="6">
|
||||
<WizardHeading><Text light size="large">Step 2/3</Text> Add knowledge</WizardHeading>
|
||||
<Divider />
|
||||
<Text align="center">
|
||||
Cognee lets you process your personal data, books, articles or company data.
|
||||
Simply add datasets to get started.
|
||||
</Text>
|
||||
<Stack gap="1">
|
||||
<UploadInput onChange={addFiles}>
|
||||
<Stack gap="2" orientation="horizontal" align="center/center">
|
||||
<UploadIcon key={files.length} />
|
||||
<Text>Upload your data</Text>
|
||||
</Stack>
|
||||
</UploadInput>
|
||||
<Stack gap="3" className={styles.files}>
|
||||
{files.map((file, index) => (
|
||||
<Stack gap="between" orientation="horizontal" align="center/" key={index}>
|
||||
<div key={index}>
|
||||
<Text bold>{file.name}</Text>
|
||||
<Text className={styles.fileSize} size="small">
|
||||
{getBiggestUnitSize(file.size)}
|
||||
</Text>
|
||||
</div>
|
||||
<GhostButton hugContent onClick={() => removeFile(file)}>
|
||||
<TrashIcon />
|
||||
</GhostButton>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Stack align="/end">
|
||||
<CTAButton disabled={isUploading || files.length === 0} onClick={uploadFiles}>
|
||||
<Stack gap="2" orientation="horizontal" align="center/center">
|
||||
<Text>Next</Text>
|
||||
{isUploading && (
|
||||
<LoadingIndicator />
|
||||
)}
|
||||
</Stack>
|
||||
</CTAButton>
|
||||
</Stack>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
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]}`;
|
||||
}
|
||||
1
cognee-frontend/src/app/wizard/AddStep/index.ts
Normal file
1
cognee-frontend/src/app/wizard/AddStep/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default } from './AddStep';
|
||||
47
cognee-frontend/src/app/wizard/CognifyStep/CognifyStep.tsx
Normal file
47
cognee-frontend/src/app/wizard/CognifyStep/CognifyStep.tsx
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { useCallback, useEffect } from 'react';
|
||||
import { CTAButton, Spacer, Stack, Text, useBoolean } from 'ohmy-ui';
|
||||
import { Divider } from '@/ui/Layout';
|
||||
import { CognifyLoadingIndicator, LoadingIndicator } from '@/ui/App';
|
||||
import { getExplorationGraphUrl } from '@/modules/exploration';
|
||||
import { WizardHeading } from '@/ui/Partials/Wizard';
|
||||
import cognifyDataset from '@/modules/datasets/cognifyDataset';
|
||||
|
||||
interface ConfigStepProps {
|
||||
onNext: () => void;
|
||||
dataset: { id: string }
|
||||
}
|
||||
|
||||
export default function CognifyStep({ onNext, dataset }: ConfigStepProps) {
|
||||
const {
|
||||
value: isCognifyRunning,
|
||||
setFalse: stopCognifyIndicator,
|
||||
} = useBoolean(true);
|
||||
|
||||
useEffect(() => {
|
||||
cognifyDataset(dataset)
|
||||
.then(() => {
|
||||
stopCognifyIndicator();
|
||||
});
|
||||
}, [stopCognifyIndicator, dataset]);
|
||||
|
||||
return (
|
||||
<Stack orientation="vertical" gap="6">
|
||||
<WizardHeading><Text light size="large">Step 3/3</Text> Cognify</WizardHeading>
|
||||
<Divider />
|
||||
|
||||
<Stack align="/center">
|
||||
<CognifyLoadingIndicator isLoading={isCognifyRunning} />
|
||||
</Stack>
|
||||
|
||||
<Text align="center">
|
||||
Cognee decomposes your data into facts and connects them in relevant clusters,
|
||||
so that you can navigate your knowledge better.
|
||||
</Text>
|
||||
<CTAButton disabled={isCognifyRunning} onClick={onNext}>
|
||||
<Stack gap="2" orientation="horizontal" align="center/center">
|
||||
<Text>Explore data</Text>
|
||||
</Stack>
|
||||
</CTAButton>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
1
cognee-frontend/src/app/wizard/CognifyStep/index.ts
Normal file
1
cognee-frontend/src/app/wizard/CognifyStep/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default } from './CognifyStep';
|
||||
22
cognee-frontend/src/app/wizard/ConfigStep/ConfigStep.tsx
Normal file
22
cognee-frontend/src/app/wizard/ConfigStep/ConfigStep.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { Stack, Text } from 'ohmy-ui';
|
||||
import { Divider } from '@/ui/Layout';
|
||||
import Settings from '@/ui/Partials/SettingsModal/Settings';
|
||||
import { WizardContent, WizardHeading } from '@/ui/Partials/Wizard';
|
||||
|
||||
interface ConfigStepProps {
|
||||
onNext: () => void;
|
||||
}
|
||||
|
||||
export default function ConfigStep({ onNext }: ConfigStepProps) {
|
||||
return (
|
||||
<Stack orientation="vertical" gap="6">
|
||||
<WizardHeading><Text light size="large">Step 1/3</Text> Basic configuration</WizardHeading>
|
||||
<Divider />
|
||||
<Text align="center">
|
||||
Cognee helps you process your data and create a mind-like structure you can explore.
|
||||
To get started you need an OpenAI API key.
|
||||
</Text>
|
||||
<Settings onDone={onNext} submitButtonText="Next" />
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
1
cognee-frontend/src/app/wizard/ConfigStep/index.ts
Normal file
1
cognee-frontend/src/app/wizard/ConfigStep/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default } from './ConfigStep';
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
.explorer {
|
||||
flex: 1;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.explorerContent {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.graphExplorer {
|
||||
width: 65%;
|
||||
overflow: hidden;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.chat {
|
||||
width: 35%;
|
||||
display: flex;
|
||||
}
|
||||
14
cognee-frontend/src/app/wizard/ExploreStep/ExploreStep.tsx
Normal file
14
cognee-frontend/src/app/wizard/ExploreStep/ExploreStep.tsx
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { Explorer } from '@/ui/Partials';
|
||||
import { Spacer } from 'ohmy-ui';
|
||||
|
||||
interface ExploreStepProps {
|
||||
dataset: { id: string };
|
||||
}
|
||||
|
||||
export default function ExploreStep({ dataset }: ExploreStepProps) {
|
||||
return (
|
||||
<Spacer horizontal="3">
|
||||
<Explorer dataset={dataset!} />
|
||||
</Spacer>
|
||||
)
|
||||
}
|
||||
1
cognee-frontend/src/app/wizard/ExploreStep/index.ts
Normal file
1
cognee-frontend/src/app/wizard/ExploreStep/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default } from './ExploreStep';
|
||||
|
|
@ -2,23 +2,12 @@
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-direction: column;
|
||||
padding: 32px;
|
||||
padding: 0;
|
||||
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;
|
||||
display: flex;
|
||||
padding: 24px 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,198 +1,83 @@
|
|||
import { useCallback, useState } from 'react';
|
||||
import { IFrameView } from '@/ui';
|
||||
import { useState } from 'react';
|
||||
import { CloseIcon, GhostButton, Spacer, Stack, useBoolean } from 'ohmy-ui';
|
||||
import { TextLogo } from '@/ui/App';
|
||||
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 ConfigStep from './ConfigStep';
|
||||
import AddStep from './AddStep';
|
||||
import CognifyStep from './CognifyStep';
|
||||
import ExploreStep from './ExploreStep';
|
||||
import { WizardContent } from '@/ui/Partials/Wizard';
|
||||
|
||||
import styles from './WizardPage.module.css';
|
||||
|
||||
interface ExplorationWindowConfig {
|
||||
url: string;
|
||||
title: string;
|
||||
}
|
||||
import { Divider } from '@/ui/Layout';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
|
||||
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 searchParams = useSearchParams()
|
||||
const presetWizardStep = searchParams.get('step') as 'config';
|
||||
const [wizardStep, setWizardStep] = useState<'config' | 'add' | 'cognify' | 'explore'>(presetWizardStep || 'config');
|
||||
const {
|
||||
value: isSettingsModalOpen,
|
||||
setTrue: openSettingsModal,
|
||||
setFalse: closeSettingsModal,
|
||||
} = useBoolean(false);
|
||||
|
||||
const dataset = { id: 'main' };
|
||||
|
||||
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>
|
||||
<Spacer inset vertical="1" horizontal="2">
|
||||
<Stack orientation="horizontal" gap="between" align="center">
|
||||
<TextLogo width={225} height={64} />
|
||||
{wizardStep === 'explore' && (
|
||||
<GhostButton hugContent onClick={onFinish}>
|
||||
<CloseIcon />
|
||||
</GhostButton>
|
||||
)}
|
||||
{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}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
<GhostButton hugContent onClick={openSettingsModal}>
|
||||
<SettingsIcon />
|
||||
</GhostButton>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Footer />
|
||||
</Spacer>
|
||||
<Divider />
|
||||
<SettingsModal isOpen={isSettingsModalOpen} onClose={closeSettingsModal} />
|
||||
<div className={styles.wizardContainer}>
|
||||
{wizardStep === 'config' && (
|
||||
<WizardContent>
|
||||
<ConfigStep onNext={() => setWizardStep('add')} />
|
||||
</WizardContent>
|
||||
)}
|
||||
|
||||
{wizardStep === 'add' && (
|
||||
<WizardContent>
|
||||
<AddStep onNext={() => setWizardStep('cognify')} />
|
||||
</WizardContent>
|
||||
)}
|
||||
|
||||
{wizardStep === 'cognify' && (
|
||||
<WizardContent>
|
||||
<CognifyStep dataset={dataset} onNext={() => setWizardStep('explore')} />
|
||||
</WizardContent>
|
||||
)}
|
||||
|
||||
{wizardStep === 'explore' && (
|
||||
<Spacer inset top="4" bottom="1" horizontal="4">
|
||||
<ExploreStep dataset={dataset} onClose={onFinish} />
|
||||
</Spacer>
|
||||
)}
|
||||
</div>
|
||||
<Spacer inset horizontal="3" wrap>
|
||||
<Footer />
|
||||
</Spacer>
|
||||
</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]}`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,30 +2,14 @@
|
|||
|
||||
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}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
export { default as LoadingIndicator } from './LoadingIndicator';
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
export { default as Logo } from './Logo';
|
||||
export { default as TextLogo } from './TextLogo';
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
export { default as Logo } from './Logo/Logo';
|
||||
export { default as TextLogo } from './Logo/TextLogo';
|
||||
export { default as LoadingIndicator } from './Loading/LoadingIndicator';
|
||||
1
cognee-frontend/src/modules/exploration/index.ts
Normal file
1
cognee-frontend/src/modules/exploration/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default as getExplorationGraphUrl } from './getExplorationGraphUrl';
|
||||
|
|
@ -30,7 +30,7 @@ interface DataViewProps {
|
|||
}
|
||||
|
||||
export default function DataView({ datasetId, data, onClose, onDataAdd }: DataViewProps) {
|
||||
const handleDataDelete = () => {};
|
||||
// const handleDataDelete = () => {};
|
||||
const [rawData, setRawData] = useState<ArrayBuffer | null>(null);
|
||||
const [selectedData, setSelectedData] = useState<Data | null>(null);
|
||||
|
||||
|
|
@ -40,6 +40,8 @@ export default function DataView({ datasetId, data, onClose, onDataAdd }: DataVi
|
|||
fetch(`http://0.0.0.0:8000/datasets/${datasetId}/data/${dataItem.id}/raw`)
|
||||
.then((response) => response.arrayBuffer())
|
||||
.then(setRawData);
|
||||
|
||||
document.body.click(); // Close the dropdown menu.
|
||||
}, [datasetId]);
|
||||
|
||||
const resetDataPreview = useCallback(() => {
|
||||
|
|
@ -54,10 +56,12 @@ export default function DataView({ datasetId, data, onClose, onDataAdd }: DataVi
|
|||
return (
|
||||
<Stack orientation="vertical" gap="4">
|
||||
<Stack gap="2" orientation="horizontal" align="/end">
|
||||
<UploadInput onChange={handleDataAdd}>
|
||||
<Text>Add data</Text>
|
||||
</UploadInput>
|
||||
<GhostButton onClick={onClose}>
|
||||
<div>
|
||||
<UploadInput onChange={handleDataAdd}>
|
||||
<Text>Add data</Text>
|
||||
</UploadInput>
|
||||
</div>
|
||||
<GhostButton hugContent onClick={onClose}>
|
||||
<CloseIcon />
|
||||
</GhostButton>
|
||||
</Stack>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
.dataPreviewModal {
|
||||
left: 5% !important;
|
||||
padding: 0 !important;
|
||||
max-width: 90% !important;
|
||||
height: 80%;
|
||||
top: 5% !important;
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
import { IFrameView } from '@/ui';
|
||||
import { IFrameView } from '@/ui/Partials';
|
||||
import { CloseIcon, GhostButton, Modal, Spacer, Stack, Text } from 'ohmy-ui';
|
||||
import styles from './RawDataPreview.module.css';
|
||||
|
||||
interface RawDataPreviewProps {
|
||||
fileName: string;
|
||||
|
|
@ -12,11 +14,12 @@ export default function RawDataPreview({ fileName, rawData, onClose }: RawDataPr
|
|||
const src = `data:application/pdf;base64,${arrayBufferToBase64(rawData)}`.replace(';', file_header + encodeURIComponent(fileName) + ';');
|
||||
|
||||
return (
|
||||
<IFrameView
|
||||
src={src}
|
||||
title={fileName}
|
||||
onClose={onClose}
|
||||
/>
|
||||
<Modal isOpen onClose={onClose} className={styles.dataPreviewModal}>
|
||||
<Spacer horizontal="2" vertical="3" wrap>
|
||||
<Text>{fileName}</Text>
|
||||
</Spacer>
|
||||
<IFrameView src={src} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,3 +4,13 @@
|
|||
border-radius: var(--border-radius);
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.explorerModal {
|
||||
left: 5% !important;
|
||||
padding: 0 !important;
|
||||
max-width: 90% !important;
|
||||
height: 80%;
|
||||
top: 5% !important;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { useCallback, useState } from 'react';
|
||||
import { IFrameView } from '@/ui';
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Explorer } from '@/ui/Partials';
|
||||
import StatusIcon from './StatusIcon';
|
||||
import { LoadingIndicator } from '@/modules/app';
|
||||
import { DropdownMenu, GhostButton, Stack, Text, UploadInput, CTAButton, useBoolean, NeutralButton } from "ohmy-ui";
|
||||
import { LoadingIndicator } from '@/ui/App';
|
||||
import { DropdownMenu, GhostButton, Stack, Text, CTAButton, useBoolean, Modal, Spacer } from "ohmy-ui";
|
||||
import styles from "./DatasetsView.module.css";
|
||||
import { SearchView } from '@/ui/Partials';
|
||||
|
||||
interface Dataset {
|
||||
id: string;
|
||||
|
|
@ -12,29 +12,18 @@ interface Dataset {
|
|||
status: string;
|
||||
}
|
||||
|
||||
const DatasetItem = GhostButton.mixClassName()("div")
|
||||
|
||||
interface ExplorationWindowConfig {
|
||||
url: string;
|
||||
title: string;
|
||||
}
|
||||
const DatasetItem = GhostButton.remix({ Component: 'div' });
|
||||
|
||||
interface DatasetsViewProps {
|
||||
datasets: Dataset[];
|
||||
onDataAdd: (dataset: Dataset, files: File[]) => void;
|
||||
onDatasetClick: (dataset: Dataset) => void;
|
||||
onDatasetDelete: (dataset: Dataset) => void;
|
||||
onDatasetCognify: (dataset: Dataset) => Promise<void>;
|
||||
onDatasetExplore: (dataset: Dataset) => Promise<string>;
|
||||
}
|
||||
|
||||
export default function DatasetsView({
|
||||
datasets,
|
||||
onDatasetClick,
|
||||
onDataAdd,
|
||||
onDatasetCognify,
|
||||
onDatasetDelete,
|
||||
onDatasetExplore,
|
||||
}: DatasetsViewProps) {
|
||||
const {
|
||||
value: isCognifyRunning,
|
||||
|
|
@ -51,55 +40,18 @@ export default function DatasetsView({
|
|||
.finally(() => enableCognifyRun());
|
||||
}
|
||||
|
||||
// const handleDatasetDelete = (event: React.MouseEvent<HTMLButtonElement>, dataset: Dataset) => {
|
||||
// event.stopPropagation();
|
||||
// onDatasetDelete(dataset);
|
||||
// }
|
||||
|
||||
const [explorationWindowProps, setExplorationWindowProps] = useState<ExplorationWindowConfig | null>(null);
|
||||
const [dataset, setExplorationDataset] = useState<{ id: string } | 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();
|
||||
|
||||
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();
|
||||
setExplorationDataset(dataset);
|
||||
showExplorationWindow();
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -114,23 +66,11 @@ export default function DatasetsView({
|
|||
<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>) => handleExploreDataset(event, dataset)}
|
||||
>
|
||||
<Text>Explore</Text>
|
||||
</CTAButton>
|
||||
) : (
|
||||
<CTAButton
|
||||
onClick={(event: React.MouseEvent<HTMLButtonElement>) => handleCognifyDataset(event, dataset)}
|
||||
|
|
@ -143,14 +83,11 @@ export default function DatasetsView({
|
|||
</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>Delete</Text>
|
||||
</NegativeButton> */}
|
||||
<Link href="/wizard?step=add">
|
||||
<GhostButton>
|
||||
<Text>Add data</Text>
|
||||
</GhostButton>
|
||||
</Link>
|
||||
</Stack>
|
||||
</DropdownMenu>
|
||||
</Stack>
|
||||
|
|
@ -158,16 +95,12 @@ export default function DatasetsView({
|
|||
</DatasetItem>
|
||||
))}
|
||||
</Stack>
|
||||
{isSearchWindowOpen && (
|
||||
<SearchView onClose={closeSearchWindow} />
|
||||
)}
|
||||
{isExplorationWindowShown && (
|
||||
<IFrameView
|
||||
src={explorationWindowProps!.url}
|
||||
title={explorationWindowProps!.title}
|
||||
onClose={hideExplorationWindow}
|
||||
/>
|
||||
)}
|
||||
<Modal onClose={hideExplorationWindow} isOpen={isExplorationWindowShown} className={styles.explorerModal}>
|
||||
<Spacer horizontal="2" vertical="3" wrap>
|
||||
<Text>{dataset?.id}</Text>
|
||||
</Spacer>
|
||||
<Explorer dataset={dataset!} />
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
.donut1 {
|
||||
width: 106px;
|
||||
height: 106px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(90deg, #D82EB5 0.52%, #9245FD 103.83%);
|
||||
}
|
||||
.donut1.spin {
|
||||
animation: rotate1 1s linear infinite;
|
||||
}
|
||||
|
||||
.donut2 {
|
||||
width: 76px;
|
||||
height: 76px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(90deg, #D82EB5 0.52%, #9245FD 103.83%);
|
||||
position: relative;
|
||||
left: 15px;
|
||||
top: 15px;
|
||||
}
|
||||
.donut2.spin {
|
||||
background: linear-gradient(270deg, #D82EB5 0.52%, #9245FD 103.83%);
|
||||
animation: rotate1 1s linear infinite;
|
||||
}
|
||||
|
||||
.donut3 {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(90deg, #D82EB5 0.52%, #9245FD 103.83%);
|
||||
position: relative;
|
||||
left: 15px;
|
||||
top: 15px;
|
||||
}
|
||||
.donut3.spin {
|
||||
animation: rotate1 1s linear infinite;
|
||||
}
|
||||
|
||||
.dot {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background: #351A4B;
|
||||
position: relative;
|
||||
left: 15px;
|
||||
top: 15px;
|
||||
}
|
||||
|
||||
@keyframes rotate1 {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import classNames from 'classnames';
|
||||
import styles from './CognifyLoadingIndicator.module.css';
|
||||
|
||||
function CognifyLoadingIndicator({ isLoading = true }) {
|
||||
return (
|
||||
<div className={classNames(styles.donut1, isLoading && styles.spin)}>
|
||||
<div className={classNames(styles.donut2, isLoading && styles.spin)}>
|
||||
<div className={classNames(styles.donut3, isLoading && styles.spin)}>
|
||||
<div className={styles.dot} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CognifyLoadingIndicator;
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid white;
|
||||
border: 2px solid var(--global-color-primary);
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
animation: spin 2s linear infinite;
|
||||
|
|
@ -10,6 +10,5 @@ export default function TextLogo({ width = 160, height = 42, color = 'currentCol
|
|||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
);
|
||||
}
|
||||
29
cognee-frontend/src/ui/App/Logo/TextLogo.v2.tsx
Normal file
29
cognee-frontend/src/ui/App/Logo/TextLogo.v2.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
export default function TextLogo({ width = 285, height = 81, color = 'currentColor' }) {
|
||||
return (
|
||||
<svg width={width} height={height} viewBox="0 0 285 81" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M42.0964 46.4597C39.6678 49.6212 36.2632 51.8922 32.4114 52.92C28.5596 53.9479 24.4762 53.6749 20.7954 52.1436C17.1147 50.6123 14.0426 47.9083 12.0565 44.4517C10.0704 40.9951 9.2813 36.9793 9.81189 33.0282C10.3425 29.0771 12.163 25.4118 14.9907 22.6016C17.8184 19.7914 21.4949 17.9937 25.4493 17.4877C29.4036 16.9816 33.4144 17.7956 36.8586 19.8032" stroke={color} strokeWidth="6.03175" strokeLinecap="round"/>
|
||||
<path d="M190.754 51.1936L199.5 35.4365L208.699 19.7656C205.249 17.7739 201.238 16.9762 197.289 17.4961C193.34 18.016 189.672 19.8246 186.856 22.6413C184.039 25.458 182.23 29.1253 181.71 33.0746C181.191 37.0239 181.988 41.0345 183.98 44.4842C185.972 47.9339 189.046 50.63 192.726 52.1544C196.406 53.6787 200.487 53.9462 204.334 52.9152C208.182 51.8842 211.582 49.6125 214.007 46.4522C214.701 45.5482 215.303 44.5859 215.811 43.5794" stroke={color} strokeWidth="6.03175" strokeLinecap="round"/>
|
||||
<path d="M260.873 35.4365C260.873 39.4199 259.559 43.292 257.134 46.4522C254.709 49.6124 251.309 51.8842 247.461 52.9152C243.614 53.9461 239.533 53.6787 235.853 52.1543C232.173 50.63 229.099 47.9338 227.107 44.4841C225.115 41.0344 224.317 37.0239 224.837 33.0746C225.357 29.1253 227.166 25.4579 229.983 22.6413C232.799 19.8246 236.467 18.016 240.416 17.4961C244.365 16.9761 248.376 17.7739 251.825 19.7656L242.627 35.4365L233.881 51.1936" stroke={color} strokeWidth="6.03175" strokeLinecap="round"/>
|
||||
<circle cx="112.945" cy="32.4206" r="15.2302" stroke={color} strokeWidth="6.03175" strokeLinecap="round"/>
|
||||
<path d="M128.126 52.627C128.126 62.6207 120.025 70.7222 110.031 70.7222C104.317 70.7222 99.221 68.0734 95.9048 63.9365" stroke={color} strokeWidth="6.03175" strokeLinecap="round"/>
|
||||
<path d="M128.175 17.1905L128.175 52.627" stroke={color} strokeWidth="6.03175" strokeLinecap="round"/>
|
||||
<path d="M170.698 30.7619L170.698 52.4762" stroke={color} strokeWidth="6.03175" strokeLinecap="round"/>
|
||||
<path d="M170.698 30.1587C170.698 22.9966 164.143 17.1905 156.056 17.1905" stroke={color} strokeWidth="6.03175" strokeLinecap="round"/>
|
||||
<path d="M141.746 30.1587C141.746 22.9966 148.153 17.1905 156.056 17.1905" stroke={color} strokeWidth="6.03175" strokeLinecap="round"/>
|
||||
<path d="M141.746 17.3413L141.746 52.627" stroke={color} strokeWidth="6.03175" strokeLinecap="round"/>
|
||||
<circle cx="69.0635" cy="35.4365" r="18.0952" stroke="url(#paint0_linear_103_348)" strokeWidth="6.03175" strokeLinecap="round"/>
|
||||
<path fillRule="evenodd" clipRule="evenodd" d="M69.0637 56.3968C67.3981 56.3968 66.0479 55.0466 66.0479 53.3809L66.0479 17.4921C66.0479 15.8264 67.3981 14.4762 69.0637 14.4762C70.7293 14.4762 72.0796 15.8264 72.0796 17.4921L72.0796 53.3809C72.0796 55.0466 70.7293 56.3968 69.0637 56.3968Z" fill="url(#paint1_linear_103_348)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_103_348" x1="50.8501" y1="13.1077" x2="87.277" y2="13.1084" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="#D82EB5"/>
|
||||
<stop offset="1" stopColor="#9245FD"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_103_348" x1="72.0443" y1="56.5336" x2="72.1623" y2="14.3395" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="#D82EB5"/>
|
||||
<stop offset="1" stopColor="#9245FD"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
);
|
||||
}
|
||||
4
cognee-frontend/src/ui/App/index.ts
Normal file
4
cognee-frontend/src/ui/App/index.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export { default as Logo } from './Logo/Logo';
|
||||
export { default as TextLogo } from './Logo/TextLogo.v2';
|
||||
export { default as LoadingIndicator } from './Loading/DefaultLoadingIndicator/LoadingIndicator';
|
||||
export { default as CognifyLoadingIndicator } from './Loading/CognifyLoadingIndicator/CognifyLoadingIndicator';
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
.iFrameViewContainer {
|
||||
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;
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
import { CloseIcon, GhostButton, Spacer, Stack, Text } from 'ohmy-ui';
|
||||
import styles from './IFrameView.module.css';
|
||||
|
||||
interface IFrameViewProps {
|
||||
src: string;
|
||||
title: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export default function IFrameView({ title, src, onClose }: IFrameViewProps) {
|
||||
return (
|
||||
<div className={styles.iFrameViewContainer}>
|
||||
<Stack gap="between" align="center/" orientation="horizontal">
|
||||
<Spacer horizontal="2">
|
||||
<Text>{title}</Text>
|
||||
</Spacer>
|
||||
<GhostButton onClick={onClose}>
|
||||
<CloseIcon />
|
||||
</GhostButton>
|
||||
</Stack>
|
||||
<iframe
|
||||
src={src}
|
||||
width="100%"
|
||||
height="100%"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,66 +1,7 @@
|
|||
export default function SettingsIcon({ width = "32px", height = "32px", color = "white" }) {
|
||||
export default function SettingsIcon({ width = 32, height = 33, color = "#E8EAED" }) {
|
||||
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 width={width} height={height} viewBox="0 0 54 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.2482 55.75L20.1336 46.8322C19.1495 46.5357 18.0853 46.0691 16.9408 45.4324C15.7964 44.7962 14.8231 44.1145 14.0209 43.3874L5.79611 46.8854L0.0449219 36.8646L7.15432 31.5042C7.06336 30.9472 6.98833 30.3731 6.92923 29.7822C6.86962 29.1912 6.83982 28.6169 6.83982 28.0594C6.83982 27.5414 6.86962 26.9969 6.92923 26.426C6.98833 25.8545 7.06336 25.2111 7.15432 24.4958L0.0449219 19.1354L5.79611 9.23329L13.9615 12.672C14.8824 11.9053 15.8786 11.2136 16.9501 10.5969C18.021 9.98023 19.0624 9.50385 20.0743 9.16777L21.2482 0.25H32.7522L33.8668 9.22713C35.0487 9.64235 36.0932 10.1187 37.0002 10.6562C37.9072 11.1938 38.8412 11.8657 39.8022 12.672L48.2043 9.23329L53.9555 19.1354L46.6087 24.6739C46.7788 25.31 46.8738 25.8941 46.8939 26.426C46.9134 26.9573 46.9232 27.482 46.9232 28C46.9232 28.4784 46.9034 28.9833 46.8638 29.5147C46.8242 30.0466 46.7333 30.69 46.5909 31.4449L53.819 36.8646L48.0678 46.8854L39.8022 43.328C38.8412 44.1343 37.8746 44.826 36.9023 45.4031C35.93 45.9802 34.9182 46.4368 33.8668 46.7729L32.7522 55.75H21.2482ZM23.9169 52.6667H29.9471L31.0856 44.3178C32.6391 43.9067 34.0374 43.3424 35.2805 42.625C36.5241 41.9076 37.7901 40.9243 39.0784 39.675L46.769 42.9542L49.8346 37.7125L43.0867 32.6427C43.3437 31.765 43.5138 30.9577 43.597 30.2208C43.6797 29.4833 43.7211 28.7431 43.7211 28C43.7211 27.2173 43.6797 26.4771 43.597 25.7792C43.5138 25.0819 43.3437 24.3141 43.0867 23.476L49.9533 18.2875L46.8877 13.0458L39.019 16.3427C38.0863 15.319 36.8599 14.3593 35.3398 13.4636C33.8203 12.5684 32.3824 11.9746 31.0263 11.6822L30.0835 3.33333H23.9346L22.9741 11.6229C21.4206 11.9548 19.9925 12.4895 18.6898 13.227C17.3876 13.9639 16.0921 14.9768 14.8033 16.2656L7.11269 13.0458L4.04709 18.2875L10.7356 23.2802C10.4787 23.9719 10.2988 24.7229 10.196 25.5333C10.0932 26.3437 10.0419 27.1857 10.0419 28.0594C10.0419 28.842 10.0932 29.6187 10.196 30.3896C10.2988 31.1604 10.4589 31.9115 10.6763 32.6427L4.04709 37.7125L7.11269 42.9542L14.7439 39.7167C15.9536 40.9382 17.2096 41.9177 18.5118 42.6551C19.8145 43.392 21.2822 43.966 22.9148 44.3771L23.9169 52.6667ZM26.9169 35.7083C29.0676 35.7083 30.8901 34.9611 32.3845 33.4668C33.8783 31.9729 34.6253 30.1506 34.6253 28C34.6253 25.8494 33.8783 24.0271 32.3845 22.5333C30.8901 21.0389 29.0676 20.2917 26.9169 20.2917C24.755 20.2917 22.9297 21.0389 21.4409 22.5333C19.9527 24.0271 19.2086 25.8494 19.2086 28C19.2086 30.1506 19.9527 31.9729 21.4409 33.4668C22.9297 34.9611 24.755 35.7083 26.9169 35.7083Z" fill={color} />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
5
cognee-frontend/src/ui/Layout/Divider/Divider.module.css
Normal file
5
cognee-frontend/src/ui/Layout/Divider/Divider.module.css
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
.divider {
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, #D82EB5 0.52%, #9245FD 103.83%);
|
||||
}
|
||||
7
cognee-frontend/src/ui/Layout/Divider/Divider.tsx
Normal file
7
cognee-frontend/src/ui/Layout/Divider/Divider.tsx
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import styles from './Divider.module.css';
|
||||
|
||||
export default function Divider() {
|
||||
return (
|
||||
<div className={styles.divider} />
|
||||
);
|
||||
}
|
||||
1
cognee-frontend/src/ui/Layout/index.ts
Normal file
1
cognee-frontend/src/ui/Layout/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default as Divider } from './Divider/Divider';
|
||||
21
cognee-frontend/src/ui/Partials/Explorer/Explorer.module.css
Normal file
21
cognee-frontend/src/ui/Partials/Explorer/Explorer.module.css
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
.explorer {
|
||||
flex: 1;
|
||||
min-height: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.explorerContent {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.graphExplorer {
|
||||
width: 65%;
|
||||
overflow: hidden;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.chat {
|
||||
width: 35%;
|
||||
display: flex;
|
||||
}
|
||||
50
cognee-frontend/src/ui/Partials/Explorer/Explorer.tsx
Normal file
50
cognee-frontend/src/ui/Partials/Explorer/Explorer.tsx
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { useCallback, useEffect, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Spacer, Stack } from 'ohmy-ui';
|
||||
import { getExplorationGraphUrl } from '@/modules/exploration';
|
||||
import { IFrameView, SearchView } from '@/ui/Partials';
|
||||
import { LoadingIndicator } from '@/ui/App';
|
||||
import styles from './Explorer.module.css';
|
||||
|
||||
interface ExplorerProps {
|
||||
dataset: { id: string };
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export default function Explorer({ dataset, className, style }: ExplorerProps) {
|
||||
const [graphUrl, setGraphUrl] = useState<string | null>(null);
|
||||
|
||||
const exploreData = useCallback(() => {
|
||||
getExplorationGraphUrl(dataset)
|
||||
.then((graphUrl) => {
|
||||
setGraphUrl(graphUrl);
|
||||
});
|
||||
}, [dataset]);
|
||||
|
||||
useEffect(() => {
|
||||
exploreData();
|
||||
}, [exploreData]);
|
||||
|
||||
return (
|
||||
<Stack
|
||||
gap="6"
|
||||
style={style}
|
||||
orientation="horizontal"
|
||||
className={classNames(styles.explorerContent, className)}
|
||||
>
|
||||
<div className={styles.graphExplorer}>
|
||||
{!graphUrl ? (
|
||||
<Spacer horizontal="2" wrap>
|
||||
<LoadingIndicator />
|
||||
</Spacer>
|
||||
) : (
|
||||
<IFrameView src={graphUrl} />
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.chat}>
|
||||
<SearchView />
|
||||
</div>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import Link from 'next/link';
|
||||
import { Stack } from 'ohmy-ui';
|
||||
import { DiscordIcon, GithubIcon } from '@/ui/Icons';
|
||||
import { TextLogo } from '@/modules/app';
|
||||
// import { TextLogo } from '@/ui/App';
|
||||
import styles from './Footer.module.css';
|
||||
|
||||
export default function Footer() {
|
||||
|
|
@ -9,7 +9,7 @@ export default function Footer() {
|
|||
<footer className={styles.footer}>
|
||||
<Stack orientation="horizontal" gap="between">
|
||||
<div className={styles.leftSide}>
|
||||
<TextLogo width={92} height={24} />
|
||||
{/* <TextLogo width={92} height={24} /> */}
|
||||
</div>
|
||||
<div className={styles.rightSide}>
|
||||
<Link target="_blank" href="https://github.com/topoteretes/cognee">
|
||||
|
|
|
|||
13
cognee-frontend/src/ui/Partials/IFrameView/IFrameView.tsx
Normal file
13
cognee-frontend/src/ui/Partials/IFrameView/IFrameView.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
interface IFrameViewProps {
|
||||
src: string;
|
||||
}
|
||||
|
||||
export default function IFrameView({ src }: IFrameViewProps) {
|
||||
return (
|
||||
<iframe
|
||||
src={src}
|
||||
width="100%"
|
||||
height="100%"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,21 +1,10 @@
|
|||
|
||||
.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;
|
||||
overflow: hidden;
|
||||
border: 1px solid white;
|
||||
background: var(--global-background-default);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.messagesContainer {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,8 @@
|
|||
import { CTAButton, CloseIcon, GhostButton, Input, Spacer, Stack, Text, DropdownSelect } 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;
|
||||
}
|
||||
import { useCallback, useState } from 'react';
|
||||
import { CTAButton, Stack, Text, DropdownSelect, TextArea, useBoolean } from 'ohmy-ui';
|
||||
import styles from './SearchView.module.css';
|
||||
|
||||
interface Message {
|
||||
id: string;
|
||||
|
|
@ -14,29 +10,31 @@ interface Message {
|
|||
text: string;
|
||||
}
|
||||
|
||||
export default function SearchView({ onClose }: SearchViewProps) {
|
||||
interface SelectOption {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export default function SearchView() {
|
||||
const [messages, setMessages] = useState<Message[]>([]);
|
||||
const [inputValue, setInputValue] = useState<string>("");
|
||||
|
||||
const handleInputChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const handleInputChange = useCallback((event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setInputValue(event.target.value);
|
||||
}, []);
|
||||
|
||||
const searchOptions = [{
|
||||
value: 'SIMILARITY',
|
||||
label: 'Similarity',
|
||||
}, {
|
||||
value: 'NEIGHBOR',
|
||||
label: 'Neighbor',
|
||||
label: 'Look for similar graph nodes',
|
||||
}, {
|
||||
value: 'SUMMARY',
|
||||
label: 'Summary',
|
||||
label: 'Get a summary related to query',
|
||||
}, {
|
||||
value: 'ADJACENT',
|
||||
label: 'Adjacent',
|
||||
label: 'Look for graph node\'s neighbors',
|
||||
}, {
|
||||
value: 'CATEGORIES',
|
||||
label: 'Categories',
|
||||
label: 'Search by categories (Comma separated categories)',
|
||||
}];
|
||||
const [searchType, setSearchType] = useState(searchOptions[0]);
|
||||
|
||||
|
|
@ -78,43 +76,39 @@ export default function SearchView({ onClose }: SearchViewProps) {
|
|||
})
|
||||
}, [inputValue, searchType]);
|
||||
|
||||
const {
|
||||
value: isInputExpanded,
|
||||
setTrue: expandInput,
|
||||
setFalse: contractInput,
|
||||
} = useBoolean(false);
|
||||
|
||||
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}>
|
||||
<div className={styles.messagesContainer}>
|
||||
<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>
|
||||
</div>
|
||||
<form onSubmit={handleSearchSubmit}>
|
||||
<Stack orientation="horizontal" gap="2">
|
||||
<DropdownSelect
|
||||
value={searchType}
|
||||
options={searchOptions}
|
||||
onChange={setSearchType}
|
||||
/>
|
||||
<Input value={inputValue} onChange={handleInputChange} name="searchInput" placeholder="Search" />
|
||||
<CTAButton type="submit">Search</CTAButton>
|
||||
</Stack>
|
||||
</form>
|
||||
</Stack>
|
||||
<DropdownSelect<SelectOption>
|
||||
value={searchType}
|
||||
options={searchOptions}
|
||||
onChange={setSearchType}
|
||||
/>
|
||||
<div className={styles.messagesContainer}>
|
||||
<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>
|
||||
</div>
|
||||
<form onSubmit={handleSearchSubmit}>
|
||||
<Stack orientation="horizontal" align="end/" gap="2">
|
||||
<TextArea style={{ height: isInputExpanded ? '128px' : '38px' }} onFocus={expandInput} onBlur={contractInput} value={inputValue} onChange={handleInputChange} name="searchInput" placeholder="Search" />
|
||||
<CTAButton hugContent type="submit">Search</CTAButton>
|
||||
</Stack>
|
||||
</form>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
187
cognee-frontend/src/ui/Partials/SettingsModal/Settings.tsx
Normal file
187
cognee-frontend/src/ui/Partials/SettingsModal/Settings.tsx
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
import { useCallback, useEffect, useState } from 'react';
|
||||
import {
|
||||
CTAButton,
|
||||
DropdownSelect,
|
||||
FormGroup,
|
||||
FormInput,
|
||||
FormLabel,
|
||||
H3,
|
||||
Input,
|
||||
Spacer,
|
||||
Stack,
|
||||
useBoolean,
|
||||
} from 'ohmy-ui';
|
||||
import { LoadingIndicator } from '@/ui/App';
|
||||
|
||||
interface SelectOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export default function Settings({ onDone = () => {}, submitButtonText = 'Save' }) {
|
||||
const [llmConfig, setLLMConfig] = useState<{
|
||||
apiKey: string;
|
||||
model: SelectOption;
|
||||
models: {
|
||||
openai: SelectOption[];
|
||||
ollama: SelectOption[];
|
||||
anthropic: SelectOption[];
|
||||
};
|
||||
provider: SelectOption;
|
||||
providers: SelectOption[];
|
||||
}>();
|
||||
const [vectorDBConfig, setVectorDBConfig] = useState<{
|
||||
url: string;
|
||||
apiKey: string;
|
||||
provider: SelectOption;
|
||||
options: SelectOption[];
|
||||
}>();
|
||||
|
||||
const {
|
||||
value: isSaving,
|
||||
setTrue: startSaving,
|
||||
setFalse: stopSaving,
|
||||
} = useBoolean(false);
|
||||
|
||||
const saveConfig = (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
|
||||
const newVectorConfig = {
|
||||
provider: vectorDBConfig?.provider.value,
|
||||
url: event.target.vectorDBUrl.value,
|
||||
apiKey: event.target.vectorDBApiKey.value,
|
||||
};
|
||||
|
||||
const newLLMConfig = {
|
||||
provider: llmConfig?.provider.value,
|
||||
model: llmConfig?.model.value,
|
||||
apiKey: event.target.llmApiKey.value,
|
||||
};
|
||||
|
||||
startSaving();
|
||||
|
||||
fetch('http://0.0.0.0:8000/settings', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
llm: newLLMConfig,
|
||||
vectorDB: newVectorConfig,
|
||||
}),
|
||||
})
|
||||
.then(() => {
|
||||
onDone();
|
||||
})
|
||||
.finally(() => stopSaving());
|
||||
};
|
||||
|
||||
const handleVectorDBChange = useCallback((newVectorDBProvider: SelectOption) => {
|
||||
setVectorDBConfig((config) => {
|
||||
if (config?.provider !== newVectorDBProvider) {
|
||||
return {
|
||||
...config,
|
||||
provider: newVectorDBProvider,
|
||||
url: '',
|
||||
apiKey: '',
|
||||
};
|
||||
}
|
||||
return config;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleLLMProviderChange = useCallback((newLLMProvider: SelectOption) => {
|
||||
setLLMConfig((config) => {
|
||||
if (config?.provider !== newLLMProvider) {
|
||||
return {
|
||||
...config,
|
||||
provider: newLLMProvider,
|
||||
model: config?.models[newLLMProvider.value][0],
|
||||
apiKey: '',
|
||||
};
|
||||
}
|
||||
return config;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleLLMModelChange = useCallback((newLLMModel: SelectOption) => {
|
||||
setLLMConfig((config) => {
|
||||
if (config?.model !== newLLMModel) {
|
||||
return {
|
||||
...config,
|
||||
model: newLLMModel,
|
||||
};
|
||||
}
|
||||
return config;
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchConfig = async () => {
|
||||
const response = await fetch('http://0.0.0.0:8000/settings');
|
||||
const settings = await response.json();
|
||||
|
||||
if (!settings.llm.model) {
|
||||
settings.llm.model = settings.llm.models[settings.llm.provider.value][0];
|
||||
}
|
||||
setLLMConfig(settings.llm);
|
||||
setVectorDBConfig(settings.vectorDB);
|
||||
};
|
||||
fetchConfig();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<form onSubmit={saveConfig} style={{ width: '100%' }}>
|
||||
<Stack gap="4" orientation="vertical">
|
||||
<Stack gap="4" orientation="vertical">
|
||||
<FormGroup orientation="vertical" align="center/" gap="2">
|
||||
<FormLabel>LLM provider:</FormLabel>
|
||||
<DropdownSelect
|
||||
value={llmConfig?.provider || null}
|
||||
options={llmConfig?.providers || []}
|
||||
onChange={handleLLMProviderChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup orientation="vertical" align="center/" gap="2">
|
||||
<FormLabel>LLM model:</FormLabel>
|
||||
<DropdownSelect
|
||||
value={llmConfig?.model || null}
|
||||
options={llmConfig?.provider ? llmConfig?.models[llmConfig?.provider.value] : []}
|
||||
onChange={handleLLMModelChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormInput>
|
||||
<Input defaultValue={llmConfig?.apiKey} name="llmApiKey" placeholder="LLM API key" />
|
||||
</FormInput>
|
||||
</Stack>
|
||||
|
||||
<Stack gap="2" orientation="vertical">
|
||||
<FormGroup orientation="vertical" align="center/" gap="2">
|
||||
<FormLabel>Vector DB provider:</FormLabel>
|
||||
<DropdownSelect
|
||||
value={vectorDBConfig?.provider || null}
|
||||
options={vectorDBConfig?.options || []}
|
||||
onChange={handleVectorDBChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormInput>
|
||||
<Input defaultValue={vectorDBConfig?.url} name="vectorDBUrl" placeholder="Vector DB instance url" />
|
||||
</FormInput>
|
||||
<FormInput>
|
||||
<Input defaultValue={vectorDBConfig?.apiKey} name="vectorDBApiKey" placeholder="Vector DB API key" />
|
||||
</FormInput>
|
||||
<Stack align="/end">
|
||||
<Spacer top="2">
|
||||
<CTAButton type="submit">
|
||||
<Stack gap="2" orientation="vertical" align="center/">
|
||||
{submitButtonText}
|
||||
{isSaving && <LoadingIndicator />}
|
||||
</Stack>
|
||||
</CTAButton>
|
||||
</Spacer>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,177 +1,10 @@
|
|||
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;
|
||||
}
|
||||
import { Modal } from 'ohmy-ui';
|
||||
import Settings from './Settings';
|
||||
|
||||
export default function SettingsModal({ isOpen = false, onClose = () => {} }) {
|
||||
const [llmConfig, setLLMConfig] = useState<{
|
||||
apiKey: string;
|
||||
model: SelectOption;
|
||||
models: {
|
||||
openai: SelectOption[];
|
||||
ollama: SelectOption[];
|
||||
anthropic: SelectOption[];
|
||||
};
|
||||
provider: SelectOption;
|
||||
providers: SelectOption[];
|
||||
}>();
|
||||
const [vectorDBConfig, setVectorDBConfig] = useState<{
|
||||
url: string;
|
||||
apiKey: string;
|
||||
provider: SelectOption;
|
||||
options: SelectOption[];
|
||||
}>();
|
||||
|
||||
const {
|
||||
value: isSaving,
|
||||
setTrue: startSaving,
|
||||
setFalse: stopSaving,
|
||||
} = useBoolean(false);
|
||||
|
||||
const saveConfig = (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
|
||||
const newVectorConfig = {
|
||||
provider: vectorDBConfig?.provider.value,
|
||||
url: event.target.vectorDBUrl.value,
|
||||
apiKey: event.target.vectorDBApiKey.value,
|
||||
};
|
||||
|
||||
const newLLMConfig = {
|
||||
provider: llmConfig?.provider.value,
|
||||
model: llmConfig?.model.value,
|
||||
apiKey: event.target.llmApiKey.value,
|
||||
};
|
||||
|
||||
startSaving();
|
||||
|
||||
fetch('http://0.0.0.0:8000/settings', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
llm: newLLMConfig,
|
||||
vectorDB: newVectorConfig,
|
||||
}),
|
||||
})
|
||||
.then(() => {
|
||||
onClose();
|
||||
})
|
||||
.finally(() => stopSaving());
|
||||
};
|
||||
|
||||
const handleVectorDBChange = useCallback((newVectorDBProvider: SelectOption) => {
|
||||
setVectorDBConfig((config) => {
|
||||
if (config?.provider !== newVectorDBProvider) {
|
||||
return {
|
||||
...config,
|
||||
provider: newVectorDBProvider,
|
||||
url: '',
|
||||
apiKey: '',
|
||||
};
|
||||
}
|
||||
return config;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleLLMProviderChange = useCallback((newLLMProvider: SelectOption) => {
|
||||
setLLMConfig((config) => {
|
||||
if (config?.provider !== newLLMProvider) {
|
||||
return {
|
||||
...config,
|
||||
provider: newLLMProvider,
|
||||
model: config?.models[newLLMProvider.value][0],
|
||||
apiKey: '',
|
||||
};
|
||||
}
|
||||
return config;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleLLMModelChange = useCallback((newLLMModel: SelectOption) => {
|
||||
setLLMConfig((config) => {
|
||||
if (config?.model !== newLLMModel) {
|
||||
return {
|
||||
...config,
|
||||
model: newLLMModel,
|
||||
};
|
||||
}
|
||||
return config;
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchVectorDBChoices = async () => {
|
||||
const response = await fetch('http://0.0.0.0:8000/settings');
|
||||
const settings = await response.json();
|
||||
|
||||
if (!settings.llm.model) {
|
||||
settings.llm.model = settings.llm.models[settings.llm.provider.value][0];
|
||||
}
|
||||
setLLMConfig(settings.llm);
|
||||
setVectorDBConfig(settings.vectorDB);
|
||||
};
|
||||
isOpen && fetchVectorDBChoices();
|
||||
}, [isOpen]);
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<Stack gap="8" orientation="vertical" align="center/">
|
||||
<H2>Settings</H2>
|
||||
<form onSubmit={saveConfig} style={{ width: '100%' }}>
|
||||
<Stack gap="4" orientation="vertical">
|
||||
<Stack gap="2" orientation="vertical">
|
||||
<H3>LLM Config</H3>
|
||||
<FormGroup orientation="horizontal" align="center/" gap="4">
|
||||
<FormLabel>LLM provider:</FormLabel>
|
||||
<DropdownSelect
|
||||
value={llmConfig?.provider}
|
||||
options={llmConfig?.providers}
|
||||
onChange={handleLLMProviderChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup orientation="horizontal" align="center/" gap="4">
|
||||
<FormLabel>LLM model:</FormLabel>
|
||||
<DropdownSelect
|
||||
value={llmConfig?.model}
|
||||
options={llmConfig?.provider ? llmConfig?.models[llmConfig?.provider.value] : []}
|
||||
onChange={handleLLMModelChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormInput>
|
||||
<Input defaultValue={llmConfig?.apiKey} name="llmApiKey" placeholder="LLM API key" />
|
||||
</FormInput>
|
||||
</Stack>
|
||||
|
||||
<Stack gap="2" orientation="vertical">
|
||||
<H3>Vector Database Config</H3>
|
||||
<FormGroup orientation="horizontal" align="center/" gap="4">
|
||||
<FormLabel>Vector DB provider:</FormLabel>
|
||||
<DropdownSelect
|
||||
value={vectorDBConfig?.provider}
|
||||
options={vectorDBConfig?.options}
|
||||
onChange={handleVectorDBChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormInput>
|
||||
<Input defaultValue={vectorDBConfig?.url} name="vectorDBUrl" placeholder="Vector DB instance url" />
|
||||
</FormInput>
|
||||
<FormInput>
|
||||
<Input defaultValue={vectorDBConfig?.apiKey} name="vectorDBApiKey" placeholder="Vector DB API key" />
|
||||
</FormInput>
|
||||
<Stack align="/end">
|
||||
<Spacer top="2">
|
||||
<CTAButton type="submit">Save</CTAButton>
|
||||
</Spacer>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</form>
|
||||
</Stack>
|
||||
<Settings onDone={onClose} />
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
.wizardContent {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
background: linear-gradient(90deg, #D82EB5 0.52%, #9245FD 103.83%);
|
||||
padding: 24px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.wizardContent::before {
|
||||
content: '';
|
||||
width: calc(100% - 6px);
|
||||
height: calc(100% - 6px);
|
||||
max-width: 394px;
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 3px;
|
||||
background-color: #351A4B;
|
||||
}
|
||||
|
||||
.wizardContent > * {
|
||||
position: relative;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import { withStyles } from 'ohmy-ui';
|
||||
import styles from './WizardContent.module.css';
|
||||
|
||||
const WizardContent = withStyles<{ children: React.ReactNode }>('div', { className: styles.wizardContent });
|
||||
|
||||
export default WizardContent;
|
||||
11
cognee-frontend/src/ui/Partials/Wizard/WizardHeading.tsx
Normal file
11
cognee-frontend/src/ui/Partials/Wizard/WizardHeading.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { H1 } from 'ohmy-ui';
|
||||
|
||||
interface WizardHeadingProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function WizardHeading({ children, ...props }: WizardHeadingProps) {
|
||||
return (
|
||||
<H1 {...props} align="center" size="small" style={{ color: '#40A9FF' }}>{children}</H1>
|
||||
);
|
||||
}
|
||||
2
cognee-frontend/src/ui/Partials/Wizard/index.ts
Normal file
2
cognee-frontend/src/ui/Partials/Wizard/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export { default as WizardHeading } from './WizardHeading';
|
||||
export { default as WizardContent } from './WizardContent/WizardContent';
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
export { default as Footer } from './Footer/Footer';
|
||||
export { default as SettingsModal } from './SettingsModal/SettingsModal';
|
||||
export { default as SearchView } from './SearchView/SearchView';
|
||||
export { default as IFrameView } from './IFrameView/IFrameView';
|
||||
export { default as Explorer } from './Explorer/Explorer';
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
export { default as IFrameView } from './IFrameView/IFrameView';
|
||||
|
|
@ -124,7 +124,7 @@ async def get_dataset_status(datasets: Annotated[list, Query(alias = "dataset")]
|
|||
|
||||
return JSONResponse(
|
||||
status_code = 200,
|
||||
content = datasets_statuses
|
||||
content = { dataset["data_id"]: dataset["status"] for dataset in datasets_statuses },
|
||||
)
|
||||
|
||||
@app.get("/datasets/{dataset_id}/data/{data_id}/raw", response_class=FileResponse)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ from cognee.shared.data_models import ChunkStrategy, KnowledgeGraph
|
|||
from cognee.utils import send_telemetry
|
||||
from cognee.modules.tasks import create_task_status_table, update_task_status
|
||||
from cognee.shared.SourceCodeGraph import SourceCodeGraph
|
||||
from asyncio import Lock
|
||||
from cognee.modules.tasks import get_task_status
|
||||
|
||||
config = Config()
|
||||
config.load()
|
||||
|
|
@ -39,6 +41,8 @@ USER_ID = "default_user"
|
|||
|
||||
logger = logging.getLogger("cognify")
|
||||
|
||||
update_status_lock = Lock()
|
||||
|
||||
async def cognify(datasets: Union[str, List[str]] = None):
|
||||
"""This function is responsible for the cognitive processing of the content."""
|
||||
# Has to be loaded in advance, multithreading doesn't work without it.
|
||||
|
|
@ -57,10 +61,22 @@ async def cognify(datasets: Union[str, List[str]] = None):
|
|||
|
||||
awaitables = []
|
||||
|
||||
async def handle_cognify_task(dataset_name: str):
|
||||
async with update_status_lock:
|
||||
task_status = get_task_status([dataset_name])
|
||||
|
||||
if task_status == "DATASET_PROCESSING_STARTED":
|
||||
logger.error(f"Dataset {dataset_name} is already being processed.")
|
||||
return
|
||||
|
||||
update_task_status(dataset_name, "DATASET_PROCESSING_STARTED")
|
||||
await cognify(dataset_name)
|
||||
update_task_status(dataset_name, "DATASET_PROCESSING_FINISHED")
|
||||
|
||||
# datasets is a list of dataset names
|
||||
if isinstance(datasets, list):
|
||||
for dataset in datasets:
|
||||
awaitables.append(cognify(dataset))
|
||||
for dataset_name in datasets:
|
||||
awaitables.append(handle_cognify_task(dataset_name))
|
||||
|
||||
graphs = await asyncio.gather(*awaitables)
|
||||
return graphs[0]
|
||||
|
|
@ -124,8 +140,6 @@ async def cognify(datasets: Union[str, List[str]] = None):
|
|||
file_count = 0
|
||||
files_batch = []
|
||||
|
||||
update_task_status(dataset_name, "DATASET_PROCESSING_STARTED")
|
||||
|
||||
for (dataset_name, files) in dataset_files:
|
||||
for file_metadata in files:
|
||||
graph_topology = infrastructure_config.get_config()["graph_model"]
|
||||
|
|
@ -153,8 +167,6 @@ async def cognify(datasets: Union[str, List[str]] = None):
|
|||
if len(files_batch) > 0:
|
||||
await process_batch(files_batch)
|
||||
|
||||
update_task_status(dataset_name, "DATASET_PROCESSING_FINISHED")
|
||||
|
||||
return graph_client.graph
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from duckdb import CatalogException
|
||||
from cognee.modules.discovery import discover_directory_datasets
|
||||
from cognee.infrastructure import infrastructure_config
|
||||
from cognee.modules.tasks import get_task_status
|
||||
|
||||
class datasets():
|
||||
@staticmethod
|
||||
|
|
@ -22,11 +23,8 @@ class datasets():
|
|||
|
||||
@staticmethod
|
||||
def get_status(dataset_ids: list[str]) -> dict:
|
||||
db = infrastructure_config.get_config("database_engine")
|
||||
try:
|
||||
return db.get_data("cognee_task_status", {
|
||||
"data_id": dataset_ids
|
||||
})
|
||||
return get_task_status(dataset_ids)
|
||||
except CatalogException:
|
||||
return {}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,10 @@ class DuckDBAdapter():
|
|||
result["data_id"]: result["status"] for result in results
|
||||
}
|
||||
|
||||
def execute_query(self, query):
|
||||
with self.get_connection() as connection:
|
||||
return connection.sql(query).to_df().to_dict("records")
|
||||
|
||||
def load_cognify_data(self, data):
|
||||
with self.get_connection() as connection:
|
||||
# Ensure the "cognify" table exists
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
from .config import llm_config
|
||||
from .config import get_llm_config
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
from functools import lru_cache
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
class LLMConfig():
|
||||
llm_provider: str = None
|
||||
llm_model: str = None
|
||||
llm_endpoint: str = None
|
||||
llm_api_key: str = None
|
||||
class LLMConfig(BaseSettings):
|
||||
llm_provider: str = "openai"
|
||||
llm_model: str = "gpt-4o"
|
||||
llm_endpoint: str = ""
|
||||
llm_api_key: str = ""
|
||||
|
||||
model_config = SettingsConfigDict(env_file = ".env", extra = "allow")
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
|
|
@ -13,4 +17,6 @@ class LLMConfig():
|
|||
"apiKey": self.llm_api_key,
|
||||
}
|
||||
|
||||
llm_config = LLMConfig()
|
||||
@lru_cache
|
||||
def get_llm_config():
|
||||
return LLMConfig()
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
from enum import Enum
|
||||
import json
|
||||
import logging
|
||||
from cognee.infrastructure.llm import llm_config
|
||||
from cognee.infrastructure.llm import get_llm_config
|
||||
|
||||
# Define an Enum for LLM Providers
|
||||
class LLMProvider(Enum):
|
||||
|
|
@ -13,6 +13,8 @@ class LLMProvider(Enum):
|
|||
|
||||
def get_llm_client():
|
||||
"""Get the LLM client based on the configuration using Enums."""
|
||||
llm_config = get_llm_config()
|
||||
|
||||
logging.error(json.dumps(llm_config.to_dict()))
|
||||
provider = LLMProvider(llm_config.llm_provider)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from cognee.config import Config
|
||||
from cognee.infrastructure import infrastructure_config
|
||||
from cognee.infrastructure.llm import llm_config
|
||||
from cognee.infrastructure.llm import get_llm_config
|
||||
|
||||
def get_settings():
|
||||
config = Config()
|
||||
|
|
@ -30,6 +30,8 @@ def get_settings():
|
|||
"label": "Anthropic",
|
||||
}]
|
||||
|
||||
llm_config = get_llm_config()
|
||||
|
||||
return dict(
|
||||
llm = {
|
||||
"provider": {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import json
|
||||
import logging
|
||||
from pydantic import BaseModel
|
||||
from cognee.infrastructure.llm import llm_config
|
||||
from cognee.infrastructure.llm import get_llm_config
|
||||
from cognee.infrastructure import infrastructure_config
|
||||
|
||||
class LLMConfig(BaseModel):
|
||||
|
|
@ -10,6 +10,8 @@ class LLMConfig(BaseModel):
|
|||
provider: str
|
||||
|
||||
async def save_llm_config(new_llm_config: LLMConfig):
|
||||
llm_config = get_llm_config()
|
||||
|
||||
llm_config.llm_provider = new_llm_config.provider
|
||||
llm_config.llm_model = new_llm_config.model
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
from .get_task_status import get_task_status
|
||||
from .update_task_status import update_task_status
|
||||
from .create_task_status_table import create_task_status_table
|
||||
|
|
|
|||
18
cognee/modules/tasks/get_task_status.py
Normal file
18
cognee/modules/tasks/get_task_status.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from cognee.infrastructure.InfrastructureConfig import infrastructure_config
|
||||
|
||||
def get_task_status(data_ids: [str]):
|
||||
db_engine = infrastructure_config.get_config("database_engine")
|
||||
|
||||
formatted_data_ids = ", ".join([f"'{data_id}'" for data_id in data_ids])
|
||||
|
||||
results = db_engine.execute_query(
|
||||
f"""SELECT data_id, status
|
||||
FROM (
|
||||
SELECT data_id, status, ROW_NUMBER() OVER (PARTITION BY data_id ORDER BY created_at DESC) as rn
|
||||
FROM cognee_task_status
|
||||
WHERE data_id IN ({formatted_data_ids})
|
||||
) t
|
||||
WHERE rn = 1;"""
|
||||
)
|
||||
|
||||
return results
|
||||
21
poetry.lock
generated
21
poetry.lock
generated
|
|
@ -5681,6 +5681,25 @@ files = [
|
|||
[package.dependencies]
|
||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-settings"
|
||||
version = "2.2.1"
|
||||
description = "Settings management using Pydantic"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"},
|
||||
{file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pydantic = ">=2.3.0"
|
||||
python-dotenv = ">=0.21.0"
|
||||
|
||||
[package.extras]
|
||||
toml = ["tomli (>=2.0.1)"]
|
||||
yaml = ["pyyaml (>=6.0.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.18.0"
|
||||
|
|
@ -8518,4 +8537,4 @@ weaviate = ["weaviate-client"]
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.9.0,<3.12"
|
||||
content-hash = "a8347b417527887fff3aea06f51acdd4d49d9ca76a8901005673c9831d42a765"
|
||||
content-hash = "325ea9dcaff8a1c09711aae43ed06bc59b18b3da2fbbb1a9499cb708f7f79e74"
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ protobuf = "<5.0.0"
|
|||
langchain-community = "0.0.38"
|
||||
deepeval = "^0.21.42"
|
||||
falkordb = "^1.0.4"
|
||||
pydantic-settings = "^2.2.1"
|
||||
|
||||
|
||||
[tool.poetry.extras]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue