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")