diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml.disabled similarity index 100% rename from .github/workflows/pre-commit.yml rename to .github/workflows/pre-commit.yml.disabled diff --git a/.github/workflows/radon.yml b/.github/workflows/radon.yml index 6c53a74..d17fce0 100644 --- a/.github/workflows/radon.yml +++ b/.github/workflows/radon.yml @@ -38,10 +38,10 @@ jobs: if [ -n "$CHANGED_FILES" ]; then echo "Running Cyclomatic Complexity check..." - radon cc $CHANGED_FILES -a -s -n D --exclude "AutoGGUF.quantize_model" + radon cc $CHANGED_FILES -a -s -n E --exclude "AutoGGUF.quantize_model" echo "Running Maintainability Index check..." - radon mi $CHANGED_FILES -s -n D + radon mi $CHANGED_FILES -s -n E else echo "No Python files to analyze." fi @@ -56,8 +56,8 @@ jobs: fi if [ -n "$CHANGED_FILES" ]; then - CC_OUTPUT=$(radon cc $CHANGED_FILES -a -s -n D --exclude "AutoGGUF.quantize_model") - MI_OUTPUT=$(radon mi $CHANGED_FILES -s -n D) + CC_OUTPUT=$(radon cc $CHANGED_FILES -a -s -n E --exclude "AutoGGUF.quantize_model") + MI_OUTPUT=$(radon mi $CHANGED_FILES -s -n E) if [ -n "$CC_OUTPUT" ] || [ -n "$MI_OUTPUT" ]; then echo "Radon detected code complexity or maintainability issues:" diff --git a/src/AutoGGUF.py b/src/AutoGGUF.py index 22bb0b5..147b70d 100644 --- a/src/AutoGGUF.py +++ b/src/AutoGGUF.py @@ -1,26 +1,26 @@ import json import re import shutil -from datetime import datetime -import psutil -import requests from functools import partial from PySide6.QtCore import * from PySide6.QtGui import * from PySide6.QtWidgets import * -from DownloadThread import DownloadThread -from GPUMonitor import GPUMonitor -from KVOverrideEntry import KVOverrideEntry -from Logger import Logger -from ModelInfoDialog import ModelInfoDialog -from QuantizationThread import QuantizationThread -from TaskListItem import TaskListItem -from error_handling import show_error, handle_error -from imports_and_globals import ensure_directory, open_file_safe, resource_path -from localizations import * -from ui_update import * +from src.GPUMonitor import GPUMonitor +from src.KVOverrideEntry import KVOverrideEntry +from src.Logger import Logger +from src.ModelInfoDialog import ModelInfoDialog +from src.imports_and_globals import ( + open_file_safe, + resource_path, + show_about, + ensure_directory, +) +from src.localizations import * +import src.ui_update +import src.lora_conversion +import src.utils class AutoGGUF(QMainWindow): @@ -37,17 +37,35 @@ def __init__(self): ensure_directory(os.path.abspath("models")) # References - self.update_base_model_visibility = partial(update_base_model_visibility, self) - self.update_assets = update_assets.__get__(self) - self.update_cuda_option = update_cuda_option.__get__(self) - self.update_cuda_backends = update_cuda_backends.__get__(self) - self.update_threads_spinbox = partial(update_threads_spinbox, self) - self.update_threads_slider = partial(update_threads_slider, self) - self.update_gpu_offload_spinbox = partial(update_gpu_offload_spinbox, self) - self.update_gpu_offload_slider = partial(update_gpu_offload_slider, self) - self.update_model_info = partial(update_model_info, self.logger, self) - self.update_system_info = partial(update_system_info, self) - self.update_download_progress = partial(update_download_progress, self) + self.update_base_model_visibility = partial( + src.ui_update.update_base_model_visibility, self + ) + self.update_assets = src.ui_update.update_assets.__get__(self) + self.update_cuda_option = src.ui_update.update_cuda_option.__get__(self) + self.update_cuda_backends = src.ui_update.update_cuda_backends.__get__(self) + self.download_llama_cpp = src.utils.download_llama_cpp.__get__(self) + self.refresh_releases = src.utils.refresh_releases.__get__(self) + self.browse_lora_input = src.utils.browse_lora_input.__get__(self) + self.browse_lora_output = src.utils.browse_lora_output.__get__(self) + self.convert_lora = src.lora_conversion.convert_lora.__get__(self) + self.show_about = show_about.__get__(self) + self.update_threads_spinbox = partial( + src.ui_update.update_threads_spinbox, self + ) + self.update_threads_slider = partial(src.ui_update.update_threads_slider, self) + self.update_gpu_offload_spinbox = partial( + src.ui_update.update_gpu_offload_spinbox, self + ) + self.update_gpu_offload_slider = partial( + src.ui_update.update_gpu_offload_slider, self + ) + self.update_model_info = partial( + src.ui_update.update_model_info, self.logger, self + ) + self.update_system_info = partial(src.ui_update.update_system_info, self) + self.update_download_progress = partial( + src.ui_update.update_download_progress, self + ) # Create a central widget and main layout central_widget = QWidget() @@ -711,14 +729,6 @@ def refresh_backends(self): self.backend_combo.setEnabled(False) self.logger.info(FOUND_VALID_BACKENDS.format(self.backend_combo.count())) - def show_about(self): - about_text = ( - "AutoGGUF\n\n" - f"Version: {AUTOGGUF_VERSION}\n\n" - "A tool for managing and converting GGUF models." - ) - QMessageBox.about(self, "About AutoGGUF", about_text) - def save_preset(self): self.logger.info(SAVING_PRESET) preset = { @@ -1060,87 +1070,6 @@ def restart_task(self, task_item): task_item.update_status(IN_PROGRESS) break - def browse_lora_input(self): - self.logger.info(BROWSING_FOR_LORA_INPUT_DIRECTORY) - lora_input_path = QFileDialog.getExistingDirectory( - self, SELECT_LORA_INPUT_DIRECTORY - ) - if lora_input_path: - self.lora_input.setText(os.path.abspath(lora_input_path)) - ensure_directory(lora_input_path) - - def browse_lora_output(self): - self.logger.info(BROWSING_FOR_LORA_OUTPUT_FILE) - lora_output_file, _ = QFileDialog.getSaveFileName( - self, SELECT_LORA_OUTPUT_FILE, "", GGUF_AND_BIN_FILES - ) - if lora_output_file: - self.lora_output.setText(os.path.abspath(lora_output_file)) - - def convert_lora(self): - self.logger.info(STARTING_LORA_CONVERSION) - try: - lora_input_path = self.lora_input.text() - lora_output_path = self.lora_output.text() - lora_output_type = self.lora_output_type_combo.currentText() - - if not lora_input_path: - raise ValueError(LORA_INPUT_PATH_REQUIRED) - if not lora_output_path: - raise ValueError(LORA_OUTPUT_PATH_REQUIRED) - - if lora_output_type == "GGUF": # Use new file and parameters for GGUF - command = [ - "python", - "src/convert_lora_to_gguf.py", - "--outfile", - lora_output_path, - lora_input_path, - ] - base_model_path = self.base_model_path.text() - if not base_model_path: - raise ValueError(BASE_MODEL_PATH_REQUIRED) - command.extend(["--base", base_model_path]) - else: # Use old GGML parameters for GGML - command = ["python", "src/convert_lora_to_ggml.py", lora_input_path] - - logs_path = self.logs_input.text() - ensure_directory(logs_path) - - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - log_file = os.path.join(logs_path, f"lora_conversion_{timestamp}.log") - - command_str = " ".join(command) - self.logger.info(f"{LORA_CONVERSION_COMMAND}: {command_str}") - - thread = QuantizationThread(command, os.getcwd(), log_file) - self.quant_threads.append(thread) - - task_name = LORA_CONVERSION_FROM_TO.format( - os.path.basename(lora_input_path), os.path.basename(lora_output_path) - ) - task_item = TaskListItem(task_name, log_file, show_progress_bar=False) - list_item = QListWidgetItem(self.task_list) - list_item.setSizeHint(task_item.sizeHint()) - self.task_list.addItem(list_item) - self.task_list.setItemWidget(list_item, task_item) - - thread.status_signal.connect(task_item.update_status) - thread.finished_signal.connect( - lambda: self.lora_conversion_finished( - thread, lora_input_path, lora_output_path - ) - ) - thread.error_signal.connect( - lambda err: handle_error(self.logger, err, task_item) - ) - thread.start() - self.logger.info(LORA_CONVERSION_TASK_STARTED) - except ValueError as e: - show_error(self.logger, str(e)) - except Exception as e: - show_error(self.logger, ERROR_STARTING_LORA_CONVERSION.format(str(e))) - def lora_conversion_finished(self, thread, input_path, output_path): self.logger.info(LORA_CONVERSION_FINISHED) if thread in self.quant_threads: @@ -1194,43 +1123,6 @@ def download_finished(self, extract_dir): if index >= 0: self.backend_combo.setCurrentIndex(index) - def refresh_releases(self): - 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 - 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 requests.exceptions.RequestException as e: - show_error(self.logger, ERROR_FETCHING_RELEASES.format(str(e))) - - def download_llama_cpp(self): - self.logger.info(STARTING_LLAMACPP_DOWNLOAD) - asset = self.asset_combo.currentData() - if not asset: - show_error(self.logger, NO_ASSET_SELECTED) - return - - llama_bin = os.path.abspath("llama_bin") - os.makedirs(llama_bin, exist_ok=True) - - save_path = os.path.join(llama_bin, asset["name"]) - - self.download_thread = DownloadThread(asset["browser_download_url"], save_path) - self.download_thread.progress_signal.connect(self.update_download_progress) - self.download_thread.finished_signal.connect(self.download_finished) - self.download_thread.error_signal.connect(self.download_error) - self.download_thread.start() - - self.download_button.setEnabled(False) - self.download_progress.setValue(0) - def download_finished(self, extract_dir): self.download_button.setEnabled(True) self.download_progress.setValue(100) diff --git a/src/GPUMonitor.py b/src/GPUMonitor.py index 4f460c9..07e3515 100644 --- a/src/GPUMonitor.py +++ b/src/GPUMonitor.py @@ -15,7 +15,7 @@ QComboBox, ) -from localizations import ( +from src.localizations import ( GPU_USAGE_FORMAT, GPU_DETAILS, GPU_USAGE_OVER_TIME, diff --git a/src/error_handling.py b/src/error_handling.py index 98534d8..46bc424 100644 --- a/src/error_handling.py +++ b/src/error_handling.py @@ -1,5 +1,5 @@ from PySide6.QtWidgets import QMessageBox -from localizations import * +from src.localizations import * def show_error(logger, message): diff --git a/src/imports_and_globals.py b/src/imports_and_globals.py index 7566fef..234f16b 100644 --- a/src/imports_and_globals.py +++ b/src/imports_and_globals.py @@ -38,6 +38,17 @@ from PySide6.QtCore import QTimer, Signal, QThread, Qt, QSize from PySide6.QtGui import QCloseEvent, QAction +from src.localizations import * + + +def show_about(self): + about_text = ( + "AutoGGUF\n\n" + f"Version: {AUTOGGUF_VERSION}\n\n" + "A tool for managing and converting GGUF models." + ) + QMessageBox.about(self, "About AutoGGUF", about_text) + def ensure_directory(path): if not os.path.exists(path): diff --git a/src/localizations.py b/src/localizations.py index 2497b2a..7c88132 100644 --- a/src/localizations.py +++ b/src/localizations.py @@ -877,7 +877,9 @@ def __init__(self): self.DOWNLOAD_FINISHED_EXTRACTED_TO = "下载完成。已解压到:{0}" self.LLAMACPP_DOWNLOADED_AND_EXTRACTED = "llama.cpp二进制文件已下载并解压到{0}" self.NO_SUITABLE_CUDA_BACKEND_FOUND = "未找到合适的CUDA后端进行提取" - self.LLAMACPP_BINARY_DOWNLOADED_AND_EXTRACTED = "llama.cpp二进制文件已下载并解压到{0}" + self.LLAMACPP_BINARY_DOWNLOADED_AND_EXTRACTED = ( + "llama.cpp二进制文件已下载并解压到{0}" + ) self.REFRESHING_LLAMACPP_RELEASES = "刷新llama.cpp版本" self.UPDATING_ASSET_LIST = "更新资源列表" self.UPDATING_CUDA_OPTIONS = "更新CUDA选项" @@ -941,7 +943,9 @@ def __init__(self): self.USE_THIS_TYPE_FOR_OUTPUT_WEIGHT = "对output.weight张量使用此类型" self.TOKEN_EMBEDDING_TYPE = "词元嵌入类型:" self.USE_THIS_TYPE_FOR_TOKEN_EMBEDDINGS = "对词元嵌入张量使用此类型" - self.WILL_GENERATE_QUANTIZED_MODEL_IN_SAME_SHARDS = "将生成与输入相同分片的量化模型" + self.WILL_GENERATE_QUANTIZED_MODEL_IN_SAME_SHARDS = ( + "将生成与输入相同分片的量化模型" + ) self.OVERRIDE_MODEL_METADATA = "覆盖模型元数据" self.INPUT_DATA_FILE_FOR_IMATRIX = "IMatrix生成的输入数据文件" self.MODEL_TO_BE_QUANTIZED = "要量化的模型" @@ -988,7 +992,9 @@ def __init__(self): self.MODEL_DIRECTORY_REQUIRED = "需要模型目录" self.HF_TO_GGUF_CONVERSION_COMMAND = "HF到GGUF转换命令:{}" self.CONVERTING_TO_GGUF = "将{}转换为GGUF" - self.ERROR_STARTING_HF_TO_GGUF_CONVERSION = "启动HuggingFace到GGUF转换时出错:{}" + self.ERROR_STARTING_HF_TO_GGUF_CONVERSION = ( + "启动HuggingFace到GGUF转换时出错:{}" + ) self.HF_TO_GGUF_CONVERSION_TASK_STARTED = "HuggingFace到GGUF转换任务已开始" @@ -1436,7 +1442,9 @@ def __init__(self): self.NO_MODEL_SELECTED = "कोई मॉडल चयनित नहीं" self.REFRESH_RELEASES = "रिलीज़ रीफ्रेश करें" self.NO_SUITABLE_CUDA_BACKENDS = "कोई उपयुक्त CUDA बैकएंड नहीं मिला" - self.LLAMACPP_DOWNLOADED_EXTRACTED = "llama.cpp बाइनरी डाउनलोड और {0} में निकाली गई\nCUDA फ़ाइलें {1} में निकाली गईं" + self.LLAMACPP_DOWNLOADED_EXTRACTED = ( + "llama.cpp बाइनरी डाउनलोड और {0} में निकाली गई\nCUDA फ़ाइलें {1} में निकाली गईं" + ) self.CUDA_FILES_EXTRACTED = "CUDA फ़ाइलें निकाली गईं" self.NO_SUITABLE_CUDA_BACKEND_EXTRACTION = ( "निष्कर्षण के लिए कोई उपयुक्त CUDA बैकएंड नहीं मिला" @@ -1465,7 +1473,9 @@ def __init__(self): self.RESTARTING_TASK = "कार्य पुनः आरंभ हो रहा है: {0}" self.IN_PROGRESS = "प्रगति में" self.DOWNLOAD_FINISHED_EXTRACTED_TO = "डाउनलोड समाप्त। निकाला गया: {0}" - self.LLAMACPP_DOWNLOADED_AND_EXTRACTED = "llama.cpp बाइनरी डाउनलोड और {0} में निकाली गई\nCUDA फ़ाइलें {1} में निकाली गईं" + self.LLAMACPP_DOWNLOADED_AND_EXTRACTED = ( + "llama.cpp बाइनरी डाउनलोड और {0} में निकाली गई\nCUDA फ़ाइलें {1} में निकाली गईं" + ) self.NO_SUITABLE_CUDA_BACKEND_FOUND = ( "निष्कर्षण के लिए कोई उपयुक्त CUDA बैकएंड नहीं मिला" ) @@ -1487,25 +1497,17 @@ def __init__(self): self.DELETING_TASK = "कार्य हटाया जा रहा है: {0}" self.LOADING_MODELS = "मॉडल लोड हो रहे हैं" self.LOADED_MODELS = "{0} मॉडल लोड किए गए" - self.BROWSING_FOR_MODELS_DIRECTORY = ( - "मॉडल निर्देशिका के लिए ब्राउज़ किया जा रहा है" - ) + self.BROWSING_FOR_MODELS_DIRECTORY = "मॉडल निर्देशिका के लिए ब्राउज़ किया जा रहा है" self.SELECT_MODELS_DIRECTORY = "मॉडल निर्देशिका चुनें" - self.BROWSING_FOR_OUTPUT_DIRECTORY = ( - "आउटपुट निर्देशिका के लिए ब्राउज़ किया जा रहा है" - ) + self.BROWSING_FOR_OUTPUT_DIRECTORY = "आउटपुट निर्देशिका के लिए ब्राउज़ किया जा रहा है" self.SELECT_OUTPUT_DIRECTORY = "आउटपुट निर्देशिका चुनें" - self.BROWSING_FOR_LOGS_DIRECTORY = ( - "लॉग निर्देशिका के लिए ब्राउज़ किया जा रहा है" - ) + self.BROWSING_FOR_LOGS_DIRECTORY = "लॉग निर्देशिका के लिए ब्राउज़ किया जा रहा है" self.SELECT_LOGS_DIRECTORY = "लॉग निर्देशिका चुनें" self.BROWSING_FOR_IMATRIX_FILE = "IMatrix फ़ाइल के लिए ब्राउज़ किया जा रहा है" self.SELECT_IMATRIX_FILE = "IMatrix फ़ाइल चुनें" self.RAM_USAGE_FORMAT = "{0:.1f}% ({1} MB / {2} MB)" self.CPU_USAGE_FORMAT = "CPU उपयोग: {0:.1f}%" - self.VALIDATING_QUANTIZATION_INPUTS = ( - "क्वांटाइजेशन इनपुट सत्यापित किए जा रहे हैं" - ) + self.VALIDATING_QUANTIZATION_INPUTS = "क्वांटाइजेशन इनपुट सत्यापित किए जा रहे हैं" self.MODELS_PATH_REQUIRED = "मॉडल पथ आवश्यक है" self.OUTPUT_PATH_REQUIRED = "आउटपुट पथ आवश्यक है" self.LOGS_PATH_REQUIRED = "लॉग पथ आवश्यक है" @@ -1532,9 +1534,7 @@ def __init__(self): self.STARTING_IMATRIX_GENERATION = "IMatrix उत्पादन शुरू हो रहा है" self.BACKEND_PATH_NOT_EXIST = "बैकएंड पथ मौजूद नहीं है: {0}" self.GENERATING_IMATRIX = "IMatrix उत्पन्न किया जा रहा है" - self.ERROR_STARTING_IMATRIX_GENERATION = ( - "IMatrix उत्पादन शुरू करने में त्रुटि: {0}" - ) + self.ERROR_STARTING_IMATRIX_GENERATION = "IMatrix उत्पादन शुरू करने में त्रुटि: {0}" self.IMATRIX_GENERATION_TASK_STARTED = "IMatrix उत्पादन कार्य शुरू हुआ" self.ERROR_MESSAGE = "त्रुटि: {0}" self.TASK_ERROR = "कार्य त्रुटि: {0}" @@ -1544,14 +1544,14 @@ def __init__(self): self.ALLOWS_REQUANTIZING = ( "पहले से क्वांटाइज़ किए गए टेंसर को पुनः क्वांटाइज़ करने की अनुमति देता है" ) - self.LEAVE_OUTPUT_WEIGHT = ( - "output.weight को अक्वांटाइज़ (या पुनः क्वांटाइज़) छोड़ देगा" + self.LEAVE_OUTPUT_WEIGHT = "output.weight को अक्वांटाइज़ (या पुनः क्वांटाइज़) छोड़ देगा" + self.DISABLE_K_QUANT_MIXTURES = ( + "k-quant मिश्रण को अक्षम करें और सभी टेंसर को एक ही प्रकार में क्वांटाइज़ करें" ) - self.DISABLE_K_QUANT_MIXTURES = "k-quant मिश्रण को अक्षम करें और सभी टेंसर को एक ही प्रकार में क्वांटाइज़ करें" - self.USE_DATA_AS_IMPORTANCE_MATRIX = "क्वांट अनुकूलन के लिए फ़ाइल में डेटा को महत्व मैट्रिक्स के रूप में उपयोग करें" - self.USE_IMPORTANCE_MATRIX_FOR_TENSORS = ( - "इन टेंसर के लिए महत्व मैट्रिक्स का उपयोग करें" + self.USE_DATA_AS_IMPORTANCE_MATRIX = ( + "क्वांट अनुकूलन के लिए फ़ाइल में डेटा को महत्व मैट्रिक्स के रूप में उपयोग करें" ) + self.USE_IMPORTANCE_MATRIX_FOR_TENSORS = "इन टेंसर के लिए महत्व मैट्रिक्स का उपयोग करें" self.DONT_USE_IMPORTANCE_MATRIX_FOR_TENSORS = ( "इन टेंसर के लिए महत्व मैट्रिक्स का उपयोग न करें" ) @@ -2008,7 +2008,9 @@ def __init__(self): self.RESTART = "再起動" self.DELETE = "削除" self.CONFIRM_DELETION = "このタスクを削除してもよろしいですか?" - self.TASK_RUNNING_WARNING = "一部のタスクはまだ実行中です。終了してもよろしいですか?" + self.TASK_RUNNING_WARNING = ( + "一部のタスクはまだ実行中です。終了してもよろしいですか?" + ) self.YES = "はい" self.NO = "いいえ" self.DOWNLOAD_COMPLETE = "ダウンロード完了" @@ -2021,11 +2023,11 @@ def __init__(self): self.NO_MODEL_SELECTED = "モデルが選択されていません" self.REFRESH_RELEASES = "リリースを更新" self.NO_SUITABLE_CUDA_BACKENDS = "適切なCUDAバックエンドが見つかりませんでした" - self.LLAMACPP_DOWNLOADED_EXTRACTED = ( - "llama.cppバイナリがダウンロードされ、{0}に抽出されました\nCUDAファイルは{1}に抽出されました" - ) + self.LLAMACPP_DOWNLOADED_EXTRACTED = "llama.cppバイナリがダウンロードされ、{0}に抽出されました\nCUDAファイルは{1}に抽出されました" self.CUDA_FILES_EXTRACTED = "CUDAファイルはに抽出されました" - self.NO_SUITABLE_CUDA_BACKEND_EXTRACTION = "抽出に適したCUDAバックエンドが見つかりませんでした" + self.NO_SUITABLE_CUDA_BACKEND_EXTRACTION = ( + "抽出に適したCUDAバックエンドが見つかりませんでした" + ) self.ERROR_FETCHING_RELEASES = "リリースの取得中にエラーが発生しました: {0}" self.CONFIRM_DELETION_TITLE = "削除の確認" self.LOG_FOR = "{0}のログ" @@ -2050,10 +2052,10 @@ def __init__(self): self.RESTARTING_TASK = "タスクを再起動しています: {0}" self.IN_PROGRESS = "処理中" self.DOWNLOAD_FINISHED_EXTRACTED_TO = "ダウンロードが完了しました。抽出先: {0}" - self.LLAMACPP_DOWNLOADED_AND_EXTRACTED = ( - "llama.cppバイナリがダウンロードされ、{0}に抽出されました\nCUDAファイルは{1}に抽出されました" + self.LLAMACPP_DOWNLOADED_AND_EXTRACTED = "llama.cppバイナリがダウンロードされ、{0}に抽出されました\nCUDAファイルは{1}に抽出されました" + self.NO_SUITABLE_CUDA_BACKEND_FOUND = ( + "抽出に適したCUDAバックエンドが見つかりませんでした" ) - self.NO_SUITABLE_CUDA_BACKEND_FOUND = "抽出に適したCUDAバックエンドが見つかりませんでした" self.LLAMACPP_BINARY_DOWNLOADED_AND_EXTRACTED = ( "llama.cppバイナリがダウンロードされ、{0}に抽出されました" ) @@ -2103,24 +2105,42 @@ def __init__(self): self.STARTING_IMATRIX_GENERATION = "IMatrixの生成を開始しています" self.BACKEND_PATH_NOT_EXIST = "バックエンドパスが存在しません: {0}" self.GENERATING_IMATRIX = "IMatrixを生成しています" - self.ERROR_STARTING_IMATRIX_GENERATION = "IMatrixの生成を開始中にエラーが発生しました: {0}" + self.ERROR_STARTING_IMATRIX_GENERATION = ( + "IMatrixの生成を開始中にエラーが発生しました: {0}" + ) self.IMATRIX_GENERATION_TASK_STARTED = "IMatrix生成タスクが開始されました" self.ERROR_MESSAGE = "エラー: {0}" self.TASK_ERROR = "タスクエラー: {0}" self.APPLICATION_CLOSING = "アプリケーションを終了しています" self.APPLICATION_CLOSED = "アプリケーションが終了しました" self.SELECT_QUANTIZATION_TYPE = "量子化タイプを選択してください" - self.ALLOWS_REQUANTIZING = "すでに量子化されているテンソルの再量子化を許可します" + self.ALLOWS_REQUANTIZING = ( + "すでに量子化されているテンソルの再量子化を許可します" + ) self.LEAVE_OUTPUT_WEIGHT = "output.weightは(再)量子化されません" - self.DISABLE_K_QUANT_MIXTURES = "k-quant混合を無効にし、すべてのテンソルを同じタイプに量子化します" - self.USE_DATA_AS_IMPORTANCE_MATRIX = "量子化最適化の重要度マトリックスとしてファイル内のデータを使用します" - self.USE_IMPORTANCE_MATRIX_FOR_TENSORS = "これらのテンソルに重要度マトリックスを使用します" - self.DONT_USE_IMPORTANCE_MATRIX_FOR_TENSORS = "これらのテンソルに重要度マトリックスを使用しません" + self.DISABLE_K_QUANT_MIXTURES = ( + "k-quant混合を無効にし、すべてのテンソルを同じタイプに量子化します" + ) + self.USE_DATA_AS_IMPORTANCE_MATRIX = ( + "量子化最適化の重要度マトリックスとしてファイル内のデータを使用します" + ) + self.USE_IMPORTANCE_MATRIX_FOR_TENSORS = ( + "これらのテンソルに重要度マトリックスを使用します" + ) + self.DONT_USE_IMPORTANCE_MATRIX_FOR_TENSORS = ( + "これらのテンソルに重要度マトリックスを使用しません" + ) self.OUTPUT_TENSOR_TYPE = "出力テンソルタイプ:" - self.USE_THIS_TYPE_FOR_OUTPUT_WEIGHT = "output.weightテンソルにこのタイプを使用します" + self.USE_THIS_TYPE_FOR_OUTPUT_WEIGHT = ( + "output.weightテンソルにこのタイプを使用します" + ) self.TOKEN_EMBEDDING_TYPE = "トークン埋め込みタイプ:" - self.USE_THIS_TYPE_FOR_TOKEN_EMBEDDINGS = "トークン埋め込みテンソルにこのタイプを使用します" - self.WILL_GENERATE_QUANTIZED_MODEL_IN_SAME_SHARDS = "入力と同じシャードで量子化されたモデルを生成します" + self.USE_THIS_TYPE_FOR_TOKEN_EMBEDDINGS = ( + "トークン埋め込みテンソルにこのタイプを使用します" + ) + self.WILL_GENERATE_QUANTIZED_MODEL_IN_SAME_SHARDS = ( + "入力と同じシャードで量子化されたモデルを生成します" + ) self.OVERRIDE_MODEL_METADATA = "モデルメタデータを上書きする" self.INPUT_DATA_FILE_FOR_IMATRIX = "IMatrix生成用の入力データファイル" self.MODEL_TO_BE_QUANTIZED = "量子化されるモデル" @@ -2777,11 +2797,11 @@ def __init__(self): self.NO_MODEL_SELECTED = "모델이 선택되지 않았습니다" self.REFRESH_RELEASES = "릴리스 새로 고침" self.NO_SUITABLE_CUDA_BACKENDS = "적합한 CUDA 백엔드를 찾을 수 없습니다" - self.LLAMACPP_DOWNLOADED_EXTRACTED = ( - "llama.cpp 바이너리가 다운로드되어 {0}에 추출되었습니다.\nCUDA 파일이 {1}에 추출되었습니다." - ) + self.LLAMACPP_DOWNLOADED_EXTRACTED = "llama.cpp 바이너리가 다운로드되어 {0}에 추출되었습니다.\nCUDA 파일이 {1}에 추출되었습니다." self.CUDA_FILES_EXTRACTED = "CUDA 파일이 에 추출되었습니다." - self.NO_SUITABLE_CUDA_BACKEND_EXTRACTION = "추출에 적합한 CUDA 백엔드를 찾을 수 없습니다." + self.NO_SUITABLE_CUDA_BACKEND_EXTRACTION = ( + "추출에 적합한 CUDA 백엔드를 찾을 수 없습니다." + ) self.ERROR_FETCHING_RELEASES = "릴리스를 가져오는 중 오류가 발생했습니다: {0}" self.CONFIRM_DELETION_TITLE = "삭제 확인" self.LOG_FOR = "{0}에 대한 로그" @@ -2805,11 +2825,13 @@ def __init__(self): self.TASK_PRESET_SAVED_TO = "작업 프리셋이 {0}에 저장되었습니다." self.RESTARTING_TASK = "작업을 다시 시작하는 중입니다: {0}" self.IN_PROGRESS = "진행 중" - self.DOWNLOAD_FINISHED_EXTRACTED_TO = "다운로드가 완료되었습니다. 추출 위치: {0}" - self.LLAMACPP_DOWNLOADED_AND_EXTRACTED = ( - "llama.cpp 바이너리가 다운로드되어 {0}에 추출되었습니다.\nCUDA 파일이 {1}에 추출되었습니다." + self.DOWNLOAD_FINISHED_EXTRACTED_TO = ( + "다운로드가 완료되었습니다. 추출 위치: {0}" + ) + self.LLAMACPP_DOWNLOADED_AND_EXTRACTED = "llama.cpp 바이너리가 다운로드되어 {0}에 추출되었습니다.\nCUDA 파일이 {1}에 추출되었습니다." + self.NO_SUITABLE_CUDA_BACKEND_FOUND = ( + "추출에 적합한 CUDA 백엔드를 찾을 수 없습니다." ) - self.NO_SUITABLE_CUDA_BACKEND_FOUND = "추출에 적합한 CUDA 백엔드를 찾을 수 없습니다." self.LLAMACPP_BINARY_DOWNLOADED_AND_EXTRACTED = ( "llama.cpp 바이너리가 다운로드되어 {0}에 추출되었습니다." ) @@ -2846,10 +2868,14 @@ def __init__(self): self.INPUT_FILE_NOT_EXIST = "입력 파일 '{0}'이 존재하지 않습니다." self.QUANTIZING_MODEL_TO = "{0}을 {1}(으)로 양자화하는 중입니다." self.QUANTIZATION_TASK_STARTED = "{0}에 대한 양자화 작업이 시작되었습니다." - self.ERROR_STARTING_QUANTIZATION = "양자화를 시작하는 중 오류가 발생했습니다: {0}" + self.ERROR_STARTING_QUANTIZATION = ( + "양자화를 시작하는 중 오류가 발생했습니다: {0}" + ) self.UPDATING_MODEL_INFO = "모델 정보를 업데이트하는 중입니다: {0}" self.TASK_FINISHED = "작업이 완료되었습니다: {0}" - self.SHOWING_TASK_DETAILS_FOR = "다음에 대한 작업 세부 정보를 표시하는 중입니다: {0}" + self.SHOWING_TASK_DETAILS_FOR = ( + "다음에 대한 작업 세부 정보를 표시하는 중입니다: {0}" + ) self.BROWSING_FOR_IMATRIX_DATA_FILE = "IMatrix 데이터 파일을 찾아보는 중입니다." self.SELECT_DATA_FILE = "데이터 파일 선택" self.BROWSING_FOR_IMATRIX_MODEL_FILE = "IMatrix 모델 파일을 찾아보는 중입니다." @@ -2859,7 +2885,9 @@ def __init__(self): self.STARTING_IMATRIX_GENERATION = "IMatrix 생성을 시작하는 중입니다." self.BACKEND_PATH_NOT_EXIST = "백엔드 경로가 존재하지 않습니다: {0}" self.GENERATING_IMATRIX = "IMatrix를 생성하는 중입니다." - self.ERROR_STARTING_IMATRIX_GENERATION = "IMatrix 생성을 시작하는 중 오류가 발생했습니다: {0}" + self.ERROR_STARTING_IMATRIX_GENERATION = ( + "IMatrix 생성을 시작하는 중 오류가 발생했습니다: {0}" + ) self.IMATRIX_GENERATION_TASK_STARTED = "IMatrix 생성 작업이 시작되었습니다." self.ERROR_MESSAGE = "오류: {0}" self.TASK_ERROR = "작업 오류: {0}" @@ -2868,14 +2896,26 @@ def __init__(self): self.SELECT_QUANTIZATION_TYPE = "양자화 유형을 선택하세요." self.ALLOWS_REQUANTIZING = "이미 양자화된 텐서의 재양자화를 허용합니다." self.LEAVE_OUTPUT_WEIGHT = "output.weight를 (재)양자화하지 않은 상태로 둡니다." - self.DISABLE_K_QUANT_MIXTURES = "k-양자 혼합을 비활성화하고 모든 텐서를 동일한 유형으로 양자화합니다." - self.USE_DATA_AS_IMPORTANCE_MATRIX = "양자 최적화를 위한 중요도 행렬로 파일의 데이터를 사용합니다." - self.USE_IMPORTANCE_MATRIX_FOR_TENSORS = "이러한 텐서에 중요도 행렬을 사용합니다." - self.DONT_USE_IMPORTANCE_MATRIX_FOR_TENSORS = "이러한 텐서에 중요도 행렬을 사용하지 않습니다." + self.DISABLE_K_QUANT_MIXTURES = ( + "k-양자 혼합을 비활성화하고 모든 텐서를 동일한 유형으로 양자화합니다." + ) + self.USE_DATA_AS_IMPORTANCE_MATRIX = ( + "양자 최적화를 위한 중요도 행렬로 파일의 데이터를 사용합니다." + ) + self.USE_IMPORTANCE_MATRIX_FOR_TENSORS = ( + "이러한 텐서에 중요도 행렬을 사용합니다." + ) + self.DONT_USE_IMPORTANCE_MATRIX_FOR_TENSORS = ( + "이러한 텐서에 중요도 행렬을 사용하지 않습니다." + ) self.OUTPUT_TENSOR_TYPE = "출력 텐서 유형:" - self.USE_THIS_TYPE_FOR_OUTPUT_WEIGHT = "output.weight 텐서에 이 유형을 사용합니다." + self.USE_THIS_TYPE_FOR_OUTPUT_WEIGHT = ( + "output.weight 텐서에 이 유형을 사용합니다." + ) self.TOKEN_EMBEDDING_TYPE = "토큰 임베딩 유형:" - self.USE_THIS_TYPE_FOR_TOKEN_EMBEDDINGS = "토큰 임베딩 텐서에 이 유형을 사용합니다." + self.USE_THIS_TYPE_FOR_TOKEN_EMBEDDINGS = ( + "토큰 임베딩 텐서에 이 유형을 사용합니다." + ) self.WILL_GENERATE_QUANTIZED_MODEL_IN_SAME_SHARDS = ( "입력과 동일한 샤드에 양자화된 모델을 생성합니다." ) @@ -3830,9 +3870,7 @@ def __init__(self): self.STARTING_IMATRIX_GENERATION = "IMatrix জেনারেশন শুরু হচ্ছে" self.BACKEND_PATH_NOT_EXIST = "ব্যাকএন্ড পাথ বিদ্যমান নেই: {0}" self.GENERATING_IMATRIX = "IMatrix তৈরি করা হচ্ছে" - self.ERROR_STARTING_IMATRIX_GENERATION = ( - "IMatrix জেনারেশন শুরু করতে ত্রুটি: {0}" - ) + self.ERROR_STARTING_IMATRIX_GENERATION = "IMatrix জেনারেশন শুরু করতে ত্রুটি: {0}" self.IMATRIX_GENERATION_TASK_STARTED = "IMatrix জেনারেশন টাস্ক শুরু হয়েছে" self.ERROR_MESSAGE = "ত্রুটি: {0}" self.TASK_ERROR = "টাস্ক ত্রুটি: {0}" @@ -3840,11 +3878,13 @@ def __init__(self): self.APPLICATION_CLOSED = "অ্যাপ্লিকেশন বন্ধ" self.SELECT_QUANTIZATION_TYPE = "কোয়ান্টাইজেশন ধরণ নির্বাচন করুন" self.ALLOWS_REQUANTIZING = "যে টেন্সরগুলি ইতিমধ্যে কোয়ান্টাইজ করা হয়েছে তাদের পুনরায় কোয়ান্টাইজ করার অনুমতি দেয়" - self.LEAVE_OUTPUT_WEIGHT = ( - "output.weight কে (পুনরায়) কোয়ান্টাইজ না করে রেখে দেবে" + self.LEAVE_OUTPUT_WEIGHT = "output.weight কে (পুনরায়) কোয়ান্টাইজ না করে রেখে দেবে" + self.DISABLE_K_QUANT_MIXTURES = ( + "k-কোয়ান্ট মিশ্রণগুলি অক্ষম করুন এবং সমস্ত টেন্সরকে একই ধরণের কোয়ান্টাইজ করুন" + ) + self.USE_DATA_AS_IMPORTANCE_MATRIX = ( + "কোয়ান্ট অপ্টিমাইজেশনের জন্য ফাইলের ডেটা গুরুত্বপূর্ণ ম্যাট্রিক্স হিসাবে ব্যবহার করুন" ) - self.DISABLE_K_QUANT_MIXTURES = "k-কোয়ান্ট মিশ্রণগুলি অক্ষম করুন এবং সমস্ত টেন্সরকে একই ধরণের কোয়ান্টাইজ করুন" - self.USE_DATA_AS_IMPORTANCE_MATRIX = "কোয়ান্ট অপ্টিমাইজেশনের জন্য ফাইলের ডেটা গুরুত্বপূর্ণ ম্যাট্রিক্স হিসাবে ব্যবহার করুন" self.USE_IMPORTANCE_MATRIX_FOR_TENSORS = ( "এই টেন্সরগুলির জন্য গুরুত্বপূর্ণ ম্যাট্রিক্স ব্যবহার করুন" ) @@ -5948,7 +5988,9 @@ def __init__(self): "llama.cpp 二進位檔案已下載並解壓縮至 {0}\nCUDA 檔案已解壓縮至 {1}" ) self.NO_SUITABLE_CUDA_BACKEND_FOUND = "找不到合適的 CUDA 後端進行解壓縮" - self.LLAMACPP_BINARY_DOWNLOADED_AND_EXTRACTED = "llama.cpp 二進位檔案已下載並解壓縮至 {0}" + self.LLAMACPP_BINARY_DOWNLOADED_AND_EXTRACTED = ( + "llama.cpp 二進位檔案已下載並解壓縮至 {0}" + ) self.REFRESHING_LLAMACPP_RELEASES = "正在重新整理 llama.cpp 版本" self.UPDATING_ASSET_LIST = "正在更新資源清單" self.UPDATING_CUDA_OPTIONS = "正在更新 CUDA 選項" @@ -6005,14 +6047,18 @@ def __init__(self): self.ALLOWS_REQUANTIZING = "允許重新量化已量化的張量" self.LEAVE_OUTPUT_WEIGHT = "將保留 output.weight 不被(重新)量化" self.DISABLE_K_QUANT_MIXTURES = "停用 k-quant 混合並將所有張量量化為相同類型" - self.USE_DATA_AS_IMPORTANCE_MATRIX = "使用檔案中的資料作為量化最佳化的重要性矩陣" + self.USE_DATA_AS_IMPORTANCE_MATRIX = ( + "使用檔案中的資料作為量化最佳化的重要性矩陣" + ) self.USE_IMPORTANCE_MATRIX_FOR_TENSORS = "對這些張量使用重要性矩陣" self.DONT_USE_IMPORTANCE_MATRIX_FOR_TENSORS = "不要對這些張量使用重要性矩陣" self.OUTPUT_TENSOR_TYPE = "輸出張量類型:" self.USE_THIS_TYPE_FOR_OUTPUT_WEIGHT = "對 output.weight 張量使用此類型" self.TOKEN_EMBEDDING_TYPE = "權杖嵌入類型:" self.USE_THIS_TYPE_FOR_TOKEN_EMBEDDINGS = "對權杖嵌入張量使用此類型" - self.WILL_GENERATE_QUANTIZED_MODEL_IN_SAME_SHARDS = "將在與輸入相同的分片中產生量化模型" + self.WILL_GENERATE_QUANTIZED_MODEL_IN_SAME_SHARDS = ( + "將在與輸入相同的分片中產生量化模型" + ) self.OVERRIDE_MODEL_METADATA = "覆蓋模型中繼資料" self.INPUT_DATA_FILE_FOR_IMATRIX = "IMatrix 產生的輸入資料檔案" self.MODEL_TO_BE_QUANTIZED = "要量化的模型" diff --git a/src/lora_conversion.py b/src/lora_conversion.py new file mode 100644 index 0000000..d3a29ee --- /dev/null +++ b/src/lora_conversion.py @@ -0,0 +1,74 @@ +from datetime import datetime + +from PySide6.QtWidgets import QListWidgetItem + +from src.QuantizationThread import QuantizationThread +from src.TaskListItem import TaskListItem +from src.error_handling import handle_error, show_error +from src.imports_and_globals import ensure_directory +from src.localizations import * + + +def convert_lora(self): + self.logger.info(STARTING_LORA_CONVERSION) + try: + lora_input_path = self.lora_input.text() + lora_output_path = self.lora_output.text() + lora_output_type = self.lora_output_type_combo.currentText() + + if not lora_input_path: + raise ValueError(LORA_INPUT_PATH_REQUIRED) + if not lora_output_path: + raise ValueError(LORA_OUTPUT_PATH_REQUIRED) + + if lora_output_type == "GGUF": # Use new file and parameters for GGUF + command = [ + "python", + "src/convert_lora_to_gguf.py", + "--outfile", + lora_output_path, + lora_input_path, + ] + base_model_path = self.base_model_path.text() + if not base_model_path: + raise ValueError(BASE_MODEL_PATH_REQUIRED) + command.extend(["--base", base_model_path]) + else: # Use old GGML parameters for GGML + command = ["python", "src/convert_lora_to_ggml.py", lora_input_path] + + logs_path = self.logs_input.text() + ensure_directory(logs_path) + + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + log_file = os.path.join(logs_path, f"lora_conversion_{timestamp}.log") + + command_str = " ".join(command) + self.logger.info(f"{LORA_CONVERSION_COMMAND}: {command_str}") + + thread = QuantizationThread(command, os.getcwd(), log_file) + self.quant_threads.append(thread) + + task_name = LORA_CONVERSION_FROM_TO.format( + os.path.basename(lora_input_path), os.path.basename(lora_output_path) + ) + task_item = TaskListItem(task_name, log_file, show_progress_bar=False) + list_item = QListWidgetItem(self.task_list) + list_item.setSizeHint(task_item.sizeHint()) + self.task_list.addItem(list_item) + self.task_list.setItemWidget(list_item, task_item) + + thread.status_signal.connect(task_item.update_status) + thread.finished_signal.connect( + lambda: self.lora_conversion_finished( + thread, lora_input_path, lora_output_path + ) + ) + thread.error_signal.connect( + lambda err: handle_error(self.logger, err, task_item) + ) + thread.start() + self.logger.info(LORA_CONVERSION_TASK_STARTED) + except ValueError as e: + show_error(self.logger, str(e)) + except Exception as e: + show_error(self.logger, ERROR_STARTING_LORA_CONVERSION.format(str(e))) diff --git a/src/main.py b/src/main.py index 849da85..0275a52 100644 --- a/src/main.py +++ b/src/main.py @@ -4,7 +4,7 @@ from PySide6.QtCore import QTimer from PySide6.QtWidgets import QApplication -from AutoGGUF import AutoGGUF +from src.AutoGGUF import AutoGGUF from flask import Flask, jsonify server = Flask(__name__) diff --git a/src/ui_update.py b/src/ui_update.py index f1fbaf9..2212fc9 100644 --- a/src/ui_update.py +++ b/src/ui_update.py @@ -1,4 +1,4 @@ -from localizations import * +from src.localizations import * import psutil diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 0000000..cceacd5 --- /dev/null +++ b/src/utils.py @@ -0,0 +1,66 @@ +from PySide6.QtWidgets import QFileDialog + +from error_handling import show_error +from localizations import * +import requests + +from src.DownloadThread import DownloadThread +from src.imports_and_globals import ensure_directory + + +def browse_lora_input(self): + self.logger.info(BROWSING_FOR_LORA_INPUT_DIRECTORY) + lora_input_path = QFileDialog.getExistingDirectory( + self, SELECT_LORA_INPUT_DIRECTORY + ) + if lora_input_path: + self.lora_input.setText(os.path.abspath(lora_input_path)) + ensure_directory(lora_input_path) + + +def browse_lora_output(self): + self.logger.info(BROWSING_FOR_LORA_OUTPUT_FILE) + lora_output_file, _ = QFileDialog.getSaveFileName( + self, SELECT_LORA_OUTPUT_FILE, "", GGUF_AND_BIN_FILES + ) + if lora_output_file: + self.lora_output.setText(os.path.abspath(lora_output_file)) + + +def download_llama_cpp(self): + self.logger.info(STARTING_LLAMACPP_DOWNLOAD) + asset = self.asset_combo.currentData() + if not asset: + show_error(self.logger, NO_ASSET_SELECTED) + return + + llama_bin = os.path.abspath("llama_bin") + os.makedirs(llama_bin, exist_ok=True) + + save_path = os.path.join(llama_bin, asset["name"]) + + self.download_thread = DownloadThread(asset["browser_download_url"], save_path) + self.download_thread.progress_signal.connect(self.update_download_progress) + self.download_thread.finished_signal.connect(self.download_finished) + self.download_thread.error_signal.connect(self.download_error) + self.download_thread.start() + + self.download_button.setEnabled(False) + self.download_progress.setValue(0) + + +def refresh_releases(self): + 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 + 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 requests.exceptions.RequestException as e: + show_error(self.logger, ERROR_FETCHING_RELEASES.format(str(e)))