Anthonyg5005 commited on
Commit
bb75186
1 Parent(s): 2425168

Local windows exl2 quant

Browse files

These are the files I personally use for myself but I guess I'll just release them while I work on the multi-quant script. All I did was modify existing scripts to make it work with a venv

README.md CHANGED
@@ -16,7 +16,9 @@ Feel free to send in PRs or use this code however you'd like.\
16
 
17
  - [Manage branches (create/delete)](https://huggingface.co/Anthonyg5005/hf-scripts/blob/main/manage%20branches.py)
18
 
19
- - [EXL2 Private Quant V3](https://colab.research.google.com/drive/1Vc7d6JU3Z35OVHmtuMuhT830THJnzNfS?usp=sharing) **(COLAB)**
 
 
20
 
21
  - [Upload folder to repo](https://huggingface.co/Anthonyg5005/hf-scripts/blob/main/upload%20folder%20to%20repo.py)
22
 
@@ -38,8 +40,11 @@ Feel free to send in PRs or use this code however you'd like.\
38
  - Manage branches
39
  - Run script and follow prompts. You will be required to be logged in to HF Hub. If you are not logged in, you will need a WRITE token. You can get one in your [HuggingFace settings](https://huggingface.co/settings/tokens). May get some updates in the future for handling more situations. All active updates will be on the [unfinished](https://huggingface.co/Anthonyg5005/hf-scripts/tree/unfinished) branch. Colab and Kaggle keys are supported.
40
 
41
- - EXL2 Private Quant
42
- - Allows you to quantize to exl2 using colab. This version creates a exl2 quant to upload to private repo. Should work on any Linux jupyterlab server with CUDA, ROCM should be supported by exl2 but not tested.
 
 
 
43
 
44
  - Upload folder to repo
45
  - Uploads user specified folder to specified repo, can create private repos too. Not the same as git commit and push, instead uploads any additional files.
 
16
 
17
  - [Manage branches (create/delete)](https://huggingface.co/Anthonyg5005/hf-scripts/blob/main/manage%20branches.py)
18
 
19
+ - [EXL2 Single Quant V3](https://colab.research.google.com/drive/1Vc7d6JU3Z35OVHmtuMuhT830THJnzNfS?usp=sharing) **(COLAB)**
20
+
21
+ - [EXL2 Local Quant Windows](https://huggingface.co/Anthonyg5005/hf-scripts/resolve/main/exl2-windows-local/exl2-windows-local.zip?download=true)
22
 
23
  - [Upload folder to repo](https://huggingface.co/Anthonyg5005/hf-scripts/blob/main/upload%20folder%20to%20repo.py)
24
 
 
40
  - Manage branches
41
  - Run script and follow prompts. You will be required to be logged in to HF Hub. If you are not logged in, you will need a WRITE token. You can get one in your [HuggingFace settings](https://huggingface.co/settings/tokens). May get some updates in the future for handling more situations. All active updates will be on the [unfinished](https://huggingface.co/Anthonyg5005/hf-scripts/tree/unfinished) branch. Colab and Kaggle keys are supported.
42
 
43
+ - EXL2 Single Quant
44
+ - Allows you to quantize to exl2 using colab. This version creates a exl2 quant to upload to private repo. Should work on any Linux jupyterlab server with CUDA, ROCM should be supported by exl2 but not tested. Only 7B tested on colab.
45
+
46
+ - EXL2 Local Quant Windows
47
+ - Easily creates environment to quantize models to exl2 using Windows to your local machine.
48
 
49
  - Upload folder to repo
50
  - Uploads user specified folder to specified repo, can create private repos too. Not the same as git commit and push, instead uploads any additional files.
exl2-windows-local/convert-model-auto.bat ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ set /p "model=Folder name: "
2
+ set /p "bpw=Target BPW: "
3
+ mkdir %model%-exl2-%bpw%bpw
4
+ mkdir %model%-exl2-%bpw%bpw-WD
5
+ copy %model%\config.json %model%-exl2-%bpw%bpw-WD
6
+ venv\scripts\python.exe convert.py -i %model% -o %model%-exl2-%bpw%bpw-WD -cf %model%-exl2-%bpw%bpw -b %bpw%
exl2-windows-local/download multiple models.ps1 ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Prompt user for the number of models to download
2
+ $numberOfModels = Read-Host "Enter the number of models to download"
3
+
4
+ # Initialize an array to store model repos
5
+ $modelRepos = @()
6
+
7
+ # Loop to collect model repos
8
+ for ($i = 1; $i -le $numberOfModels; $i++) {
9
+ $modelRepo = Read-Host "Enter Model Repo $i"
10
+ $modelRepos += $modelRepo
11
+ }
12
+
13
+ # Function to download a model in a new PowerShell window
14
+ function Get-Model {
15
+ param (
16
+ [string]$modelRepo
17
+ )
18
+
19
+ # Start a new PowerShell window and execute the download-model.py script
20
+ Start-Process powershell -ArgumentList "-NoProfile -ExecutionPolicy Bypass -Command .\venv\Scripts\activate.ps1; python.exe download-model.py $modelRepo" -NoNewWindow
21
+ }
22
+
23
+ # Loop through each model repo and download in a new PowerShell window
24
+ foreach ($repo in $modelRepos) {
25
+ Get-Model -modelRepo $repo
26
+ }
27
+
28
+ Write-Host "Downloads initiated for $numberOfModels models. Check the progress in the new PowerShell windows."
exl2-windows-local/download-model.py ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Downloads models from Hugging Face to models/username_modelname.
3
+
4
+ Example:
5
+ python download-model.py facebook/opt-1.3b
6
+
7
+ '''
8
+
9
+ import argparse
10
+ import base64
11
+ import datetime
12
+ import hashlib
13
+ import json
14
+ import os
15
+ import re
16
+ import sys
17
+ from pathlib import Path
18
+
19
+ import requests
20
+ import tqdm
21
+ from requests.adapters import HTTPAdapter
22
+ from tqdm.contrib.concurrent import thread_map
23
+ from huggingface_hub import get_token
24
+
25
+ base = "https://huggingface.co"
26
+
27
+
28
+ class ModelDownloader:
29
+ def __init__(self, max_retries=5):
30
+ self.max_retries = max_retries
31
+
32
+ def get_session(self):
33
+ session = requests.Session()
34
+ if self.max_retries:
35
+ session.mount('https://cdn-lfs.huggingface.co', HTTPAdapter(max_retries=self.max_retries))
36
+ session.mount('https://huggingface.co', HTTPAdapter(max_retries=self.max_retries))
37
+
38
+ if os.getenv('HF_USER') is not None and os.getenv('HF_PASS') is not None:
39
+ session.auth = (os.getenv('HF_USER'), os.getenv('HF_PASS'))
40
+
41
+ try:
42
+ from huggingface_hub import get_token
43
+ token = get_token()
44
+ except ImportError:
45
+ token = os.getenv("HF_TOKEN")
46
+
47
+ if token is not None:
48
+ session.headers = {'authorization': f'Bearer {token}'}
49
+
50
+ return session
51
+
52
+ def sanitize_model_and_branch_names(self, model, branch):
53
+ if model[-1] == '/':
54
+ model = model[:-1]
55
+
56
+ if model.startswith(base + '/'):
57
+ model = model[len(base) + 1:]
58
+
59
+ model_parts = model.split(":")
60
+ model = model_parts[0] if len(model_parts) > 0 else model
61
+ branch = model_parts[1] if len(model_parts) > 1 else branch
62
+
63
+ if branch is None:
64
+ branch = "main"
65
+ else:
66
+ pattern = re.compile(r"^[a-zA-Z0-9._-]+$")
67
+ if not pattern.match(branch):
68
+ raise ValueError(
69
+ "Invalid branch name. Only alphanumeric characters, period, underscore and dash are allowed.")
70
+
71
+ return model, branch
72
+
73
+ def get_download_links_from_huggingface(self, model, branch, text_only=False, specific_file=None):
74
+ session = self.get_session()
75
+ page = f"/api/models/{model}/tree/{branch}"
76
+ cursor = b""
77
+
78
+ links = []
79
+ sha256 = []
80
+ classifications = []
81
+ has_pytorch = False
82
+ has_pt = False
83
+ has_gguf = False
84
+ has_safetensors = False
85
+ is_lora = False
86
+ while True:
87
+ url = f"{base}{page}" + (f"?cursor={cursor.decode()}" if cursor else "")
88
+ r = session.get(url, timeout=10)
89
+ r.raise_for_status()
90
+ content = r.content
91
+
92
+ dict = json.loads(content)
93
+ if len(dict) == 0:
94
+ break
95
+
96
+ for i in range(len(dict)):
97
+ fname = dict[i]['path']
98
+ if specific_file not in [None, ''] and fname != specific_file:
99
+ continue
100
+
101
+ if not is_lora and fname.endswith(('adapter_config.json', 'adapter_model.bin')):
102
+ is_lora = True
103
+
104
+ is_pytorch = re.match(r"(pytorch|adapter|gptq)_model.*\.bin", fname)
105
+ is_safetensors = re.match(r".*\.safetensors", fname)
106
+ is_pt = re.match(r".*\.pt", fname)
107
+ is_gguf = re.match(r'.*\.gguf', fname)
108
+ is_tiktoken = re.match(r".*\.tiktoken", fname)
109
+ is_tokenizer = re.match(r"(tokenizer|ice|spiece).*\.model", fname) or is_tiktoken
110
+ is_text = re.match(r".*\.(txt|json|py|md)", fname) or is_tokenizer
111
+ if any((is_pytorch, is_safetensors, is_pt, is_gguf, is_tokenizer, is_text)):
112
+ if 'lfs' in dict[i]:
113
+ sha256.append([fname, dict[i]['lfs']['oid']])
114
+
115
+ if is_text:
116
+ links.append(f"https://huggingface.co/{model}/resolve/{branch}/{fname}")
117
+ classifications.append('text')
118
+ continue
119
+
120
+ if not text_only:
121
+ links.append(f"https://huggingface.co/{model}/resolve/{branch}/{fname}")
122
+ if is_safetensors:
123
+ has_safetensors = True
124
+ classifications.append('safetensors')
125
+ elif is_pytorch:
126
+ has_pytorch = True
127
+ classifications.append('pytorch')
128
+ elif is_pt:
129
+ has_pt = True
130
+ classifications.append('pt')
131
+ elif is_gguf:
132
+ has_gguf = True
133
+ classifications.append('gguf')
134
+
135
+ cursor = base64.b64encode(f'{{"file_name":"{dict[-1]["path"]}"}}'.encode()) + b':50'
136
+ cursor = base64.b64encode(cursor)
137
+ cursor = cursor.replace(b'=', b'%3D')
138
+
139
+ # If both pytorch and safetensors are available, download safetensors only
140
+ if (has_pytorch or has_pt) and has_safetensors:
141
+ for i in range(len(classifications) - 1, -1, -1):
142
+ if classifications[i] in ['pytorch', 'pt']:
143
+ links.pop(i)
144
+
145
+ # For GGUF, try to download only the Q4_K_M if no specific file is specified.
146
+ # If not present, exclude all GGUFs, as that's likely a repository with both
147
+ # GGUF and fp16 files.
148
+ if has_gguf and specific_file is None:
149
+ has_q4km = False
150
+ for i in range(len(classifications) - 1, -1, -1):
151
+ if 'q4_k_m' in links[i].lower():
152
+ has_q4km = True
153
+
154
+ if has_q4km:
155
+ for i in range(len(classifications) - 1, -1, -1):
156
+ if 'q4_k_m' not in links[i].lower():
157
+ links.pop(i)
158
+ else:
159
+ for i in range(len(classifications) - 1, -1, -1):
160
+ if links[i].lower().endswith('.gguf'):
161
+ links.pop(i)
162
+
163
+ is_llamacpp = has_gguf and specific_file is not None
164
+ return links, sha256, is_lora, is_llamacpp
165
+
166
+ def get_output_folder(self, model, branch, is_lora, is_llamacpp=False):
167
+ base_folder = '.' if not is_lora else 'loras'
168
+
169
+ # If the model is of type GGUF, save directly in the base_folder
170
+ if is_llamacpp:
171
+ return Path(base_folder)
172
+
173
+ output_folder = f"{'_'.join(model.split('/')[-2:])}"
174
+ if branch != 'main':
175
+ output_folder += f'_{branch}'
176
+
177
+ output_folder = Path(base_folder) / output_folder
178
+ return output_folder
179
+
180
+ def get_single_file(self, url, output_folder, start_from_scratch=False):
181
+ session = self.get_session()
182
+ filename = Path(url.rsplit('/', 1)[1])
183
+ output_path = output_folder / filename
184
+ headers = {}
185
+ mode = 'wb'
186
+ if output_path.exists() and not start_from_scratch:
187
+
188
+ # Check if the file has already been downloaded completely
189
+ r = session.get(url, stream=True, timeout=10)
190
+ total_size = int(r.headers.get('content-length', 0))
191
+ if output_path.stat().st_size >= total_size:
192
+ return
193
+
194
+ # Otherwise, resume the download from where it left off
195
+ headers = {'Range': f'bytes={output_path.stat().st_size}-'}
196
+ mode = 'ab'
197
+
198
+ with session.get(url, stream=True, headers=headers, timeout=10) as r:
199
+ r.raise_for_status() # Do not continue the download if the request was unsuccessful
200
+ total_size = int(r.headers.get('content-length', 0))
201
+ block_size = 1024 * 1024 # 1MB
202
+
203
+ tqdm_kwargs = {
204
+ 'total': total_size,
205
+ 'unit': 'iB',
206
+ 'unit_scale': True,
207
+ 'bar_format': '{l_bar}{bar}| {n_fmt:6}/{total_fmt:6} {rate_fmt:6}'
208
+ }
209
+
210
+ if 'COLAB_GPU' in os.environ:
211
+ tqdm_kwargs.update({
212
+ 'position': 0,
213
+ 'leave': True
214
+ })
215
+
216
+ with open(output_path, mode) as f:
217
+ with tqdm.tqdm(**tqdm_kwargs) as t:
218
+ count = 0
219
+ for data in r.iter_content(block_size):
220
+ t.update(len(data))
221
+ f.write(data)
222
+ if total_size != 0 and self.progress_bar is not None:
223
+ count += len(data)
224
+ self.progress_bar(float(count) / float(total_size), f"{filename}")
225
+
226
+ def start_download_threads(self, file_list, output_folder, start_from_scratch=False, threads=4):
227
+ thread_map(lambda url: self.get_single_file(url, output_folder, start_from_scratch=start_from_scratch), file_list, max_workers=threads, disable=True)
228
+
229
+ def download_model_files(self, model, branch, links, sha256, output_folder, progress_bar=None, start_from_scratch=False, threads=4, specific_file=None, is_llamacpp=False):
230
+ self.progress_bar = progress_bar
231
+
232
+ # Create the folder and writing the metadata
233
+ output_folder.mkdir(parents=True, exist_ok=True)
234
+
235
+ if not is_llamacpp:
236
+ metadata = f'url: https://huggingface.co/{model}\n' \
237
+ f'branch: {branch}\n' \
238
+ f'download date: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}\n'
239
+
240
+ sha256_str = '\n'.join([f' {item[1]} {item[0]}' for item in sha256])
241
+ if sha256_str:
242
+ metadata += f'sha256sum:\n{sha256_str}'
243
+
244
+ metadata += '\n'
245
+ (output_folder / 'huggingface-metadata.txt').write_text(metadata)
246
+
247
+ if specific_file:
248
+ print(f"Downloading {specific_file} to {output_folder}")
249
+ else:
250
+ print(f"Downloading the model to {output_folder}")
251
+
252
+ self.start_download_threads(links, output_folder, start_from_scratch=start_from_scratch, threads=threads)
253
+
254
+ def check_model_files(self, model, branch, links, sha256, output_folder):
255
+ # Validate the checksums
256
+ validated = True
257
+ for i in range(len(sha256)):
258
+ fpath = (output_folder / sha256[i][0])
259
+
260
+ if not fpath.exists():
261
+ print(f"The following file is missing: {fpath}")
262
+ validated = False
263
+ continue
264
+
265
+ with open(output_folder / sha256[i][0], "rb") as f:
266
+ file_hash = hashlib.file_digest(f, "sha256").hexdigest()
267
+ if file_hash != sha256[i][1]:
268
+ print(f'Checksum failed: {sha256[i][0]} {sha256[i][1]}')
269
+ validated = False
270
+ else:
271
+ print(f'Checksum validated: {sha256[i][0]} {sha256[i][1]}')
272
+
273
+ if validated:
274
+ print('[+] Validated checksums of all model files!')
275
+ else:
276
+ print('[-] Invalid checksums. Rerun download-model.py with the --clean flag.')
277
+
278
+
279
+ if __name__ == '__main__':
280
+
281
+ parser = argparse.ArgumentParser()
282
+ parser.add_argument('MODEL', type=str, default=None, nargs='?')
283
+ parser.add_argument('--branch', type=str, default='main', help='Name of the Git branch to download from.')
284
+ parser.add_argument('--threads', type=int, default=4, help='Number of files to download simultaneously.')
285
+ parser.add_argument('--text-only', action='store_true', help='Only download text files (txt/json).')
286
+ parser.add_argument('--specific-file', type=str, default=None, help='Name of the specific file to download (if not provided, downloads all).')
287
+ parser.add_argument('--output', type=str, default=None, help='The folder where the model should be saved.')
288
+ parser.add_argument('--clean', action='store_true', help='Does not resume the previous download.')
289
+ parser.add_argument('--check', action='store_true', help='Validates the checksums of model files.')
290
+ parser.add_argument('--max-retries', type=int, default=5, help='Max retries count when get error in download time.')
291
+ args = parser.parse_args()
292
+
293
+ branch = args.branch
294
+ model = args.MODEL
295
+ specific_file = args.specific_file
296
+
297
+ if model is None:
298
+ print("Error: Please specify the model you'd like to download (e.g. 'python download-model.py facebook/opt-1.3b').")
299
+ sys.exit()
300
+
301
+ downloader = ModelDownloader(max_retries=args.max_retries)
302
+ # Clean up the model/branch names
303
+ try:
304
+ model, branch = downloader.sanitize_model_and_branch_names(model, branch)
305
+ except ValueError as err_branch:
306
+ print(f"Error: {err_branch}")
307
+ sys.exit()
308
+
309
+ # Get the download links from Hugging Face
310
+ links, sha256, is_lora, is_llamacpp = downloader.get_download_links_from_huggingface(model, branch, text_only=args.text_only, specific_file=specific_file)
311
+
312
+ # Get the output folder
313
+ if args.output:
314
+ output_folder = Path(args.output)
315
+ else:
316
+ output_folder = downloader.get_output_folder(model, branch, is_lora, is_llamacpp=is_llamacpp)
317
+
318
+ if args.check:
319
+ # Check previously downloaded files
320
+ downloader.check_model_files(model, branch, links, sha256, output_folder)
321
+ else:
322
+ # Download files
323
+ downloader.download_model_files(model, branch, links, sha256, output_folder, specific_file=specific_file, threads=args.threads, is_llamacpp=is_llamacpp)
exl2-windows-local/exl2-windows-local.zip ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4bf9e29ba5ce1e3d287652ea6ebe31c028a46549af6f127f5314ad83a2d0489a
3
+ size 6319
exl2-windows-local/files here soon DELETED
@@ -1 +0,0 @@
1
-
 
 
exl2-windows-local/instructions.txt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ install the CUDA toolkit
2
+
3
+ Nvidia Maxwell or higher
4
+ https://developer.nvidia.com/cuda-downloads?target_os=Windows&target_arch=x86_64
5
+
6
+ Nvidia Kepler or higher
7
+ https://developer.nvidia.com/cuda-11-8-0-download-archive?target_os=Windows&target_arch=x86_64
8
+
9
+ Haven't done much testing but Visual Studio with desktop development for C++ might be required. I've gotten cl.exe errors on a previous install
10
+
11
+ make sure you setup the environment by using windows-setup.bat
12
+ after everything is done just download a model using "download multiple models.ps1" set the number of models to download, then enter the model directory(s)
13
+ to quant, use convert-model-auto.bat. Enter the model's folder name, then the BPW for the model
exl2-windows-local/windows-setup.bat ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @echo off
2
+
3
+ setlocal
4
+
5
+ REM check if "venv" subdirectory exists, if not, create one
6
+ if not exist "venv\" (
7
+ python -m venv venv
8
+ ) else (
9
+ echo venv directory already exists. If something is broken, delete everything but exl2-quant.py and run this script again.
10
+ pause
11
+ exit
12
+ )
13
+
14
+ REM ask if the user has git installed
15
+ set /p gitinst="Do you have git installed? (y/n) "
16
+
17
+ if "%gitinst%"=="y" (
18
+ echo Setting up environment
19
+ ) else (
20
+ echo Please install git before running this script.
21
+ pause
22
+ exit
23
+ )
24
+
25
+ REM if CUDA version 12 install pytorch for 12.1, else if CUDA 11 install pytorch for 11.8
26
+ echo CUDA path: %CUDA_HOME%
27
+ set /p cuda_version="Please enter your CUDA version (11 or 12): "
28
+
29
+ if "%cuda_version%"=="11" (
30
+ echo Installing PyTorch for CUDA 11.8...
31
+ venv\scripts\python.exe -m pip install torch --index-url https://download.pytorch.org/whl/cu118 -q --upgrade
32
+ ) else if "%cuda_version%"=="12" (
33
+ echo Installing PyTorch for CUDA 12.1...
34
+ venv\scripts\python.exe -m pip install torch --index-url https://download.pytorch.org/whl/cu121 -q --upgrade
35
+ ) else (
36
+ echo Invalid CUDA version. Please enter 11 or 12.
37
+ pause
38
+ exit
39
+ )
40
+
41
+ REM download stuff
42
+ echo Downloading files...
43
+ git clone https://github.com/turboderp/exllamav2
44
+
45
+ echo Installing pip packages...
46
+
47
+ venv\scripts\python.exe -m pip install -r exllamav2/requirements.txt -q
48
+ venv\scripts\python.exe -m pip install huggingface-hub -q
49
+ venv\scripts\python.exe -m pip install .\exllamav2 -q
50
+
51
+ move "download multiple models.ps1" exllamav2
52
+ move convert-model-auto.bat exllamav2
53
+ move download-model.py exllamav2
54
+ move venv exllamav2
55
+
56
+ powershell -c (New-Object Media.SoundPlayer "C:\Windows\Media\tada.wav").PlaySync();
57
+ echo Environment setup complete. Read instructions.txt for further instructions.
58
+ pause