From b4648d808415122e43d7f93618dd02be41606941 Mon Sep 17 00:00:00 2001 From: Christian Azinn Date: Sun, 14 Apr 2024 22:06:18 -0400 Subject: [PATCH] fix broken stuff and test implement custom scheduler --- .gitignore | 3 +- Homepage.py | 2 +- pages/Convert_Safetensors.py | 29 ++++++++---- pages/Quantize_GGUF.py | 32 ++++--------- pages/Queue_GUI.py | 10 ++++ pages/Upload_Converted_To_HF.py | 3 +- util/__pycache__/constants.cpython-310.pyc | Bin 0 -> 716 bytes util/__pycache__/find.cpython-310.pyc | Bin 1172 -> 1595 bytes util/__pycache__/key.cpython-310.pyc | Bin 0 -> 1471 bytes util/__pycache__/scheduler.cpython-310.pyc | Bin 0 -> 4454 bytes util/find.py | 52 --------------------- util/scheduler.py | 33 +++++++------ 12 files changed, 63 insertions(+), 101 deletions(-) create mode 100644 util/__pycache__/constants.cpython-310.pyc create mode 100644 util/__pycache__/key.cpython-310.pyc create mode 100644 util/__pycache__/scheduler.cpython-310.pyc delete mode 100644 util/find.py diff --git a/.gitignore b/.gitignore index fa7f0c6..766c4db 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ llama.cpp/* logs/* .vscode/* TODO.md -testing/* \ No newline at end of file +testing/* +util/*.txt \ No newline at end of file diff --git a/Homepage.py b/Homepage.py index 0e823d6..9856af7 100755 --- a/Homepage.py +++ b/Homepage.py @@ -10,7 +10,7 @@ Page("pages/Docs.py", "Docs", ":books:"), Section("Manually convert models", icon=":arrows_counterclockwise:"), Page("pages/Hugging_Face_Downloader.py", "Download model", ":inbox_tray:"), - Page("pages/Convert_Safetensors.py", "Convert Safetensors to High Precision", ":gem:"), + Page("pages/Convert_Safetensors.py", "Safetensors to GGUF", ":gem:"), Page("pages/Create_IMatrix.py", "Create Importance Matrix", ":chart_with_upwards_trend:"), Page("pages/Quantize_GGUF.py", "Quantize GGUF", ":heavy_plus_sign:" ), Page("pages/Upload_Converted_To_HF.py", "Upload model to HuggingFace", ":outbox_tray:"), diff --git a/pages/Convert_Safetensors.py b/pages/Convert_Safetensors.py index 4f639f7..fda24ed 100644 --- a/pages/Convert_Safetensors.py +++ b/pages/Convert_Safetensors.py @@ -1,12 +1,14 @@ # IMPORTS --------------------------------------------------------------------------------- import subprocess, threading, queue, streamlit as st +from pathlib import Path from apscheduler.schedulers.background import BackgroundScheduler from st_pages import add_indentation from util.constants import config -from util.find import find_llama_models_dir +from util.scheduler import * # FUNCTIONS --------------------------------------------------------------------------------- +""" # Initialize queue command_queue = queue.Queue() @@ -23,8 +25,13 @@ def process_queue(): scheduler.start() # Initialize queue and start a background thread for processing commands +""" -def run_command(model_folder, out_type): +# TODO fix this up and add a different command for each outtype +def run_command(model_folder, q): + for option in q: + if q[option]: + out_type = option.lower() base_dir = Path("llama.cpp/models") input_dir = base_dir / model_folder target_dir = input_dir / "High-Precision-Quantization" @@ -40,7 +47,10 @@ def run_command(model_folder, out_type): "--outfile", str(target_dir / output_file), "--outtype", out_type.lower() ] - print("First statement", target_dir) + return command + return f"python3 {str(convert_script_path)} {str(input_dir)} --outfile {str(target_dir / output_file)} --outtype {out_type.lower()}" + + """ try: subprocess.run(command, check=True) return "Command completed successfully." @@ -55,6 +65,7 @@ def trigger_command(model_folder, options): if options[option]: command_queue.put((model_folder, option.lower())) return "Commands queued. They will run sequentially." +""" # UI CODE --------------------------------------------------------------------------------- @@ -63,18 +74,20 @@ def trigger_command(model_folder, options): st.title("High Precision Quantization") -models_dir = Path("llama.cpp/models/") +models_dir = Path("llama.cpp/models") model_folders = [f.name for f in models_dir.iterdir() if f.is_dir()] if models_dir.exists() else ["Directory not found"] model_folder = st.selectbox("Select a Model Folder", model_folders) -options = {option: st.checkbox(label=option) for option in config['checkbox_high_options']} +options = {option: st.checkbox(label=option) for option in config['conversion_quants']} if st.button("Run Commands"): if not any(options.values()): st.error("Please select at least one quantization type before running commands.") else: - status = trigger_command(model_folder, options) - st.text(status) + # status = trigger_command(model_folder, options) + schedule = scheduler() + schedule.add_job(run_command(model_folder, options)) + # st.text(status) with st.expander("Step One: Model Conversion with High Precision", expanded=False): @@ -94,4 +107,4 @@ def trigger_command(model_folder, options): """) # Start the thread to process commands -threading.Thread(target=process_queue, daemon=True).start() +# threading.Thread(target=process_queue, daemon=True).start() diff --git a/pages/Quantize_GGUF.py b/pages/Quantize_GGUF.py index 3c17964..608bce4 100644 --- a/pages/Quantize_GGUF.py +++ b/pages/Quantize_GGUF.py @@ -4,7 +4,6 @@ from pathlib import Path from st_pages import add_indentation from util.constants import config -from util.find import find_llama_cpp_dir # FUNCTIONS --------------------------------------------------------------------------------- @@ -30,12 +29,12 @@ def schedule_quantize_task(command): except subprocess.CalledProcessError as e: return f"Error in task execution: {e}" -def trigger_command(modelpath, options, use_docker): +def trigger_command(modelpath, options): if not any(options.values()): return "Error: Please select at least one quantization option." debug_output = "" - llama_cpp_dir = find_llama_cpp_dir() + llama_cpp_dir = Path("llama.cpp") if llama_cpp_dir: base_dir = llama_cpp_dir / 'models' gguf_files = list_gguf_files(base_dir) @@ -63,22 +62,10 @@ def trigger_command(modelpath, options, use_docker): output_path = medium_precision_dir / f"{modified_model_file}-{option.upper()}.GGUF" absolute_path = os.getcwd().replace('\\', '/') - - if use_docker: - - docker_image = "luxaplexx/convert-compaan-ollama" - - output_path_in_docker = f"/models/{model_name_only}/Medium-Precision-Quantization/{modified_model_file}-{option.upper()}.GGUF" - command = [ - "docker", "run", "--rm", - "-v", f"{absolute_path}/{base_dir}:/models", - docker_image, "quantize", f"/models/{model_name_only}/High-Precision-Quantization/{model_file}", - str(output_path_in_docker), option - ] - if sys.platform == "linux": - command = [str(base_dir.parent / 'quantize'), str(source_path), str(output_path), option] - else: - command = [str(base_dir / 'quantize'), str(source_path), str(output_path), option] + # if sys.platform == "linux": + # command = [str(base_dir.parent / 'quantize'), str(source_path), str(output_path), option] + # else: + command = [str(llama_cpp_dir / 'quantize'), str(source_path), str(output_path), option] print(command) @@ -98,8 +85,7 @@ def trigger_command(modelpath, options, use_docker): gguf_files = list_gguf_files(models_dir) selected_gguf_file = st.selectbox("Select a GGUF File", gguf_files) -options = {option: st.checkbox(label=option) for option in shared['checkbox_options']} -use_docker = st.checkbox("Use Docker Container") +options = {option: st.checkbox(label=option) for option in config['quantization_I'] + config['quantization_K']} run_commands = st.button("Run Selected Commands") @@ -108,8 +94,8 @@ def trigger_command(modelpath, options, use_docker): if not any(options.values()): st.error("Please select at least one quantization type before running commands.") # Proceed only if at least one quantization type is selected or if Docker is selected with a type - elif any(options.values()) or (use_docker and any(options.values())): - status = trigger_command(selected_gguf_file, options, use_docker) + elif any(options.values()): + status = trigger_command(selected_gguf_file, options) st.text_area("Debug Output", status, height=300) else: # This should not happen, but we include it for robustness diff --git a/pages/Queue_GUI.py b/pages/Queue_GUI.py index e69de29..f2fec9e 100644 --- a/pages/Queue_GUI.py +++ b/pages/Queue_GUI.py @@ -0,0 +1,10 @@ +import streamlit as st +from st_pages import add_indentation +from util.scheduler import * + +# UI CODE --------------------------------------------------------------------------------- + +add_indentation() + +if st.button('Run'): + scheduler().toggle() \ No newline at end of file diff --git a/pages/Upload_Converted_To_HF.py b/pages/Upload_Converted_To_HF.py index 139e881..1e7daf7 100755 --- a/pages/Upload_Converted_To_HF.py +++ b/pages/Upload_Converted_To_HF.py @@ -4,13 +4,12 @@ from huggingface_hub import HfApi from requests.exceptions import HTTPError from pathlib import Path # Import pathlib -from util.find import find_llama_cpp_dir from util.key import decrypt_token # FUNCTIONS --------------------------------------------------------------------------------- # Search for the llama.cpp directory -llama_cpp_dir, models_dir = find_llama_cpp_dir() +llama_cpp_dir, models_dir = Path("llama.cpp"), Path("llama.cpp/models") if not llama_cpp_dir: st.error("llama.cpp directory not found. Please check the file structure.") diff --git a/util/__pycache__/constants.cpython-310.pyc b/util/__pycache__/constants.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e2e3e9b5f1bdde820db713526393d424a6aafb6f GIT binary patch literal 716 zcmaJ z75ov3;7K~~Xu|nU&iPKyB@Hi^O9rgTv*q4X&M+R8@pai??13Z=fWW}U&;&F!=7uKD z-{&t3Yy~DRfY=~KkTH<)`@)5ZOI^d6aPrdXY@RL|0Ku+6oa6;BO%nsSoeEJ+hA=d<&8*tblJzf0XGqcdtiQ;@U2`;$ve z)z!&IR~Bo=;@?Tj^sbCvCXS9u4FSTuC}02@)L9 zFygUzFyd8sM;e~j-H-`4aeWxe?dHUKZWGt4NHU)Xg$U>LeAElp^** zyp#9!ZQhbqlgMA7;GXpB@+4EY8y+59d`X!fBfG;q0ySnveJ=wwlM}KJGT}Nw3odkTk|`zLFRFHsk@3 z4mjncRU&yR114Kq)@}~y(dLA&^Ir3ep4wE0tocsw-0SG@1{l?z7W14(Gw9CH0io;C zD0({bw9y!~+pO_!GhlnmKBN=ae-?vC^N(SdpTJb8g6CM1OLRdOsA3$l6ZE{dz_qE= z@PxO}g4Bdl@U$jt>k`S^HL2;85QNbgdfoYt!VG13U1JOYf!_d-0X(YF7GTINn1Vf$ zy1#cVA>u3^PG&P@XYl%>ydqE!$Y>PUQisZoqG>9UC{m70%0j$Jq^s+ejPqBC+|hET zmYvC5$|SEMcyxs$)ivY@$fnZX&~>~S*=BAUbWKk<`bR#1dU*iGCmy!3Yd#N?Uq17; zGDhVgh+yXQ9K5+w;HXwv$t2E1TFE^qD@Tt~q%X~V$N+gM3@MB`3{i}!j9E-6Y$+@$tSyYqj8V)f zjKK_=>@PtY{5IzCGcu}7u45GEFUil(Db`QR%uCTLs4U{1yqIw>Bg^DOCM#tgph``~ zTWp!d@hO=_noPHt^bBq>rWAq1Aq4N_eM||mtRQtvMQlLo7JFt%Y7s~^OA!Z18Rukc zW&>`p4qgynY;qZM5E~PS$vpWSvx*VO14W`h;ucq0eraAxd_iJK2H13<5g_p*unI8{ ziyK7nPF7(tij)R2fp$U+0pr6%U)WR?_(gA_`D2#`7?2g4n5i^C>2KczG$ S)s7LUq8Q|M4h9w$0Y(782}73v diff --git a/util/__pycache__/key.cpython-310.pyc b/util/__pycache__/key.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cfb89719caa6283d8b09748d690107fe7e450e6e GIT binary patch literal 1471 zcmZ`(UyBpL!mNN6;pk!F4x%_wiT8w~B;%g5u3kg>l=xZ4DT zpD>DNAd*R*vME2~oOqFnsdwgq_oV-po%u45A?85VWP~}Cb=kmNlg$$rxBh_z7IPcE zP&!ivod5ICydKf=O(S<4+QV_%&}t|L=S!oCSlAjg1DR;sCT5(ZYA^$Yk4#e(uD)=skI;1s?1+QhG#?BNcb9L$7`6d=1Nm+wrwmdRw3F^pW@Dz}eCi2V2`;%Z6Y8%Z5_X9Q!sf`9x*b0~X82_He&b z$$?Y2D^;XPmfCxLr9Hq>L01TY{ebX4fba=^ir+2%4usF+udwSjHhqd7VChlxAvF4k z)Smu=_{ z*bTDylw}WnX8dK3v$f!C)s#UgKCnN8CIf-hj-1RH)CUWRLL)it$k zv}0=@4~dj4UX<*zE<^O%J6JRDC!>vcf4C0HVB0MHo%1OXSD$TAIj2n4PuLHv_;mpd z^;a0xs?SQX)YYnNRHz8k30ttZ+1KyN4JInmW)4w zf#L~>t7%Ul=~}3cFM0HbxNi9*Q?<0v8`q&Y`ZpA$7uWiG9O}oBz3=ipztF?k>t%QB ze!6`n(@&Eo=Pnpkg;RFBly=AOpmR0hsy2Ey&E-5*Khn=q&>ut2qaX^SS}Xhyh%Q+z literal 0 HcmV?d00001 diff --git a/util/__pycache__/scheduler.cpython-310.pyc b/util/__pycache__/scheduler.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..956ec58de225c5590383a3da59cbdbeacc61f0e6 GIT binary patch literal 4454 zcmai2TW=f36`q-0E|)8cx>&X>TTy7kO2ag^>Lg7H#Yo+_QH-Kh)5@q3p(smpRx;@& zmz`ZkHbE9aq^A~5`yK=kAN@!ABj&YFdG?!8METAvFH2fPDD0X0oSE-jN8$Xu$MEz1 zxqk516~_KYjr7k(<1W7FPau*>9}Ox+5seG7e7VDD#4>Fhgxrk<6y z%$%@ezVA}&QzjjmJz+9?EYO#e)*dUl-(hc7;@bYK53nSd)3FjYzMx2&J+zA^775CMl;@uwyL4@xBhT1Y_uxPTG-rb$F*Q9 z8ZNojdZu%uR*v=;AdXNjidPO{q4O@j=qnJP?Q_ZYh2&D4Fo0l58>KCa=BgZU6s0S3 zCw$+Lo}9y2R_5hAN>>)-0?M3RluIZ*xhyZBoRcf^BFenHBv(<+%gb^NWkFt(SLHf( zT9B{F4fHI^*8$*lmBB%(gw60r$0ykttaea|SBRZDHD3 zX`$DZ3^XTgP|wgg39L(*-A?XrZNKf`il4@v`6>Vn{MeV&+|jI*SHxMn#@kRVO=Fj7u<&l!yDwmU~6Q~h_bbfr@YTdV+{Li_%h|cLFI&pY-82B3) zib%IS?ub0M&pM0aqa{d z`tSgQ^%<-$nDv>iJ%jh3(|Z`5a(2~K+(z??=APzC^P`fZ?XcxH)dCGQ%oGh+HmnFR1WJX)Qlv0w%(s-z;rA1S~{C>=BgP;djK=!#PTD6LnZyqJaoBC`M_gpv|v zp+~Fjt~CS5_tQHNkk74MMT(_f2LT*KsuO_fI*7JfVN2aWtz;)i(aqHxM1DeKY;ck+SkV23ws_FrywKQIFxd zN1Ac&xpRkpoB;L-cn$z__>Hs9h4HyZb7r1cy+ijU1sbw7aFIfu%XXf&90Bngn)Y*$ z&gvx7(ToYkVfO#P zy7Q#c6F*}1LfwOjTVw(~Yp{a_$1!i@3hz2?8paEMkTwjsj!d7OI@0d*Bqkw7CvJeC zFuvd=FP5??b1~?@MWf^nbS8>bt%af$)Z(FYc!P$GUm%A%jaZ&A8HTz&Oo%AtChox& z9w*ycKPw2EcP>pzZn$W6WP1fo6Vc9%M-w{U1zu|ml&>)%sJufhac3wSijPTjvSvo7 zkJ8wZ)u<9K22hG9#?CbHqe;ZkxnZ!mJ+8hp+p!i9#+0fw4~=h){(_BD&h^UBxn3UQ zHo0Iz4=F#G!)H|fEl3<03hRTGIpqZEKb`ktQAb9H`~VrkzbNCg;|$u4Bu%^8mbbczaNJ#E;1M^XhBtJ)h3ll9QOcV{Z2W z9u65i0;*5cIza4fJg7uZivCl-+D1-WjM~+zA4Lc4Ab3`+#Kn%-E~?jP;@T%lg{oL< z7US^>q#N7CozArxW5olkFwmL{HIxWCnS3 zmq+i$(2%+%DPdagAss-=h893)$+Mwm8*OypDWMm2XIdLcmWX$6r!|85upU}h$NQ5q zR3mX@nnuox4}8_AHSx-niA2<|a4aKQMP9R%Gx+OVJe-%FqGg;PZV_@FJGnzKo=y5+oyP6`QFmLd%75)RDSdqg3 literal 0 HcmV?d00001 diff --git a/util/find.py b/util/find.py deleted file mode 100644 index 3efea42..0000000 --- a/util/find.py +++ /dev/null @@ -1,52 +0,0 @@ -import streamlit as st -from pathlib import Path - -# find the 'llama.cpp/models' directory -@st.cache_data -def find_llama_models_dir(start_path, max_up=4, max_down=3): - def search_upwards(path, depth): - if depth > max_up: - return None - if (path / "llama.cpp/models").exists(): - return path / "llama.cpp/models" - return search_upwards(path.parent, depth + 1) - - @st.cache_data - def search_downwards(path, depth): - if depth > max_down: - return None - if (path / "llama.cpp/models").exists(): - return path / "llama.cpp/models" - for child in [d for d in path.iterdir() if d.is_dir()]: - found = search_downwards(child, depth + 1) - if found: - return found - return None - - # Search upwards - found_path = search_upwards(start_path, 4) - if found_path: - return found_path # Return the found 'llama.cpp/models' directory - - # Search downwards - return search_downwards(start_path, 3) - -# find the 'llama.cpp' directory -@st.cache_data -def find_llama_cpp_dir(): - # Search for llama.cpp directory two levels up - current_dir = Path(__file__).resolve().parent - for _ in range(2): - current_dir = current_dir.parent - llama_cpp_dir = current_dir / 'llama.cpp' - if llama_cpp_dir.is_dir(): - return llama_cpp_dir - - # If not found, search two levels down - current_dir = Path(__file__).resolve().parent - for _ in range(2): - current_dir = current_dir / 'llama.cpp' - if current_dir.is_dir(): - return current_dir - - return None \ No newline at end of file diff --git a/util/scheduler.py b/util/scheduler.py index b9e7686..1c204c3 100644 --- a/util/scheduler.py +++ b/util/scheduler.py @@ -1,7 +1,7 @@ # IMPORTS --------------------------------------------------------------------------------- from pathlib import Path from datetime import datetime -import subprocess, streamlit as st +import subprocess, streamlit as st, os # FUNCTIONS --------------------------------------------------------------------------------- @@ -10,19 +10,21 @@ def scheduler(): return Scheduler() +# TODO commands are actually lists of strings so you may need to refactor to handle that + # the scheduler singleton class (do i need st.cache_resource here?) @st.cache_resource class Scheduler: # constructor: set up basic attributes def __init__(self): - path = Path(__file__) - self.queuePath = path + "/queue.txt" - self.outPath = path + "/completed.txt" - self.active = True + thispath = Path(__file__).parent + self.queuePath = os.path.join(thispath, "queue.txt") + self.outPath = os.path.join(thispath, "completed.txt") + self.active = False self.job = None self.command = "" - self.mostRecentError = "" + self.lastLog = "" # toggle active status (i.e. pause/unpause) def toggle(self): @@ -36,7 +38,7 @@ def add_job(self, job, position=-1): # the simple one if position == -1: with open(self.queuePath, "a") as f: - f.write(job + "\n") + f.write(''.join(job + ["\n"])) # the slightly less simple one else: with open(self.queuePath, "r") as f: @@ -46,7 +48,7 @@ def add_job(self, job, position=-1): f.writelines(lines) # remove a job from the queue - def remove_job(self, job, position=-1): + def remove_job(self, position=-1): with open(self.queuePath, "r") as f: lines = f.readlines() lines.pop(position) @@ -74,8 +76,8 @@ def get_completed(self): return f.readlines() # return the most recent error - def get_error(self): - return self.mostRecentError + def get_log(self): + return self.log # pop the next job in the queue def get_next_job(self): @@ -85,7 +87,7 @@ def get_next_job(self): job = lines.pop(0) with open(self.queuePath, "w") as f: f.writelines(lines) - return job + return job.strip().split(" ") return None # switch the jobs at index posiiton1 and position2 @@ -105,14 +107,16 @@ def run_next_job(self): self.job = subprocess.run(self.command, check=True) # log the job as completed if it works with open(self.outPath, "a") as f: - f.write(f"Task executed successfully at {self.time()}: {self.command}\n") + self.log = f"Task executed successfully at {self.time()}: {self.command}\n" + f.write(self.log) # log errors except subprocess.CalledProcessError as e: self.mostRecentError = f"Error in task execution: {e}" self.active = False # log the job as failed with open(self.outPath, "a") as f: - f.write(f"Error in task execution for task {self.command} at {self.time()}: {e}\n") + self.log = f"Error in task execution for task {self.command} at {self.time()}: {e}\n" + f.write(self.log) # automatically loop through the jobs while active but only while there are jobs # else you're wasting compute @@ -128,7 +132,8 @@ def terminate(self, requeue=False): # log the job as terminated if not requeue if not requeue: with open(self.outPath, "a") as f: - f.write(f"Terminated task {self.command} at {self.time()}\n") + self.log = f"Terminated task {self.command} at {self.time()}\n" + f.write(self.log) # if requeue, add the job back to the queue else: self.add_job(self.command, 0)