-
Notifications
You must be signed in to change notification settings - Fork 85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cog 337 llama index support #186
Changes from all commits
ec5fd80
b05a07f
93445bf
804ca26
c151d7b
fb84aa0
7d222ee
094e45d
d5aa316
98dc18c
2615b35
e4c39e8
733caa7
8c7fdc4
f13146d
cc53693
af99e4f
417b119
4c7a4e2
c4700b1
f6e8294
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,63 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
name: test | llama index notebook | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
on: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
workflow_dispatch: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pull_request: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
branches: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- main | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
types: [labeled, synchronize] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
concurrency: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cancel-in-progress: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
env: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
RUNTIME__LOG_LEVEL: ERROR | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
jobs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
get_docs_changes: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
name: docs changes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uses: ./.github/workflows/get_docs_changes.yml | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
run_notebook_test: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
name: test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
needs: get_docs_changes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if: needs.get_docs_changes.outputs.changes_outside_docs == 'true' && github.event.label.name == 'run-checks' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defaults: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
run: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
shell: bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- name: Check out | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uses: actions/checkout@master | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- name: Setup Python | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uses: actions/setup-python@v5 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
python-version: '3.11.x' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- name: Install Poetry | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uses: snok/[email protected] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
virtualenvs-create: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
virtualenvs-in-project: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
installer-parallel: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- name: Install dependencies | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
poetry install --no-interaction --all-extras --no-root | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
poetry add jupyter --no-interaction | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- name: Execute Jupyter Notebook | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
env: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ENV: 'dev' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GRAPHISTRY_USERNAME: ${{ secrets.GRAPHISTRY_USERNAME }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GRAPHISTRY_PASSWORD: ${{ secrets.GRAPHISTRY_PASSWORD }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
poetry run jupyter nbconvert \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--to notebook \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--execute notebooks/cognee_llama_index.ipynb \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--output executed_notebook.ipynb \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
--ExecutePreprocessor.timeout=1200 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+52
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance notebook execution error handling and fix EOF.
run: |
poetry run jupyter nbconvert \
--to notebook \
--execute notebooks/cognee_llama_index.ipynb \
--output executed_notebook.ipynb \
- --ExecutePreprocessor.timeout=1200
+ --ExecutePreprocessor.timeout=1200 \
+ || {
+ echo "::error::Notebook execution failed"
+ cat executed_notebook.ipynb
+ exit 1
+ }
+ 📝 Committable suggestion
Suggested change
🧰 Tools🪛 yamllint[error] 63-63: no new line character at the end of file (new-line-at-end-of-file) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
from .ingest_data import ingest_data | ||
from .save_data_to_storage import save_data_to_storage | ||
from .save_data_item_to_storage import save_data_item_to_storage | ||
from .save_data_item_with_metadata_to_storage import save_data_item_with_metadata_to_storage |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,92 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import dlt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import cognee.modules.ingestion as ingestion | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from typing import Any | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from cognee.shared.utils import send_telemetry | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from cognee.modules.users.models import User | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from cognee.infrastructure.databases.relational import get_relational_engine | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from cognee.modules.data.methods import create_dataset | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from cognee.modules.users.permissions.methods import give_permission_on_document | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from .get_dlt_destination import get_dlt_destination | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from .save_data_item_with_metadata_to_storage import save_data_item_with_metadata_to_storage | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async def ingest_data_with_metadata(data: Any, dataset_name: str, user: User): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
destination = get_dlt_destination() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pipeline = dlt.pipeline( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pipeline_name = "file_load_from_filesystem", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
destination = destination, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@dlt.resource(standalone = True, merge_key = "id") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async def data_resources(data: Any, user: User): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if not isinstance(data, list): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# Convert data to a list as we work with lists further down. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data = [data] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# Process data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for data_item in data: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
file_path = save_data_item_with_metadata_to_storage(data_item, dataset_name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# Ingest data and add metadata | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
with open(file_path.replace("file://", ""), mode = "rb") as file: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Use a Robust Method to Parse File URIs The current approach of using Here's how you might adjust the code: +from urllib.parse import urlparse
+parsed_url = urlparse(file_path)
+file_system_path = parsed_url.path
-with open(file_path.replace("file://", ""), mode="rb") as file:
+with open(file_system_path, mode="rb") as file:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
classified_data = ingestion.classify(file) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+32
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add Exception Handling for File Operations Opening a file can raise exceptions such as I can help implement appropriate exception handling if needed. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data_id = ingestion.identify(classified_data) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
file_metadata = classified_data.get_metadata() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from sqlalchemy import select | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from cognee.modules.data.models import Data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0xideas marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
db_engine = get_relational_engine() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async with db_engine.get_async_session() as session: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dataset = await create_dataset(dataset_name, user.id, session) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data_point = (await session.execute( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
select(Data).filter(Data.id == data_id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
)).scalar_one_or_none() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if data_point is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data_point.name = file_metadata["name"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data_point.raw_data_location = file_metadata["file_path"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data_point.extension = file_metadata["extension"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data_point.mime_type = file_metadata["mime_type"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await session.merge(data_point) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await session.commit() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data_point = Data( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id = data_id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
name = file_metadata["name"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
raw_data_location = file_metadata["file_path"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
extension = file_metadata["extension"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mime_type = file_metadata["mime_type"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dataset.data.append(data_point) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await session.commit() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+44
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure Proper Transaction Management and Exception Handling in Database Operations While using async sessions, it's important to handle exceptions that may occur during database operations to prevent partial commits or data inconsistencies. Consider adding exception handling and ensuring that transactions are properly managed. I can assist in implementing robust exception handling for database transactions if you'd like.
Comment on lines
+51
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Refactor to Reduce Code Duplication in Data Handling The code blocks for updating an existing Here is a suggested refactor: if data_point is not None:
- data_point.name = file_metadata["name"]
- data_point.raw_data_location = file_metadata["file_path"]
- data_point.extension = file_metadata["extension"]
- data_point.mime_type = file_metadata["mime_type"]
-
- await session.merge(data_point)
- await session.commit()
+ pass # Existing data_point, no need to create a new one
else:
data_point = Data(
id=data_id,
- # These fields will be set below
)
dataset.data.append(data_point)
- await session.commit()
+# Set or update shared attributes
+data_point.name = file_metadata["name"]
+data_point.raw_data_location = file_metadata["file_path"]
+data_point.extension = file_metadata["extension"]
+data_point.mime_type = file_metadata["mime_type"]
+await session.merge(data_point)
+await session.commit() 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
yield { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"id": data_id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"name": file_metadata["name"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"file_path": file_metadata["file_path"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"extension": file_metadata["extension"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"mime_type": file_metadata["mime_type"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await give_permission_on_document(user, data_id, "read") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await give_permission_on_document(user, data_id, "write") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
send_telemetry("cognee.add EXECUTION STARTED", user_id = user.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
run_info = pipeline.run( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data_resources(data, user), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
table_name = "file_metadata", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dataset_name = dataset_name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
write_disposition = "merge", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
send_telemetry("cognee.add EXECUTION COMPLETED", user_id = user.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return run_info |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from typing import Union, BinaryIO | ||
from cognee.modules.ingestion import save_data_to_file | ||
|
||
def save_data_item_to_storage(data_item: Union[BinaryIO, str], dataset_name: str) -> str: | ||
|
||
# data is a file object coming from upload. | ||
if hasattr(data_item, "file"): | ||
file_path = save_data_to_file(data_item.file, dataset_name, filename=data_item.filename) | ||
|
||
elif isinstance(data_item, str): | ||
# data is a file path | ||
if data_item.startswith("file://") or data_item.startswith("/"): | ||
file_path = data_item.replace("file://", "") | ||
Comment on lines
+12
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Based on the gathered information, I can now provide the final response: Add path validation and sanitization to prevent path traversal vulnerabilities The current implementation lacks proper path validation, which could lead to security issues:
Required changes:
Example vulnerable operations found:
🔗 Analysis chainAdd path validation for security. Direct handling of file paths without validation could lead to path traversal vulnerabilities. Consider:
Let's check if there are any path validation utilities in the codebase: Let me search for more specific path-related security implementations: Let me check if there are any security-related utilities or path validation functions in the codebase: Let me check how the file paths are being used after they're processed: 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Search for path validation utilities
rg -l "(?i)(validate|sanitize|clean|check).*path"
Length of output: 63 Script: #!/bin/bash
# Search for path-related security checks and normalizations
rg -i "path|directory" -A 3 -B 3 cognee/tasks/ingestion/
Length of output: 11512 Script: #!/bin/bash
# Search for security-related utilities and path validation functions
rg -i "def.*secure|sanitize|validate|normalize.*path" -g "*.py"
# Also check for any security-related imports
rg -i "from.*security|import.*pathlib|import.*os\.path" -g "*.py"
Length of output: 1185 Script: #!/bin/bash
# Check for file operations and how paths are used
rg -A 5 "open\(.*file_path" -g "*.py"
# Also check for the save_data_to_file implementation
rg -A 10 "def save_data_to_file" -g "*.py"
Length of output: 6430 |
||
# data is text | ||
else: | ||
file_path = save_data_to_file(data_item, dataset_name) | ||
else: | ||
raise ValueError(f"Data type not supported: {type(data_item)}") | ||
|
||
return file_path |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,28 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
from typing import Union, BinaryIO, Any | ||||||||||||||||||||||||||||||||||||||||||||||||||
from cognee.modules.ingestion import save_data_to_file | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
def save_data_item_with_metadata_to_storage(data_item: Union[BinaryIO, str, Any], dataset_name: str) -> str: | ||||||||||||||||||||||||||||||||||||||||||||||||||
# Dynamic import is used because the llama_index module is optional. | ||||||||||||||||||||||||||||||||||||||||||||||||||
# For the same reason Any is accepted as a data item | ||||||||||||||||||||||||||||||||||||||||||||||||||
from llama_index.core import Document | ||||||||||||||||||||||||||||||||||||||||||||||||||
from .transform_data import get_data_from_llama_index | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+4
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling for dynamic imports. The dynamic imports could fail silently if the optional dependencies are not installed. Consider adding explicit error handling. - from llama_index.core import Document
- from .transform_data import get_data_from_llama_index
+ try:
+ from llama_index.core import Document
+ from .transform_data import get_data_from_llama_index
+ except ImportError as e:
+ raise ImportError(
+ "Failed to import required dependencies. "
+ "Please ensure llama_index is installed for Document support."
+ ) from e 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
# Check if data is of type Document or any of it's subclasses | ||||||||||||||||||||||||||||||||||||||||||||||||||
if isinstance(data_item, Document): | ||||||||||||||||||||||||||||||||||||||||||||||||||
file_path = get_data_from_llama_index(data_item, dataset_name) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
# data is a file object coming from upload. | ||||||||||||||||||||||||||||||||||||||||||||||||||
elif hasattr(data_item, "file"): | ||||||||||||||||||||||||||||||||||||||||||||||||||
file_path = save_data_to_file(data_item.file, dataset_name, filename=data_item.filename) | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+14
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add robust file object validation. The current implementation makes assumptions about the file object structure without proper validation. - elif hasattr(data_item, "file"):
- file_path = save_data_to_file(data_item.file, dataset_name, filename=data_item.filename)
+ elif hasattr(data_item, "file") and hasattr(data_item, "filename"):
+ if not data_item.file:
+ raise ValueError("File object is empty")
+ if not data_item.filename:
+ raise ValueError("Filename is missing")
+ file_path = save_data_to_file(data_item.file, dataset_name, filename=data_item.filename) 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
elif isinstance(data_item, str): | ||||||||||||||||||||||||||||||||||||||||||||||||||
# data is a file path | ||||||||||||||||||||||||||||||||||||||||||||||||||
if data_item.startswith("file://") or data_item.startswith("/"): | ||||||||||||||||||||||||||||||||||||||||||||||||||
file_path = data_item.replace("file://", "") | ||||||||||||||||||||||||||||||||||||||||||||||||||
# data is text | ||||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||||
file_path = save_data_to_file(data_item, dataset_name) | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+18
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance string input validation and handling. The current string handling could be improved with better file path validation and text content limits. elif isinstance(data_item, str):
+ if not data_item.strip():
+ raise ValueError("Empty string input")
+
# data is a file path
if data_item.startswith("file://") or data_item.startswith("/"):
file_path = data_item.replace("file://", "")
+ # Verify file exists and is accessible
+ import os
+ if not os.path.isfile(file_path):
+ raise FileNotFoundError(f"File not found: {file_path}")
# data is text
else:
+ # Add reasonable size limit for text content
+ if len(data_item) > 10_000_000: # 10MB limit
+ raise ValueError("Text content exceeds size limit")
file_path = save_data_to_file(data_item, dataset_name) 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||||
raise ValueError(f"Data type not supported: {type(data_item)}") | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
return file_path |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,18 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from llama_index.core import Document | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from llama_index.core.schema import ImageDocument | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from cognee.modules.ingestion import save_data_to_file | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
from typing import Union | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def get_data_from_llama_index(data_point: Union[Document, ImageDocument], dataset_name: str) -> str: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# Specific type checking is used to ensure it's not a child class from Document | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if type(data_point) == Document: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
borisarzentar marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
file_path = data_point.metadata.get("file_path") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if file_path is None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
file_path = save_data_to_file(data_point.text, dataset_name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return file_path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return file_path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
elif type(data_point) == ImageDocument: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if data_point.image_path is None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
file_path = save_data_to_file(data_point.text, dataset_name) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return file_path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return data_point.image_path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+6
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Refactor to reduce code duplication and improve error handling The function has similar logic patterns that could be consolidated, and it needs better error handling. Consider this improved implementation: def get_data_from_llama_index(data_point: Union[Document, ImageDocument], dataset_name: str) -> str:
+ """Extract or generate a file path from a LlamaIndex document.
+
+ Args:
+ data_point: A Document or ImageDocument from LlamaIndex
+ dataset_name: Name of the dataset for file path generation
+
+ Returns:
+ str: Path to the file containing the document's content
+
+ Raises:
+ TypeError: If data_point is neither Document nor ImageDocument
+ """
+ if isinstance(data_point, ImageDocument):
+ return data_point.image_path or save_data_to_file(data_point.text, dataset_name)
+ elif isinstance(data_point, Document):
+ return data_point.metadata.get("file_path") or save_data_to_file(data_point.text, dataset_name)
+ else:
+ raise TypeError(f"Expected Document or ImageDocument, got {type(data_point).__name__}") This refactored version:
📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff8-8: Use (E721) 14-14: Use (E721) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add Poetry caching for faster workflow execution.
Consider these improvements for the Python/Poetry setup:
📝 Committable suggestion