diff --git a/requirements.txt b/requirements.txt index ce4e421..5a01a31 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,15 +1,20 @@ -psutil~=6.0.0 -requests~=2.32.3 -numpy<3.0.0 -torch~=2.4.0 -sentencepiece~=0.2.0 +# System Monitoring PyYAML~=6.0.2 +psutil~=6.0.0 pynvml~=11.5.3 +# GUI Library PySide6~=6.7.2 -python-dotenv~=1.0.1 +# llama.cpp tools (external) safetensors~=0.4.4 +numpy<3.0.0 +torch~=2.4.0 +sentencepiece~=0.2.0 +# PyPI build setuptools~=74.0.0 +# HuggingFace Download/Upload huggingface-hub~=0.24.6 +# AutoFP8 (external) transformers~=4.44.2 +# Local Server fastapi~=0.112.2 uvicorn~=0.30.6 diff --git a/src/AutoGGUF.py b/src/AutoGGUF.py index af93d3f..527a5e8 100644 --- a/src/AutoGGUF.py +++ b/src/AutoGGUF.py @@ -2,15 +2,15 @@ import json import re import shutil +import urllib.request +import urllib.error from datetime import datetime from functools import partial from typing import Any, Dict, List, Tuple -import requests from PySide6.QtCore import * from PySide6.QtGui import * from PySide6.QtWidgets import * -from dotenv import load_dotenv import lora_conversion import presets @@ -44,7 +44,7 @@ def __init__(self, args: List[str]) -> None: self.setGeometry(100, 100, width, height) self.setWindowFlag(Qt.FramelessWindowHint) - load_dotenv() # Loads the .env file + self.load_dotenv() # Loads the .env file # Configuration self.model_dir_name = os.environ.get("AUTOGGUF_MODEL_DIR_NAME", "models") @@ -805,6 +805,41 @@ def __init__(self, args: List[str]) -> None: self.logger.info(AUTOGGUF_INITIALIZATION_COMPLETE) + def load_dotenv(self): + if not os.path.isfile(".env"): + self.logger.warning(".env file not found.") + return + + try: + with open(".env") as f: + for line in f: + # Strip leading/trailing whitespace + line = line.strip() + + # Ignore comments and empty lines + if not line or line.startswith("#"): + continue + + # Match key-value pairs (unquoted and quoted values) + match = re.match(r"^([^=]+)=(.*)$", line) + if not match: + self.logger.warning(f"Could not parse line: {line}") + continue + + key, value = match.groups() + + # Remove any surrounding quotes from the value + if value.startswith(("'", '"')) and value.endswith(("'", '"')): + value = value[1:-1] + + # Decode escape sequences + value = bytes(value, "utf-8").decode("unicode_escape") + + # Set the environment variable + os.environ[key.strip()] = value.strip() + except Exception as e: + self.logger.error(f"Error loading .env: {e}") + def load_plugins(self) -> Dict[str, Dict[str, Any]]: plugins = {} plugin_dir = "plugins" @@ -881,17 +916,22 @@ def apply_plugins(self) -> None: def check_for_updates(self) -> None: try: - response = requests.get( - "https://api.github.com/repos/leafspark/AutoGGUF/releases/latest" - ) - response.raise_for_status() # Raise an exception for bad status codes + url = "https://api.github.com/repos/leafspark/AutoGGUF/releases/latest" + req = urllib.request.Request(url) + + with urllib.request.urlopen(req) as response: + if response.status != 200: + raise urllib.error.HTTPError( + url, response.status, "HTTP Error", response.headers, None + ) + + latest_release = json.loads(response.read().decode("utf-8")) + latest_version = latest_release["tag_name"].replace("v", "") - latest_release = response.json() - latest_version = latest_release["tag_name"].replace("v", "") + if latest_version > AUTOGGUF_VERSION.replace("v", ""): + self.prompt_for_update(latest_release) - if latest_version > AUTOGGUF_VERSION.replace("v", ""): - self.prompt_for_update(latest_release) - except requests.exceptions.RequestException as e: + except urllib.error.URLError as e: self.logger.warning(f"{ERROR_CHECKING_FOR_UPDATES} {e}") def prompt_for_update(self, release) -> None: diff --git a/src/DownloadThread.py b/src/DownloadThread.py index 2157c94..2d56fa8 100644 --- a/src/DownloadThread.py +++ b/src/DownloadThread.py @@ -1,7 +1,7 @@ import os +import urllib.request +import urllib.error import zipfile - -import requests from PySide6.QtCore import QThread, Signal @@ -17,19 +17,28 @@ def __init__(self, url, save_path) -> None: def run(self) -> None: try: - response = requests.get(self.url, stream=True) - response.raise_for_status() - total_size = int(response.headers.get("content-length", 0)) - block_size = 8192 - downloaded = 0 - - with open(self.save_path, "wb") as file: - for data in response.iter_content(block_size): - size = file.write(data) - downloaded += size - if total_size: - progress = int((downloaded / total_size) * 100) - self.progress_signal.emit(progress) + req = urllib.request.Request(self.url) + + with urllib.request.urlopen(req) as response: + if response.status != 200: + raise urllib.error.HTTPError( + self.url, response.status, "HTTP Error", response.headers, None + ) + + total_size = int(response.headers.get("Content-Length", 0)) + block_size = 8192 + downloaded = 0 + + with open(self.save_path, "wb") as file: + while True: + data = response.read(block_size) + if not data: + break + size = file.write(data) + downloaded += size + if total_size: + progress = int((downloaded / total_size) * 100) + self.progress_signal.emit(progress) # Extract the downloaded zip file extract_dir = os.path.splitext(self.save_path)[0]