reformat
This commit is contained in:
parent
6a087cbdfc
commit
30fd84e20d
9 changed files with 126 additions and 74 deletions
|
|
@ -43,12 +43,10 @@ Perfect for managing Cognee from the terminal or SSH sessions!
|
||||||
|
|
||||||
# Import and run TUI
|
# Import and run TUI
|
||||||
from cognee.cli.tui import run_tui
|
from cognee.cli.tui import run_tui
|
||||||
|
|
||||||
run_tui(mouse=not args.no_mouse)
|
run_tui(mouse=not args.no_mouse)
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
fmt.note("\nTUI closed by user")
|
fmt.note("\nTUI closed by user")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise CliCommandException(
|
raise CliCommandException(f"Failed to start TUI: {str(e)}", error_code=1) from e
|
||||||
f"Failed to start TUI: {str(e)}",
|
|
||||||
error_code=1
|
|
||||||
) from e
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""Cognee TUI - Terminal User Interface"""
|
"""Cognee TUI - Terminal User Interface"""
|
||||||
|
|
||||||
from cognee.cli.tui.app import run_tui, CogneeTUI
|
from cognee.cli.tui.app import run_tui, CogneeTUI
|
||||||
|
|
||||||
__all__ = ["run_tui", "CogneeTUI"]
|
__all__ = ["run_tui", "CogneeTUI"]
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
Cognee TUI - Main Application
|
Cognee TUI - Main Application
|
||||||
Text-based User Interface for managing Cognee knowledge graphs
|
Text-based User Interface for managing Cognee knowledge graphs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import ClassVar
|
from typing import ClassVar
|
||||||
from textual.app import App, ComposeResult
|
from textual.app import App, ComposeResult
|
||||||
from textual.binding import Binding
|
from textual.binding import Binding
|
||||||
|
|
@ -75,6 +76,7 @@ class CogneeTUI(App):
|
||||||
Binding("?", "help", "Help"),
|
Binding("?", "help", "Help"),
|
||||||
Binding("d", "toggle_dark", "Toggle Dark Mode"),
|
Binding("d", "toggle_dark", "Toggle Dark Mode"),
|
||||||
]
|
]
|
||||||
|
|
||||||
def on_mount(self) -> None:
|
def on_mount(self) -> None:
|
||||||
"""Initialize the app with the home screen"""
|
"""Initialize the app with the home screen"""
|
||||||
self.push_screen(HomeScreen())
|
self.push_screen(HomeScreen())
|
||||||
|
|
@ -104,7 +106,6 @@ class CogneeTUI(App):
|
||||||
self.push_screen(HelpScreen(help_text))
|
self.push_screen(HelpScreen(help_text))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class HelpScreen(Screen):
|
class HelpScreen(Screen):
|
||||||
"""Help screen"""
|
"""Help screen"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""Screens for Cognee TUI"""
|
"""Screens for Cognee TUI"""
|
||||||
|
|
||||||
from cognee.cli.tui.screens.home import HomeScreen
|
from cognee.cli.tui.screens.home import HomeScreen
|
||||||
from cognee.cli.tui.screens.context import ContextScreen
|
from cognee.cli.tui.screens.context import ContextScreen
|
||||||
from cognee.cli.tui.screens.query import QueryScreen
|
from cognee.cli.tui.screens.query import QueryScreen
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""Context Management Screen"""
|
"""Context Management Screen"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
|
|
@ -49,15 +50,23 @@ class ContextScreen(Screen):
|
||||||
yield DataTable(id="files_table")
|
yield DataTable(id="files_table")
|
||||||
# Tables are the primary UI (no dropdowns)
|
# Tables are the primary UI (no dropdowns)
|
||||||
yield Input(placeholder="comma-separated node sets (optional)", id="nodeset_input")
|
yield Input(placeholder="comma-separated node sets (optional)", id="nodeset_input")
|
||||||
yield Static("\nEnter text or a file path to add to the selected dataset:", classes="center")
|
yield Static(
|
||||||
|
"\nEnter text or a file path to add to the selected dataset:", classes="center"
|
||||||
|
)
|
||||||
yield Input(placeholder="Text or /absolute/path/to/file.pdf", id="data_input")
|
yield Input(placeholder="Text or /absolute/path/to/file.pdf", id="data_input")
|
||||||
yield Button("Add to Context", id="add_btn", variant="primary")
|
yield Button("Add to Context", id="add_btn", variant="primary")
|
||||||
yield Button("Cognify (process data)", id="cognify_btn", variant="success")
|
yield Button("Cognify (process data)", id="cognify_btn", variant="success")
|
||||||
yield Static("\nSearch (runs against selected dataset context):", classes="center")
|
yield Static("\nSearch (runs against selected dataset context):", classes="center")
|
||||||
yield Input(placeholder="e.g., What are the main topics?", id="search_input")
|
yield Input(placeholder="e.g., What are the main topics?", id="search_input")
|
||||||
yield Button("Search", id="search_btn", variant="default")
|
yield Button("Search", id="search_btn", variant="default")
|
||||||
yield Checkbox("Save search output to searched_context.md", id="save_search_checkbox", value=False)
|
yield Checkbox(
|
||||||
yield Static("\nExport context to Markdown (runs one or more queries):", classes="center")
|
"Save search output to searched_context.md",
|
||||||
|
id="save_search_checkbox",
|
||||||
|
value=False,
|
||||||
|
)
|
||||||
|
yield Static(
|
||||||
|
"\nExport context to Markdown (runs one or more queries):", classes="center"
|
||||||
|
)
|
||||||
yield Input(placeholder="Queries to export (comma-separated)", id="export_queries")
|
yield Input(placeholder="Queries to export (comma-separated)", id="export_queries")
|
||||||
yield Button("Export Context to MD", id="export_btn", variant="default")
|
yield Button("Export Context to MD", id="export_btn", variant="default")
|
||||||
yield Static("", id="status")
|
yield Static("", id="status")
|
||||||
|
|
@ -93,7 +102,9 @@ class ContextScreen(Screen):
|
||||||
self._dataset_row_to_id.clear()
|
self._dataset_row_to_id.clear()
|
||||||
self._dataset_row_keys = []
|
self._dataset_row_keys = []
|
||||||
for d in normalized:
|
for d in normalized:
|
||||||
row_key = ds_table.add_row(d.get("name", ""), d.get("id", ""), d.get("created_at", "") or "")
|
row_key = ds_table.add_row(
|
||||||
|
d.get("name", ""), d.get("id", ""), d.get("created_at", "") or ""
|
||||||
|
)
|
||||||
self._dataset_row_to_id[row_key] = d["id"]
|
self._dataset_row_to_id[row_key] = d["id"]
|
||||||
self._dataset_row_keys.append(row_key)
|
self._dataset_row_keys.append(row_key)
|
||||||
# Focus datasets table and preselect first row if available
|
# Focus datasets table and preselect first row if available
|
||||||
|
|
@ -149,7 +160,17 @@ class ContextScreen(Screen):
|
||||||
self._file_row_to_id.clear()
|
self._file_row_to_id.clear()
|
||||||
self._file_row_keys = []
|
self._file_row_keys = []
|
||||||
for i in normalized:
|
for i in normalized:
|
||||||
row_key = files_table.add_row(i.get("name", ""), i.get("id", ""), (i.get("original_data_location") or i.get("raw_data_location") or i.get("orig") or i.get("raw") or "") )
|
row_key = files_table.add_row(
|
||||||
|
i.get("name", ""),
|
||||||
|
i.get("id", ""),
|
||||||
|
(
|
||||||
|
i.get("original_data_location")
|
||||||
|
or i.get("raw_data_location")
|
||||||
|
or i.get("orig")
|
||||||
|
or i.get("raw")
|
||||||
|
or ""
|
||||||
|
),
|
||||||
|
)
|
||||||
self._file_row_to_id[row_key] = i["id"]
|
self._file_row_to_id[row_key] = i["id"]
|
||||||
self._file_row_keys.append(row_key)
|
self._file_row_keys.append(row_key)
|
||||||
self._selected_data_id = None
|
self._selected_data_id = None
|
||||||
|
|
@ -169,8 +190,10 @@ class ContextScreen(Screen):
|
||||||
await self._set_status("[red]Please enter text or a file path[/red]")
|
await self._set_status("[red]Please enter text or a file path[/red]")
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
await self._set_status(f"Adding data to dataset [b]{dataset_name}[/b] "
|
await self._set_status(
|
||||||
f"{'(with node sets: ' + ', '.join(node_set) + ')' if node_set else ''}...")
|
f"Adding data to dataset [b]{dataset_name}[/b] "
|
||||||
|
f"{'(with node sets: ' + ', '.join(node_set) + ')' if node_set else ''}..."
|
||||||
|
)
|
||||||
with redirect_stdout(io.StringIO()), redirect_stderr(io.StringIO()):
|
with redirect_stdout(io.StringIO()), redirect_stderr(io.StringIO()):
|
||||||
await cognee.add(content, dataset_name=dataset_name, node_set=node_set)
|
await cognee.add(content, dataset_name=dataset_name, node_set=node_set)
|
||||||
await self._set_status("[green]✓ Added successfully.[/green] You can now run Cognify.")
|
await self._set_status("[green]✓ Added successfully.[/green] You can now run Cognify.")
|
||||||
|
|
@ -202,7 +225,11 @@ class ContextScreen(Screen):
|
||||||
if ds_name:
|
if ds_name:
|
||||||
kwargs["datasets"] = [ds_name]
|
kwargs["datasets"] = [ds_name]
|
||||||
results = await cognee.search(query_text=query_text, **kwargs)
|
results = await cognee.search(query_text=query_text, **kwargs)
|
||||||
rendered = "\n".join(f"- {str(item)}" for item in results) if isinstance(results, list) else str(results)
|
rendered = (
|
||||||
|
"\n".join(f"- {str(item)}" for item in results)
|
||||||
|
if isinstance(results, list)
|
||||||
|
else str(results)
|
||||||
|
)
|
||||||
await self._set_status(f"[b]Search results[/b]:\n{rendered}")
|
await self._set_status(f"[b]Search results[/b]:\n{rendered}")
|
||||||
# Optionally save to searched_context.md
|
# Optionally save to searched_context.md
|
||||||
if save_cb.value:
|
if save_cb.value:
|
||||||
|
|
@ -211,10 +238,17 @@ class ContextScreen(Screen):
|
||||||
if self._selected_data_id:
|
if self._selected_data_id:
|
||||||
data_item = self._data_items_by_id.get(self._selected_data_id)
|
data_item = self._data_items_by_id.get(self._selected_data_id)
|
||||||
if data_item:
|
if data_item:
|
||||||
loc = data_item.get("original_data_location") or data_item.get("raw_data_location") or data_item.get("orig") or data_item.get("raw")
|
loc = (
|
||||||
|
data_item.get("original_data_location")
|
||||||
|
or data_item.get("raw_data_location")
|
||||||
|
or data_item.get("orig")
|
||||||
|
or data_item.get("raw")
|
||||||
|
)
|
||||||
if isinstance(loc, str) and loc.startswith("file://"):
|
if isinstance(loc, str) and loc.startswith("file://"):
|
||||||
loc = loc[len("file://") :]
|
loc = loc[len("file://") :]
|
||||||
if isinstance(loc, str) and (loc.startswith("/") or (len(loc) > 2 and loc[1:3] in (":\\", ":/"))):
|
if isinstance(loc, str) and (
|
||||||
|
loc.startswith("/") or (len(loc) > 2 and loc[1:3] in (":\\", ":/"))
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
p = Path(loc)
|
p = Path(loc)
|
||||||
target_dir = p.parent if p.exists() or p.parent.exists() else None
|
target_dir = p.parent if p.exists() or p.parent.exists() else None
|
||||||
|
|
@ -241,7 +275,9 @@ class ContextScreen(Screen):
|
||||||
# Accept absolute POSIX paths or file:// URIs
|
# Accept absolute POSIX paths or file:// URIs
|
||||||
if isinstance(loc, str) and loc.startswith("file://"):
|
if isinstance(loc, str) and loc.startswith("file://"):
|
||||||
loc = loc[len("file://") :]
|
loc = loc[len("file://") :]
|
||||||
if not isinstance(loc, str) or not (loc.startswith("/") or loc[1:3] == ":\\" or loc[1:3] == ":/"):
|
if not isinstance(loc, str) or not (
|
||||||
|
loc.startswith("/") or loc[1:3] == ":\\" or loc[1:3] == ":/"
|
||||||
|
):
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
p = Path(loc)
|
p = Path(loc)
|
||||||
|
|
@ -266,17 +302,21 @@ class ContextScreen(Screen):
|
||||||
return
|
return
|
||||||
export_path = self._choose_export_path(data_item)
|
export_path = self._choose_export_path(data_item)
|
||||||
if not export_path:
|
if not export_path:
|
||||||
await self._set_status("[red]Can't determine a local file path to save Markdown next to the original file.[/red]")
|
await self._set_status(
|
||||||
|
"[red]Can't determine a local file path to save Markdown next to the original file.[/red]"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
raw_queries = (export_queries.value or "").strip()
|
raw_queries = (export_queries.value or "").strip()
|
||||||
queries = [q.strip() for q in raw_queries.split(",") if q.strip()]
|
queries = [q.strip() for q in raw_queries.split(",") if q.strip()]
|
||||||
await self._set_status("Running export...")
|
await self._set_status("Running export...")
|
||||||
md_parts: list[str] = []
|
md_parts: list[str] = []
|
||||||
md_parts.append(f"# Context Export for {data_item.get('name','selected item')}")
|
md_parts.append(f"# Context Export for {data_item.get('name', 'selected item')}")
|
||||||
# Include simple metadata block
|
# Include simple metadata block
|
||||||
md_parts.append("")
|
md_parts.append("")
|
||||||
md_parts.append("## Source")
|
md_parts.append("## Source")
|
||||||
md_parts.append(f"- Dataset: {self._dataset_id_to_name.get(self._selected_dataset_id, self.DEFAULT_DATASET)}")
|
md_parts.append(
|
||||||
|
f"- Dataset: {self._dataset_id_to_name.get(self._selected_dataset_id, self.DEFAULT_DATASET)}"
|
||||||
|
)
|
||||||
if data_item.get("orig"):
|
if data_item.get("orig"):
|
||||||
md_parts.append(f"- Original: {data_item.get('orig')}")
|
md_parts.append(f"- Original: {data_item.get('orig')}")
|
||||||
if data_item.get("raw"):
|
if data_item.get("raw"):
|
||||||
|
|
@ -409,7 +449,11 @@ class ContextScreen(Screen):
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
if event.key in ("up", "down"):
|
if event.key in ("up", "down"):
|
||||||
max_rows = len(self._file_row_keys) if table.id == "files_table" else len(self._dataset_row_keys)
|
max_rows = (
|
||||||
|
len(self._file_row_keys)
|
||||||
|
if table.id == "files_table"
|
||||||
|
else len(self._dataset_row_keys)
|
||||||
|
)
|
||||||
if max_rows <= 0:
|
if max_rows <= 0:
|
||||||
return
|
return
|
||||||
if event.key == "up":
|
if event.key == "up":
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""Home Screen for Cognee TUI"""
|
"""Home Screen for Cognee TUI"""
|
||||||
|
|
||||||
from textual.screen import Screen
|
from textual.screen import Screen
|
||||||
from textual.app import ComposeResult
|
from textual.app import ComposeResult
|
||||||
from textual.widgets import Header, Footer, Button, Static
|
from textual.widgets import Header, Footer, Button, Static
|
||||||
|
|
@ -31,14 +32,17 @@ class HomeScreen(Screen):
|
||||||
|
|
||||||
if button_id == "context":
|
if button_id == "context":
|
||||||
from cognee.cli.tui.screens.context import ContextScreen
|
from cognee.cli.tui.screens.context import ContextScreen
|
||||||
|
|
||||||
self.app.push_screen(ContextScreen())
|
self.app.push_screen(ContextScreen())
|
||||||
|
|
||||||
elif button_id == "query":
|
elif button_id == "query":
|
||||||
from cognee.cli.tui.screens.query import QueryScreen
|
from cognee.cli.tui.screens.query import QueryScreen
|
||||||
|
|
||||||
self.app.push_screen(QueryScreen())
|
self.app.push_screen(QueryScreen())
|
||||||
|
|
||||||
elif button_id == "settings":
|
elif button_id == "settings":
|
||||||
from cognee.cli.tui.screens.settings import SettingsScreen
|
from cognee.cli.tui.screens.settings import SettingsScreen
|
||||||
|
|
||||||
self.app.push_screen(SettingsScreen())
|
self.app.push_screen(SettingsScreen())
|
||||||
|
|
||||||
elif button_id == "help":
|
elif button_id == "help":
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""Query Screen"""
|
"""Query Screen"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from textual.screen import Screen
|
from textual.screen import Screen
|
||||||
from textual.app import ComposeResult
|
from textual.app import ComposeResult
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
"""Settings Screen"""
|
"""Settings Screen"""
|
||||||
|
|
||||||
from textual.screen import Screen
|
from textual.screen import Screen
|
||||||
from textual.app import ComposeResult
|
from textual.app import ComposeResult
|
||||||
from textual.widgets import Header, Footer, Button, Static
|
from textual.widgets import Header, Footer, Button, Static
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
"""Custom widgets for Cognee TUI"""
|
"""Custom widgets for Cognee TUI"""
|
||||||
|
|
||||||
# Custom widgets can be added here as needed
|
# Custom widgets can be added here as needed
|
||||||
__all__ = []
|
__all__ = []
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue