format: ruff format

This commit is contained in:
Daulet Amirkhanov 2025-09-10 14:16:02 +01:00
parent 88ac0fc46c
commit db705f75ab
2 changed files with 124 additions and 114 deletions

View file

@ -32,30 +32,30 @@ def get_frontend_download_info() -> Tuple[str, str]:
Downloads the real frontend from GitHub releases, matching the installed version. Downloads the real frontend from GitHub releases, matching the installed version.
""" """
version = get_cognee_version() version = get_cognee_version()
# Clean up version string (remove -local suffix for development) # Clean up version string (remove -local suffix for development)
clean_version = version.replace('-local', '') clean_version = version.replace("-local", "")
# Download from specific release tag to ensure version compatibility # Download from specific release tag to ensure version compatibility
download_url = f"https://github.com/topoteretes/cognee/archive/refs/tags/v{clean_version}.zip" download_url = f"https://github.com/topoteretes/cognee/archive/refs/tags/v{clean_version}.zip"
return download_url, version return download_url, version
def download_frontend_assets(force: bool = False) -> bool: def download_frontend_assets(force: bool = False) -> bool:
""" """
Download and cache frontend assets. Download and cache frontend assets.
Args: Args:
force: If True, re-download even if already cached force: If True, re-download even if already cached
Returns: Returns:
bool: True if successful, False otherwise bool: True if successful, False otherwise
""" """
cache_dir = get_frontend_cache_dir() cache_dir = get_frontend_cache_dir()
frontend_dir = cache_dir / "frontend" frontend_dir = cache_dir / "frontend"
version_file = cache_dir / "version.txt" version_file = cache_dir / "version.txt"
# Check if already downloaded and up to date # Check if already downloaded and up to date
if not force and frontend_dir.exists() and version_file.exists(): if not force and frontend_dir.exists() and version_file.exists():
try: try:
@ -66,37 +66,39 @@ def download_frontend_assets(force: bool = False) -> bool:
return True return True
except Exception as e: except Exception as e:
logger.debug(f"Error checking cached version: {e}") logger.debug(f"Error checking cached version: {e}")
download_url, version = get_frontend_download_info() download_url, version = get_frontend_download_info()
logger.info("Downloading cognee frontend assets...") logger.info("Downloading cognee frontend assets...")
logger.info("This is a one-time download and will be cached for future use.") logger.info("This is a one-time download and will be cached for future use.")
try: try:
# Create a temporary directory for download # Create a temporary directory for download
with tempfile.TemporaryDirectory() as temp_dir: with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir) temp_path = Path(temp_dir)
archive_path = temp_path / "cognee-main.zip" archive_path = temp_path / "cognee-main.zip"
# Download the actual cognee repository from releases # Download the actual cognee repository from releases
logger.info(f"Downloading cognee v{version.replace('-local', '')} from GitHub releases...") logger.info(
f"Downloading cognee v{version.replace('-local', '')} from GitHub releases..."
)
logger.info(f"URL: {download_url}") logger.info(f"URL: {download_url}")
response = requests.get(download_url, stream=True, timeout=60) response = requests.get(download_url, stream=True, timeout=60)
response.raise_for_status() response.raise_for_status()
with open(archive_path, 'wb') as f: with open(archive_path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192): for chunk in response.iter_content(chunk_size=8192):
f.write(chunk) f.write(chunk)
# Extract the archive and find the cognee-frontend directory # Extract the archive and find the cognee-frontend directory
if frontend_dir.exists(): if frontend_dir.exists():
shutil.rmtree(frontend_dir) shutil.rmtree(frontend_dir)
with zipfile.ZipFile(archive_path, 'r') as zip_file: with zipfile.ZipFile(archive_path, "r") as zip_file:
# Extract to temp directory first # Extract to temp directory first
extract_dir = temp_path / "extracted" extract_dir = temp_path / "extracted"
zip_file.extractall(extract_dir) zip_file.extractall(extract_dir)
# Find the cognee-frontend directory in the extracted content # Find the cognee-frontend directory in the extracted content
# The archive structure will be: cognee-{version}/cognee-frontend/ # The archive structure will be: cognee-{version}/cognee-frontend/
cognee_frontend_source = None cognee_frontend_source = None
@ -104,26 +106,32 @@ def download_frontend_assets(force: bool = False) -> bool:
if "cognee-frontend" in dirs: if "cognee-frontend" in dirs:
cognee_frontend_source = Path(root) / "cognee-frontend" cognee_frontend_source = Path(root) / "cognee-frontend"
break break
if not cognee_frontend_source or not cognee_frontend_source.exists(): if not cognee_frontend_source or not cognee_frontend_source.exists():
logger.error("Could not find cognee-frontend directory in downloaded release archive") logger.error(
"Could not find cognee-frontend directory in downloaded release archive"
)
logger.error("This might indicate a version mismatch or missing release.") logger.error("This might indicate a version mismatch or missing release.")
return False return False
# Copy the cognee-frontend to our cache # Copy the cognee-frontend to our cache
shutil.copytree(cognee_frontend_source, frontend_dir) shutil.copytree(cognee_frontend_source, frontend_dir)
logger.debug(f"Frontend extracted to: {frontend_dir}") logger.debug(f"Frontend extracted to: {frontend_dir}")
# Write version info # Write version info
version_file.write_text(version) version_file.write_text(version)
logger.info(f"✓ Cognee frontend v{version.replace('-local', '')} downloaded and cached successfully!") logger.info(
f"✓ Cognee frontend v{version.replace('-local', '')} downloaded and cached successfully!"
)
return True return True
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
if "404" in str(e): if "404" in str(e):
logger.error(f"Release v{version.replace('-local', '')} not found on GitHub.") logger.error(f"Release v{version.replace('-local', '')} not found on GitHub.")
logger.error("This version might not have been released yet, or you're using a development version.") logger.error(
"This version might not have been released yet, or you're using a development version."
)
logger.error("Try using a stable release version of cognee.") logger.error("Try using a stable release version of cognee.")
else: else:
logger.error(f"Failed to download from GitHub: {str(e)}") logger.error(f"Failed to download from GitHub: {str(e)}")
@ -135,35 +143,33 @@ def download_frontend_assets(force: bool = False) -> bool:
return False return False
def find_frontend_path() -> Optional[Path]: def find_frontend_path() -> Optional[Path]:
""" """
Find the cognee-frontend directory. Find the cognee-frontend directory.
Checks both development location and cached download location. Checks both development location and cached download location.
""" """
current_file = Path(__file__) current_file = Path(__file__)
# First, try development paths (for contributors/developers) # First, try development paths (for contributors/developers)
dev_search_paths = [ dev_search_paths = [
current_file.parents[4] / "cognee-frontend", # from cognee/api/v1/ui/ui.py to project root current_file.parents[4] / "cognee-frontend", # from cognee/api/v1/ui/ui.py to project root
current_file.parents[3] / "cognee-frontend", # fallback path current_file.parents[3] / "cognee-frontend", # fallback path
current_file.parents[2] / "cognee-frontend", # another fallback current_file.parents[2] / "cognee-frontend", # another fallback
] ]
for path in dev_search_paths: for path in dev_search_paths:
if path.exists() and (path / "package.json").exists(): if path.exists() and (path / "package.json").exists():
logger.debug(f"Found development frontend at: {path}") logger.debug(f"Found development frontend at: {path}")
return path return path
# Then try cached download location (for pip-installed users) # Then try cached download location (for pip-installed users)
cache_dir = get_frontend_cache_dir() cache_dir = get_frontend_cache_dir()
cached_frontend = cache_dir / "frontend" cached_frontend = cache_dir / "frontend"
if cached_frontend.exists() and (cached_frontend / "package.json").exists(): if cached_frontend.exists() and (cached_frontend / "package.json").exists():
logger.debug(f"Found cached frontend at: {cached_frontend}") logger.debug(f"Found cached frontend at: {cached_frontend}")
return cached_frontend return cached_frontend
return None return None
@ -174,25 +180,23 @@ def check_node_npm() -> tuple[bool, str]:
""" """
try: try:
# Check Node.js # Check Node.js
result = subprocess.run(["node", "--version"], result = subprocess.run(["node", "--version"], capture_output=True, text=True, timeout=10)
capture_output=True, text=True, timeout=10)
if result.returncode != 0: if result.returncode != 0:
return False, "Node.js is not installed or not in PATH" return False, "Node.js is not installed or not in PATH"
node_version = result.stdout.strip() node_version = result.stdout.strip()
logger.debug(f"Found Node.js version: {node_version}") logger.debug(f"Found Node.js version: {node_version}")
# Check npm # Check npm
result = subprocess.run(["npm", "--version"], result = subprocess.run(["npm", "--version"], capture_output=True, text=True, timeout=10)
capture_output=True, text=True, timeout=10)
if result.returncode != 0: if result.returncode != 0:
return False, "npm is not installed or not in PATH" return False, "npm is not installed or not in PATH"
npm_version = result.stdout.strip() npm_version = result.stdout.strip()
logger.debug(f"Found npm version: {npm_version}") logger.debug(f"Found npm version: {npm_version}")
return True, f"Node.js {node_version}, npm {npm_version}" return True, f"Node.js {node_version}, npm {npm_version}"
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
return False, "Timeout checking Node.js/npm installation" return False, "Timeout checking Node.js/npm installation"
except FileNotFoundError: except FileNotFoundError:
@ -210,25 +214,25 @@ def install_frontend_dependencies(frontend_path: Path) -> bool:
if node_modules.exists(): if node_modules.exists():
logger.debug("Frontend dependencies already installed") logger.debug("Frontend dependencies already installed")
return True return True
logger.info("Installing frontend dependencies (this may take a few minutes)...") logger.info("Installing frontend dependencies (this may take a few minutes)...")
try: try:
result = subprocess.run( result = subprocess.run(
["npm", "install"], ["npm", "install"],
cwd=frontend_path, cwd=frontend_path,
capture_output=True, capture_output=True,
text=True, text=True,
timeout=300 # 5 minutes timeout timeout=300, # 5 minutes timeout
) )
if result.returncode == 0: if result.returncode == 0:
logger.info("Frontend dependencies installed successfully") logger.info("Frontend dependencies installed successfully")
return True return True
else: else:
logger.error(f"Failed to install dependencies: {result.stderr}") logger.error(f"Failed to install dependencies: {result.stderr}")
return False return False
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
logger.error("Timeout installing frontend dependencies") logger.error("Timeout installing frontend dependencies")
return False return False
@ -244,16 +248,17 @@ def is_development_frontend(frontend_path: Path) -> bool:
package_json_path = frontend_path / "package.json" package_json_path = frontend_path / "package.json"
if not package_json_path.exists(): if not package_json_path.exists():
return False return False
try: try:
import json import json
with open(package_json_path) as f: with open(package_json_path) as f:
package_data = json.load(f) package_data = json.load(f)
# Development frontend has Next.js as dependency # Development frontend has Next.js as dependency
dependencies = package_data.get("dependencies", {}) dependencies = package_data.get("dependencies", {})
dev_dependencies = package_data.get("devDependencies", {}) dev_dependencies = package_data.get("devDependencies", {})
return "next" in dependencies or "next" in dev_dependencies return "next" in dependencies or "next" in dev_dependencies
except Exception: except Exception:
return False return False
@ -268,27 +273,20 @@ def start_python_server(frontend_path: Path, host: str, port: int) -> Optional[s
# Change to the frontend directory # Change to the frontend directory
original_cwd = os.getcwd() original_cwd = os.getcwd()
os.chdir(frontend_path) os.chdir(frontend_path)
# Use subprocess to run the server so we can return a process handle # Use subprocess to run the server so we can return a process handle
cmd = [ cmd = ["python", "-m", "http.server", str(port), "--bind", host]
"python", "-m", "http.server", str(port),
"--bind", host
]
process = subprocess.Popen( process = subprocess.Popen(
cmd, cmd, cwd=frontend_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
cwd=frontend_path,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
) )
# Restore original directory # Restore original directory
os.chdir(original_cwd) os.chdir(original_cwd)
# Give it a moment to start # Give it a moment to start
time.sleep(2) time.sleep(2)
# Check if process is still running # Check if process is still running
if process.poll() is not None: if process.poll() is not None:
stdout, stderr = process.communicate() stdout, stderr = process.communicate()
@ -296,9 +294,9 @@ def start_python_server(frontend_path: Path, host: str, port: int) -> Optional[s
logger.error(f"stdout: {stdout}") logger.error(f"stdout: {stdout}")
logger.error(f"stderr: {stderr}") logger.error(f"stderr: {stderr}")
return None return None
return process return process
except Exception as e: except Exception as e:
logger.error(f"Failed to start Python HTTP server: {str(e)}") logger.error(f"Failed to start Python HTTP server: {str(e)}")
# Restore original directory on error # Restore original directory on error
@ -315,9 +313,9 @@ def prompt_user_for_download() -> bool:
Returns True if user consents, False otherwise. Returns True if user consents, False otherwise.
""" """
try: try:
print("\n" + "="*60) print("\n" + "=" * 60)
print("🎨 Cognee UI Setup Required") print("🎨 Cognee UI Setup Required")
print("="*60) print("=" * 60)
print("The cognee frontend is not available on your system.") print("The cognee frontend is not available on your system.")
print("This is required to use the web interface.") print("This is required to use the web interface.")
print("\nWhat will happen:") print("\nWhat will happen:")
@ -326,34 +324,39 @@ def prompt_user_for_download() -> bool:
print("• Install dependencies with npm (requires Node.js)") print("• Install dependencies with npm (requires Node.js)")
print("• This is a one-time setup per cognee version") print("• This is a one-time setup per cognee version")
print("\nThe frontend will then be available offline for future use.") print("\nThe frontend will then be available offline for future use.")
response = input("\nWould you like to download the frontend now? (y/N): ").strip().lower() response = input("\nWould you like to download the frontend now? (y/N): ").strip().lower()
return response in ['y', 'yes'] return response in ["y", "yes"]
except (KeyboardInterrupt, EOFError): except (KeyboardInterrupt, EOFError):
print("\nOperation cancelled by user.") print("\nOperation cancelled by user.")
return False return False
def start_ui(host: str = "localhost", port: int = 3000, open_browser: bool = True, auto_download: bool = False) -> Optional[subprocess.Popen]: def start_ui(
host: str = "localhost",
port: int = 3000,
open_browser: bool = True,
auto_download: bool = False,
) -> Optional[subprocess.Popen]:
""" """
Start the cognee frontend UI server. Start the cognee frontend UI server.
This function will: This function will:
1. Find the cognee-frontend directory (development) or download it (pip install) 1. Find the cognee-frontend directory (development) or download it (pip install)
2. Check if Node.js and npm are available (for development mode) 2. Check if Node.js and npm are available (for development mode)
3. Install dependencies if needed (development mode) 3. Install dependencies if needed (development mode)
4. Start the appropriate server 4. Start the appropriate server
5. Optionally open the browser 5. Optionally open the browser
Args: Args:
host: Host to bind the server to (default: localhost) host: Host to bind the server to (default: localhost)
port: Port to run the server on (default: 3000) port: Port to run the server on (default: 3000)
open_browser: Whether to open the browser automatically (default: True) open_browser: Whether to open the browser automatically (default: True)
auto_download: If True, download frontend without prompting (default: False) auto_download: If True, download frontend without prompting (default: False)
Returns: Returns:
subprocess.Popen object representing the running server, or None if failed subprocess.Popen object representing the running server, or None if failed
Example: Example:
>>> import cognee >>> import cognee
>>> server = cognee.start_ui() >>> server = cognee.start_ui()
@ -362,19 +365,21 @@ def start_ui(host: str = "localhost", port: int = 3000, open_browser: bool = Tru
>>> server.terminate() >>> server.terminate()
""" """
logger.info("Starting cognee UI...") logger.info("Starting cognee UI...")
# Find frontend directory # Find frontend directory
frontend_path = find_frontend_path() frontend_path = find_frontend_path()
if not frontend_path: if not frontend_path:
logger.info("Frontend not found locally. This is normal for pip-installed cognee.") logger.info("Frontend not found locally. This is normal for pip-installed cognee.")
# Offer to download the frontend # Offer to download the frontend
if auto_download or prompt_user_for_download(): if auto_download or prompt_user_for_download():
if download_frontend_assets(): if download_frontend_assets():
frontend_path = find_frontend_path() frontend_path = find_frontend_path()
if not frontend_path: if not frontend_path:
logger.error("Download succeeded but frontend still not found. This is unexpected.") logger.error(
"Download succeeded but frontend still not found. This is unexpected."
)
return None return None
else: else:
logger.error("Failed to download frontend assets.") logger.error("Failed to download frontend assets.")
@ -383,30 +388,30 @@ def start_ui(host: str = "localhost", port: int = 3000, open_browser: bool = Tru
logger.info("Frontend download declined. UI functionality not available.") logger.info("Frontend download declined. UI functionality not available.")
logger.info("You can still use all other cognee features without the web interface.") logger.info("You can still use all other cognee features without the web interface.")
return None return None
# Check Node.js and npm # Check Node.js and npm
node_available, node_message = check_node_npm() node_available, node_message = check_node_npm()
if not node_available: if not node_available:
logger.error(f"Cannot start UI: {node_message}") logger.error(f"Cannot start UI: {node_message}")
logger.error("Please install Node.js from https://nodejs.org/ to use the UI functionality") logger.error("Please install Node.js from https://nodejs.org/ to use the UI functionality")
return None return None
logger.debug(f"Environment check passed: {node_message}") logger.debug(f"Environment check passed: {node_message}")
# Install dependencies if needed # Install dependencies if needed
if not install_frontend_dependencies(frontend_path): if not install_frontend_dependencies(frontend_path):
logger.error("Failed to install frontend dependencies") logger.error("Failed to install frontend dependencies")
return None return None
# Prepare environment variables # Prepare environment variables
env = os.environ.copy() env = os.environ.copy()
env['HOST'] = host env["HOST"] = host
env['PORT'] = str(port) env["PORT"] = str(port)
# Start the development server # Start the development server
logger.info(f"Starting frontend server at http://{host}:{port}") logger.info(f"Starting frontend server at http://{host}:{port}")
logger.info("This may take a moment to compile and start...") logger.info("This may take a moment to compile and start...")
try: try:
process = subprocess.Popen( process = subprocess.Popen(
["npm", "run", "dev"], ["npm", "run", "dev"],
@ -414,12 +419,12 @@ def start_ui(host: str = "localhost", port: int = 3000, open_browser: bool = Tru
env=env, env=env,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stderr=subprocess.PIPE,
text=True text=True,
) )
# Give it a moment to start up # Give it a moment to start up
time.sleep(3) time.sleep(3)
# Check if process is still running # Check if process is still running
if process.poll() is not None: if process.poll() is not None:
stdout, stderr = process.communicate() stdout, stderr = process.communicate()
@ -427,25 +432,26 @@ def start_ui(host: str = "localhost", port: int = 3000, open_browser: bool = Tru
logger.error(f"stdout: {stdout}") logger.error(f"stdout: {stdout}")
logger.error(f"stderr: {stderr}") logger.error(f"stderr: {stderr}")
return None return None
# Open browser if requested # Open browser if requested
if open_browser: if open_browser:
def open_browser_delayed(): def open_browser_delayed():
time.sleep(5) # Give Next.js time to fully start time.sleep(5) # Give Next.js time to fully start
try: try:
webbrowser.open(f"http://{host}:{port}") # TODO: use dashboard url? webbrowser.open(f"http://{host}:{port}") # TODO: use dashboard url?
except Exception as e: except Exception as e:
logger.warning(f"Could not open browser automatically: {e}") logger.warning(f"Could not open browser automatically: {e}")
browser_thread = threading.Thread(target=open_browser_delayed, daemon=True) browser_thread = threading.Thread(target=open_browser_delayed, daemon=True)
browser_thread.start() browser_thread.start()
logger.info("✓ Cognee UI is starting up...") logger.info("✓ Cognee UI is starting up...")
logger.info(f"✓ Open your browser to: http://{host}:{port}") logger.info(f"✓ Open your browser to: http://{host}:{port}")
logger.info("✓ The UI will be available once Next.js finishes compiling") logger.info("✓ The UI will be available once Next.js finishes compiling")
return process return process
except Exception as e: except Exception as e:
logger.error(f"Failed to start frontend server: {str(e)}") logger.error(f"Failed to start frontend server: {str(e)}")
return None return None
@ -454,16 +460,16 @@ def start_ui(host: str = "localhost", port: int = 3000, open_browser: bool = Tru
def stop_ui(process: subprocess.Popen) -> bool: def stop_ui(process: subprocess.Popen) -> bool:
""" """
Stop a running UI server process. Stop a running UI server process.
Args: Args:
process: The subprocess.Popen object returned by start_ui() process: The subprocess.Popen object returned by start_ui()
Returns: Returns:
bool: True if stopped successfully, False otherwise bool: True if stopped successfully, False otherwise
""" """
if not process: if not process:
return False return False
try: try:
process.terminate() process.terminate()
try: try:
@ -472,10 +478,10 @@ def stop_ui(process: subprocess.Popen) -> bool:
logger.warning("Process didn't terminate gracefully, forcing kill") logger.warning("Process didn't terminate gracefully, forcing kill")
process.kill() process.kill()
process.wait() process.wait()
logger.info("UI server stopped") logger.info("UI server stopped")
return True return True
except Exception as e: except Exception as e:
logger.error(f"Error stopping UI server: {str(e)}") logger.error(f"Error stopping UI server: {str(e)}")
return False return False

View file

@ -13,29 +13,33 @@ import time
async def main(): async def main():
# First, let's add some data to cognee for the UI to display # First, let's add some data to cognee for the UI to display
print("Adding sample data to cognee...") print("Adding sample data to cognee...")
await cognee.add("Natural language processing (NLP) is an interdisciplinary subfield of computer science and information retrieval.") await cognee.add(
await cognee.add("Machine learning (ML) is a subset of artificial intelligence that focuses on algorithms and statistical models.") "Natural language processing (NLP) is an interdisciplinary subfield of computer science and information retrieval."
)
await cognee.add(
"Machine learning (ML) is a subset of artificial intelligence that focuses on algorithms and statistical models."
)
# Generate the knowledge graph # Generate the knowledge graph
print("Generating knowledge graph...") print("Generating knowledge graph...")
await cognee.cognify() await cognee.cognify()
print("\n" + "="*60) print("\n" + "=" * 60)
print("Starting cognee UI...") print("Starting cognee UI...")
print("="*60) print("=" * 60)
# Start the UI server # Start the UI server
server = cognee.start_ui( server = cognee.start_ui(
host="localhost", host="localhost",
port=3000, port=3000,
open_browser=True # This will automatically open your browser open_browser=True, # This will automatically open your browser
) )
if server: if server:
print("UI server started successfully!") print("UI server started successfully!")
print("The interface will be available at: http://localhost:3000") print("The interface will be available at: http://localhost:3000")
print("\nPress Ctrl+C to stop the server when you're done...") print("\nPress Ctrl+C to stop the server when you're done...")
try: try:
# Keep the server running # Keep the server running
while server.poll() is None: # While process is still running while server.poll() is None: # While process is still running