Skip to content

Commit c8af657

Browse files
Hide unavailable backends & Add tooltip over backend count (ggml-org#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>
1 parent 45456fa commit c8af657

File tree

1 file changed

+85
-34
lines changed

1 file changed

+85
-34
lines changed

koboldcpp.py

Lines changed: 85 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,6 @@ def show_new_gui():
662662
return
663663

664664
import customtkinter as ctk
665-
666665
nextstate = 0 #0=exit, 1=launch, 2=oldgui
667666
windowwidth = 520
668667
windowheight = 500
@@ -685,13 +684,22 @@ def show_new_gui():
685684
tabcontentframe.grid_propagate(False)
686685

687686
tabcontent = {}
688-
687+
lib_option_pairs = [
688+
(lib_openblas, "Use OpenBLAS"),
689+
(lib_clblast, "Use CLBlast"),
690+
(lib_cublas, "Use CuBLAS"),
691+
(lib_default, "Use No BLAS"),
692+
(lib_noavx2, "Use NoAVX2 Mode (Old CPU)"),
693+
(lib_failsafe, "Failsafe Mode (Old CPU)")]
694+
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)
689695
# slider data
690696
blasbatchsize_values = ["-1", "32", "64", "128", "256", "512", "1024"]
691697
blasbatchsize_text = ["Don't Batch BLAS","32","64","128","256","512","1024"]
692698
contextsize_text = ["512", "1024", "2048", "3072", "4096", "6144", "8192"]
693-
runopts = ["Use OpenBLAS","Use CLBlast", "Use CuBLAS", "Use No BLAS","Use OpenBLAS (Old CPU, noavx2)","Failsafe Mode (Old CPU, noavx)"]
694-
699+
runopts = [opt for lib, opt in lib_option_pairs if file_exists(lib) or os.name == 'nt' and file_exists(opt + ".dll")]
700+
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")]
701+
if not any(runopts):
702+
show_gui_warning("No Backend Available")
695703
def tabbuttonaction(name):
696704
for t in tabcontent:
697705
if name == t:
@@ -757,6 +765,32 @@ def getfilename(var, text):
757765
button.grid(row=row+1, column=1, stick="nw")
758766
return
759767

768+
def show_tooltip(event, tooltip_text=None):
769+
if hasattr(show_tooltip, "_tooltip"):
770+
tooltip = show_tooltip._tooltip
771+
else:
772+
tooltip = ctk.CTkToplevel(root)
773+
tooltip.configure(fg_color="#ffffe0")
774+
tooltip.withdraw()
775+
tooltip.overrideredirect(True)
776+
tooltip_label = ctk.CTkLabel(tooltip, text=tooltip_text, text_color="#000000", fg_color="#ffffe0")
777+
tooltip_label.pack(expand=True, padx=2, pady=1)
778+
show_tooltip._tooltip = tooltip
779+
x, y = root.winfo_pointerxy()
780+
tooltip.wm_geometry(f"+{x + 10}+{y + 10}")
781+
tooltip.deiconify()
782+
def hide_tooltip(event):
783+
if hasattr(show_tooltip, "_tooltip"):
784+
tooltip = show_tooltip._tooltip
785+
tooltip.withdraw()
786+
def setup_backend_tooltip(parent):
787+
num_backends_built = makelabel(parent, str(len(runopts)) + "/6", 5, 2)
788+
num_backends_built.grid(row=1, column=2, padx=0, pady=0)
789+
num_backends_built.configure(text_color="#00ff00")
790+
# Bind the backend count label with the tooltip function
791+
num_backends_built.bind("<Enter>", 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 "")))
792+
num_backends_built.bind("<Leave>", hide_tooltip)
793+
760794
# Vars - should be in scope to be used by multiple widgets
761795
gpulayers_var = ctk.StringVar(value="0")
762796
threads_var = ctk.StringVar(value=str(default_threads))
@@ -857,7 +891,10 @@ def changerunmode(a,b,c):
857891

858892
runoptbox = ctk.CTkComboBox(quick_tab, values=runopts, width=180,variable=runopts_var, state="readonly")
859893
runoptbox.grid(row=1, column=1,padx=8, stick="nw")
860-
runoptbox.set("Use OpenBLAS")
894+
runoptbox.set(runopts[0]) # Set to first available option
895+
896+
# Tell user how many backends are available
897+
setup_backend_tooltip(quick_tab)
861898

862899
# threads
863900
makelabelentry(quick_tab, "Threads:" , threads_var, 8, 50)
@@ -869,7 +906,6 @@ def changerunmode(a,b,c):
869906
quick_boxes = {"Launch Browser": launchbrowser , "High Priority" : highpriority, "Streaming Mode":stream, "Use SmartContext":smartcontext, "Unban Tokens":unbantokens, "Disable MMAP":disablemmap,}
870907
for idx, name, in enumerate(quick_boxes):
871908
makecheckbox(quick_tab, name, quick_boxes[name], int(idx/2) +20, idx%2)
872-
873909
# context size
874910
makeslider(quick_tab, "Context Size:", contextsize_text, context_var, 0, len(contextsize_text)-1, 30, set=2)
875911

@@ -890,9 +926,13 @@ def changerunmode(a,b,c):
890926
makelabel(hardware_tab, "Presets:", 1)
891927
runoptbox = ctk.CTkComboBox(hardware_tab, values=runopts, width=180,variable=runopts_var, state="readonly")
892928
runoptbox.grid(row=1, column=1,padx=8, stick="nw")
893-
runoptbox.set("Use OpenBLAS")
929+
runoptbox.set(runopts[0]) # Set to first available option
894930
runopts_var.trace('w', changerunmode)
895931
changerunmode(1,1,1)
932+
933+
# Tell user how many backends are available
934+
setup_backend_tooltip(hardware_tab)
935+
896936
# threads
897937
makelabelentry(hardware_tab, "Threads:" , threads_var, 8, 50)
898938

@@ -1018,20 +1058,20 @@ def export_vars():
10181058
gpuchoiceidx = 0
10191059
if gpu_choice_var.get()!="All":
10201060
gpuchoiceidx = int(gpu_choice_var.get())-1
1021-
if runopts_var.get() == runopts[1]:
1061+
if runopts_var.get() == "Use CLBlast":
10221062
args.useclblast = [[0,0], [1,0], [0,1]][gpuchoiceidx]
1023-
if runopts_var.get() == runopts[2]:
1063+
if runopts_var.get() == "Use CuBLAS":
10241064
if gpu_choice_var.get()=="All":
10251065
args.usecublas = ["lowvram"] if lowvram_var.get() == 1 else ["normal"]
10261066
else:
10271067
args.usecublas = ["lowvram",str(gpuchoiceidx)] if lowvram_var.get() == 1 else ["normal",str(gpuchoiceidx)]
10281068
if gpulayers_var.get():
10291069
args.gpulayers = int(gpulayers_var.get())
1030-
if runopts_var.get()==runopts[3]:
1070+
if runopts_var.get()=="Use No BLAS":
10311071
args.noblas = True
1032-
if runopts_var.get()==runopts[4]:
1072+
if runopts_var.get()=="Use NoAVX2 Mode (Old CPU)":
10331073
args.noavx2 = True
1034-
if runopts_var.get()==runopts[5]:
1074+
if runopts_var.get()=="Failsafe Mode (Old CPU)":
10351075
args.noavx2 = True
10361076
args.noblas = True
10371077
args.nommap = True
@@ -1070,38 +1110,42 @@ def import_vars(dict):
10701110
stream.set(1 if "stream" in dict and dict["stream"] else 0)
10711111
smartcontext.set(1 if "smartcontext" in dict and dict["smartcontext"] else 0)
10721112
unbantokens.set(1 if "unbantokens" in dict and dict["unbantokens"] else 0)
1073-
runopts_var.set(runopts[0])
10741113
if "useclblast" in dict and dict["useclblast"]:
1075-
runopts_var.set(runopts[1])
1076-
gpu_choice_var.set(str(["0 0", "1 0", "0 1"].index(str(dict["useclblast"][0]) + " " + str(dict["useclblast"][1])) + 1))
1114+
if clblast_option is not None:
1115+
runopts_var.set(clblast_option)
1116+
gpu_choice_var.set(str(["0 0", "1 0", "0 1"].index(str(dict["useclblast"][0]) + " " + str(dict["useclblast"][1])) + 1))
10771117
elif "usecublas" in dict and dict["usecublas"]:
1078-
runopts_var.set(runopts[2])
1079-
if len(dict["usecublas"])==1:
1080-
lowvram_var.set(1 if dict["usecublas"][0]=="lowvram" else 0)
1081-
else:
1082-
lowvram_var.set(1 if "lowvram" in dict["usecublas"] else 0)
1083-
gpu_choice_var.set("1")
1084-
for g in range(3):
1085-
if str(g) in dict["usecublas"]:
1086-
gpu_choice_var.set(str(g+1))
1087-
break
1118+
if cublas_option is not None:
1119+
runopts_var.set(cublas_option)
1120+
if len(dict["usecublas"])==1:
1121+
lowvram_var.set(1 if dict["usecublas"][0]=="lowvram" else 0)
1122+
else:
1123+
lowvram_var.set(1 if "lowvram" in dict["usecublas"] else 0)
1124+
gpu_choice_var.set("1")
1125+
for g in range(3):
1126+
if str(g) in dict["usecublas"]:
1127+
gpu_choice_var.set(str(g+1))
1128+
break
10881129
if "gpulayers" in dict and dict["gpulayers"]:
10891130
gpulayers_var.set(dict["gpulayers"])
10901131

10911132
if "noavx2" in dict and "noblas" in dict and dict["noblas"] and dict["noavx2"]:
1092-
runopts_var.set(runopts[5])
1133+
if failsafe_option is not None:
1134+
runopts_var.set(failsafe_option)
10931135
elif "noavx2" in dict and dict["noavx2"]:
1094-
runopts_var.set(runopts[4])
1136+
if openblas_noavx2_option is not None:
1137+
runopts_var.set(openblas_noavx2_option)
10951138
elif "noblas" in dict and dict["noblas"]:
1096-
runopts_var.set(runopts[3])
1139+
if default_option is not None:
1140+
runopts_var.set(default_option)
1141+
elif openblas_option is not None:
1142+
runopts_var.set(openblas_option)
10971143
if "blasthreads" in dict and dict["blasthreads"]:
10981144
blas_threads_var.set(str(dict["blasthreads"]))
10991145
else:
11001146
blas_threads_var.set("")
1101-
11021147
if "contextsize" in dict and dict["contextsize"]:
11031148
context_var.set(contextsize_text.index(str(dict["contextsize"])))
1104-
11051149
if "ropeconfig" in dict and dict["ropeconfig"] and len(dict["ropeconfig"])>1:
11061150
if dict["ropeconfig"][0]>0:
11071151
customrope_var.set(1)
@@ -1199,13 +1243,20 @@ def display_help():
11991243
time.sleep(2)
12001244
sys.exit(2)
12011245

1202-
def show_gui_warning():
1246+
def show_gui_warning(issue=None):
12031247
from tkinter import messagebox
12041248
import tkinter as tk
12051249
root = tk.Tk()
12061250
root.attributes("-alpha", 0)
1207-
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.")
1208-
root.destroy()
1251+
if issue == "No Backend Available":
1252+
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.")
1253+
root.destroy()
1254+
print("No Backend Available (i.e Default, OpenBLAS, CLBlast, CuBLAS). To use the program, please run the 'make' command from the directory.")
1255+
time.sleep(2)
1256+
sys.exit(2)
1257+
else:
1258+
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.")
1259+
root.destroy()
12091260

12101261
def show_old_gui():
12111262
import tkinter as tk
@@ -1236,7 +1287,7 @@ def guilaunch():
12361287
blaschoice = tk.StringVar()
12371288
blaschoice.set("BLAS = 512")
12381289

1239-
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)"]
1290+
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)"]
12401291
runchoice = tk.StringVar()
12411292
runchoice.set("Use OpenBLAS")
12421293

0 commit comments

Comments
 (0)