Merge pull request #432 from topoteretes/COG-975
feat: Add data visualization for Anthropic
This commit is contained in:
commit
6c6ba3270c
15 changed files with 802 additions and 631 deletions
7
.github/pull_request_template.md
vendored
Normal file
7
.github/pull_request_template.md
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<!-- .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
|
||||||
53
.github/workflows/approve_dco.yaml
vendored
Normal file
53
.github/workflows/approve_dco.yaml
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
name: DCO Check
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, edited, reopened, synchronize, ready_for_review]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-dco:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Validate Developer Certificate of Origin statement
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
# If using the built-in GITHUB_TOKEN, ensure it has 'read:org' permission.
|
||||||
|
# In GitHub Enterprise or private orgs, you might need a PAT (personal access token) with read:org scope.
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const orgName = 'YOUR_ORGANIZATION_NAME'; // Replace with your org
|
||||||
|
const prUser = context.payload.pull_request.user.login;
|
||||||
|
const prBody = context.payload.pull_request.body || '';
|
||||||
|
|
||||||
|
// Exact text you require in the PR body
|
||||||
|
const requiredStatement = "I affirm that all code in every commit of this pull request conforms to the terms of the Topoteretes Developer Certificate of Origin";
|
||||||
|
|
||||||
|
// 1. Check if user is in the org
|
||||||
|
let isOrgMember = false;
|
||||||
|
try {
|
||||||
|
// Attempt to get membership info
|
||||||
|
const membership = await github.rest.orgs.getMembershipForUser({
|
||||||
|
org: orgName,
|
||||||
|
username: prUser,
|
||||||
|
});
|
||||||
|
// If we get here without an error, user is in the org
|
||||||
|
isOrgMember = true;
|
||||||
|
console.log(`${prUser} is a member of ${orgName}. Skipping DCO check.`);
|
||||||
|
} catch (error) {
|
||||||
|
// If we get a 404, user is NOT an org member
|
||||||
|
if (error.status === 404) {
|
||||||
|
console.log(`${prUser} is NOT a member of ${orgName}. Enforcing DCO check.`);
|
||||||
|
} else {
|
||||||
|
// Some other error—fail the workflow or handle accordingly
|
||||||
|
core.setFailed(`Error checking organization membership: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. If user is not in the org, enforce the DCO statement
|
||||||
|
if (!isOrgMember) {
|
||||||
|
if (!prBody.includes(requiredStatement)) {
|
||||||
|
core.setFailed(
|
||||||
|
`DCO check failed. The PR body must include the following statement:\n\n${requiredStatement}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
67
.github/workflows/dockerhub.yml
vendored
67
.github/workflows/dockerhub.yml
vendored
|
|
@ -1,8 +1,9 @@
|
||||||
name: build | Build and Push Docker Image to DockerHub
|
name: build | Build and Push Docker Image to dockerhub
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
|
- dev
|
||||||
- main
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
@ -10,42 +11,38 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
- name: Extract Git information
|
- name: Extract metadata
|
||||||
id: git-info
|
id: meta
|
||||||
run: |
|
uses: docker/metadata-action@v5
|
||||||
echo "BRANCH_NAME=${GITHUB_REF_NAME}" >> "$GITHUB_ENV"
|
with:
|
||||||
echo "COMMIT_SHA=${GITHUB_SHA::7}" >> "$GITHUB_ENV"
|
images: cognee/cognee
|
||||||
|
tags: |
|
||||||
|
type=ref,event=branch
|
||||||
|
type=sha,prefix={{branch}}-
|
||||||
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
|
|
||||||
- name: Build and Push Docker Image
|
- name: Build and push
|
||||||
run: |
|
uses: docker/build-push-action@v5
|
||||||
IMAGE_NAME=cognee/cognee
|
with:
|
||||||
TAG_VERSION="${BRANCH_NAME}-${COMMIT_SHA}"
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=registry,ref=cognee/cognee:buildcache
|
||||||
|
cache-to: type=registry,ref=cognee/cognee:buildcache,mode=max
|
||||||
|
|
||||||
echo "Building image: ${IMAGE_NAME}:${TAG_VERSION}"
|
- name: Image digest
|
||||||
docker buildx build \
|
run: echo ${{ steps.build.outputs.digest }}
|
||||||
--platform linux/amd64,linux/arm64 \
|
|
||||||
--push \
|
|
||||||
--tag "${IMAGE_NAME}:${TAG_VERSION}" \
|
|
||||||
--tag "${IMAGE_NAME}:latest" \
|
|
||||||
.
|
|
||||||
|
|
||||||
- name: Verify pushed Docker images
|
|
||||||
run: |
|
|
||||||
# Verify both platform variants
|
|
||||||
for PLATFORM in "linux/amd64" "linux/arm64"; do
|
|
||||||
echo "Verifying image for $PLATFORM..."
|
|
||||||
docker buildx imagetools inspect "${IMAGE_NAME}:${TAG_VERSION}" --format "{{.Manifest.$PLATFORM.Digest}}"
|
|
||||||
done
|
|
||||||
echo "Successfully verified images in Docker Hub"
|
|
||||||
4
.github/workflows/test_python_3_10.yml
vendored
4
.github/workflows/test_python_3_10.yml
vendored
|
|
@ -42,6 +42,10 @@ jobs:
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: poetry install --no-interaction -E docs
|
run: poetry install --no-interaction -E docs
|
||||||
|
- name: Download NLTK tokenizer data
|
||||||
|
run: |
|
||||||
|
poetry run python -m nltk.downloader punkt_tab averaged_perceptron_tagger_eng
|
||||||
|
|
||||||
|
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: poetry run pytest cognee/tests/unit/
|
run: poetry run pytest cognee/tests/unit/
|
||||||
|
|
|
||||||
5
.github/workflows/test_python_3_11.yml
vendored
5
.github/workflows/test_python_3_11.yml
vendored
|
|
@ -44,6 +44,11 @@ jobs:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: poetry install --no-interaction -E docs
|
run: poetry install --no-interaction -E docs
|
||||||
|
|
||||||
|
- name: Download NLTK tokenizer data
|
||||||
|
run: |
|
||||||
|
poetry run python -m nltk.downloader punkt_tab averaged_perceptron_tagger_eng
|
||||||
|
|
||||||
|
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: poetry run pytest cognee/tests/unit/
|
run: poetry run pytest cognee/tests/unit/
|
||||||
|
|
||||||
|
|
|
||||||
3
.github/workflows/test_python_3_12.yml
vendored
3
.github/workflows/test_python_3_12.yml
vendored
|
|
@ -43,6 +43,9 @@ jobs:
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: poetry install --no-interaction -E docs
|
run: poetry install --no-interaction -E docs
|
||||||
|
- name: Download NLTK tokenizer data
|
||||||
|
run: |
|
||||||
|
poetry run python -m nltk.downloader punkt_tab averaged_perceptron_tagger_eng
|
||||||
|
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: poetry run pytest cognee/tests/unit/
|
run: poetry run pytest cognee/tests/unit/
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,15 @@ source .venv/bin/activate
|
||||||
4. Add the new server to your Claude config:
|
4. Add the new server to your Claude config:
|
||||||
|
|
||||||
The file should be located here: ~/Library/Application\ Support/Claude/
|
The file should be located here: ~/Library/Application\ Support/Claude/
|
||||||
|
```
|
||||||
|
cd ~/Library/Application\ Support/Claude/
|
||||||
|
```
|
||||||
You need to create claude_desktop_config.json in this folder if it doesn't exist
|
You need to create claude_desktop_config.json in this folder if it doesn't exist
|
||||||
|
Make sure to add your paths and LLM API key to the file bellow
|
||||||
|
Use your editor of choice, for example Nano:
|
||||||
|
```
|
||||||
|
nano claude_desktop_config.json
|
||||||
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -83,3 +91,17 @@ npx -y @smithery/cli install cognee --client claude
|
||||||
|
|
||||||
Define cognify tool in server.py
|
Define cognify tool in server.py
|
||||||
Restart your Claude desktop.
|
Restart your Claude desktop.
|
||||||
|
|
||||||
|
|
||||||
|
To use debugger, run:
|
||||||
|
```bash
|
||||||
|
npx @modelcontextprotocol/inspector uv --directory /Users/name/folder run cognee
|
||||||
|
```
|
||||||
|
|
||||||
|
To apply new changes while development you do:
|
||||||
|
|
||||||
|
1. Poetry lock in cognee folder
|
||||||
|
2. uv sync --dev --all-extras --reinstall
|
||||||
|
3. npx @modelcontextprotocol/inspector uv --directory /Users/vasilije/cognee/cognee-mcp run cognee
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import os
|
||||||
import asyncio
|
import asyncio
|
||||||
from contextlib import redirect_stderr, redirect_stdout
|
from contextlib import redirect_stderr, redirect_stdout
|
||||||
|
|
||||||
|
from sqlalchemy.testing.plugin.plugin_base import logging
|
||||||
|
|
||||||
import cognee
|
import cognee
|
||||||
import mcp.server.stdio
|
import mcp.server.stdio
|
||||||
import mcp.types as types
|
import mcp.types as types
|
||||||
|
|
@ -10,6 +12,8 @@ from cognee.api.v1.search import SearchType
|
||||||
from cognee.shared.data_models import KnowledgeGraph
|
from cognee.shared.data_models import KnowledgeGraph
|
||||||
from mcp.server import NotificationOptions, Server
|
from mcp.server import NotificationOptions, Server
|
||||||
from mcp.server.models import InitializationOptions
|
from mcp.server.models import InitializationOptions
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
server = Server("cognee-mcp")
|
server = Server("cognee-mcp")
|
||||||
|
|
||||||
|
|
@ -87,9 +91,46 @@ async def handle_list_tools() -> list[types.Tool]:
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
types.Tool(
|
||||||
|
name="visualize",
|
||||||
|
description="Visualize the knowledge graph.",
|
||||||
|
inputSchema={
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"query": {"type": "string"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_freshest_png(directory: str) -> Image.Image:
|
||||||
|
if not os.path.exists(directory):
|
||||||
|
raise FileNotFoundError(f"Directory {directory} does not exist")
|
||||||
|
|
||||||
|
# List all files in 'directory' that end with .png
|
||||||
|
files = [f for f in os.listdir(directory) if f.endswith(".png")]
|
||||||
|
if not files:
|
||||||
|
raise FileNotFoundError("No PNG files found in the given directory.")
|
||||||
|
|
||||||
|
# Sort by integer value of the filename (minus the '.png')
|
||||||
|
# Example filename: 1673185134.png -> integer 1673185134
|
||||||
|
try:
|
||||||
|
files_sorted = sorted(files, key=lambda x: int(x.replace(".png", "")))
|
||||||
|
except ValueError as e:
|
||||||
|
raise ValueError("Invalid PNG filename format. Expected timestamp format.") from e
|
||||||
|
|
||||||
|
# The "freshest" file has the largest timestamp
|
||||||
|
freshest_filename = files_sorted[-1]
|
||||||
|
freshest_path = os.path.join(directory, freshest_filename)
|
||||||
|
|
||||||
|
# Open the image with PIL and return the PIL Image object
|
||||||
|
try:
|
||||||
|
return Image.open(freshest_path)
|
||||||
|
except (IOError, OSError) as e:
|
||||||
|
raise IOError(f"Failed to open PNG file {freshest_path}") from e
|
||||||
|
|
||||||
|
|
||||||
@server.call_tool()
|
@server.call_tool()
|
||||||
async def handle_call_tool(
|
async def handle_call_tool(
|
||||||
name: str, arguments: dict | None
|
name: str, arguments: dict | None
|
||||||
|
|
@ -154,6 +195,20 @@ async def handle_call_tool(
|
||||||
text="Pruned",
|
text="Pruned",
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
elif name == "visualize":
|
||||||
|
with open(os.devnull, "w") as fnull:
|
||||||
|
with redirect_stdout(fnull), redirect_stderr(fnull):
|
||||||
|
try:
|
||||||
|
results = await cognee.visualize_graph()
|
||||||
|
return [
|
||||||
|
types.TextContent(
|
||||||
|
type="text",
|
||||||
|
text=results,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
except (FileNotFoundError, IOError, ValueError) as e:
|
||||||
|
raise ValueError(f"Failed to create visualization: {str(e)}")
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Unknown tool: {name}")
|
raise ValueError(f"Unknown tool: {name}")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||||
description = "A MCP server project"
|
description = "A MCP server project"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"mcp>=1.1.1",
|
"mcp>=1.1.1",
|
||||||
"openai==1.59.4",
|
"openai==1.59.4",
|
||||||
|
|
@ -51,7 +52,7 @@ dependencies = [
|
||||||
"pydantic-settings>=2.2.1,<3.0.0",
|
"pydantic-settings>=2.2.1,<3.0.0",
|
||||||
"anthropic>=0.26.1,<1.0.0",
|
"anthropic>=0.26.1,<1.0.0",
|
||||||
"sentry-sdk[fastapi]>=2.9.0,<3.0.0",
|
"sentry-sdk[fastapi]>=2.9.0,<3.0.0",
|
||||||
"fastapi-users[sqlalchemy]", # Optional
|
"fastapi-users[sqlalchemy]>=14.0.0", # Optional
|
||||||
"alembic>=1.13.3,<2.0.0",
|
"alembic>=1.13.3,<2.0.0",
|
||||||
"asyncpg==0.30.0", # Optional
|
"asyncpg==0.30.0", # Optional
|
||||||
"pgvector>=0.3.5,<0.4.0", # Optional
|
"pgvector>=0.3.5,<0.4.0", # Optional
|
||||||
|
|
@ -91,4 +92,4 @@ dev = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
cognee = "cognee_mcp:main"
|
cognee = "cognee_mcp:main"
|
||||||
18
cognee-mcp/uv.lock
generated
18
cognee-mcp/uv.lock
generated
|
|
@ -561,7 +561,7 @@ name = "click"
|
||||||
version = "8.1.7"
|
version = "8.1.7"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "colorama", marker = "platform_system == 'Windows'" },
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 }
|
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 }
|
||||||
wheels = [
|
wheels = [
|
||||||
|
|
@ -570,7 +570,7 @@ wheels = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cognee"
|
name = "cognee"
|
||||||
version = "0.1.21"
|
version = "0.1.22"
|
||||||
source = { directory = "../" }
|
source = { directory = "../" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "aiofiles" },
|
{ name = "aiofiles" },
|
||||||
|
|
@ -633,7 +633,7 @@ requires-dist = [
|
||||||
{ name = "dlt", extras = ["sqlalchemy"], specifier = ">=1.4.1,<2.0.0" },
|
{ name = "dlt", extras = ["sqlalchemy"], specifier = ">=1.4.1,<2.0.0" },
|
||||||
{ name = "falkordb", marker = "extra == 'falkordb'", specifier = "==1.0.9" },
|
{ name = "falkordb", marker = "extra == 'falkordb'", specifier = "==1.0.9" },
|
||||||
{ name = "fastapi", specifier = ">=0.109.2,<0.116.0" },
|
{ name = "fastapi", specifier = ">=0.109.2,<0.116.0" },
|
||||||
{ name = "fastapi-users", extras = ["sqlalchemy"] },
|
{ name = "fastapi-users", extras = ["sqlalchemy"], specifier = "==14.0.0" },
|
||||||
{ name = "filetype", specifier = ">=1.2.0,<2.0.0" },
|
{ name = "filetype", specifier = ">=1.2.0,<2.0.0" },
|
||||||
{ name = "graphistry", specifier = ">=0.33.5,<0.34.0" },
|
{ name = "graphistry", specifier = ">=0.33.5,<0.34.0" },
|
||||||
{ name = "groq", marker = "extra == 'groq'", specifier = "==0.8.0" },
|
{ name = "groq", marker = "extra == 'groq'", specifier = "==0.8.0" },
|
||||||
|
|
@ -647,12 +647,12 @@ requires-dist = [
|
||||||
{ name = "langfuse", specifier = ">=2.32.0,<3.0.0" },
|
{ name = "langfuse", specifier = ">=2.32.0,<3.0.0" },
|
||||||
{ name = "langsmith", marker = "extra == 'langchain'", specifier = "==0.2.3" },
|
{ name = "langsmith", marker = "extra == 'langchain'", specifier = "==0.2.3" },
|
||||||
{ name = "litellm", specifier = "==1.57.2" },
|
{ name = "litellm", specifier = "==1.57.2" },
|
||||||
{ name = "llama-index-core", marker = "extra == 'llama-index'", specifier = ">=0.12.10.post1,<0.13.0" },
|
{ name = "llama-index-core", marker = "extra == 'llama-index'", specifier = ">=0.12.11,<0.13.0" },
|
||||||
{ name = "matplotlib", specifier = ">=3.8.3,<4.0.0" },
|
{ name = "matplotlib", specifier = ">=3.8.3,<4.0.0" },
|
||||||
{ name = "neo4j", marker = "extra == 'neo4j'", specifier = ">=5.20.0,<6.0.0" },
|
{ name = "neo4j", marker = "extra == 'neo4j'", specifier = ">=5.20.0,<6.0.0" },
|
||||||
{ name = "nest-asyncio", specifier = "==1.6.0" },
|
{ name = "nest-asyncio", specifier = "==1.6.0" },
|
||||||
{ name = "networkx", specifier = ">=3.2.1,<4.0.0" },
|
{ name = "networkx", specifier = ">=3.2.1,<4.0.0" },
|
||||||
{ name = "nltk", specifier = ">=3.8.1,<4.0.0" },
|
{ name = "nltk", specifier = "==3.9.1" },
|
||||||
{ name = "numpy", specifier = "==1.26.4" },
|
{ name = "numpy", specifier = "==1.26.4" },
|
||||||
{ name = "openai", specifier = "==1.59.4" },
|
{ name = "openai", specifier = "==1.59.4" },
|
||||||
{ name = "pandas", specifier = "==2.2.3" },
|
{ name = "pandas", specifier = "==2.2.3" },
|
||||||
|
|
@ -674,7 +674,7 @@ requires-dist = [
|
||||||
{ name = "tiktoken", specifier = "==0.7.0" },
|
{ name = "tiktoken", specifier = "==0.7.0" },
|
||||||
{ name = "transformers", specifier = ">=4.46.3,<5.0.0" },
|
{ name = "transformers", specifier = ">=4.46.3,<5.0.0" },
|
||||||
{ name = "typing-extensions", specifier = "==4.12.2" },
|
{ name = "typing-extensions", specifier = "==4.12.2" },
|
||||||
{ name = "unstructured", extras = ["csv", "doc", "docx", "epub", "md", "odt", "org", "ppt", "pptx", "rst", "rtf", "tsv", "xlsx"], marker = "extra == 'docs'", specifier = ">=0.16.10,<0.17.0" },
|
{ name = "unstructured", extras = ["csv", "doc", "docx", "epub", "md", "odt", "org", "ppt", "pptx", "rst", "rtf", "tsv", "xlsx"], marker = "extra == 'docs'", specifier = ">=0.16.13,<0.17.0" },
|
||||||
{ name = "uvicorn", specifier = "==0.22.0" },
|
{ name = "uvicorn", specifier = "==0.22.0" },
|
||||||
{ name = "weaviate-client", marker = "extra == 'weaviate'", specifier = "==4.9.6" },
|
{ name = "weaviate-client", marker = "extra == 'weaviate'", specifier = "==4.9.6" },
|
||||||
]
|
]
|
||||||
|
|
@ -777,7 +777,7 @@ requires-dist = [
|
||||||
{ name = "dlt", extras = ["sqlalchemy"], specifier = ">=1.4.1,<2.0.0" },
|
{ name = "dlt", extras = ["sqlalchemy"], specifier = ">=1.4.1,<2.0.0" },
|
||||||
{ name = "falkordb", specifier = "==1.0.9" },
|
{ name = "falkordb", specifier = "==1.0.9" },
|
||||||
{ name = "fastapi", specifier = ">=0.109.2,<0.110.0" },
|
{ name = "fastapi", specifier = ">=0.109.2,<0.110.0" },
|
||||||
{ name = "fastapi-users", extras = ["sqlalchemy"] },
|
{ name = "fastapi-users", extras = ["sqlalchemy"], specifier = ">=14.0.0" },
|
||||||
{ name = "filetype", specifier = ">=1.2.0,<2.0.0" },
|
{ name = "filetype", specifier = ">=1.2.0,<2.0.0" },
|
||||||
{ name = "gitpython", specifier = ">=3.1.43,<4.0.0" },
|
{ name = "gitpython", specifier = ">=3.1.43,<4.0.0" },
|
||||||
{ name = "graphistry", specifier = ">=0.33.5,<0.34.0" },
|
{ name = "graphistry", specifier = ">=0.33.5,<0.34.0" },
|
||||||
|
|
@ -3359,7 +3359,7 @@ name = "portalocker"
|
||||||
version = "2.10.1"
|
version = "2.10.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "pywin32", marker = "platform_system == 'Windows'" },
|
{ name = "pywin32", marker = "sys_platform == 'win32'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/ed/d3/c6c64067759e87af98cc668c1cc75171347d0f1577fab7ca3749134e3cd4/portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f", size = 40891 }
|
sdist = { url = "https://files.pythonhosted.org/packages/ed/d3/c6c64067759e87af98cc668c1cc75171347d0f1577fab7ca3749134e3cd4/portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f", size = 40891 }
|
||||||
wheels = [
|
wheels = [
|
||||||
|
|
@ -4954,7 +4954,7 @@ name = "tqdm"
|
||||||
version = "4.67.1"
|
version = "4.67.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "colorama", marker = "platform_system == 'Windows'" },
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 }
|
sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 }
|
||||||
wheels = [
|
wheels = [
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from .api.v1.config.config import config
|
||||||
from .api.v1.datasets.datasets import datasets
|
from .api.v1.datasets.datasets import datasets
|
||||||
from .api.v1.prune import prune
|
from .api.v1.prune import prune
|
||||||
from .api.v1.search import SearchType, get_search_history, search
|
from .api.v1.search import SearchType, get_search_history, search
|
||||||
from .api.v1.visualize import visualize
|
from .api.v1.visualize import visualize_graph
|
||||||
from .shared.utils import create_cognee_style_network_with_logo
|
from .shared.utils import create_cognee_style_network_with_logo
|
||||||
|
|
||||||
# Pipelines
|
# Pipelines
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,6 @@ async def visualize_graph(label: str = "name"):
|
||||||
logging.info(graph_data)
|
logging.info(graph_data)
|
||||||
|
|
||||||
graph = await create_cognee_style_network_with_logo(graph_data, label=label)
|
graph = await create_cognee_style_network_with_logo(graph_data, label=label)
|
||||||
|
logging.info("The HTML file has been stored on your home directory! Navigate there with cd ~")
|
||||||
|
|
||||||
return graph
|
return graph
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,7 @@ import networkx as nx
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import tiktoken
|
import tiktoken
|
||||||
import nltk
|
import time
|
||||||
import base64
|
|
||||||
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -23,13 +21,40 @@ from cognee.infrastructure.databases.graph import get_graph_engine
|
||||||
|
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
import pathlib
|
import pathlib
|
||||||
|
import nltk
|
||||||
from cognee.shared.exceptions import IngestionError
|
from cognee.shared.exceptions import IngestionError
|
||||||
|
|
||||||
# Analytics Proxy Url, currently hosted by Vercel
|
# Analytics Proxy Url, currently hosted by Vercel
|
||||||
proxy_url = "https://test.prometh.ai"
|
proxy_url = "https://test.prometh.ai"
|
||||||
|
|
||||||
|
|
||||||
|
def get_entities(tagged_tokens):
|
||||||
|
nltk.download("maxent_ne_chunker", quiet=True)
|
||||||
|
from nltk.chunk import ne_chunk
|
||||||
|
|
||||||
|
return ne_chunk(tagged_tokens)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_pos_tags(sentence):
|
||||||
|
"""Extract Part-of-Speech (POS) tags for words in a sentence."""
|
||||||
|
|
||||||
|
# Ensure that the necessary NLTK resources are downloaded
|
||||||
|
nltk.download("words", quiet=True)
|
||||||
|
nltk.download("punkt", quiet=True)
|
||||||
|
nltk.download("averaged_perceptron_tagger", quiet=True)
|
||||||
|
|
||||||
|
from nltk.tag import pos_tag
|
||||||
|
from nltk.tokenize import word_tokenize
|
||||||
|
|
||||||
|
# Tokenize the sentence into words
|
||||||
|
tokens = word_tokenize(sentence)
|
||||||
|
|
||||||
|
# Tag each word with its corresponding POS tag
|
||||||
|
pos_tags = pos_tag(tokens)
|
||||||
|
|
||||||
|
return pos_tags
|
||||||
|
|
||||||
|
|
||||||
def get_anonymous_id():
|
def get_anonymous_id():
|
||||||
"""Creates or reads a anonymous user id"""
|
"""Creates or reads a anonymous user id"""
|
||||||
home_dir = str(pathlib.Path(pathlib.Path(__file__).parent.parent.parent.resolve()))
|
home_dir = str(pathlib.Path(pathlib.Path(__file__).parent.parent.parent.resolve()))
|
||||||
|
|
@ -243,33 +268,6 @@ async def render_graph(
|
||||||
# return df.replace([np.inf, -np.inf, np.nan], None)
|
# return df.replace([np.inf, -np.inf, np.nan], None)
|
||||||
|
|
||||||
|
|
||||||
def get_entities(tagged_tokens):
|
|
||||||
nltk.download("maxent_ne_chunker", quiet=True)
|
|
||||||
from nltk.chunk import ne_chunk
|
|
||||||
|
|
||||||
return ne_chunk(tagged_tokens)
|
|
||||||
|
|
||||||
|
|
||||||
def extract_pos_tags(sentence):
|
|
||||||
"""Extract Part-of-Speech (POS) tags for words in a sentence."""
|
|
||||||
|
|
||||||
# Ensure that the necessary NLTK resources are downloaded
|
|
||||||
nltk.download("words", quiet=True)
|
|
||||||
nltk.download("punkt", quiet=True)
|
|
||||||
nltk.download("averaged_perceptron_tagger", quiet=True)
|
|
||||||
|
|
||||||
from nltk.tag import pos_tag
|
|
||||||
from nltk.tokenize import word_tokenize
|
|
||||||
|
|
||||||
# Tokenize the sentence into words
|
|
||||||
tokens = word_tokenize(sentence)
|
|
||||||
|
|
||||||
# Tag each word with its corresponding POS tag
|
|
||||||
pos_tags = pos_tag(tokens)
|
|
||||||
|
|
||||||
return pos_tags
|
|
||||||
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -396,6 +394,7 @@ async def create_cognee_style_network_with_logo(
|
||||||
|
|
||||||
from bokeh.embed import file_html
|
from bokeh.embed import file_html
|
||||||
from bokeh.resources import CDN
|
from bokeh.resources import CDN
|
||||||
|
from bokeh.io import export_png
|
||||||
|
|
||||||
logging.info("Converting graph to serializable format...")
|
logging.info("Converting graph to serializable format...")
|
||||||
G = await convert_to_serializable_graph(G)
|
G = await convert_to_serializable_graph(G)
|
||||||
|
|
@ -445,13 +444,14 @@ async def create_cognee_style_network_with_logo(
|
||||||
|
|
||||||
logging.info(f"Saving visualization to {output_filename}...")
|
logging.info(f"Saving visualization to {output_filename}...")
|
||||||
html_content = file_html(p, CDN, title)
|
html_content = file_html(p, CDN, title)
|
||||||
with open(output_filename, "w") as f:
|
|
||||||
|
home_dir = os.path.expanduser("~")
|
||||||
|
|
||||||
|
# Construct the final output file path
|
||||||
|
output_filepath = os.path.join(home_dir, output_filename)
|
||||||
|
with open(output_filepath, "w") as f:
|
||||||
f.write(html_content)
|
f.write(html_content)
|
||||||
|
|
||||||
logging.info("Visualization complete.")
|
|
||||||
|
|
||||||
if bokeh_object:
|
|
||||||
return p
|
|
||||||
return html_content
|
return html_content
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -512,7 +512,7 @@ if __name__ == "__main__":
|
||||||
G,
|
G,
|
||||||
output_filename="example_network.html",
|
output_filename="example_network.html",
|
||||||
title="Example Cognee Network",
|
title="Example Cognee Network",
|
||||||
node_attribute="group", # Attribute to use for coloring nodes
|
label="group", # Attribute to use for coloring nodes
|
||||||
layout_func=nx.spring_layout, # Layout function
|
layout_func=nx.spring_layout, # Layout function
|
||||||
layout_scale=3.0, # Scale for the layout
|
layout_scale=3.0, # Scale for the layout
|
||||||
logo_alpha=0.2,
|
logo_alpha=0.2,
|
||||||
|
|
|
||||||
1109
poetry.lock
generated
1109
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -40,7 +40,6 @@ networkx = "^3.2.1"
|
||||||
aiosqlite = "^0.20.0"
|
aiosqlite = "^0.20.0"
|
||||||
pandas = "2.2.3"
|
pandas = "2.2.3"
|
||||||
filetype = "^1.2.0"
|
filetype = "^1.2.0"
|
||||||
nltk = "^3.8.1"
|
|
||||||
dlt = {extras = ["sqlalchemy"], version = "^1.4.1"}
|
dlt = {extras = ["sqlalchemy"], version = "^1.4.1"}
|
||||||
aiofiles = "^23.2.1"
|
aiofiles = "^23.2.1"
|
||||||
qdrant-client = {version = "^1.9.0", optional = true}
|
qdrant-client = {version = "^1.9.0", optional = true}
|
||||||
|
|
@ -64,19 +63,20 @@ langfuse = "^2.32.0"
|
||||||
pydantic-settings = "^2.2.1"
|
pydantic-settings = "^2.2.1"
|
||||||
anthropic = "^0.26.1"
|
anthropic = "^0.26.1"
|
||||||
sentry-sdk = {extras = ["fastapi"], version = "^2.9.0"}
|
sentry-sdk = {extras = ["fastapi"], version = "^2.9.0"}
|
||||||
fastapi-users = {version = "*", extras = ["sqlalchemy"]}
|
fastapi-users = {version = "14.0.0", extras = ["sqlalchemy"]}
|
||||||
alembic = "^1.13.3"
|
alembic = "^1.13.3"
|
||||||
asyncpg = {version = "0.30.0", optional = true}
|
asyncpg = {version = "0.30.0", optional = true}
|
||||||
pgvector = {version = "^0.3.5", optional = true}
|
pgvector = {version = "^0.3.5", optional = true}
|
||||||
psycopg2 = {version = "^2.9.10", optional = true}
|
psycopg2 = {version = "^2.9.10", optional = true}
|
||||||
llama-index-core = {version = "^0.12.10.post1", optional = true}
|
llama-index-core = {version = "^0.12.11", optional = true}
|
||||||
deepeval = {version = "^2.0.1", optional = true}
|
deepeval = {version = "^2.0.1", optional = true}
|
||||||
transformers = "^4.46.3"
|
transformers = "^4.46.3"
|
||||||
pymilvus = {version = "^2.5.0", optional = true}
|
pymilvus = {version = "^2.5.0", optional = true}
|
||||||
unstructured = { extras = ["csv", "doc", "docx", "epub", "md", "odt", "org", "ppt", "pptx", "rst", "rtf", "tsv", "xlsx"], version = "^0.16.10", optional = true }
|
unstructured = { extras = ["csv", "doc", "docx", "epub", "md", "odt", "org", "ppt", "pptx", "rst", "rtf", "tsv", "xlsx"], version = "^0.16.13", optional = true }
|
||||||
pre-commit = "^4.0.1"
|
pre-commit = "^4.0.1"
|
||||||
httpx = "0.27.0"
|
httpx = "0.27.0"
|
||||||
bokeh="^3.6.2"
|
bokeh="^3.6.2"
|
||||||
|
nltk = "3.9.1"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue