@@ -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"\n Missing: { ', ' .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 \n To 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 \n To 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 \n To use new GUI, please install the customtkinter python module." )
1259+         root .destroy ()
12091260
12101261def  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