fix: cognee ui with new visualization (#733)

<!-- .github/pull_request_template.md -->

## Description
<!-- Provide a clear description of the changes in this PR -->

## 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>
This commit is contained in:
Boris 2025-04-18 15:23:51 +02:00 committed by GitHub
parent 54fb400d91
commit 751eca7aaf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 194 additions and 232 deletions

View file

@ -9,9 +9,9 @@ import SignInForm from '@/ui/Partials/SignInForm/SignInForm';
export default function AuthPage() {
return (
<main className={styles.main}>
<Spacer inset vertical="1" horizontal="2">
<Spacer inset vertical="2" horizontal="2">
<Stack orientation="horizontal" gap="between" align="center">
<TextLogo width={225} height={64} />
<TextLogo width={158} height={44} color="white" />
</Stack>
</Spacer>
<Divider />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -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;
}

View file

@ -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 {

View file

@ -68,9 +68,9 @@ export default function Home() {
return (
<main className={styles.main}>
<Spacer inset vertical="1" horizontal="2">
<Spacer inset vertical="2" horizontal="2">
<Stack orientation="horizontal" gap="between" align="center">
<TextLogo width={225} height={64} />
<TextLogo width={158} height={44} color="white" />
<GhostButton hugContent onClick={openSettingsModal}>
<SettingsIcon />
</GhostButton>

View file

@ -21,7 +21,7 @@ export default function AddStep({ onNext }: ConfigStepProps) {
const uploadFiles = useCallback(() => {
disableUploading()
addData({ id: 'main' }, files)
addData({ name: 'main' }, files)
.then(() => {
onNext();
})

View file

@ -33,9 +33,9 @@ export default function WizardPage({
return (
<main className={styles.main}>
<Spacer inset vertical="1" horizontal="2">
<Spacer inset vertical="2" horizontal="2">
<Stack orientation="horizontal" gap="between" align="center">
<TextLogo width={225} height={64} />
<TextLogo width={158} height={44} color="white" />
{wizardStep === 'explore' && (
<GhostButton hugContent onClick={onFinish}>
<CloseIcon />

View file

@ -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());
}

View file

@ -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',

View file

@ -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;

View file

@ -1,13 +0,0 @@
export default function Logo({ width = 29, height = 32, className = '' }) {
return (
<svg width={width} height={height} viewBox="0 0 29 32" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
<path d="M15.3691 31.0517C13.0426 30.9916 10.7881 30.2321 8.89943 28.8722C6.69031 27.2555 4.876 25.1595 3.59261 22.7415L3.56616 22.6957C2.14681 20.3193 1.27502 17.6565 1.01422 14.9008C0.811029 12.541 1.29935 10.1731 2.41954 8.08614C3.63274 5.92912 5.41754 4.14864 7.5775 2.94069C9.65642 1.6311 12.063 0.935339 14.52 0.933546C16.8401 0.992115 19.0886 1.74958 20.9713 3.10686C23.1849 4.73118 25.0019 6.83563 26.2861 9.26236L26.3126 9.30818C27.7245 11.677 28.591 14.3306 28.849 17.0762C29.0537 19.4354 28.5744 21.8036 27.4686 23.8976C26.2597 26.0637 24.4714 27.8503 22.3042 29.0573C20.2272 30.3637 17.8228 31.0552 15.3691 31.0517ZM21.918 24.2438C22.6157 23.6083 23.1845 22.8444 23.5932 21.9938C24.2654 20.5264 24.4947 18.8948 24.2529 17.299C23.951 15.3261 23.27 13.4303 22.2473 11.7164L22.219 11.6674C21.2879 9.90905 20.021 8.35045 18.4898 7.07987C17.2707 6.06818 15.7705 5.45503 14.1917 5.32326C13.2645 5.26502 12.3349 5.39081 11.4565 5.69339L21.918 24.2438ZM6.28845 10.0042C5.6116 11.4657 5.37963 13.094 5.62144 14.6864C5.92664 16.6685 6.61266 18.5729 7.64165 20.2943L7.6681 20.3401C8.59695 22.0928 9.86088 23.6461 11.3882 24.9118C12.61 25.9214 14.1095 26.5364 15.6883 26.6756C16.6098 26.7374 17.5343 26.6166 18.409 26.3203L7.95451 7.77844C7.26261 8.4076 6.69714 9.16303 6.28845 10.0042Z" fill="url(#paint0_linear_28_77)"/>
<defs>
<linearGradient id="paint0_linear_28_77" x1="21" y1="-1.5" x2="4.55895" y2="29.4033" gradientUnits="userSpaceOnUse">
<stop stopColor="#FF3CAC"/>
<stop offset="1" stopColor="#5200FF"/>
</linearGradient>
</defs>
</svg>
);
}

View file

@ -0,0 +1,7 @@
export default function TextLogo({ width = 158, height = 44, color = 'currentColor', className = '' }) {
return (
<svg width={width} height={height} viewBox="0 0 158 44" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}>
<path fillRule="evenodd" clipRule="evenodd" d="M11.7496 4.92654C7.83308 4.92654 4.8585 7.94279 4.8585 11.3612V14.9304C4.8585 18.3488 7.83308 21.3651 11.7496 21.3651C13.6831 21.3651 15.0217 20.8121 16.9551 19.3543C18.0458 18.5499 19.5331 18.8013 20.3263 19.9072C21.1195 21.0132 20.8717 22.5213 19.781 23.3257C17.3518 25.0851 15.0217 26.2414 11.7 26.2414C5.35425 26.2414 0 21.2646 0 14.9304V11.3612C0 4.97681 5.35425 0.0502739 11.7 0.0502739C15.0217 0.0502739 17.3518 1.2065 19.781 2.96598C20.8717 3.77032 21.1195 5.27843 20.3263 6.38439C19.5331 7.49035 18.0458 7.69144 16.9551 6.93737C15.0217 5.52979 13.6831 4.92654 11.7496 4.92654ZM35.5463 4.92654C31.7289 4.92654 28.6552 8.04333 28.6552 11.8639V14.478C28.6552 18.2986 31.7289 21.4154 35.5463 21.4154C39.3141 21.4154 42.3878 18.2986 42.3878 14.478V11.8639C42.3878 8.04333 39.3141 4.92654 35.5463 4.92654ZM23.7967 11.8639C23.7967 5.32871 29.0518 0 35.5463 0C42.0408 0 47.2463 5.32871 47.2463 11.8639V14.478C47.2463 21.0132 42.0408 26.3419 35.5463 26.3419C29.0518 26.3419 23.7967 21.0635 23.7967 14.478V11.8639ZM63.3091 5.07736C59.4917 5.07736 56.418 8.19415 56.418 12.0147C56.418 15.8353 59.4917 18.9521 63.3091 18.9521C67.1265 18.9521 70.1506 15.8856 70.1506 12.0147C70.1506 8.14388 67.0769 5.07736 63.3091 5.07736ZM51.5595 11.9645C51.5595 5.42925 56.8146 0.150814 63.3091 0.150814C66.0854 0.150814 68.5642 1.10596 70.5968 2.71463L72.4311 0.904876C73.3731 -0.0502693 74.9099 -0.0502693 75.8519 0.904876C76.7938 1.86002 76.7938 3.41841 75.8519 4.37356L73.7201 6.53521C74.5629 8.19414 75.0587 10.0542 75.0587 12.0147C75.0587 18.4997 69.8532 23.8284 63.3587 23.8284C63.3091 23.8284 63.2099 23.8284 63.1603 23.8284H58.0044C57.1616 23.8284 56.4675 24.5322 56.4675 25.3868C56.4675 26.2414 57.1616 26.9452 58.0044 26.9452H64.6476H66.7794C68.5146 26.9452 70.3489 27.4479 71.7866 28.6041C73.2739 29.8106 74.2159 31.5701 74.4142 33.7317C74.7116 37.6026 72.0345 40.2166 69.8532 41.0713L63.8048 43.7859C62.5654 44.3389 61.1277 43.7859 60.6319 42.5291C60.0866 41.2723 60.6319 39.8648 61.8714 39.3118L68.0188 36.5972C68.0684 36.5972 68.118 36.5469 68.1675 36.5469C68.4154 36.4463 68.8616 36.1447 69.2087 35.6923C69.5061 35.2398 69.7044 34.7371 69.6548 34.1339C69.6053 33.229 69.2582 32.7263 68.8616 32.4247C68.4154 32.0728 67.7214 31.8214 66.8786 31.8214H58.2027C58.1531 31.8214 58.1531 31.8214 58.1035 31.8214H58.054C54.534 31.8214 51.6586 28.956 51.6586 25.3868C51.6586 23.0743 52.8485 21.0635 54.6828 19.9072C52.6997 17.7959 51.5595 15.031 51.5595 11.9645ZM90.8736 5.07736C87.0562 5.07736 83.9824 8.19415 83.9824 12.0147V23.9289C83.9824 25.2862 82.8917 26.3922 81.5532 26.3922C80.2146 26.3922 79.1239 25.2862 79.1239 23.9289V11.9645C79.1239 5.42925 84.379 0.150814 90.824 0.150814C97.2689 0.150814 102.524 5.42925 102.524 11.9645V23.8786C102.524 25.2359 101.433 26.3419 100.095 26.3419C98.7562 26.3419 97.6655 25.2359 97.6655 23.8786V11.9645C97.7647 8.14387 94.6414 5.07736 90.8736 5.07736ZM119.43 5.07736C115.513 5.07736 112.39 8.24441 112.39 12.065V14.5785C112.39 18.4494 115.513 21.5662 119.43 21.5662C120.768 21.5662 122.057 21.164 123.098 20.5105C124.238 19.8067 125.726 20.1586 126.42 21.3148C127.114 22.4711 126.767 23.9792 125.627 24.683C123.842 25.7889 121.71 26.4425 119.43 26.4425C112.885 26.4425 107.581 21.1137 107.581 14.5785V12.065C107.581 5.47952 112.935 0.201088 119.43 0.201088C125.032 0.201088 129.692 4.07194 130.931 9.3001L131.427 11.3612L121.115 15.584C119.876 16.0867 118.488 15.4834 117.942 14.2266C117.447 12.9699 118.041 11.5623 119.281 11.0596L125.478 8.54604C124.238 6.43466 122.008 5.07736 119.43 5.07736ZM146.003 5.07736C142.086 5.07736 138.963 8.24441 138.963 12.065V14.5785C138.963 18.4494 142.086 21.5662 146.003 21.5662C147.341 21.5662 148.63 21.164 149.671 20.5105C150.217 20.1586 150.663 19.8067 151.109 19.304C152.001 18.2986 153.538 18.2483 154.53 19.2034C155.521 20.1083 155.571 21.6667 154.629 22.6721C153.935 23.4262 153.092 24.13 152.2 24.683C150.415 25.7889 148.283 26.4425 146.003 26.4425C139.458 26.4425 134.154 21.1137 134.154 14.5785V12.065C134.154 5.47952 139.508 0.201088 146.003 0.201088C151.605 0.201088 156.265 4.07194 157.504 9.3001L158 11.3612L147.688 15.584C146.449 16.0867 145.061 15.4834 144.515 14.2266C144.019 12.9699 144.614 11.5623 145.854 11.0596L152.051 8.54604C150.762 6.43466 148.58 5.07736 146.003 5.07736Z" fill={color} />
</svg>
);
}

File diff suppressed because one or more lines are too long

View file

@ -1,29 +0,0 @@
export default function TextLogo({ width = 285, height = 81, color = 'white' }) {
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>
);
}

View file

@ -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';

View file

@ -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%);
}

View file

@ -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<Error | null>(null);
const [graphUrl, setGraphUrl] = useState<string | null>(null);
const [graphHtml, setGraphHtml] = useState<string | null>(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) {
<Text color="red">{error.message}</Text>
) : (
<>
{!graphUrl ? (
{!graphHtml ? (
<Spacer horizontal="2" wrap>
<LoadingIndicator />
</Spacer>
) : (
<IFrameView src={graphUrl} />
<IFrameView src="http://127.0.0.1:8000/api/v1/visualize" />
)}
</>
)}

View file

@ -13,10 +13,10 @@ export default function Footer() {
</div>
<div className={styles.rightSide}>
<Link target="_blank" href="https://github.com/topoteretes/cognee">
<GithubIcon />
<GithubIcon color="white" />
</Link>
<Link target="_blank" href="https://discord.gg/m63hxKsp4p">
<DiscordIcon />
<DiscordIcon color="white" />
</Link>
</div>
</Stack>

View file

@ -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 "";
}
}

View file

@ -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 (
<form onSubmit={saveConfig} style={{ width: '100%' }}>
<form onSubmit={saveConfig} style={{ width: "100%", overflowY: "auto", maxHeight: "500px" }}>
<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}
/>
<FormInput>
<Input defaultValue={llmConfig?.provider} name="llmProvider" placeholder="LLM provider" />
</FormInput>
</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}
/>
<FormInput>
<Input defaultValue={llmConfig?.model} name="llmModel" placeholder="LLM model" />
</FormInput>
</FormGroup>
<FormGroup orientation="vertical" align="center/" gap="2">
<FormLabel>LLM endpoint:</FormLabel>
<FormInput>
<Input defaultValue={llmConfig?.endpoint} name="llmEndpoint" placeholder="LLM endpoint url" />
</FormInput>
</FormGroup>
<FormGroup orientation="vertical" align="center/" gap="2">
<FormLabel>LLM API key:</FormLabel>
<FormInput>
<Input defaultValue={llmConfig?.apiKey} name="llmApiKey" placeholder="LLM API key" />
</FormInput>
</FormGroup>
<FormGroup orientation="vertical" align="center/" gap="2">
<FormLabel>LLM API version:</FormLabel>
<FormInput>
<Input defaultValue={llmConfig?.apiVersion} name="llmApiVersion" placeholder="LLM API version" />
</FormInput>
</FormGroup>
<FormInput>
<Input defaultValue={llmConfig?.apiKey} name="llmApiKey" placeholder="LLM API key" />
</FormInput>
</Stack>
<Stack gap="2" orientation="vertical">
@ -180,7 +173,7 @@ export default function Settings({ onDone = () => {}, submitButtonText = 'Save'
<FormLabel>Vector DB provider:</FormLabel>
<DropdownSelect
value={vectorDBConfig?.provider || null}
options={vectorDBConfig?.options || []}
options={vectorDBConfig?.providers || []}
onChange={handleVectorDBChange}
/>
</FormGroup>

View file

@ -67,13 +67,13 @@ export default function SignInForm({ onSignInSuccess = () => window.location.hre
<FormGroup orientation="vertical" align="center/" gap="2">
<FormLabel>Email:</FormLabel>
<FormInput>
<Input name="email" type="email" placeholder="Your email address" />
<Input defaultValue="default_user@example.com" name="email" type="email" placeholder="Your email address" />
</FormInput>
</FormGroup>
<FormGroup orientation="vertical" align="center/" gap="2">
<FormLabel>Password:</FormLabel>
<FormInput>
<Input name="password" type="password" placeholder="Your password" />
<Input defaultValue="default_password" name="password" type="password" placeholder="Your password" />
</FormInput>
</FormGroup>
</Stack>

View file

@ -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;

View file

@ -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)})

View file

@ -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

View file

@ -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:

View file

@ -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)})

View file

@ -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,
},
)

View file

@ -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

View file

@ -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"
)

View file

@ -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:

View file

@ -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