1+ import sys
2+ import subprocess
3+ import importlib
4+ import os
5+
6+ def install (package ):
7+ subprocess .check_call ([sys .executable , "-m" , "pip" , "install" , "-r" , "requirements.txt" ])
8+
9+ try :
10+ import torch , tqdm , safetensors , gguf , sentencepiece , yaml , numpy
11+ except ImportError :
12+ print ("Some required packages are missing. Installing from requirements.txt..." )
13+ install ("requirements.txt" )
14+ import torch , tqdm , safetensors , gguf , sentencepiece , yaml , numpy
15+
116import tkinter as tk
217from tkinter import filedialog , ttk , messagebox
3- import sys
418import os
5- import subprocess
619import shutil
720import winsound
821import tkinter .scrolledtext as scrolledtext
9- import importlib .util
10-
11- def resource_path (relative_path ):
12- """ Get absolute path to resource, works for dev and for PyInstaller """
13- try :
14- # PyInstaller creates a temp folder and stores path in _MEIPASS
15- base_path = sys ._MEIPASS
16- except Exception :
17- base_path = os .path .abspath ("." )
18-
19- return os .path .join (base_path , relative_path )
2022
2123def scroll_entry_to_end (entry ):
2224 entry .xview_moveto (1 )
2325
2426def browse_file (entry ):
2527 file_path = filedialog .askopenfilename (filetypes = [("Model files" , "*.safetensors *.sft" )])
2628 if file_path :
29+ file_path = file_path .replace ('\\ ' , '/' ) # Ensure forward slashes
2730 entry .delete (0 , tk .END )
2831 entry .insert (0 , file_path )
2932 scroll_entry_to_end (entry )
30- update_output_filename ()
33+ suggest_output_file () # Call this instead of update_output_file
3134
32- def browse_output_file (entry ):
33- file_path = filedialog .asksaveasfilename (defaultextension = ".gguf" ,
34- filetypes = [("GGUF files" , "*.gguf" )])
35- if file_path :
36- entry .delete (0 , tk .END )
37- entry .insert (0 , file_path )
38- scroll_entry_to_end (entry )
39-
40- def update_output_filename (* args ):
35+ def suggest_output_file ():
4136 input_file = input_entry .get ()
4237 quantize_level = quantize_level_var .get ()
4338 if input_file :
4439 input_dir = os .path .dirname (input_file )
45- base_name = os .path .splitext (os .path .basename (input_file ))[0 ]
46- output_file = os .path .join (input_dir , f"{ base_name } -{ quantize_level } .gguf" )
47- if '/' in input_file :
48- output_file = output_file .replace ('\\ ' , '/' )
49- elif '\\ ' in input_file :
50- output_file = output_file .replace ('/' , '\\ ' )
40+ input_filename = os .path .basename (input_file )
41+ input_name , _ = os .path .splitext (input_filename )
42+ output_file = f"{ input_dir } /{ input_name } -{ quantize_level } .gguf"
5143 output_entry .delete (0 , tk .END )
5244 output_entry .insert (0 , output_file )
5345 scroll_entry_to_end (output_entry )
5446
47+ def browse_output_file (entry ):
48+ # Get the current input file and quantization level
49+ input_file = input_entry .get ()
50+ quantize_level = quantize_level_var .get ()
51+
52+ # Generate a default output filename
53+ if input_file :
54+ input_dir = os .path .dirname (input_file )
55+ input_filename = os .path .basename (input_file )
56+ input_name , _ = os .path .splitext (input_filename )
57+ default_filename = f"{ input_name } -{ quantize_level } .gguf"
58+ else :
59+ default_filename = f"output-{ quantize_level } .gguf"
60+ input_dir = "/"
61+
62+ # Open the file dialog with the default filename
63+ file_path = filedialog .asksaveasfilename (
64+ initialdir = input_dir ,
65+ initialfile = default_filename ,
66+ defaultextension = ".gguf" ,
67+ filetypes = [("GGUF files" , "*.gguf" )]
68+ )
69+
70+ if file_path :
71+ file_path = file_path .replace ('\\ ' , '/' ) # Ensure forward slashes
72+ entry .delete (0 , tk .END )
73+ entry .insert (0 , file_path )
74+ scroll_entry_to_end (entry )
75+
5576def disable_ui ():
77+ global input_entry , output_entry , input_browse , output_browse , quantize_dropdown , run_button
5678 input_entry .config (state = 'disabled' )
5779 output_entry .config (state = 'disabled' )
5880 input_browse .config (state = 'disabled' )
@@ -61,6 +83,7 @@ def disable_ui():
6183 run_button .config (state = 'disabled' )
6284
6385def enable_ui ():
86+ global input_entry , output_entry , input_browse , output_browse , quantize_dropdown , run_button
6487 input_entry .config (state = 'normal' )
6588 output_entry .config (state = 'normal' )
6689 input_browse .config (state = 'normal' )
@@ -173,109 +196,85 @@ def run_llama_quantize():
173196 # Play sound effect
174197 winsound .PlaySound ("SystemAsterisk" , winsound .SND_ALIAS )
175198
176- def setup_environment ():
177- process_text . insert ( tk . END , "Checking environment... \n " )
178- root . update ()
179-
180- # List of required packages (added 'sentencepiece' )
181- required_packages = [ 'torch' , 'tqdm' , 'safetensors' , 'gguf' , 'sentencepiece' ]
199+ def main ():
200+ global root , process_text , input_entry , output_entry , quantize_dropdown , run_button , quantize_level_var
201+ global input_browse , output_browse # Add these two variables
202+ root = tk . Tk ()
203+ root . title ( "Easy Quantization GUI" )
204+ root . geometry ( "800x600" )
182205
183- for package in required_packages :
184- try :
185- __import__ (package )
186- process_text .insert (tk .END , f"{ package } is already installed.\n " )
187- except ImportError :
188- process_text .insert (tk .END , f"Installing { package } ...\n " )
189- root .update ()
190- try :
191- subprocess .check_call ([sys .executable , "-m" , "pip" , "install" , package ])
192- process_text .insert (tk .END , f"Successfully installed { package } .\n " )
193- except subprocess .CalledProcessError as e :
194- process_text .insert (tk .END , f"Error installing { package } : { e } \n " )
195- return False
196-
197- process_text .insert (tk .END , "Environment check completed. All dependencies are in place.\n " )
198- root .update ()
199- return True
200-
201- root = tk .Tk ()
202- root .title ("Easy Quantization GUI" )
203- root .geometry ("800x600" ) # Enlarge the main window
204-
205- # Quantize level selection
206- quantize_frame = tk .Frame (root )
207- quantize_frame .pack (pady = 10 , padx = 10 )
206+ # Quantize level selection
207+ quantize_frame = tk .Frame (root )
208+ quantize_frame .pack (pady = 10 , padx = 10 )
208209
209- quantize_label = tk .Label (quantize_frame , text = "Quantize Level:" )
210- quantize_label .pack (side = tk .LEFT )
210+ quantize_label = tk .Label (quantize_frame , text = "Quantize Level:" )
211+ quantize_label .pack (side = tk .LEFT )
211212
212- quantize_levels = ["Q2_K" , "Q3_K_S" , "Q4_0" , "Q4_1" , "Q4_K_S" , "Q5_0" , "Q5_1" , "Q5_K_S" , "Q6_K" , "Q8_0" ]
213- quantize_level_var = tk .StringVar (root )
214- quantize_level_var .set ("Q8_0" ) # Set default value to Q8_0
213+ quantize_levels = ["Q2_K" , "Q3_K_S" , "Q4_0" , "Q4_1" , "Q4_K_S" , "Q5_0" , "Q5_1" , "Q5_K_S" , "Q6_K" , "Q8_0" ]
214+ quantize_level_var = tk .StringVar (root )
215+ quantize_level_var .set ("Q8_0" ) # Set default value to Q8_0
215216
216- quantize_dropdown = ttk .Combobox (quantize_frame , textvariable = quantize_level_var , values = quantize_levels , state = "readonly" )
217- quantize_dropdown .pack (side = tk .LEFT )
218- quantize_dropdown .bind ("<<ComboboxSelected>>" , lambda event : scroll_entry_to_end ( output_entry ))
217+ quantize_dropdown = ttk .Combobox (quantize_frame , textvariable = quantize_level_var , values = quantize_levels , state = "readonly" )
218+ quantize_dropdown .pack (side = tk .LEFT )
219+ quantize_dropdown .bind ("<<ComboboxSelected>>" , lambda event : suggest_output_file ( ))
219220
220- # Input file selection
221- input_frame = tk .Frame (root )
222- input_frame .pack (pady = 10 , padx = 10 , fill = tk .X )
221+ # Input file selection
222+ input_frame = tk .Frame (root )
223+ input_frame .pack (pady = 10 , padx = 10 , fill = tk .X )
223224
224- input_label = tk .Label (input_frame , text = "Input File:" )
225- input_label .pack (side = tk .LEFT )
225+ input_label = tk .Label (input_frame , text = "Input File:" )
226+ input_label .pack (side = tk .LEFT )
226227
227- input_entry = tk .Entry (input_frame )
228- input_entry .pack (side = tk .LEFT , expand = True , fill = tk .X )
228+ input_entry = tk .Entry (input_frame )
229+ input_entry .pack (side = tk .LEFT , expand = True , fill = tk .X )
229230
230- input_browse = tk .Button (input_frame , text = "Browse" , command = lambda : browse_file (input_entry ))
231- input_browse .pack (side = tk .RIGHT )
231+ input_browse = tk .Button (input_frame , text = "Browse" , command = lambda : browse_file (input_entry ))
232+ input_browse .pack (side = tk .RIGHT )
232233
233- # Add binding to scroll input entry when it gains focus
234- input_entry .bind ("<FocusIn>" , lambda event : scroll_entry_to_end (input_entry ))
234+ # Add binding to scroll input entry when it gains focus
235+ input_entry .bind ("<FocusIn>" , lambda event : scroll_entry_to_end (input_entry ))
235236
236- # Output file selection
237- output_frame = tk .Frame (root )
238- output_frame .pack (pady = 10 , padx = 10 , fill = tk .X )
237+ # Output file selection
238+ output_frame = tk .Frame (root )
239+ output_frame .pack (pady = 10 , padx = 10 , fill = tk .X )
239240
240- output_label = tk .Label (output_frame , text = "Output File:" )
241- output_label .pack (side = tk .LEFT )
241+ output_label = tk .Label (output_frame , text = "Output File:" )
242+ output_label .pack (side = tk .LEFT )
242243
243- output_entry = tk .Entry (output_frame )
244- output_entry .pack (side = tk .LEFT , expand = True , fill = tk .X )
244+ output_entry = tk .Entry (output_frame )
245+ output_entry .pack (side = tk .LEFT , expand = True , fill = tk .X )
245246
246- output_browse = tk .Button (output_frame , text = "Browse" , command = lambda : browse_output_file (output_entry ))
247- output_browse .pack (side = tk .RIGHT )
247+ output_browse = tk .Button (output_frame , text = "Browse" , command = lambda : browse_output_file (output_entry ))
248+ output_browse .pack (side = tk .RIGHT )
248249
249- # Add binding to scroll output entry when it gains focus
250- output_entry .bind ("<FocusIn>" , lambda event : scroll_entry_to_end (output_entry ))
250+ # Add binding to scroll output entry when it gains focus
251+ output_entry .bind ("<FocusIn>" , lambda event : scroll_entry_to_end (output_entry ))
251252
252- # Run button
253- run_button = tk .Button (root , text = "Run Quantization" , command = run_llama_quantize )
254- run_button .pack (pady = 20 )
253+ # Run button
254+ run_button = tk .Button (root , text = "Run Quantization" , command = run_llama_quantize )
255+ run_button .pack (pady = 20 )
255256
256- # Add process log to bottom of main window
257- process_frame = tk .Frame (root )
258- process_frame .pack (pady = 10 , padx = 10 , fill = tk .BOTH , expand = True )
257+ # Add process log to bottom of main window
258+ process_frame = tk .Frame (root )
259+ process_frame .pack (pady = 10 , padx = 10 , fill = tk .BOTH , expand = True )
259260
260- process_label = tk .Label (process_frame , text = "Process Log:" )
261- process_label .pack (side = tk .TOP , anchor = 'w' )
261+ process_label = tk .Label (process_frame , text = "Process Log:" )
262+ process_label .pack (side = tk .TOP , anchor = 'w' )
262263
263- process_text = scrolledtext .ScrolledText (process_frame , wrap = tk .WORD , height = 15 )
264- process_text .pack (expand = True , fill = tk .BOTH )
264+ process_text = scrolledtext .ScrolledText (process_frame , wrap = tk .WORD , height = 15 )
265+ process_text .pack (expand = True , fill = tk .BOTH )
265266
266- # Setup environment before creating other UI elements
267- if not setup_environment ():
268- messagebox .showerror ("Setup Error" , "Failed to set up the environment. Please check the process log for details." )
269- root .quit ()
267+ root .mainloop ()
270268
271- # Bind events to update output filename
272- input_entry . bind ( "<KeyRelease>" , update_output_filename )
273- quantize_level_var . trace_add ( "write" , update_output_filename )
274-
275- def on_window_resize ( event ):
276- scroll_entry_to_end ( input_entry )
277- scroll_entry_to_end ( output_entry )
269+ def resource_path ( relative_path ):
270+ """ Get absolute path to resource, works for dev and for PyInstaller """
271+ try :
272+ # PyInstaller creates a temp folder and stores path in _MEIPASS
273+ base_path = sys . _MEIPASS
274+ except Exception :
275+ base_path = os . path . abspath ( "." )
278276
279- root . bind ( "<Configure>" , on_window_resize )
277+ return os . path . join ( base_path , relative_path )
280278
281- root .mainloop ()
279+ if __name__ == "__main__" :
280+ main ()
0 commit comments