diff --git a/.env.example b/.env.example index 744e2bf..d329802 100644 --- a/.env.example +++ b/.env.example @@ -10,3 +10,4 @@ AUTOGGUF_SERVER=enabled AUTOGGUF_SERVER_PORT=7001 AUTOGGUF_SERVER_API_KEY= AUTOGGUF_LANGUAGE=en-US +AUTOGGUF_BACKEND_REPO=ggerganov/llama.cpp diff --git a/README.md b/README.md index 501ef5e..a617853 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ cd build//dist/ pip install -U pyinstaller build RELEASE | DEV ``` -Find the executable in `build//dist/AutoGGUF.exe`. +Find the executable in `build//dist/AutoGGUF-x64.exe`. You can also use Nuitka, which may result in a slower build but a faster output executable: ```bash @@ -139,18 +139,21 @@ To use a specific language, set the `AUTOGGUF_LANGUAGE` environment variable to ## Issues - Some inconsistent logging +- Missing translations ## Planned Features - Time estimation for quantization - Quantization file size estimate - Perplexity testing -- bitsandbytes (coming soon) +- bitsandbytes + +Due to my limited availability and a lack of time, I won't be actively developing new features for this project as much. While I'll continue to publish builds from time to time, I strongly recommend running from source if you want to stay up to date with the latest changes. I'm still committed to keeping dependencies updated weekly and making small maintenance fixes to ensure everything runs smoothly. If you run into any problems or notice issues, please don't hesitate to let me know - I appreciate your feedback and will do my best to address them. ## Support - SSL module cannot be found error: Install OpenSSL or run from source using `python src/main.py` with the `run.bat` script (`pip install requests`) -- Check out the [Wiki](https://github.com/leafspark/AutoGGUF/wiki) for advanced usage +- Check out the [Wiki](https://github.com/leafspark/AutoGGUF/wiki) for advanced usage and configuration ## Contributing diff --git a/src/AutoGGUF.py b/src/AutoGGUF.py index d3593c0..4e813a3 100644 --- a/src/AutoGGUF.py +++ b/src/AutoGGUF.py @@ -1129,7 +1129,7 @@ def delete_model(self, item): reply = QMessageBox.question( self, CONFIRM_DELETE, - DELETE_WARNING.format(model_name), + DELETE_MODEL_WARNING.format(model_name), QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No, ) @@ -1142,7 +1142,7 @@ def delete_model(self, item): ) self.logger.info(MODEL_DELETED_SUCCESSFULLY.format(model_name)) except Exception as e: - show_error(self.logger, f"Error deleting model: {e}") + show_error(self.logger, ERROR_DELETING_MODEL.format(e)) def check_for_updates(self) -> None: try: @@ -1929,17 +1929,9 @@ def import_model(self) -> None: show_error(self.logger, INVALID_GGUF_FILE.format(file_name)) return - reply = QMessageBox.question( - self, - CONFIRM_IMPORT, - IMPORT_MODEL_CONFIRMATION.format(file_name), - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, - QMessageBox.StandardButton.No, - ) - if reply == QMessageBox.StandardButton.Yes: - self.imported_models.append(file_path) - self.load_models() - self.logger.info(MODEL_IMPORTED_SUCCESSFULLY.format(file_name)) + self.imported_models.append(file_path) + self.load_models() + self.logger.info(MODEL_IMPORTED_SUCCESSFULLY.format(file_name)) @validate_input( "imatrix_model", "imatrix_datafile", "imatrix_model", "imatrix_output" diff --git a/src/Localizations.py b/src/Localizations.py index f3145a0..7b3f672 100644 --- a/src/Localizations.py +++ b/src/Localizations.py @@ -415,6 +415,7 @@ def __init__(self): # Model actions self.CONFIRM_DELETE = "Confirm Delete" self.DELETE_MODEL_WARNING = "Are you sure you want to delete the model: {}?" + self.ERROR_DELETING_MODEL = "Error deleting model: {}" self.MODEL_RENAMED_SUCCESSFULLY = "Model renamed successfully." self.MODEL_DELETED_SUCCESSFULLY = "Model deleted successfully." @@ -451,12 +452,17 @@ def __init__(self): self.HF_REPOSITORY_TYPE = "Repository Type" self.UPLOAD_TYPE = "Upload Type" self.UPLOAD = "Upload" + self.INFO = "Info" self.EXTRA_COMMAND_ARGUMENTS = "Additional command-line arguments" - - self.INFO = "Info" self.COPIED_COMMAND_TO_CLIPBOARD = "Copied command to clipboard:" + # Repository + self.INVALID_REPOSITORY_FORMAT = ( + "Invalid repository format. Must be 'owner/repo'" + ) + self.REPO_CANNOT_BE_EMPTY = "Owner and repository name cannot be empty" + class _French(_Localization): def __init__(self): diff --git a/src/utils.py b/src/utils.py index a9b2867..186488e 100644 --- a/src/utils.py +++ b/src/utils.py @@ -169,18 +169,35 @@ def download_llama_cpp(self) -> None: self.download_progress.setValue(0) +def get_repo_from_env() -> tuple[str, str]: + repo = os.getenv("AUTOGGUF_BACKEND_REPO", "ggerganov/llama.cpp") + + if not repo or "/" not in repo: + raise ValueError(INVALID_REPOSITORY_FORMAT) + + owner, repo_name = repo.split("/", 1) + if not all(part.strip() for part in (owner, repo_name)): + raise ValueError(REPO_CANNOT_BE_EMPTY) + + return owner, repo_name + + def refresh_releases(self) -> None: self.logger.info(REFRESHING_LLAMACPP_RELEASES) try: - response = requests.get( - "https://api.github.com/repos/ggerganov/llama.cpp/releases" - ) - response.raise_for_status() # Raise an exception for bad status codes + owner, repo = get_repo_from_env() + url = f"https://api.github.com/repos/{owner}/{repo}/releases" + + response = requests.get(url) + response.raise_for_status() + releases = response.json() self.release_combo.clear() for release in releases: self.release_combo.addItem(release["tag_name"], userData=release) self.release_combo.currentIndexChanged.connect(self.update_assets) self.update_assets() + except ValueError as e: + show_error(self.logger, f"Invalid repository configuration: {str(e)}") except requests.exceptions.RequestException as e: show_error(self.logger, ERROR_FETCHING_RELEASES.format(str(e)))