From 751eca7aafe1630aedcf1bbc2234c900f110fd57 Mon Sep 17 00:00:00 2001 From: Boris Date: Fri, 18 Apr 2025 15:23:51 +0200 Subject: [PATCH] fix: cognee ui with new visualization (#733) ## Description ## DCO Affirmation I affirm that all code in every commit of this pull request conforms to the terms of the Topoteretes Developer Certificate of Origin. --------- Co-authored-by: Igor Ilic <30923996+dexters1@users.noreply.github.com> --- cognee-frontend/src/app/auth/AuthPage.tsx | 4 +- cognee-frontend/src/app/favicon.ico | Bin 25931 -> 169254 bytes cognee-frontend/src/app/favicon.png | Bin 0 -> 3119 bytes cognee-frontend/src/app/globals.css | 6 + cognee-frontend/src/app/page.module.css | 2 +- cognee-frontend/src/app/page.tsx | 4 +- .../src/app/wizard/AddStep/AddStep.tsx | 2 +- cognee-frontend/src/app/wizard/WizardPage.tsx | 4 +- .../exploration/getExplorationGraphUrl.ts | 5 +- .../src/modules/ingestion/addData.ts | 9 +- .../CognifyLoadingIndicator.module.css | 8 +- cognee-frontend/src/ui/App/Logo/Logo.tsx | 13 --- cognee-frontend/src/ui/App/Logo/TextLogo.tsx | 7 ++ .../src/ui/App/Logo/TextLogo.v1.tsx | 14 --- .../src/ui/App/Logo/TextLogo.v2.tsx | 29 ----- cognee-frontend/src/ui/App/index.ts | 3 +- .../src/ui/Layout/Divider/Divider.module.css | 2 +- .../src/ui/Partials/Explorer/Explorer.tsx | 16 +-- .../src/ui/Partials/Footer/Footer.tsx | 4 +- .../src/ui/Partials/SearchView/SearchView.tsx | 14 ++- .../ui/Partials/SettingsModal/Settings.tsx | 105 ++++++++---------- .../src/ui/Partials/SignInForm/SignInForm.tsx | 4 +- .../WizardContent/WizardContent.module.css | 2 +- cognee/api/v1/add/routers/get_add_router.py | 19 +++- cognee/api/v1/datasets/datasets.py | 3 +- .../datasets/routers/get_datasets_router.py | 22 ++-- .../v1/users/routers/get_visualize_router.py | 13 +-- cognee/modules/settings/get_settings.py | 36 +++--- .../modules/settings/save_vector_db_config.py | 4 +- .../methods/check_permission_on_documents.py | 2 +- docker-compose.yml | 65 +++++------ entrypoint.sh | 5 +- 32 files changed, 194 insertions(+), 232 deletions(-) create mode 100644 cognee-frontend/src/app/favicon.png delete mode 100644 cognee-frontend/src/ui/App/Logo/Logo.tsx create mode 100644 cognee-frontend/src/ui/App/Logo/TextLogo.tsx delete mode 100644 cognee-frontend/src/ui/App/Logo/TextLogo.v1.tsx delete mode 100644 cognee-frontend/src/ui/App/Logo/TextLogo.v2.tsx diff --git a/cognee-frontend/src/app/auth/AuthPage.tsx b/cognee-frontend/src/app/auth/AuthPage.tsx index 7b7391039..9cfb5e89f 100644 --- a/cognee-frontend/src/app/auth/AuthPage.tsx +++ b/cognee-frontend/src/app/auth/AuthPage.tsx @@ -9,9 +9,9 @@ import SignInForm from '@/ui/Partials/SignInForm/SignInForm'; export default function AuthPage() { return (
- + - + diff --git a/cognee-frontend/src/app/favicon.ico b/cognee-frontend/src/app/favicon.ico index 718d6fea4835ec2d246af9800eddb7ffb276240c..f3b120fe0f7b8c5831af123e2f003236528dcee8 100644 GIT binary patch literal 169254 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 literal 25931 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 LrJugUA?W`A8`#=m diff --git a/cognee-frontend/src/app/favicon.png b/cognee-frontend/src/app/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..90e5fa3922a669cceae0e119694dbbba9361d6ac GIT binary patch literal 3119 zcmb7`c{~(~7RSfFWqFM)WD=KKSwk@y(k0z3A3~8RL35D8iGqzc#5{QvBz{;u&Evcv5or}_ z$${eOzfs}NgP+dP;$I&AP@eZ}cP~?03(I*_8~SzD7sXwAD%MF1GfG%BOi>Lscx?PV zDyenA|Mz;MjF*|2BLWXpjVuTxq|sK@VAtgk0w72-!po9vD<-#&!qFov>cm+Ykx2sG zz9fbEClJ_o$?aP1**D#x8nJtumK!WsXju=z{(W@!s|&GS(*0ziuv%bPan8tA-LqB7 z)fekGzuM}#CJT*-NxLd&3b{d55o=;Z?XVZtoaYr(t&>nTDI&tHoafgyQA`VWg*ivu z^key!uGBnuIRfE31df((fi+SQeX{tBrk*DDY@=kLlAbgqKH_sie5tn-o(SdUBSq_5 zT*Ihk!nb*Otj~es8|2Cmu5|sKkQ1EVA0IIhqFm;eswG24I|K*C>m-e*>LmB{QidA` zE>@h!6S>6eHnS&5nbx9vEs0(Ei@p@+aO%H^P0q|2e4l?3yCKe#8U3PDz_|Az1FT)-E#48@rq^#iRv$rP$TQ>&-i|2vX>T%Cq zq(z{QZt4w*uRniXXndEIg2cwIlKkuhE)|XKEuGYPxZ+trJ+PQhhufOB86ebR8mtX> z*pZ~(lt?~*-(yp=2uXVxwR)-In-sh-OSw0vpA$$HSA^diZFaONKzstyX_lqj$`6ZA z$-CA&;Wi%Q@kOQb%BiG5Z##kYvx$bLH7xqor?R5Rk-JZn96)n-z}L*vJ?NIQkWSOy zD;kzESGO&1>tM`1xThoX%7r>?s?=|KZ(ft>$6;fCb-HCsm>3iW8Ni5#9GMMR(jc8t zKCKoB*6H&_J$F37n!cStXkzoQR+pPOq_oEeJ5MawK_b}fCkCVY^W#K~_C+g*uK)Xz z$_Dy_@yr{I?pttSZ-!{XN=~PZd6sa+FFZO!C$CLj83?86dNURVh_rppEXO$qh_9~Z zi~Yd?=8UvC)`dBLx#GawV;EttbozFG}#4YJJ}yv01aRSSTE zCBnn^yU7M39s!jLbY*)k;EWh0bt0=#WG^ks3&_}RCVP%Z6a6M(0g`x$bqC4z#KGwS zJ6R$dRLCipK3C9Pas(+yFyqlf(R^tc_58?@tqlGLBf%wLv5Gg*Jwa*6(20VbpBmr< zm9Ur@+p`?62nxXTJ`ICI#GvV%ujWr3c!Zx!Eqtf;b-yzJ==*R1F;^OlWMu98#t=dwyphY6Iijo}z z6h^8Wj(YkZl(N6@1pT36s2-a$NROicLDjr1_ek$5x}}Oo`EP+@ZnYl(*NxQ;byRb& zdwwR*kSqHeb|s<76`{5)p>c1AK@Fyg)Os_NIdhu)fv-{x6O%nw-UMB(BEdO*5{IS8nAZfx9^&?5X^PxT@Mj7l~-%jVnxGW`+TonlS~fOM|Ftn3Ujt^OMGEr@zAC+v-$yG#_h@X_kLwh{q7>QIdsrVXzYM!%<0Ip2v(13AaUY#@IyWod|nK>HP?ybZ=dKtq5D@#>wZq` zRd|DYzZLdZW}T~)JGV&pK*J<+;(OYrd9z7!m_B5A&tap zG0>LC*hDpI=*@ZNKr}Nq9q7W+)vRysa{f9{{<$mULZG?j!lbVAjtTyCdDu#(_S#8z z|9aJ`cE-f)%y`o?cE-H7=b!B%7eLsx)D6qrFOn*OqmI3AoS^tAMh7oCVGWNY=y6m0qIX?*gx(!A=%djd}XyVnpJm*nodO}y(DoVGBQ#S6!rG^c~<$pyqhW8 zK}xukmj8nt8QW!)A<6o9s()nY3z$SRQj~6K`O){9(EHY~40seM(>$Cr0@e_eJzfxK zR(Xx}$4iEfxa;;NN!YBtnCt!SDf9C0?fDeZTU|??6aHC~KR=?j!3*tR-Jb_6WRp+$ T86@uTzX!mLQJ2e%u;Kp({7R*e literal 0 HcmV?d00001 diff --git a/cognee-frontend/src/app/globals.css b/cognee-frontend/src/app/globals.css index 7179f07b6..118237db8 100644 --- a/cognee-frontend/src/app/globals.css +++ b/cognee-frontend/src/app/globals.css @@ -5,6 +5,12 @@ "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro", "Fira Mono", "Droid Sans Mono", "Courier New", monospace; + --button-padding: 14px 20px !important; + --button-border-radius: 100px !important; + --global-color-primary: #6510F4 !important; + --global-color-primary-active: #500cc5 !important; + --global-color-primary-text: white !important; + --global-color-secondary: #0DFF00 !important; --global-background-default: #0D051C; --textarea-default-color: #0D051C !important; } diff --git a/cognee-frontend/src/app/page.module.css b/cognee-frontend/src/app/page.module.css index 02878d478..696d52720 100644 --- a/cognee-frontend/src/app/page.module.css +++ b/cognee-frontend/src/app/page.module.css @@ -11,7 +11,6 @@ display: flex; flex-direction: row; flex: 1; - gap: 32px; } .datasetsView { @@ -28,6 +27,7 @@ .dataView { width: 70%; animation: grow-width 0.3s ease-in-out; + padding: 0 0 0 32px; } @keyframes grow-width { diff --git a/cognee-frontend/src/app/page.tsx b/cognee-frontend/src/app/page.tsx index e1aafe01b..3d8a04dc2 100644 --- a/cognee-frontend/src/app/page.tsx +++ b/cognee-frontend/src/app/page.tsx @@ -68,9 +68,9 @@ export default function Home() { return (
- + - + diff --git a/cognee-frontend/src/app/wizard/AddStep/AddStep.tsx b/cognee-frontend/src/app/wizard/AddStep/AddStep.tsx index f377a46e4..6052ac52c 100644 --- a/cognee-frontend/src/app/wizard/AddStep/AddStep.tsx +++ b/cognee-frontend/src/app/wizard/AddStep/AddStep.tsx @@ -21,7 +21,7 @@ export default function AddStep({ onNext }: ConfigStepProps) { const uploadFiles = useCallback(() => { disableUploading() - addData({ id: 'main' }, files) + addData({ name: 'main' }, files) .then(() => { onNext(); }) diff --git a/cognee-frontend/src/app/wizard/WizardPage.tsx b/cognee-frontend/src/app/wizard/WizardPage.tsx index 2c3aeccfd..1a9158975 100644 --- a/cognee-frontend/src/app/wizard/WizardPage.tsx +++ b/cognee-frontend/src/app/wizard/WizardPage.tsx @@ -33,9 +33,9 @@ export default function WizardPage({ return (
- + - + {wizardStep === 'explore' && ( diff --git a/cognee-frontend/src/modules/exploration/getExplorationGraphUrl.ts b/cognee-frontend/src/modules/exploration/getExplorationGraphUrl.ts index 185f16a81..080302691 100644 --- a/cognee-frontend/src/modules/exploration/getExplorationGraphUrl.ts +++ b/cognee-frontend/src/modules/exploration/getExplorationGraphUrl.ts @@ -1,13 +1,12 @@ import { fetch } from '@/utils'; export default function getExplorationGraphUrl(dataset: { id: string }) { - return fetch(`/v1/datasets/${dataset.id}/graph`) + return fetch('/v1/visualize') .then(async (response) => { if (response.status !== 200) { throw new Error((await response.text()).replaceAll("\"", "")); } return response; }) - .then((response) => response.text()) - .then((text) => text.replace('"', '')); + .then((response) => response.text()); } diff --git a/cognee-frontend/src/modules/ingestion/addData.ts b/cognee-frontend/src/modules/ingestion/addData.ts index caa280837..601c6f884 100644 --- a/cognee-frontend/src/modules/ingestion/addData.ts +++ b/cognee-frontend/src/modules/ingestion/addData.ts @@ -1,11 +1,16 @@ import { fetch } from '@/utils'; -export default function addData(dataset: { id: string }, files: File[]) { +export default function addData(dataset: { id?: string, name?: string }, files: File[]) { const formData = new FormData(); files.forEach((file) => { formData.append('data', file, file.name); }) - formData.append('datasetId', dataset.id); + if (dataset.id) { + formData.append('datasetId', dataset.id); + } + if (dataset.name) { + formData.append('datasetName', dataset.name); + } return fetch('/v1/add', { method: 'POST', diff --git a/cognee-frontend/src/ui/App/Loading/CognifyLoadingIndicator/CognifyLoadingIndicator.module.css b/cognee-frontend/src/ui/App/Loading/CognifyLoadingIndicator/CognifyLoadingIndicator.module.css index 1ce50963d..1c2388373 100644 --- a/cognee-frontend/src/ui/App/Loading/CognifyLoadingIndicator/CognifyLoadingIndicator.module.css +++ b/cognee-frontend/src/ui/App/Loading/CognifyLoadingIndicator/CognifyLoadingIndicator.module.css @@ -3,7 +3,7 @@ width: 106px; height: 106px; border-radius: 50%; - background: linear-gradient(90deg, #D82EB5 0.52%, #9245FD 103.83%); + background: linear-gradient(90deg, #6510F4 0.52%, #0DFF00 103.83%); } .donut1.spin { animation: rotate1 1s linear infinite; @@ -13,13 +13,13 @@ width: 76px; height: 76px; border-radius: 50%; - background: linear-gradient(90deg, #D82EB5 0.52%, #9245FD 103.83%); + background: linear-gradient(90deg, #6510F4 0.52%, #0DFF00 103.83%); position: relative; left: 15px; top: 15px; } .donut2.spin { - background: linear-gradient(270deg, #D82EB5 0.52%, #9245FD 103.83%); + background: linear-gradient(270deg, #6510F4 0.52%, #0DFF00 103.83%); animation: rotate1 1s linear infinite; } @@ -27,7 +27,7 @@ width: 46px; height: 46px; border-radius: 50%; - background: linear-gradient(90deg, #D82EB5 0.52%, #9245FD 103.83%); + background: linear-gradient(90deg, #6510F4 0.52%, #0DFF00 103.83%); position: relative; left: 15px; top: 15px; diff --git a/cognee-frontend/src/ui/App/Logo/Logo.tsx b/cognee-frontend/src/ui/App/Logo/Logo.tsx deleted file mode 100644 index 26dc86135..000000000 --- a/cognee-frontend/src/ui/App/Logo/Logo.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export default function Logo({ width = 29, height = 32, className = '' }) { - return ( - - - - - - - - - - ); -} \ No newline at end of file diff --git a/cognee-frontend/src/ui/App/Logo/TextLogo.tsx b/cognee-frontend/src/ui/App/Logo/TextLogo.tsx new file mode 100644 index 000000000..2ea9607a0 --- /dev/null +++ b/cognee-frontend/src/ui/App/Logo/TextLogo.tsx @@ -0,0 +1,7 @@ +export default function TextLogo({ width = 158, height = 44, color = 'currentColor', className = '' }) { + return ( + + + + ); +} diff --git a/cognee-frontend/src/ui/App/Logo/TextLogo.v1.tsx b/cognee-frontend/src/ui/App/Logo/TextLogo.v1.tsx deleted file mode 100644 index 884f63d61..000000000 --- a/cognee-frontend/src/ui/App/Logo/TextLogo.v1.tsx +++ /dev/null @@ -1,14 +0,0 @@ -export default function TextLogo({ width = 160, height = 42, color = 'currentColor', className = '' }) { - return ( - - - - - - - - - - - ); -} \ No newline at end of file diff --git a/cognee-frontend/src/ui/App/Logo/TextLogo.v2.tsx b/cognee-frontend/src/ui/App/Logo/TextLogo.v2.tsx deleted file mode 100644 index e16206363..000000000 --- a/cognee-frontend/src/ui/App/Logo/TextLogo.v2.tsx +++ /dev/null @@ -1,29 +0,0 @@ -export default function TextLogo({ width = 285, height = 81, color = 'white' }) { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} \ No newline at end of file diff --git a/cognee-frontend/src/ui/App/index.ts b/cognee-frontend/src/ui/App/index.ts index d0f095694..719972a6d 100644 --- a/cognee-frontend/src/ui/App/index.ts +++ b/cognee-frontend/src/ui/App/index.ts @@ -1,4 +1,3 @@ -export { default as Logo } from './Logo/Logo'; -export { default as TextLogo } from './Logo/TextLogo.v2'; +export { default as TextLogo } from './Logo/TextLogo'; export { default as LoadingIndicator } from './Loading/DefaultLoadingIndicator/LoadingIndicator'; export { default as CognifyLoadingIndicator } from './Loading/CognifyLoadingIndicator/CognifyLoadingIndicator'; diff --git a/cognee-frontend/src/ui/Layout/Divider/Divider.module.css b/cognee-frontend/src/ui/Layout/Divider/Divider.module.css index e9e33d6f9..ec3854f3f 100644 --- a/cognee-frontend/src/ui/Layout/Divider/Divider.module.css +++ b/cognee-frontend/src/ui/Layout/Divider/Divider.module.css @@ -1,5 +1,5 @@ .divider { height: 1px; - background: linear-gradient(90deg, #D82EB5 0.52%, #9245FD 103.83%); + background: linear-gradient(90deg, #6510F4 0.52%, #0DFF00 103.83%); } diff --git a/cognee-frontend/src/ui/Partials/Explorer/Explorer.tsx b/cognee-frontend/src/ui/Partials/Explorer/Explorer.tsx index ea50a726a..8ae30c1e9 100644 --- a/cognee-frontend/src/ui/Partials/Explorer/Explorer.tsx +++ b/cognee-frontend/src/ui/Partials/Explorer/Explorer.tsx @@ -1,9 +1,9 @@ -import { useCallback, useEffect, useState } from 'react'; import classNames from 'classnames'; +import { useCallback, useEffect, useState } from 'react'; import { Spacer, Stack, Text } from 'ohmy-ui'; -import { getExplorationGraphUrl } from '@/modules/exploration'; -import { IFrameView, SearchView } from '@/ui/Partials'; import { LoadingIndicator } from '@/ui/App'; +import { IFrameView, SearchView } from '@/ui/Partials'; +import { getExplorationGraphUrl } from '@/modules/exploration'; import styles from './Explorer.module.css'; interface ExplorerProps { @@ -14,13 +14,13 @@ interface ExplorerProps { export default function Explorer({ dataset, className, style }: ExplorerProps) { const [error, setError] = useState(null); - const [graphUrl, setGraphUrl] = useState(null); + const [graphHtml, setGraphHtml] = useState(null); const exploreData = useCallback(() => { getExplorationGraphUrl(dataset) - .then((graphUrl) => { + .then((graphHtml) => { setError(null); - setGraphUrl(graphUrl); + setGraphHtml(graphHtml); }) .catch((error) => { setError(error); @@ -43,12 +43,12 @@ export default function Explorer({ dataset, className, style }: ExplorerProps) { {error.message} ) : ( <> - {!graphUrl ? ( + {!graphHtml ? ( ) : ( - + )} )} diff --git a/cognee-frontend/src/ui/Partials/Footer/Footer.tsx b/cognee-frontend/src/ui/Partials/Footer/Footer.tsx index ac74f5dc2..17b4f854e 100644 --- a/cognee-frontend/src/ui/Partials/Footer/Footer.tsx +++ b/cognee-frontend/src/ui/Partials/Footer/Footer.tsx @@ -13,10 +13,10 @@ export default function Footer() {
- + - +
diff --git a/cognee-frontend/src/ui/Partials/SearchView/SearchView.tsx b/cognee-frontend/src/ui/Partials/SearchView/SearchView.tsx index b4fa07777..8def51c00 100644 --- a/cognee-frontend/src/ui/Partials/SearchView/SearchView.tsx +++ b/cognee-frontend/src/ui/Partials/SearchView/SearchView.tsx @@ -31,11 +31,11 @@ export default function SearchView() { value: 'INSIGHTS', label: 'Query insights from documents', }, { - value: 'SUMMARIES', - label: 'Query document summaries', + value: 'GRAPH_COMPLETION', + label: 'Completion using Cognee\'s graph based memory', }, { - value: 'CHUNKS', - label: 'Query document chunks', + value: 'RAG_COMPLETION', + label: 'Completion using RAG', }]; const [searchType, setSearchType] = useState(searchOptions[0]); @@ -167,6 +167,10 @@ type InsightMessage = [Node, Relationship, Node]; function convertToSearchTypeOutput(systemMessages: any[], searchType: string): string { + if (systemMessages.length > 0 && typeof(systemMessages[0]) === "string") { + return systemMessages[0]; + } + switch (searchType) { case 'INSIGHTS': return systemMessages.map((message: InsightMessage) => { @@ -181,6 +185,6 @@ function convertToSearchTypeOutput(systemMessages: any[], searchType: string): s case 'CHUNKS': return systemMessages.map((message: { text: string }) => message.text).join('\n'); default: - return ''; + return ""; } } diff --git a/cognee-frontend/src/ui/Partials/SettingsModal/Settings.tsx b/cognee-frontend/src/ui/Partials/SettingsModal/Settings.tsx index 08574bd6b..9d8b2ff75 100644 --- a/cognee-frontend/src/ui/Partials/SettingsModal/Settings.tsx +++ b/cognee-frontend/src/ui/Partials/SettingsModal/Settings.tsx @@ -21,7 +21,11 @@ interface SelectOption { interface SettingsForm extends HTMLFormElement { vectorDBUrl: HTMLInputElement; vectorDBApiKey: HTMLInputElement; + llmProvider: HTMLInputElement; + llmModel: HTMLInputElement; llmApiKey: HTMLInputElement; + llmEndpoint: HTMLInputElement; + llmApiVersion: HTMLInputElement; } const defaultProvider = { @@ -37,18 +41,16 @@ const defaultModel = { export default function Settings({ onDone = () => {}, submitButtonText = 'Save' }) { const [llmConfig, setLLMConfig] = useState<{ apiKey: string; - model: SelectOption; - models: { - [key: string]: SelectOption[]; - }; - provider: SelectOption; - providers: SelectOption[]; + model: string; + endpoint: string; + apiVersion: string; + provider: string; }>(); const [vectorDBConfig, setVectorDBConfig] = useState<{ url: string; apiKey: string; provider: SelectOption; - options: SelectOption[]; + providers: SelectOption[]; }>(); const { @@ -68,9 +70,11 @@ export default function Settings({ onDone = () => {}, submitButtonText = 'Save' }; const newLLMConfig = { - provider: llmConfig?.provider.value, - model: llmConfig?.model.value, + provider: formElements.llmProvider.value, + model: formElements.llmModel.value, apiKey: formElements.llmApiKey.value, + endpoint: formElements.llmEndpoint.value, + apiVersion: formElements.llmApiVersion.value, }; startSaving(); @@ -96,7 +100,7 @@ export default function Settings({ onDone = () => {}, submitButtonText = 'Save' if (config?.provider !== newVectorDBProvider) { return { ...config, - options: config?.options || [], + providers: config?.providers || [], provider: newVectorDBProvider, url: '', apiKey: '', @@ -106,43 +110,21 @@ export default function Settings({ onDone = () => {}, submitButtonText = 'Save' }); }, []); - const handleLLMProviderChange = useCallback((newLLMProvider: SelectOption) => { - setLLMConfig((config) => { - if (config?.provider !== newLLMProvider) { - return { - provider: newLLMProvider, - providers: config?.providers || [], - model: config?.models?.[newLLMProvider.value]?.[0] || defaultModel, - models: config?.models || {}, - apiKey: config?.apiKey || '', - }; - } - return config; - }); - }, []); - - const handleLLMModelChange = useCallback((newLLMModel: SelectOption) => { - setLLMConfig((config) => { - if (config?.model !== newLLMModel) { - return { - provider: config?.provider || defaultProvider, - providers: config?.providers || [], - model: newLLMModel, - models: config?.models || {}, - apiKey: config?.apiKey || '', - }; - } - return config; - }); - }, []); - useEffect(() => { const fetchConfig = async () => { const response = await fetch('/v1/settings'); const settings = await response.json(); + if (!settings.llm.provider) { + settings.llm.provider = settings.llm.providers[0].value; + } if (!settings.llm.model) { - settings.llm.model = settings.llm.models[settings.llm.provider.value][0]; + settings.llm.model = settings.llm.models[settings.llm.provider][0].value; + } + if (!settings.vectorDb.provider) { + settings.vectorDb.provider = settings.vectorDb.providers[0]; + } else { + settings.vectorDb.provider = settings.vectorDb.providers.find((provider: SelectOption) => provider.value === settings.vectorDb.provider); } setLLMConfig(settings.llm); setVectorDBConfig(settings.vectorDb); @@ -151,28 +133,39 @@ export default function Settings({ onDone = () => {}, submitButtonText = 'Save' }, []); return ( -
+ LLM provider: - + + + LLM model: - + + + + + + LLM endpoint: + + + + + + LLM API key: + + + + + + LLM API version: + + + - - - @@ -180,7 +173,7 @@ export default function Settings({ onDone = () => {}, submitButtonText = 'Save' Vector DB provider: diff --git a/cognee-frontend/src/ui/Partials/SignInForm/SignInForm.tsx b/cognee-frontend/src/ui/Partials/SignInForm/SignInForm.tsx index 24b5c6d30..a7477d126 100644 --- a/cognee-frontend/src/ui/Partials/SignInForm/SignInForm.tsx +++ b/cognee-frontend/src/ui/Partials/SignInForm/SignInForm.tsx @@ -67,13 +67,13 @@ export default function SignInForm({ onSignInSuccess = () => window.location.hre Email: - + Password: - + diff --git a/cognee-frontend/src/ui/Partials/Wizard/WizardContent/WizardContent.module.css b/cognee-frontend/src/ui/Partials/Wizard/WizardContent/WizardContent.module.css index 31e2d88fe..b9d6f2d4b 100644 --- a/cognee-frontend/src/ui/Partials/Wizard/WizardContent/WizardContent.module.css +++ b/cognee-frontend/src/ui/Partials/Wizard/WizardContent/WizardContent.module.css @@ -2,7 +2,7 @@ width: 100%; max-width: 400px; height: max-content; - background: linear-gradient(90deg, #D82EB5 0.52%, #9245FD 103.83%); + background: linear-gradient(90deg, #6510F4 0.52%, #0DFF00 103.83%); padding: 24px; margin: 0 auto; position: relative; diff --git a/cognee/api/v1/add/routers/get_add_router.py b/cognee/api/v1/add/routers/get_add_router.py index f96b6f477..a27c6c502 100644 --- a/cognee/api/v1/add/routers/get_add_router.py +++ b/cognee/api/v1/add/routers/get_add_router.py @@ -1,8 +1,10 @@ +from uuid import UUID from fastapi import Form, UploadFile, Depends from fastapi.responses import JSONResponse from fastapi import APIRouter -from typing import List +from typing import List, Optional import subprocess +from cognee.modules.data.methods import get_dataset from cognee.shared.logging_utils import get_logger import requests @@ -18,12 +20,23 @@ def get_add_router() -> APIRouter: @router.post("/", response_model=None) async def add( data: List[UploadFile], - datasetId: str = Form(...), + datasetId: Optional[UUID] = Form(default=None), + datasetName: Optional[str] = Form(default=None), user: User = Depends(get_authenticated_user), ): """This endpoint is responsible for adding data to the graph.""" from cognee.api.v1.add import add as cognee_add + if not datasetId and not datasetName: + raise ValueError("Either datasetId or datasetName must be provided.") + + if datasetId and not datasetName: + dataset = await get_dataset(user_id=user.id, dataset_id=datasetId) + try: + datasetName = dataset.name + except IndexError: + raise ValueError("No dataset found with the provided datasetName.") + try: if isinstance(data, str) and data.startswith("http"): if "github" in data: @@ -43,7 +56,7 @@ def get_add_router() -> APIRouter: return await cognee_add(file_data) else: - await cognee_add(data, datasetId, user=user) + await cognee_add(data, datasetName, user=user) except Exception as error: return JSONResponse(status_code=409, content={"error": str(error)}) diff --git a/cognee/api/v1/datasets/datasets.py b/cognee/api/v1/datasets/datasets.py index a6552d937..c81f9326c 100644 --- a/cognee/api/v1/datasets/datasets.py +++ b/cognee/api/v1/datasets/datasets.py @@ -1,3 +1,4 @@ +from uuid import UUID from cognee.modules.users.methods import get_default_user from cognee.modules.ingestion import discover_directory_datasets from cognee.modules.pipelines.operations.get_pipeline_status import get_pipeline_status @@ -26,7 +27,7 @@ class datasets: return await get_dataset_data(dataset.id) @staticmethod - async def get_status(dataset_ids: list[str]) -> dict: + async def get_status(dataset_ids: list[UUID]) -> dict: return await get_pipeline_status(dataset_ids) @staticmethod diff --git a/cognee/api/v1/datasets/routers/get_datasets_router.py b/cognee/api/v1/datasets/routers/get_datasets_router.py index e7325a713..48cd70d8d 100644 --- a/cognee/api/v1/datasets/routers/get_datasets_router.py +++ b/cognee/api/v1/datasets/routers/get_datasets_router.py @@ -59,13 +59,13 @@ def get_datasets_router() -> APIRouter: @router.delete( "/{dataset_id}", response_model=None, responses={404: {"model": ErrorResponseDTO}} ) - async def delete_dataset(dataset_id: str, user: User = Depends(get_authenticated_user)): + async def delete_dataset(dataset_id: UUID, user: User = Depends(get_authenticated_user)): from cognee.modules.data.methods import get_dataset, delete_dataset dataset = await get_dataset(user.id, dataset_id) if dataset is None: - raise EntityNotFoundError(message=f"Dataset ({dataset_id}) not found.") + raise EntityNotFoundError(message=f"Dataset ({str(dataset_id)}) not found.") await delete_dataset(dataset) @@ -75,7 +75,7 @@ def get_datasets_router() -> APIRouter: responses={404: {"model": ErrorResponseDTO}}, ) async def delete_data( - dataset_id: str, data_id: str, user: User = Depends(get_authenticated_user) + dataset_id: UUID, data_id: UUID, user: User = Depends(get_authenticated_user) ): from cognee.modules.data.methods import get_data, delete_data from cognee.modules.data.methods import get_dataset @@ -85,17 +85,17 @@ def get_datasets_router() -> APIRouter: # TODO: Handle situation differently if user doesn't have permission to access data? if dataset is None: - raise EntityNotFoundError(message=f"Dataset ({dataset_id}) not found.") + raise EntityNotFoundError(message=f"Dataset ({str(dataset_id)}) not found.") data = await get_data(user.id, data_id) if data is None: - raise EntityNotFoundError(message=f"Data ({data_id}) not found.") + raise EntityNotFoundError(message=f"Data ({str(data_id)}) not found.") await delete_data(data) @router.get("/{dataset_id}/graph", response_model=str) - async def get_dataset_graph(dataset_id: str, user: User = Depends(get_authenticated_user)): + async def get_dataset_graph(dataset_id: UUID, user: User = Depends(get_authenticated_user)): from cognee.shared.utils import render_graph from cognee.infrastructure.databases.graph import get_graph_engine @@ -119,7 +119,7 @@ def get_datasets_router() -> APIRouter: response_model=list[DataDTO], responses={404: {"model": ErrorResponseDTO}}, ) - async def get_dataset_data(dataset_id: str, user: User = Depends(get_authenticated_user)): + async def get_dataset_data(dataset_id: UUID, user: User = Depends(get_authenticated_user)): from cognee.modules.data.methods import get_dataset_data, get_dataset dataset = await get_dataset(user.id, dataset_id) @@ -127,7 +127,7 @@ def get_datasets_router() -> APIRouter: if dataset is None: return JSONResponse( status_code=404, - content=ErrorResponseDTO(f"Dataset ({dataset_id}) not found."), + content=ErrorResponseDTO(f"Dataset ({str(dataset_id)}) not found."), ) dataset_data = await get_dataset_data(dataset_id=dataset.id) @@ -139,7 +139,7 @@ def get_datasets_router() -> APIRouter: @router.get("/status", response_model=dict[str, PipelineRunStatus]) async def get_dataset_status( - datasets: Annotated[List[str], Query(alias="dataset")] = None, + datasets: Annotated[List[UUID], Query(alias="dataset")] = None, user: User = Depends(get_authenticated_user), ): from cognee.api.v1.datasets.datasets import datasets as cognee_datasets @@ -153,7 +153,7 @@ def get_datasets_router() -> APIRouter: @router.get("/{dataset_id}/data/{data_id}/raw", response_class=FileResponse) async def get_raw_data( - dataset_id: str, data_id: str, user: User = Depends(get_authenticated_user) + dataset_id: UUID, data_id: UUID, user: User = Depends(get_authenticated_user) ): from cognee.modules.data.methods import get_data from cognee.modules.data.methods import get_dataset, get_dataset_data @@ -170,7 +170,7 @@ def get_datasets_router() -> APIRouter: if dataset_data is None: raise EntityNotFoundError(message=f"No data found in dataset ({dataset_id}).") - matching_data = [data for data in dataset_data if str(data.id) == data_id] + matching_data = [data for data in dataset_data if data.id == data_id] # Check if matching_data contains an element if len(matching_data) == 0: diff --git a/cognee/api/v1/users/routers/get_visualize_router.py b/cognee/api/v1/users/routers/get_visualize_router.py index d92c9689f..153bb5bfa 100644 --- a/cognee/api/v1/users/routers/get_visualize_router.py +++ b/cognee/api/v1/users/routers/get_visualize_router.py @@ -1,9 +1,6 @@ -from fastapi import Depends -from fastapi.responses import JSONResponse from fastapi import APIRouter +from fastapi.responses import HTMLResponse, JSONResponse from cognee.shared.logging_utils import get_logger -from cognee.modules.users.models import User -from cognee.modules.users.methods import get_authenticated_user logger = get_logger() @@ -11,16 +8,14 @@ logger = get_logger() def get_visualize_router() -> APIRouter: router = APIRouter() - @router.post("/", response_model=None) - async def visualize( - user: User = Depends(get_authenticated_user), - ): + @router.get("/", response_model=None) + async def visualize(): """This endpoint is responsible for adding data to the graph.""" from cognee.api.v1.visualize import visualize_graph try: html_visualization = await visualize_graph() - return html_visualization + return HTMLResponse(html_visualization) except Exception as error: return JSONResponse(status_code=409, content={"error": str(error)}) diff --git a/cognee/modules/settings/get_settings.py b/cognee/modules/settings/get_settings.py index 063c18971..876474559 100644 --- a/cognee/modules/settings/get_settings.py +++ b/cognee/modules/settings/get_settings.py @@ -18,8 +18,10 @@ class ModelName(Enum): class LLMConfig(BaseModel): api_key: str - model: ConfigChoice - provider: ConfigChoice + model: str + provider: str + endpoint: str + api_version: str models: dict[str, list[ConfigChoice]] providers: list[ConfigChoice] @@ -27,7 +29,7 @@ class LLMConfig(BaseModel): class VectorDBConfig(BaseModel): api_key: str url: str - provider: ConfigChoice + provider: str providers: list[ConfigChoice] @@ -82,19 +84,11 @@ def get_settings() -> SettingsDict: return SettingsDict.model_validate( dict( llm={ - "provider": { - "label": llm_config.llm_provider, - "value": llm_config.llm_provider, - } - if llm_config.llm_provider - else llm_providers[0], - "model": { - "value": llm_config.llm_model, - "label": llm_config.llm_model, - } - if llm_config.llm_model - else None, - "api_key": (llm_config.llm_api_key[:-10] + "**********") + "provider": llm_config.llm_provider, + "model": llm_config.llm_model, + "endpoint": llm_config.llm_endpoint, + "api_version": llm_config.llm_api_version, + "api_key": (llm_config.llm_api_key[0:10] + "*" * (len(llm_config.llm_api_key) - 10)) if llm_config.llm_api_key else None, "providers": llm_providers, @@ -150,12 +144,12 @@ def get_settings() -> SettingsDict: }, }, vector_db={ - "provider": { - "label": vector_config.vector_db_provider, - "value": vector_config.vector_db_provider.lower(), - }, + "provider": vector_config.vector_db_provider, "url": vector_config.vector_db_url, - "api_key": vector_config.vector_db_key, + "api_key": ( + vector_config.vector_db_key[0:10] + + "*" * (len(vector_config.vector_db_key) - 10) + ), "providers": vector_dbs, }, ) diff --git a/cognee/modules/settings/save_vector_db_config.py b/cognee/modules/settings/save_vector_db_config.py index 7c48435a8..44b917cf7 100644 --- a/cognee/modules/settings/save_vector_db_config.py +++ b/cognee/modules/settings/save_vector_db_config.py @@ -13,5 +13,7 @@ async def save_vector_db_config(vector_db_config: VectorDBConfig): vector_config = get_vectordb_config() vector_config.vector_db_url = vector_db_config.url - vector_config.vector_db_key = vector_db_config.api_key vector_config.vector_db_provider = vector_db_config.provider + + if "*****" not in vector_db_config.api_key and len(vector_db_config.api_key.strip()) > 0: + vector_config.vector_db_key = vector_db_config.api_key diff --git a/cognee/modules/users/permissions/methods/check_permission_on_documents.py b/cognee/modules/users/permissions/methods/check_permission_on_documents.py index b2386b06a..54c5f0c35 100644 --- a/cognee/modules/users/permissions/methods/check_permission_on_documents.py +++ b/cognee/modules/users/permissions/methods/check_permission_on_documents.py @@ -37,5 +37,5 @@ async def check_permission_on_documents(user: User, permission_type: str, docume if not has_permissions: raise PermissionDeniedError( - message=f"User {user.email} does not have {permission_type} permission on documents" + message=f"User {user.id} does not have {permission_type} permission on documents" ) diff --git a/docker-compose.yml b/docker-compose.yml index d9ad50d63..0e5195900 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,7 @@ services: - .:/app - /app/cognee-frontend/ # Ignore frontend code environment: + - DEBUG=false # Change to true if debugging - HOST=0.0.0.0 - ENVIRONMENT=local - PYTHONPATH=. @@ -18,30 +19,32 @@ services: - "host.docker.internal:host-gateway" ports: - 8000:8000 - # - 5678:5678 # Debugging + - 5678:5678 # Debugger port deploy: resources: limits: - cpus: "2.0" + cpus: "4.0" memory: 8GB # NOTE: Frontend is a work in progress and is not intended to be used by users yet. # If you want to use Cognee with a UI environment you can run the cognee-gui.py script or # integrate the Cognee MCP Server to Cursor / Claude Desktop / Visual Studio Code ( through Cline/Roo ) -# frontend: -# container_name: frontend -# build: -# context: ./cognee-frontend -# dockerfile: Dockerfile -# volumes: -# - ./cognee-frontend/src:/app/src -# - ./cognee-frontend/public:/app/public -# ports: -# - 3000:3000 -# # - 9229:9229 # Debugging -# networks: -# - cognee-network + frontend: + container_name: frontend + profiles: + - ui + build: + context: ./cognee-frontend + dockerfile: Dockerfile + volumes: + - ./cognee-frontend/src:/app/src + - ./cognee-frontend/public:/app/public + ports: + - 3000:3000 + # - 9229:9229 # Debugging + networks: + - cognee-network neo4j: image: neo4j:latest @@ -86,21 +89,20 @@ services: ports: - "3002:8000" - # UNCOMMENT IF USING POSTGRES - # postgres: - # image: pgvector/pgvector:pg17 - # container_name: postgres - # environment: - # POSTGRES_USER: cognee - # POSTGRES_PASSWORD: cognee - # POSTGRES_DB: cognee_db - # volumes: - # - postgres_data:/var/lib/postgresql/data - # ports: - # - 5432:5432 - # networks: - # - cognee-network - # UNCOMMENT THE VOLUES SECTION BELOW AS WELL TO USE POSTGRES + postgres: + image: pgvector/pgvector:pg17 + container_name: postgres + profiles: + - postgres + environment: + POSTGRES_USER: cognee + POSTGRES_PASSWORD: cognee + POSTGRES_DB: cognee_db + # - postgres_data:/var/lib/postgresql/data + ports: + - 5432:5432 + networks: + - cognee-network networks: cognee-network: @@ -108,5 +110,4 @@ networks: volumes: chromadb_data: -# UNCOMMENT IF USING POSTGRES -# postgres_data: + postgres_data: diff --git a/entrypoint.sh b/entrypoint.sh index edb198443..5874f7e51 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -4,8 +4,7 @@ set -e # Exit on error echo "Debug mode: $DEBUG" echo "Environment: $ENVIRONMENT" -# Run Alembic migrations with proper error handling - +# Run Alembic migrations with proper error handling. # Note on UserAlreadyExists error handling: # During database migrations, we attempt to create a default user. If this user # already exists (e.g., from a previous deployment or migration), it's not a @@ -30,7 +29,7 @@ echo "Starting Gunicorn" sleep 2 # Modified Gunicorn startup with error handling -if [ "$ENVIRONMENT" = "dev" ]; then +if [ "$ENVIRONMENT" = "dev" ] || [ "$ENVIRONMENT" = "local" ]; then if [ "$DEBUG" = "true" ]; then echo "Waiting for the debugger to attach..." exec python -m debugpy --wait-for-client --listen 0.0.0.0:5678 -m gunicorn -w 3 -k uvicorn.workers.UvicornWorker -t 30000 --bind=0.0.0.0:8000 --log-level debug --reload cognee.api.client:app