Cognee gui [COG-1307] (#530)
<!-- .github/pull_request_template.md --> ## Description Add a simple GUI to add documents to Cognee and use GRAPH_COMPLETION search to get answers ## 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 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced an interactive file search interface with intuitive controls. Users can easily upload files, enter search terms, and view results in a unified display with clear notifications during processing. - **Chores** - Updated project dependencies to include `pyside6` and `qasync` for enhanced GUI functionality. - Refined background query processing to improve the accuracy and relevance of search outcomes. - Improved code readability with formatting enhancements in the search function. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
a602094598
commit
46e026f77f
5 changed files with 221 additions and 8 deletions
133
cognee-gui.py
Normal file
133
cognee-gui.py
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
import sys
|
||||||
|
import asyncio
|
||||||
|
import cognee
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PySide6.QtWidgets import (
|
||||||
|
QApplication,
|
||||||
|
QWidget,
|
||||||
|
QPushButton,
|
||||||
|
QLineEdit,
|
||||||
|
QFileDialog,
|
||||||
|
QVBoxLayout,
|
||||||
|
QLabel,
|
||||||
|
QMessageBox,
|
||||||
|
QTextEdit,
|
||||||
|
QProgressDialog,
|
||||||
|
)
|
||||||
|
from PySide6.QtCore import Qt
|
||||||
|
|
||||||
|
from qasync import QEventLoop # Import QEventLoop from qasync
|
||||||
|
except ImportError as e:
|
||||||
|
print(
|
||||||
|
"\nPlease install Cognee with optional gui dependencies or manually install missing dependencies.\n"
|
||||||
|
)
|
||||||
|
print("\nTo install with poetry use:")
|
||||||
|
print("\npoetry install -E gui\n")
|
||||||
|
print("\nOr to install with poetry and all dependencies use:")
|
||||||
|
print("\npoetry install --all-extras\n")
|
||||||
|
print("\nTo install with pip use: ")
|
||||||
|
print('\npip install ".[gui]"\n')
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
|
class FileSearchApp(QWidget):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.selected_file = None
|
||||||
|
self.init_ui()
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
# Button to open file dialog
|
||||||
|
self.file_button = QPushButton("Upload File to Cognee", parent=self)
|
||||||
|
self.file_button.clicked.connect(self.open_file_dialog)
|
||||||
|
|
||||||
|
# Label to display selected file path
|
||||||
|
self.file_label = QLabel("No file selected", parent=self)
|
||||||
|
|
||||||
|
# Line edit for search input
|
||||||
|
self.search_input = QLineEdit(parent=self)
|
||||||
|
self.search_input.setPlaceholderText("Enter text to search...")
|
||||||
|
|
||||||
|
# Button to perform search; schedule the async search on click
|
||||||
|
self.search_button = QPushButton("Cognee Search", parent=self)
|
||||||
|
self.search_button.clicked.connect(lambda: asyncio.ensure_future(self._cognee_search()))
|
||||||
|
|
||||||
|
# Text output area for search results
|
||||||
|
self.result_output = QTextEdit(parent=self)
|
||||||
|
self.result_output.setReadOnly(True)
|
||||||
|
self.result_output.setPlaceholderText("Search results will appear here...")
|
||||||
|
|
||||||
|
# Progress dialog
|
||||||
|
self.progress_dialog = QProgressDialog("Processing..", None, 0, 0, parent=self)
|
||||||
|
self.progress_dialog.setWindowModality(Qt.WindowModal)
|
||||||
|
# self.progress_dialog.setAttribute(Qt.WA_DeleteOnClose)
|
||||||
|
self.progress_dialog.setCancelButton(None) # Remove the cancel button
|
||||||
|
self.progress_dialog.close()
|
||||||
|
|
||||||
|
# Layout setup
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
layout.addWidget(self.file_button)
|
||||||
|
layout.addWidget(self.file_label)
|
||||||
|
layout.addWidget(self.search_input)
|
||||||
|
layout.addWidget(self.search_button)
|
||||||
|
layout.addWidget(self.result_output)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
self.setWindowTitle("Cognee")
|
||||||
|
self.resize(500, 300)
|
||||||
|
|
||||||
|
def open_file_dialog(self):
|
||||||
|
file_path, _ = QFileDialog.getOpenFileName(
|
||||||
|
self, "Select a File", "", "All Files (*.*);;Text Files (*.txt)"
|
||||||
|
)
|
||||||
|
if file_path:
|
||||||
|
self.selected_file = file_path
|
||||||
|
self.file_label.setText(f"Selected: {file_path}")
|
||||||
|
asyncio.ensure_future(self.process_file_async())
|
||||||
|
|
||||||
|
async def process_file_async(self):
|
||||||
|
"""Asynchronously add and process the selected file."""
|
||||||
|
# Disable the entire window
|
||||||
|
self.progress_dialog.show()
|
||||||
|
self.setEnabled(False)
|
||||||
|
try:
|
||||||
|
await cognee.add(self.selected_file)
|
||||||
|
await cognee.cognify()
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "Error", f"File processing failed: {str(e)}")
|
||||||
|
# Once finished, re-enable the window
|
||||||
|
self.setEnabled(True)
|
||||||
|
self.progress_dialog.close()
|
||||||
|
|
||||||
|
async def _cognee_search(self):
|
||||||
|
"""Performs an async search and updates the result output."""
|
||||||
|
# Disable the entire window
|
||||||
|
self.setEnabled(False)
|
||||||
|
self.progress_dialog.show()
|
||||||
|
|
||||||
|
try:
|
||||||
|
search_text = self.search_input.text().strip()
|
||||||
|
result = await cognee.search(query_text=search_text)
|
||||||
|
print(result)
|
||||||
|
# Assuming result is a list-like object; adjust if necessary
|
||||||
|
self.result_output.setText(result[0])
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "Error", f"Search failed: {str(e)}")
|
||||||
|
|
||||||
|
# Once finished, re-enable the window
|
||||||
|
self.setEnabled(True)
|
||||||
|
self.progress_dialog.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
# Create a qasync event loop and set it as the current event loop
|
||||||
|
loop = QEventLoop(app)
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
|
window = FileSearchApp()
|
||||||
|
window.show()
|
||||||
|
|
||||||
|
with loop:
|
||||||
|
loop.run_forever()
|
||||||
|
|
@ -10,7 +10,7 @@ from cognee.modules.users.methods import get_authenticated_user
|
||||||
|
|
||||||
|
|
||||||
class SearchPayloadDTO(InDTO):
|
class SearchPayloadDTO(InDTO):
|
||||||
search_type: SearchType
|
search_type: SearchType
|
||||||
query: str
|
query: str
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -38,8 +38,9 @@ def get_search_router() -> APIRouter:
|
||||||
from cognee.api.v1.search import search as cognee_search
|
from cognee.api.v1.search import search as cognee_search
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
results = await cognee_search(
|
||||||
results = await cognee_search(query_text = payload.query, query_type = payload.search_type, user=user)
|
query_text=payload.query, query_type=payload.search_type, user=user
|
||||||
|
)
|
||||||
|
|
||||||
return results
|
return results
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ async def graph_query_completion(query: str) -> list:
|
||||||
"context": retrieved_edges_to_string(found_triplets),
|
"context": retrieved_edges_to_string(found_triplets),
|
||||||
}
|
}
|
||||||
user_prompt = render_prompt("graph_context_for_question.txt", args)
|
user_prompt = render_prompt("graph_context_for_question.txt", args)
|
||||||
system_prompt = read_query_prompt("answer_simple_question_restricted.txt")
|
system_prompt = read_query_prompt("answer_simple_question.txt")
|
||||||
|
|
||||||
llm_client = get_llm_client()
|
llm_client = get_llm_client()
|
||||||
computed_answer = await llm_client.acreate_structured_output(
|
computed_answer = await llm_client.acreate_structured_output(
|
||||||
|
|
|
||||||
84
poetry.lock
generated
84
poetry.lock
generated
|
|
@ -1,4 +1,4 @@
|
||||||
# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aiofiles"
|
name = "aiofiles"
|
||||||
|
|
@ -5510,8 +5510,8 @@ files = [
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
numpy = [
|
numpy = [
|
||||||
{version = ">=1.22.4", markers = "python_version < \"3.11\""},
|
{version = ">=1.22.4", markers = "python_version < \"3.11\""},
|
||||||
{version = ">=1.23.2", markers = "python_version == \"3.11\""},
|
|
||||||
{version = ">=1.26.0", markers = "python_version >= \"3.12\""},
|
{version = ">=1.26.0", markers = "python_version >= \"3.12\""},
|
||||||
|
{version = ">=1.23.2", markers = "python_version == \"3.11\""},
|
||||||
]
|
]
|
||||||
python-dateutil = ">=2.8.2"
|
python-dateutil = ">=2.8.2"
|
||||||
pytz = ">=2020.1"
|
pytz = ">=2020.1"
|
||||||
|
|
@ -6572,8 +6572,8 @@ astroid = ">=3.3.8,<=3.4.0-dev0"
|
||||||
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
|
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
|
||||||
dill = [
|
dill = [
|
||||||
{version = ">=0.2", markers = "python_version < \"3.11\""},
|
{version = ">=0.2", markers = "python_version < \"3.11\""},
|
||||||
{version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
|
|
||||||
{version = ">=0.3.7", markers = "python_version >= \"3.12\""},
|
{version = ">=0.3.7", markers = "python_version >= \"3.12\""},
|
||||||
|
{version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
|
||||||
]
|
]
|
||||||
isort = ">=4.2.5,<5.13.0 || >5.13.0,<7"
|
isort = ">=4.2.5,<5.13.0 || >5.13.0,<7"
|
||||||
mccabe = ">=0.6,<0.8"
|
mccabe = ">=0.6,<0.8"
|
||||||
|
|
@ -6688,6 +6688,57 @@ files = [
|
||||||
[package.extras]
|
[package.extras]
|
||||||
dev = ["build", "flake8", "mypy", "pytest", "twine"]
|
dev = ["build", "flake8", "mypy", "pytest", "twine"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyside6"
|
||||||
|
version = "6.8.2.1"
|
||||||
|
description = "Python bindings for the Qt cross-platform application and UI framework"
|
||||||
|
optional = true
|
||||||
|
python-versions = "<3.14,>=3.9"
|
||||||
|
files = [
|
||||||
|
{file = "PySide6-6.8.2.1-cp39-abi3-macosx_12_0_universal2.whl", hash = "sha256:3fcb551729f235475b2abe7d919027de54a65d850e744f60716f890202273720"},
|
||||||
|
{file = "PySide6-6.8.2.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:23d2a1a77b25459a049c4276b4e0bbfb375b73d3921061b1a16bcfa64e1fe517"},
|
||||||
|
{file = "PySide6-6.8.2.1-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:bfefa80a93db06dc64c0e7beef0377c9b8ca51e007cfc34575defe065af893b6"},
|
||||||
|
{file = "PySide6-6.8.2.1-cp39-abi3-win_amd64.whl", hash = "sha256:92361e41727910e3560ea5ba494fabecc76cd20892c9fcb2ced07619081c4e65"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
PySide6-Addons = "6.8.2.1"
|
||||||
|
PySide6-Essentials = "6.8.2.1"
|
||||||
|
shiboken6 = "6.8.2.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyside6-addons"
|
||||||
|
version = "6.8.2.1"
|
||||||
|
description = "Python bindings for the Qt cross-platform application and UI framework (Addons)"
|
||||||
|
optional = true
|
||||||
|
python-versions = "<3.14,>=3.9"
|
||||||
|
files = [
|
||||||
|
{file = "PySide6_Addons-6.8.2.1-cp39-abi3-macosx_12_0_universal2.whl", hash = "sha256:5558816018042fecd0d782111ced529585a23ea9a010b518f8495764f578a01f"},
|
||||||
|
{file = "PySide6_Addons-6.8.2.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f3d85e676851ada8238bc76ebfacbee738fc0b35b3bc15c9765dd107b8ee6ec4"},
|
||||||
|
{file = "PySide6_Addons-6.8.2.1-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:d904179f16deeca4ba440b4ef78e8d54df2b994b46784ad9d53b741082f3b2a7"},
|
||||||
|
{file = "PySide6_Addons-6.8.2.1-cp39-abi3-win_amd64.whl", hash = "sha256:c761cc45022aa79d8419e671e7fb34a4a3e5b3826f1e68fcb819bd6e3a387fbb"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
PySide6-Essentials = "6.8.2.1"
|
||||||
|
shiboken6 = "6.8.2.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyside6-essentials"
|
||||||
|
version = "6.8.2.1"
|
||||||
|
description = "Python bindings for the Qt cross-platform application and UI framework (Essentials)"
|
||||||
|
optional = true
|
||||||
|
python-versions = "<3.14,>=3.9"
|
||||||
|
files = [
|
||||||
|
{file = "PySide6_Essentials-6.8.2.1-cp39-abi3-macosx_12_0_universal2.whl", hash = "sha256:ae5cc48f7e9a08e73e3ec2387ce245c8150e620b8d5a87548ebd4b8e3aeae49b"},
|
||||||
|
{file = "PySide6_Essentials-6.8.2.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5ab31e5395a4724102edd6e8ff980fa3f7cde2aa79050763a1dcc30bb914195a"},
|
||||||
|
{file = "PySide6_Essentials-6.8.2.1-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:7aed46f91d44399b4c713cf7387f5fb6f0114413fbcdbde493a528fb8e19f6ed"},
|
||||||
|
{file = "PySide6_Essentials-6.8.2.1-cp39-abi3-win_amd64.whl", hash = "sha256:18de224f09108998d194e60f2fb8a1e86367dd525dd8a6192598e80e6ada649e"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
shiboken6 = "6.8.2.1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pysocks"
|
name = "pysocks"
|
||||||
version = "1.7.1"
|
version = "1.7.1"
|
||||||
|
|
@ -7151,6 +7202,17 @@ files = [
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
cffi = {version = "*", markers = "implementation_name == \"pypy\""}
|
cffi = {version = "*", markers = "implementation_name == \"pypy\""}
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "qasync"
|
||||||
|
version = "0.27.1"
|
||||||
|
description = "Python library for using asyncio in Qt-based applications"
|
||||||
|
optional = true
|
||||||
|
python-versions = ">=3.8,<4.0"
|
||||||
|
files = [
|
||||||
|
{file = "qasync-0.27.1-py3-none-any.whl", hash = "sha256:5d57335723bc7d9b328dadd8cb2ed7978640e4bf2da184889ce50ee3ad2602c7"},
|
||||||
|
{file = "qasync-0.27.1.tar.gz", hash = "sha256:8dc768fd1ee5de1044c7c305eccf2d39d24d87803ea71189d4024fb475f4985f"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "qdrant-client"
|
name = "qdrant-client"
|
||||||
version = "1.13.2"
|
version = "1.13.2"
|
||||||
|
|
@ -8036,6 +8098,19 @@ files = [
|
||||||
{file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"},
|
{file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shiboken6"
|
||||||
|
version = "6.8.2.1"
|
||||||
|
description = "Python/C++ bindings helper module"
|
||||||
|
optional = true
|
||||||
|
python-versions = "<3.14,>=3.9"
|
||||||
|
files = [
|
||||||
|
{file = "shiboken6-6.8.2.1-cp39-abi3-macosx_12_0_universal2.whl", hash = "sha256:d3dedeb3732ecfc920c9f97da769c0022a1c3bda99346a9eba56fbf093deaa75"},
|
||||||
|
{file = "shiboken6-6.8.2.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c83e90056f13d0872cc4d2b7bf60b6d6e3b1b172f1f91910c0ba5b641af01758"},
|
||||||
|
{file = "shiboken6-6.8.2.1-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:8592401423acc693f51dbbfae5e7493cc3ed6738be79daaf90afa07f4da5bb25"},
|
||||||
|
{file = "shiboken6-6.8.2.1-cp39-abi3-win_amd64.whl", hash = "sha256:1b751d47b759762b7ca31bad278d52eca4105d3028880d93979261ebbfba810c"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "simplejson"
|
name = "simplejson"
|
||||||
version = "3.19.3"
|
version = "3.19.3"
|
||||||
|
|
@ -9670,6 +9745,7 @@ falkordb = ["falkordb"]
|
||||||
filesystem = ["botocore"]
|
filesystem = ["botocore"]
|
||||||
gemini = ["google-generativeai"]
|
gemini = ["google-generativeai"]
|
||||||
groq = ["groq"]
|
groq = ["groq"]
|
||||||
|
gui = ["pyside6", "qasync"]
|
||||||
huggingface = ["transformers"]
|
huggingface = ["transformers"]
|
||||||
langchain = ["langchain_text_splitters", "langsmith"]
|
langchain = ["langchain_text_splitters", "langsmith"]
|
||||||
llama-index = ["llama-index-core"]
|
llama-index = ["llama-index-core"]
|
||||||
|
|
@ -9685,4 +9761,4 @@ weaviate = ["weaviate-client"]
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = ">=3.10.0,<3.13"
|
python-versions = ">=3.10.0,<3.13"
|
||||||
content-hash = "2029859075342dacf6c2f2e993894daef07e50a5e2047152158bf9116a48579b"
|
content-hash = "d384b6028d84b344b40b6c7e047d592700227409aa3a4d961e157cd824fa50b5"
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,8 @@ tree-sitter = {version = "^0.24.0", optional = true}
|
||||||
tree-sitter-python = {version = "^0.23.6", optional = true}
|
tree-sitter-python = {version = "^0.23.6", optional = true}
|
||||||
plotly = {version = "^6.0.0", optional = true}
|
plotly = {version = "^6.0.0", optional = true}
|
||||||
gdown = {version = "^5.2.0", optional = true}
|
gdown = {version = "^5.2.0", optional = true}
|
||||||
|
pyside6 = {version = "^6.8.2.1", optional = true}
|
||||||
|
qasync = {version = "^0.27.1", optional = true}
|
||||||
|
|
||||||
|
|
||||||
[tool.poetry.extras]
|
[tool.poetry.extras]
|
||||||
|
|
@ -106,6 +108,7 @@ milvus = ["pymilvus"]
|
||||||
docs = ["unstructured"]
|
docs = ["unstructured"]
|
||||||
codegraph = ["fastembed", "tree-sitter", "tree-sitter-python"]
|
codegraph = ["fastembed", "tree-sitter", "tree-sitter-python"]
|
||||||
evals = ["plotly", "gdown"]
|
evals = ["plotly", "gdown"]
|
||||||
|
gui = ["pyside6", "qasync"]
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
pytest = "^7.4.0"
|
pytest = "^7.4.0"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue