From c8af65760f7341519b9cec205c85223949b0bb87 Mon Sep 17 00:00:00 2001 From: YellowRoseCx <80486540+YellowRoseCx@users.noreply.github.com> Date: Sun, 30 Jul 2023 04:50:55 -0500 Subject: [PATCH] Hide unavailable backends & Add tooltip over backend count (#352) * Hide unavailable backends & Add tooltip over backend count Hides unavailable backends from the user and if the program is launched without any backends made, it shows an error message to them stating no backends were found and to make them using the 'make' command Add tooltip when hovering over backend count label hovering over the new label that shows the backend count will explain what the numbers are, and show the users which backends are not available or built * add some code comments * hide "missing" if all are built move tooltip functions to helper functions section. hides the string "Missing: ..." from showing if all backends are available " if len(runopts)==6 else + " * small typo fix * remove wrongly added leftover device choosing code * fix labels * move tooltip to function --------- Co-authored-by: Concedo <39025047+LostRuins@users.noreply.github.com> --- koboldcpp.py | 119 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 85 insertions(+), 34 deletions(-) diff --git a/koboldcpp.py b/koboldcpp.py index 588c944dd..71b248b3b 100755 --- a/koboldcpp.py +++ b/koboldcpp.py @@ -662,7 +662,6 @@ def show_new_gui(): return import customtkinter as ctk - nextstate = 0 #0=exit, 1=launch, 2=oldgui windowwidth = 520 windowheight = 500 @@ -685,13 +684,22 @@ def show_new_gui(): tabcontentframe.grid_propagate(False) tabcontent = {} - + lib_option_pairs = [ + (lib_openblas, "Use OpenBLAS"), + (lib_clblast, "Use CLBlast"), + (lib_cublas, "Use CuBLAS"), + (lib_default, "Use No BLAS"), + (lib_noavx2, "Use NoAVX2 Mode (Old CPU)"), + (lib_failsafe, "Failsafe Mode (Old CPU)")] + openblas_option, clblast_option, cublas_option, default_option, openblas_noavx2_option, failsafe_option = (opt if file_exists(lib) or (os.name == 'nt' and file_exists(opt + ".dll")) else None for lib, opt in lib_option_pairs) # slider data blasbatchsize_values = ["-1", "32", "64", "128", "256", "512", "1024"] blasbatchsize_text = ["Don't Batch BLAS","32","64","128","256","512","1024"] contextsize_text = ["512", "1024", "2048", "3072", "4096", "6144", "8192"] - runopts = ["Use OpenBLAS","Use CLBlast", "Use CuBLAS", "Use No BLAS","Use OpenBLAS (Old CPU, noavx2)","Failsafe Mode (Old CPU, noavx)"] - + runopts = [opt for lib, opt in lib_option_pairs if file_exists(lib) or os.name == 'nt' and file_exists(opt + ".dll")] + antirunopts = [opt.replace("Use ", "") for lib, opt in lib_option_pairs if not file_exists(lib) or os.name == 'nt' and not file_exists(opt + ".dll")] + if not any(runopts): + show_gui_warning("No Backend Available") def tabbuttonaction(name): for t in tabcontent: if name == t: @@ -757,6 +765,32 @@ def show_new_gui(): button.grid(row=row+1, column=1, stick="nw") return + def show_tooltip(event, tooltip_text=None): + if hasattr(show_tooltip, "_tooltip"): + tooltip = show_tooltip._tooltip + else: + tooltip = ctk.CTkToplevel(root) + tooltip.configure(fg_color="#ffffe0") + tooltip.withdraw() + tooltip.overrideredirect(True) + tooltip_label = ctk.CTkLabel(tooltip, text=tooltip_text, text_color="#000000", fg_color="#ffffe0") + tooltip_label.pack(expand=True, padx=2, pady=1) + show_tooltip._tooltip = tooltip + x, y = root.winfo_pointerxy() + tooltip.wm_geometry(f"+{x + 10}+{y + 10}") + tooltip.deiconify() + def hide_tooltip(event): + if hasattr(show_tooltip, "_tooltip"): + tooltip = show_tooltip._tooltip + tooltip.withdraw() + def setup_backend_tooltip(parent): + num_backends_built = makelabel(parent, str(len(runopts)) + "/6", 5, 2) + num_backends_built.grid(row=1, column=2, padx=0, pady=0) + num_backends_built.configure(text_color="#00ff00") + # Bind the backend count label with the tooltip function + num_backends_built.bind("", lambda event: show_tooltip(event, f"This is the number of backends you have built and available." + (f"\nMissing: {', '.join(antirunopts)}" if len(runopts) != 6 else ""))) + num_backends_built.bind("", hide_tooltip) + # Vars - should be in scope to be used by multiple widgets gpulayers_var = ctk.StringVar(value="0") threads_var = ctk.StringVar(value=str(default_threads)) @@ -857,7 +891,10 @@ def show_new_gui(): runoptbox = ctk.CTkComboBox(quick_tab, values=runopts, width=180,variable=runopts_var, state="readonly") runoptbox.grid(row=1, column=1,padx=8, stick="nw") - runoptbox.set("Use OpenBLAS") + runoptbox.set(runopts[0]) # Set to first available option + + # Tell user how many backends are available + setup_backend_tooltip(quick_tab) # threads makelabelentry(quick_tab, "Threads:" , threads_var, 8, 50) @@ -869,7 +906,6 @@ def show_new_gui(): quick_boxes = {"Launch Browser": launchbrowser , "High Priority" : highpriority, "Streaming Mode":stream, "Use SmartContext":smartcontext, "Unban Tokens":unbantokens, "Disable MMAP":disablemmap,} for idx, name, in enumerate(quick_boxes): makecheckbox(quick_tab, name, quick_boxes[name], int(idx/2) +20, idx%2) - # context size makeslider(quick_tab, "Context Size:", contextsize_text, context_var, 0, len(contextsize_text)-1, 30, set=2) @@ -890,9 +926,13 @@ def show_new_gui(): makelabel(hardware_tab, "Presets:", 1) runoptbox = ctk.CTkComboBox(hardware_tab, values=runopts, width=180,variable=runopts_var, state="readonly") runoptbox.grid(row=1, column=1,padx=8, stick="nw") - runoptbox.set("Use OpenBLAS") + runoptbox.set(runopts[0]) # Set to first available option runopts_var.trace('w', changerunmode) changerunmode(1,1,1) + + # Tell user how many backends are available + setup_backend_tooltip(hardware_tab) + # threads makelabelentry(hardware_tab, "Threads:" , threads_var, 8, 50) @@ -1018,20 +1058,20 @@ def show_new_gui(): gpuchoiceidx = 0 if gpu_choice_var.get()!="All": gpuchoiceidx = int(gpu_choice_var.get())-1 - if runopts_var.get() == runopts[1]: + if runopts_var.get() == "Use CLBlast": args.useclblast = [[0,0], [1,0], [0,1]][gpuchoiceidx] - if runopts_var.get() == runopts[2]: + if runopts_var.get() == "Use CuBLAS": if gpu_choice_var.get()=="All": args.usecublas = ["lowvram"] if lowvram_var.get() == 1 else ["normal"] else: args.usecublas = ["lowvram",str(gpuchoiceidx)] if lowvram_var.get() == 1 else ["normal",str(gpuchoiceidx)] if gpulayers_var.get(): args.gpulayers = int(gpulayers_var.get()) - if runopts_var.get()==runopts[3]: + if runopts_var.get()=="Use No BLAS": args.noblas = True - if runopts_var.get()==runopts[4]: + if runopts_var.get()=="Use NoAVX2 Mode (Old CPU)": args.noavx2 = True - if runopts_var.get()==runopts[5]: + if runopts_var.get()=="Failsafe Mode (Old CPU)": args.noavx2 = True args.noblas = True args.nommap = True @@ -1070,38 +1110,42 @@ def show_new_gui(): stream.set(1 if "stream" in dict and dict["stream"] else 0) smartcontext.set(1 if "smartcontext" in dict and dict["smartcontext"] else 0) unbantokens.set(1 if "unbantokens" in dict and dict["unbantokens"] else 0) - runopts_var.set(runopts[0]) if "useclblast" in dict and dict["useclblast"]: - runopts_var.set(runopts[1]) - gpu_choice_var.set(str(["0 0", "1 0", "0 1"].index(str(dict["useclblast"][0]) + " " + str(dict["useclblast"][1])) + 1)) + if clblast_option is not None: + runopts_var.set(clblast_option) + gpu_choice_var.set(str(["0 0", "1 0", "0 1"].index(str(dict["useclblast"][0]) + " " + str(dict["useclblast"][1])) + 1)) elif "usecublas" in dict and dict["usecublas"]: - runopts_var.set(runopts[2]) - if len(dict["usecublas"])==1: - lowvram_var.set(1 if dict["usecublas"][0]=="lowvram" else 0) - else: - lowvram_var.set(1 if "lowvram" in dict["usecublas"] else 0) - gpu_choice_var.set("1") - for g in range(3): - if str(g) in dict["usecublas"]: - gpu_choice_var.set(str(g+1)) - break + if cublas_option is not None: + runopts_var.set(cublas_option) + if len(dict["usecublas"])==1: + lowvram_var.set(1 if dict["usecublas"][0]=="lowvram" else 0) + else: + lowvram_var.set(1 if "lowvram" in dict["usecublas"] else 0) + gpu_choice_var.set("1") + for g in range(3): + if str(g) in dict["usecublas"]: + gpu_choice_var.set(str(g+1)) + break if "gpulayers" in dict and dict["gpulayers"]: gpulayers_var.set(dict["gpulayers"]) if "noavx2" in dict and "noblas" in dict and dict["noblas"] and dict["noavx2"]: - runopts_var.set(runopts[5]) + if failsafe_option is not None: + runopts_var.set(failsafe_option) elif "noavx2" in dict and dict["noavx2"]: - runopts_var.set(runopts[4]) + if openblas_noavx2_option is not None: + runopts_var.set(openblas_noavx2_option) elif "noblas" in dict and dict["noblas"]: - runopts_var.set(runopts[3]) + if default_option is not None: + runopts_var.set(default_option) + elif openblas_option is not None: + runopts_var.set(openblas_option) if "blasthreads" in dict and dict["blasthreads"]: blas_threads_var.set(str(dict["blasthreads"])) else: blas_threads_var.set("") - if "contextsize" in dict and dict["contextsize"]: context_var.set(contextsize_text.index(str(dict["contextsize"]))) - if "ropeconfig" in dict and dict["ropeconfig"] and len(dict["ropeconfig"])>1: if dict["ropeconfig"][0]>0: customrope_var.set(1) @@ -1199,13 +1243,20 @@ def show_new_gui(): time.sleep(2) sys.exit(2) -def show_gui_warning(): +def show_gui_warning(issue=None): from tkinter import messagebox import tkinter as tk root = tk.Tk() root.attributes("-alpha", 0) - messagebox.showerror(title="New GUI failed, using Old GUI", message="The new GUI failed to load.\n\nTo use new GUI, please install the customtkinter python module.") - root.destroy() + if issue == "No Backend Available": + messagebox.showerror(title="No Backends Available!", message="KoboldCPP couldn't locate any backends to use.\n\nTo use the program, please run the 'make' command from the directory.") + root.destroy() + print("No Backend Available (i.e Default, OpenBLAS, CLBlast, CuBLAS). To use the program, please run the 'make' command from the directory.") + time.sleep(2) + sys.exit(2) + else: + messagebox.showerror(title="New GUI failed, using Old GUI", message="The new GUI failed to load.\n\nTo use new GUI, please install the customtkinter python module.") + root.destroy() def show_old_gui(): import tkinter as tk @@ -1236,7 +1287,7 @@ def show_old_gui(): blaschoice = tk.StringVar() blaschoice.set("BLAS = 512") - runopts = ["Use OpenBLAS","Use CLBLast GPU #1","Use CLBLast GPU #2","Use CLBLast GPU #3","Use CuBLAS GPU","Use No BLAS","Use OpenBLAS (Old CPU, noavx2)","Failsafe Mode (Old CPU, noavx)"] + runopts = ["Use OpenBLAS","Use CLBLast GPU #1","Use CLBLast GPU #2","Use CLBLast GPU #3","Use CuBLAS GPU","Use No BLAS","Use NoAVX2 Mode (Old CPU)","Failsafe Mode (Old CPU)"] runchoice = tk.StringVar() runchoice.set("Use OpenBLAS")