|
from PyQt6.QtWidgets import QMainWindow, QFileDialog
|
|
from PyQt6.QtCore import Qt
|
|
from ui_main import Ui_MainWindow
|
|
import configparser
|
|
import subprocess
|
|
import os
|
|
from PyQt6.QtCore import Qt, QPoint
|
|
from PyQt6.QtWidgets import QStackedWidget
|
|
from PyQt6.QtWidgets import QMainWindow, QFileDialog
|
|
|
|
class UILoader(QMainWindow, Ui_MainWindow):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.setupUi(self)
|
|
self.setWindowFlag(Qt.WindowType.FramelessWindowHint)
|
|
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
|
|
self.init_ui()
|
|
self.update_batch_size_label(3)
|
|
self.update_ctx_size_label(4)
|
|
|
|
self.offset = None
|
|
|
|
def init_ui(self):
|
|
self.minimize_button.clicked.connect(self.showMinimized)
|
|
self.close_button.clicked.connect(self.close)
|
|
self.model_browse_button.clicked.connect(self.browse_model)
|
|
self.run_server_button.clicked.connect(self.run_server)
|
|
self.save_config_button.clicked.connect(self.save_config)
|
|
self.load_config_button.clicked.connect(self.load_config)
|
|
|
|
self.top_bar.mousePressEvent = self.mouse_press_event
|
|
self.top_bar.mouseMoveEvent = self.mouse_move_event
|
|
|
|
def mouse_press_event(self, event):
|
|
self.offset = event.pos()
|
|
|
|
def update_threads_label(self, value):
|
|
self.threads_label.setText(f"Threads: {value + 1}")
|
|
|
|
def mouse_move_event(self, event):
|
|
if self.offset is not None and event.buttons() == Qt.MouseButton.LeftButton:
|
|
self.move(self.pos() + event.pos() - self.offset)
|
|
|
|
def browse_model(self):
|
|
model_path, _ = QFileDialog.getOpenFileName(self, "Select Model", os.getcwd(), "Model Files (*.gguf)")
|
|
self.model_path_line_edit.setText(model_path)
|
|
|
|
def run_server(self):
|
|
model_path = self.model_path_line_edit.text()
|
|
batch_size = self.batch_size_values[self.batch_size_slider.value()]
|
|
ctx_size = self.ctx_size_values[self.ctx_size_slider.value()]
|
|
layers_offload = self.layers_offload_spin_box.value()
|
|
threads = self.threads_spin_box.value()
|
|
use_flash_attention = self.flash_attention_checkbox.isChecked()
|
|
is_moe = self.moe_checkbox.isChecked()
|
|
moe_experts_string = ""
|
|
if is_moe:
|
|
experts_use = self.moe_experts_spin_box.value()
|
|
moe_experts_string = f"--override-kv llama.expert_used_count=int:{experts_use}"
|
|
|
|
custom_rope_freq_base = self.rope_freq_base_spin_box.value() if self.rope_freq_base_checkbox.isChecked() else None
|
|
mlock = self.mlock_checkbox.isChecked()
|
|
no_mmap = self.no_mmap_checkbox.isChecked()
|
|
no_kv_offload = self.no_kv_offload_checkbox.isChecked()
|
|
|
|
command = [
|
|
"LlamaCPP\\llama-server.exe",
|
|
f"--model {model_path}",
|
|
f"--batch-size {batch_size}",
|
|
f"--ctx-size {ctx_size}",
|
|
f"--n-gpu-layers {layers_offload}",
|
|
f"--threads {threads}",
|
|
]
|
|
|
|
if use_flash_attention:
|
|
command.append("--flash-attn")
|
|
if mlock:
|
|
command.append("--mlock")
|
|
if no_mmap:
|
|
command.append("--no-mmap")
|
|
if no_kv_offload:
|
|
command.append("--no-kv-offload")
|
|
if custom_rope_freq_base is not None:
|
|
command.append(f"--rope-freq-base {custom_rope_freq_base}")
|
|
if moe_experts_string:
|
|
command.append(moe_experts_string)
|
|
|
|
print(" ".join(command))
|
|
subprocess.run(" ".join(command), shell=True)
|
|
|
|
def save_config(self):
|
|
config = configparser.ConfigParser()
|
|
config["Server"] = {
|
|
"model_path": self.model_path_line_edit.text(),
|
|
"batch_size": str(self.batch_size_slider.value()),
|
|
"ctx_size": str(self.ctx_size_slider.value()),
|
|
"layers_offload": str(self.layers_offload_spin_box.value()),
|
|
"threads": str(self.threads_spin_box.value()),
|
|
"use_flash_attention": str(self.flash_attention_checkbox.isChecked()),
|
|
"is_moe": str(self.moe_checkbox.isChecked()),
|
|
"moe_experts": str(self.moe_experts_spin_box.value()),
|
|
"rope_freq_base_custom": str(self.rope_freq_base_checkbox.isChecked()),
|
|
"rope_freq_base_value": str(self.rope_freq_base_spin_box.value()),
|
|
"mlock": str(self.mlock_checkbox.isChecked()),
|
|
"no_mmap": str(self.no_mmap_checkbox.isChecked()),
|
|
"no_kv_offload": str(self.no_kv_offload_checkbox.isChecked()),
|
|
}
|
|
|
|
file_path, _ = QFileDialog.getSaveFileName(self, "Save Configuration", os.getcwd(), "INI Files (*.ini)")
|
|
if file_path:
|
|
with open(file_path, "w") as config_file:
|
|
config.write(config_file)
|
|
|
|
def load_config(self):
|
|
file_path, _ = QFileDialog.getOpenFileName(self, "Load Configuration", os.getcwd(), "INI Files (*.ini)")
|
|
if file_path:
|
|
config = configparser.ConfigParser()
|
|
config.read(file_path)
|
|
|
|
self.model_path_line_edit.setText(config.get("Server", "model_path", fallback=""))
|
|
self.batch_size_slider.setValue(config.getint("Server", "batch_size", fallback=512))
|
|
self.ctx_size_slider.setValue(config.getint("Server", "ctx_size", fallback=8192))
|
|
self.layers_offload_spin_box.setValue(config.getint("Server", "layers_offload", fallback=22))
|
|
self.threads_spin_box.setValue(config.getint("Server", "threads", fallback=14))
|
|
self.flash_attention_checkbox.setChecked(config.getboolean("Server", "use_flash_attention", fallback=False))
|
|
self.moe_checkbox.setChecked(config.getboolean("Server", "is_moe", fallback=False))
|
|
self.moe_experts_spin_box.setValue(config.getint("Server", "moe_experts", fallback=1))
|
|
self.rope_freq_base_checkbox.setChecked(config.getboolean("Server", "rope_freq_base_custom", fallback=False))
|
|
self.rope_freq_base_spin_box.setValue(config.getint("Server", "rope_freq_base_value", fallback=1))
|
|
self.mlock_checkbox.setChecked(config.getboolean("Server", "mlock", fallback=False))
|
|
self.no_mmap_checkbox.setChecked(config.getboolean("Server", "no_mmap", fallback=False))
|
|
self.no_kv_offload_checkbox.setChecked(config.getboolean("Server", "no_kv_offload", fallback=False)) |