webscout 6.4__py3-none-any.whl → 6.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of webscout might be problematic. Click here for more details.

Files changed (116) hide show
  1. webscout/AIutel.py +7 -54
  2. webscout/DWEBS.py +48 -26
  3. webscout/{YTdownloader.py → Extra/YTToolkit/YTdownloader.py} +990 -1103
  4. webscout/Extra/YTToolkit/__init__.py +3 -0
  5. webscout/{transcriber.py → Extra/YTToolkit/transcriber.py} +1 -1
  6. webscout/Extra/YTToolkit/ytapi/__init__.py +6 -0
  7. webscout/Extra/YTToolkit/ytapi/channel.py +307 -0
  8. webscout/Extra/YTToolkit/ytapi/errors.py +13 -0
  9. webscout/Extra/YTToolkit/ytapi/extras.py +45 -0
  10. webscout/Extra/YTToolkit/ytapi/https.py +88 -0
  11. webscout/Extra/YTToolkit/ytapi/patterns.py +61 -0
  12. webscout/Extra/YTToolkit/ytapi/playlist.py +59 -0
  13. webscout/Extra/YTToolkit/ytapi/pool.py +8 -0
  14. webscout/Extra/YTToolkit/ytapi/query.py +37 -0
  15. webscout/Extra/YTToolkit/ytapi/stream.py +60 -0
  16. webscout/Extra/YTToolkit/ytapi/utils.py +62 -0
  17. webscout/Extra/YTToolkit/ytapi/video.py +102 -0
  18. webscout/Extra/__init__.py +2 -1
  19. webscout/Extra/autocoder/autocoder_utiles.py +119 -101
  20. webscout/Extra/autocoder/rawdog.py +679 -680
  21. webscout/Extra/gguf.py +441 -441
  22. webscout/Extra/markdownlite/__init__.py +862 -0
  23. webscout/Extra/weather_ascii.py +2 -2
  24. webscout/Provider/AISEARCH/__init__.py +2 -0
  25. webscout/Provider/AISEARCH/ooai.py +155 -0
  26. webscout/Provider/Amigo.py +70 -85
  27. webscout/Provider/{prefind.py → Jadve.py} +72 -70
  28. webscout/Provider/Netwrck.py +235 -0
  29. webscout/Provider/Openai.py +4 -3
  30. webscout/Provider/PI.py +292 -221
  31. webscout/Provider/PizzaGPT.py +3 -3
  32. webscout/Provider/Reka.py +0 -1
  33. webscout/Provider/TTS/__init__.py +5 -1
  34. webscout/Provider/TTS/deepgram.py +183 -0
  35. webscout/Provider/TTS/elevenlabs.py +137 -0
  36. webscout/Provider/TTS/gesserit.py +151 -0
  37. webscout/Provider/TTS/murfai.py +139 -0
  38. webscout/Provider/TTS/parler.py +134 -107
  39. webscout/Provider/TTS/streamElements.py +360 -275
  40. webscout/Provider/TTS/utils.py +280 -0
  41. webscout/Provider/TTS/voicepod.py +116 -116
  42. webscout/Provider/TeachAnything.py +15 -2
  43. webscout/Provider/Youchat.py +42 -8
  44. webscout/Provider/__init__.py +8 -21
  45. webscout/Provider/meta.py +794 -779
  46. webscout/Provider/multichat.py +230 -0
  47. webscout/Provider/promptrefine.py +2 -2
  48. webscout/Provider/talkai.py +10 -13
  49. webscout/Provider/turboseek.py +5 -4
  50. webscout/Provider/tutorai.py +8 -112
  51. webscout/Provider/typegpt.py +5 -7
  52. webscout/Provider/x0gpt.py +81 -9
  53. webscout/Provider/yep.py +123 -361
  54. webscout/__init__.py +33 -28
  55. webscout/conversation.py +24 -9
  56. webscout/exceptions.py +188 -20
  57. webscout/litprinter/__init__.py +719 -831
  58. webscout/litprinter/colors.py +54 -0
  59. webscout/optimizers.py +420 -270
  60. webscout/prompt_manager.py +279 -279
  61. webscout/scout/__init__.py +8 -0
  62. webscout/scout/core/__init__.py +7 -0
  63. webscout/scout/core/crawler.py +140 -0
  64. webscout/scout/core/scout.py +571 -0
  65. webscout/scout/core/search_result.py +96 -0
  66. webscout/scout/core/text_analyzer.py +63 -0
  67. webscout/scout/core/text_utils.py +277 -0
  68. webscout/scout/core/web_analyzer.py +52 -0
  69. webscout/scout/core.py +884 -0
  70. webscout/scout/element.py +460 -0
  71. webscout/scout/parsers/__init__.py +69 -0
  72. webscout/scout/parsers/html5lib_parser.py +172 -0
  73. webscout/scout/parsers/html_parser.py +236 -0
  74. webscout/scout/parsers/lxml_parser.py +178 -0
  75. webscout/scout/utils.py +38 -0
  76. webscout/update_checker.py +184 -125
  77. webscout/version.py +1 -1
  78. webscout/zeroart/__init__.py +55 -0
  79. webscout/zeroart/base.py +60 -0
  80. webscout/zeroart/effects.py +99 -0
  81. webscout/zeroart/fonts.py +816 -0
  82. webscout/zerodir/__init__.py +225 -0
  83. {webscout-6.4.dist-info → webscout-6.6.dist-info}/METADATA +18 -231
  84. webscout-6.6.dist-info/RECORD +197 -0
  85. webscout-6.6.dist-info/top_level.txt +2 -0
  86. webstoken/__init__.py +30 -0
  87. webstoken/classifier.py +189 -0
  88. webstoken/keywords.py +216 -0
  89. webstoken/language.py +128 -0
  90. webstoken/ner.py +164 -0
  91. webstoken/normalizer.py +35 -0
  92. webstoken/processor.py +77 -0
  93. webstoken/sentiment.py +206 -0
  94. webstoken/stemmer.py +73 -0
  95. webstoken/t.py +75 -0
  96. webstoken/tagger.py +60 -0
  97. webstoken/tokenizer.py +158 -0
  98. webscout/Agents/Onlinesearcher.py +0 -182
  99. webscout/Agents/__init__.py +0 -2
  100. webscout/Agents/functioncall.py +0 -248
  101. webscout/Bing_search.py +0 -251
  102. webscout/Provider/Perplexity.py +0 -599
  103. webscout/Provider/RoboCoders.py +0 -206
  104. webscout/Provider/genspark.py +0 -225
  105. webscout/Provider/perplexitylabs.py +0 -265
  106. webscout/Provider/twitterclone.py +0 -251
  107. webscout/Provider/upstage.py +0 -230
  108. webscout/gpt4free.py +0 -666
  109. webscout/requestsHTMLfix.py +0 -775
  110. webscout/webai.py +0 -2590
  111. webscout-6.4.dist-info/RECORD +0 -154
  112. webscout-6.4.dist-info/top_level.txt +0 -1
  113. /webscout/Provider/{felo_search.py → AISEARCH/felo_search.py} +0 -0
  114. {webscout-6.4.dist-info → webscout-6.6.dist-info}/LICENSE.md +0 -0
  115. {webscout-6.4.dist-info → webscout-6.6.dist-info}/WHEEL +0 -0
  116. {webscout-6.4.dist-info → webscout-6.6.dist-info}/entry_points.txt +0 -0
webscout/Extra/gguf.py CHANGED
@@ -1,441 +1,441 @@
1
- """
2
- Yo fam! 🔥 Welcome to GGUF Converter - your ultimate tool for converting models to GGUF format! 💪
3
-
4
- - Converting HuggingFace models to GGUF format 🚀
5
- - Multiple quantization methods for different needs 🎯
6
- - Easy upload back to HuggingFace Hub 📤
7
-
8
- Usage:
9
- >>> python -m webscout.Extra.gguf convert -m "OEvortex/HelpingAI-Lite-1.5T" -q "q4_k_m,q5_k_m"
10
- >>> # With upload options:
11
- >>> python -m webscout.Extra.gguf convert -m "your-model" -u "username" -t "token" -q "q4_k_m"
12
-
13
- Features:
14
- - Smart dependency checking 🔍
15
- - CUDA support detection ⚡
16
- - Progress tracking that keeps it real 📈
17
- - Multiple quantization options 🎮
18
-
19
- Join the squad on Discord and level up your AI game! 🎮
20
- """
21
-
22
- import subprocess
23
- import os
24
- import sys
25
- import shutil
26
- from pathlib import Path
27
- from typing import List, Optional, Dict, Any
28
- from pyfiglet import figlet_format
29
- from rich.console import Console
30
- from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn
31
- from rich.panel import Panel
32
- from rich.table import Table
33
- from ..Litlogger import LitLogger, LogFormat, ColorScheme
34
- from ..swiftcli import CLI, option
35
-
36
- # Initialize LitLogger with ocean vibes
37
- logger = LitLogger(
38
- name="GGUFConverter",
39
- format=LogFormat.MODERN_EMOJI,
40
- color_scheme=ColorScheme.OCEAN
41
- )
42
-
43
- console = Console()
44
-
45
- class ConversionError(Exception):
46
- """Custom exception for when things don't go as planned! ⚠️"""
47
- pass
48
-
49
- class ModelConverter:
50
- """Handles the conversion of Hugging Face models to GGUF format."""
51
-
52
- VALID_METHODS = {
53
- "q2_k": "2-bit quantization",
54
- "q3_k_l": "3-bit quantization (large)",
55
- "q3_k_m": "3-bit quantization (medium)",
56
- "q3_k_s": "3-bit quantization (small)",
57
- "q4_0": "4-bit quantization (version 0)",
58
- "q4_1": "4-bit quantization (version 1)",
59
- "q4_k_m": "4-bit quantization (medium)",
60
- "q4_k_s": "4-bit quantization (small)",
61
- "q5_0": "5-bit quantization (version 0)",
62
- "q5_1": "5-bit quantization (version 1)",
63
- "q5_k_m": "5-bit quantization (medium)",
64
- "q5_k_s": "5-bit quantization (small)",
65
- "q6_k": "6-bit quantization",
66
- "q8_0": "8-bit quantization"
67
- }
68
-
69
- def __init__(self, model_id: str, username: Optional[str] = None,
70
- token: Optional[str] = None, quantization_methods: str = "q4_k_m,q5_k_m"):
71
- self.model_id = model_id
72
- self.username = username
73
- self.token = token
74
- self.quantization_methods = quantization_methods.split(',')
75
- self.model_name = model_id.split('/')[-1]
76
- self.workspace = Path(os.getcwd())
77
-
78
- def validate_inputs(self) -> None:
79
- """Validates all input parameters."""
80
- if not '/' in self.model_id:
81
- raise ValueError("Invalid model ID format. Expected format: 'organization/model-name'")
82
-
83
- invalid_methods = [m for m in self.quantization_methods if m not in self.VALID_METHODS]
84
- if invalid_methods:
85
- raise ValueError(
86
- f"Invalid quantization methods: {', '.join(invalid_methods)}.\n"
87
- f"Valid methods are: {', '.join(self.VALID_METHODS.keys())}"
88
- )
89
-
90
- if bool(self.username) != bool(self.token):
91
- raise ValueError("Both username and token must be provided for upload, or neither.")
92
-
93
- @staticmethod
94
- def check_dependencies() -> Dict[str, bool]:
95
- """Check if all required dependencies are installed."""
96
- dependencies = {
97
- 'git': 'Git version control',
98
- 'pip3': 'Python package installer',
99
- 'huggingface-cli': 'Hugging Face CLI',
100
- 'nvcc': 'NVIDIA CUDA Compiler (optional)'
101
- }
102
-
103
- status = {}
104
- for cmd, desc in dependencies.items():
105
- status[cmd] = subprocess.run(['which', cmd], capture_output=True, text=True).returncode == 0
106
-
107
- return status
108
-
109
- def setup_llama_cpp(self) -> None:
110
- """Sets up and builds llama.cpp repository."""
111
- llama_path = self.workspace / "llama.cpp"
112
-
113
- with console.status("[bold green]Setting up llama.cpp...") as status:
114
- if not llama_path.exists():
115
- logger.info("Cloning llama.cpp repository...")
116
- subprocess.run(['git', 'clone', 'https://github.com/ggerganov/llama.cpp'], check=True)
117
-
118
- os.chdir(llama_path)
119
- logger.info("Installing requirements...")
120
- subprocess.run(['pip3', 'install', '-r', 'requirements.txt'], check=True)
121
-
122
- has_cuda = subprocess.run(['nvcc', '--version'], capture_output=True).returncode == 0
123
-
124
- logger.info("Building llama.cpp...")
125
- subprocess.run(['make', 'clean'], check=True)
126
- if has_cuda:
127
- status.update("[bold green]Building with CUDA support...")
128
- subprocess.run(['make', 'LLAMA_CUBLAS=1'], check=True)
129
- else:
130
- status.update("[bold yellow]Building without CUDA support...")
131
- subprocess.run(['make'], check=True)
132
-
133
- os.chdir(self.workspace)
134
-
135
- def display_config(self) -> None:
136
- """Displays the current configuration in a formatted table."""
137
- table = Table(title="Configuration", show_header=True, header_style="bold magenta")
138
- table.add_column("Setting", style="cyan")
139
- table.add_column("Value", style="green")
140
-
141
- table.add_row("Model ID", self.model_id)
142
- table.add_row("Model Name", self.model_name)
143
- table.add_row("Username", self.username or "Not provided")
144
- table.add_row("Token", "****" if self.token else "Not provided")
145
- table.add_row("Quantization Methods", "\n".join(
146
- f"{method} ({self.VALID_METHODS[method]})"
147
- for method in self.quantization_methods
148
- ))
149
-
150
- console.print(Panel(table))
151
-
152
- def convert(self) -> None:
153
- """Performs the model conversion process."""
154
- try:
155
- # Display banner and configuration
156
- console.print(f"[bold green]{figlet_format('GGUF Converter')}[/]\n", justify="center")
157
- self.display_config()
158
-
159
- # Validate inputs
160
- self.validate_inputs()
161
-
162
- # Check dependencies
163
- deps = self.check_dependencies()
164
- missing = [name for name, installed in deps.items() if not installed and name != 'nvcc']
165
- if missing:
166
- raise ConversionError(f"Missing required dependencies: {', '.join(missing)}")
167
-
168
- # Setup llama.cpp
169
- self.setup_llama_cpp()
170
-
171
- # Create and execute conversion script
172
- script_path = self.workspace / "gguf.sh"
173
- if not script_path.exists():
174
- self._create_conversion_script(script_path)
175
-
176
- # Prepare command
177
- command = ["bash", str(script_path), "-m", self.model_id]
178
- if self.username and self.token:
179
- command.extend(["-u", self.username, "-t", self.token])
180
- command.extend(["-q", ",".join(self.quantization_methods)])
181
-
182
- # Execute conversion with progress tracking
183
- with Progress(
184
- SpinnerColumn(),
185
- TextColumn("[progress.description]{task.description}"),
186
- BarColumn(),
187
- TaskProgressColumn(),
188
- console=console
189
- ) as progress:
190
- task = progress.add_task("Converting model...", total=None)
191
-
192
- process = subprocess.Popen(
193
- command,
194
- stdout=subprocess.PIPE,
195
- stderr=subprocess.PIPE,
196
- text=True,
197
- bufsize=1,
198
- universal_newlines=True
199
- )
200
-
201
- while True:
202
- output = process.stdout.readline()
203
- if output == '' and process.poll() is not None:
204
- break
205
- if output:
206
- progress.update(task, description=output.strip())
207
- logger.info(output.strip())
208
-
209
- stderr = process.stderr.read()
210
- if stderr:
211
- logger.warning(stderr)
212
-
213
- if process.returncode != 0:
214
- raise ConversionError(f"Conversion failed with return code {process.returncode}")
215
-
216
- progress.update(task, completed=True)
217
-
218
- # Display success message
219
- console.print(Panel.fit(
220
- "[bold green]✓[/] Conversion completed successfully!\n\n"
221
- f"[cyan]Output files can be found in: {self.workspace / self.model_name}[/]",
222
- title="Success",
223
- border_style="green"
224
- ))
225
-
226
- except Exception as e:
227
- console.print(Panel.fit(
228
- f"[bold red]✗[/] {str(e)}",
229
- title="Error",
230
- border_style="red"
231
- ))
232
- raise
233
-
234
- def _create_conversion_script(self, script_path: Path) -> None:
235
- """Creates the conversion shell script."""
236
- script_content = """cat << "EOF"
237
- Made with love in India
238
- EOF
239
-
240
- # Default values
241
- MODEL_ID=""
242
- USERNAME=""
243
- TOKEN=""
244
- QUANTIZATION_METHODS="q4_k_m,q5_k_m" # Default to "q4_k_m,q5_k_m" if not provided
245
-
246
- # Display help/usage information
247
- usage() {
248
- echo "Usage: $0 -m MODEL_ID [-u USERNAME] [-t TOKEN] [-q QUANTIZATION_METHODS]"
249
- echo
250
- echo "Options:"
251
- echo " -m MODEL_ID Required: Set the HF model ID"
252
- echo " -u USERNAME Optional: Set the username"
253
- echo " -t TOKEN Optional: Set the token"
254
- echo " -q QUANTIZATION_METHODS Optional: Set the quantization methods (default: q4_k_m,q5_k_m)"
255
- echo " -h Display this help and exit"
256
- echo
257
- }
258
-
259
- # Parse command-line options
260
- while getopts ":m:u:t:q:h" opt; do
261
- case ${opt} in
262
- m )
263
- MODEL_ID=$OPTARG
264
- ;;
265
- u )
266
- USERNAME=$OPTARG
267
- ;;
268
- t )
269
- TOKEN=$OPTARG
270
- ;;
271
- q )
272
- QUANTIZATION_METHODS=$OPTARG
273
- ;;
274
- h )
275
- usage
276
- exit 0
277
- ;;
278
- \? )
279
- echo "Invalid Option: -$OPTARG" 1>&2
280
- usage
281
- exit 1
282
- ;;
283
- : )
284
- echo "Invalid Option: -$OPTARG requires an argument" 1>&2
285
- usage
286
- exit 1
287
- ;;
288
- esac
289
- done
290
- shift $((OPTIND -1))
291
-
292
- # Ensure MODEL_ID is provided
293
- if [ -z "$MODEL_ID" ]; then
294
- echo "Error: MODEL_ID is required."
295
- usage
296
- exit 1
297
- fi
298
-
299
- # # Echoing the arguments for checking
300
- # echo "MODEL_ID: $MODEL_ID"
301
- # echo "USERNAME: ${USERNAME:-'Not provided'}"
302
- # echo "TOKEN: ${TOKEN:-'Not provided'}"
303
- # echo "QUANTIZATION_METHODS: $QUANTIZATION_METHODS"
304
-
305
- # Splitting string into an array for quantization methods, if provided
306
- IFS=',' read -r -a QUANTIZATION_METHOD_ARRAY <<< "$QUANTIZATION_METHODS"
307
- echo "Quantization Methods: ${QUANTIZATION_METHOD_ARRAY[@]}"
308
-
309
- MODEL_NAME=$(echo "$MODEL_ID" | awk -F'/' '{print $NF}')
310
-
311
-
312
- # ----------- llama.cpp setup block-----------
313
- # Check if llama.cpp is already installed and skip the build step if it is
314
- if [ ! -d "llama.cpp" ]; then
315
- echo "llama.cpp not found. Cloning and setting up..."
316
- git clone https://github.com/ggerganov/llama.cpp
317
- cd llama.cpp && git pull
318
- # Install required packages
319
- pip3 install -r requirements.txt
320
- # Build llama.cpp as it's freshly cloned
321
- if ! command -v nvcc &> /dev/null
322
- then
323
- echo "nvcc could not be found, building llama without LLAMA_CUBLAS"
324
- make clean && make
325
- else
326
- make clean && LLAMA_CUBLAS=1 make
327
- fi
328
- cd ..
329
- else
330
- echo "llama.cpp found. Assuming it's already built and up to date."
331
- # Optionally, still update dependencies
332
- # cd llama.cpp && pip3 install -r requirements.txt && cd ..
333
- fi
334
- # ----------- llama.cpp setup block-----------
335
-
336
-
337
-
338
- # Download model
339
- #todo : shall we put condition to check if model has been already downloaded? similar to autogguf?
340
- echo "Downloading the model..."
341
- huggingface-cli download "$MODEL_ID" --local-dir "./${MODEL_NAME}" --local-dir-use-symlinks False --revision main
342
-
343
-
344
- # Convert to fp16
345
- FP16="${MODEL_NAME}/${MODEL_NAME,,}.fp16.bin"
346
- echo "Converting the model to fp16..."
347
- python3 llama.cpp/convert_hf_to_gguf.py "$MODEL_NAME" --outtype f16 --outfile "$FP16"
348
-
349
- # Quantize the model
350
- echo "Quantizing the model..."
351
- for METHOD in "${QUANTIZATION_METHOD_ARRAY[@]}"; do
352
- QTYPE="${MODEL_NAME}/${MODEL_NAME,,}.${METHOD^^}.gguf"
353
- ./llama.cpp/llama-quantize "$FP16" "$QTYPE" "$METHOD"
354
- done
355
-
356
-
357
- # Check if USERNAME and TOKEN are provided
358
- if [[ -n "$USERNAME" && -n "$TOKEN" ]]; then
359
-
360
- # Login to Hugging Face
361
- echo "Logging in to Hugging Face..."
362
- huggingface-cli login --token "$TOKEN"
363
-
364
-
365
- # Uploading .gguf, .md files, and config.json
366
- echo "Uploading .gguf, .md files, and config.json..."
367
-
368
-
369
- # Define a temporary directory
370
- TEMP_DIR="./temp_upload_dir"
371
-
372
- # Create the temporary directory
373
- mkdir -p "${TEMP_DIR}"
374
-
375
- # Copy the specific files to the temporary directory
376
- find "./${MODEL_NAME}" -type f \( -name "*.gguf" -o -name "*.md" -o -name "config.json" \) -exec cp {} "${TEMP_DIR}/" \;
377
-
378
- # Upload the temporary directory to Hugging Face
379
- huggingface-cli upload "${USERNAME}/${MODEL_NAME}-GGUF" "${TEMP_DIR}" --private
380
-
381
- # Remove the temporary directory after upload
382
- rm -rf "${TEMP_DIR}"
383
- echo "Upload completed."
384
- else
385
- echo "USERNAME and TOKEN must be provided for upload."
386
- fi
387
-
388
- echo "Script completed."
389
- """
390
- script_path.write_text(script_content)
391
- script_path.chmod(0o755)
392
-
393
- # Initialize CLI with HAI vibes
394
- app = CLI(
395
- name="gguf",
396
- help="Convert HuggingFace models to GGUF format with style! 🔥",
397
- version="1.0.0"
398
- )
399
-
400
- @app.command(name="convert")
401
- @option("-m", "--model-id", help="The HuggingFace model ID (e.g., 'OEvortex/HelpingAI-Lite-1.5T')", required=True)
402
- @option("-u", "--username", help="Your HuggingFace username for uploads", default=None)
403
- @option("-t", "--token", help="Your HuggingFace API token for uploads", default=None)
404
- @option("-q", "--quantization", help="Comma-separated quantization methods", default="q4_k_m,q5_k_m")
405
- def convert_command(model_id: str, username: Optional[str] = None,
406
- token: Optional[str] = None, quantization: str = "q4_k_m,q5_k_m"):
407
- """
408
- Convert and quantize HuggingFace models to GGUF format! 🚀
409
-
410
- Args:
411
- model_id (str): Your model's HF ID (like 'OEvortex/HelpingAI-Lite-1.5T') 🎯
412
- username (str, optional): Your HF username for uploads 👤
413
- token (str, optional): Your HF API token 🔑
414
- quantization (str): Quantization methods (default: q4_k_m,q5_k_m) 🎮
415
-
416
- Example:
417
- >>> python -m webscout.Extra.gguf convert \\
418
- ... -m "OEvortex/HelpingAI-Lite-1.5T" \\
419
- ... -q "q4_k_m,q5_k_m"
420
- """
421
- try:
422
- converter = ModelConverter(
423
- model_id=model_id,
424
- username=username,
425
- token=token,
426
- quantization_methods=quantization
427
- )
428
- converter.convert()
429
- except (ConversionError, ValueError) as e:
430
- logger.error(f"Conversion failed: {str(e)}")
431
- sys.exit(1)
432
- except Exception as e:
433
- logger.error(f"Unexpected error: {str(e)}")
434
- sys.exit(1)
435
-
436
- def main():
437
- """Fire up the GGUF converter! 🚀"""
438
- app.run()
439
-
440
- if __name__ == "__main__":
441
- main()
1
+ """
2
+ Yo fam! 🔥 Welcome to GGUF Converter - your ultimate tool for converting models to GGUF format! 💪
3
+
4
+ - Converting HuggingFace models to GGUF format 🚀
5
+ - Multiple quantization methods for different needs 🎯
6
+ - Easy upload back to HuggingFace Hub 📤
7
+
8
+ Usage:
9
+ >>> python -m webscout.Extra.gguf convert -m "OEvortex/HelpingAI-Lite-1.5T" -q "q4_k_m,q5_k_m"
10
+ >>> # With upload options:
11
+ >>> python -m webscout.Extra.gguf convert -m "your-model" -u "username" -t "token" -q "q4_k_m"
12
+
13
+ Features:
14
+ - Smart dependency checking 🔍
15
+ - CUDA support detection ⚡
16
+ - Progress tracking that keeps it real 📈
17
+ - Multiple quantization options 🎮
18
+
19
+ Join the squad on Discord and level up your AI game! 🎮
20
+ """
21
+
22
+ import subprocess
23
+ import os
24
+ import sys
25
+ import shutil
26
+ from pathlib import Path
27
+ from typing import List, Optional, Dict, Any
28
+ from webscout.zeroart import figlet_format
29
+ from rich.console import Console
30
+ from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn
31
+ from rich.panel import Panel
32
+ from rich.table import Table
33
+ from ..Litlogger import LitLogger, LogFormat, ColorScheme
34
+ from ..swiftcli import CLI, option
35
+
36
+ # Initialize LitLogger with ocean vibes
37
+ logger = LitLogger(
38
+ name="GGUFConverter",
39
+ format=LogFormat.MODERN_EMOJI,
40
+ color_scheme=ColorScheme.OCEAN
41
+ )
42
+
43
+ console = Console()
44
+
45
+ class ConversionError(Exception):
46
+ """Custom exception for when things don't go as planned! ⚠️"""
47
+ pass
48
+
49
+ class ModelConverter:
50
+ """Handles the conversion of Hugging Face models to GGUF format."""
51
+
52
+ VALID_METHODS = {
53
+ "q2_k": "2-bit quantization",
54
+ "q3_k_l": "3-bit quantization (large)",
55
+ "q3_k_m": "3-bit quantization (medium)",
56
+ "q3_k_s": "3-bit quantization (small)",
57
+ "q4_0": "4-bit quantization (version 0)",
58
+ "q4_1": "4-bit quantization (version 1)",
59
+ "q4_k_m": "4-bit quantization (medium)",
60
+ "q4_k_s": "4-bit quantization (small)",
61
+ "q5_0": "5-bit quantization (version 0)",
62
+ "q5_1": "5-bit quantization (version 1)",
63
+ "q5_k_m": "5-bit quantization (medium)",
64
+ "q5_k_s": "5-bit quantization (small)",
65
+ "q6_k": "6-bit quantization",
66
+ "q8_0": "8-bit quantization"
67
+ }
68
+
69
+ def __init__(self, model_id: str, username: Optional[str] = None,
70
+ token: Optional[str] = None, quantization_methods: str = "q4_k_m,q5_k_m"):
71
+ self.model_id = model_id
72
+ self.username = username
73
+ self.token = token
74
+ self.quantization_methods = quantization_methods.split(',')
75
+ self.model_name = model_id.split('/')[-1]
76
+ self.workspace = Path(os.getcwd())
77
+
78
+ def validate_inputs(self) -> None:
79
+ """Validates all input parameters."""
80
+ if not '/' in self.model_id:
81
+ raise ValueError("Invalid model ID format. Expected format: 'organization/model-name'")
82
+
83
+ invalid_methods = [m for m in self.quantization_methods if m not in self.VALID_METHODS]
84
+ if invalid_methods:
85
+ raise ValueError(
86
+ f"Invalid quantization methods: {', '.join(invalid_methods)}.\n"
87
+ f"Valid methods are: {', '.join(self.VALID_METHODS.keys())}"
88
+ )
89
+
90
+ if bool(self.username) != bool(self.token):
91
+ raise ValueError("Both username and token must be provided for upload, or neither.")
92
+
93
+ @staticmethod
94
+ def check_dependencies() -> Dict[str, bool]:
95
+ """Check if all required dependencies are installed."""
96
+ dependencies = {
97
+ 'git': 'Git version control',
98
+ 'pip3': 'Python package installer',
99
+ 'huggingface-cli': 'Hugging Face CLI',
100
+ 'nvcc': 'NVIDIA CUDA Compiler (optional)'
101
+ }
102
+
103
+ status = {}
104
+ for cmd, desc in dependencies.items():
105
+ status[cmd] = subprocess.run(['which', cmd], capture_output=True, text=True).returncode == 0
106
+
107
+ return status
108
+
109
+ def setup_llama_cpp(self) -> None:
110
+ """Sets up and builds llama.cpp repository."""
111
+ llama_path = self.workspace / "llama.cpp"
112
+
113
+ with console.status("[bold green]Setting up llama.cpp...") as status:
114
+ if not llama_path.exists():
115
+ logger.info("Cloning llama.cpp repository...")
116
+ subprocess.run(['git', 'clone', 'https://github.com/ggerganov/llama.cpp'], check=True)
117
+
118
+ os.chdir(llama_path)
119
+ logger.info("Installing requirements...")
120
+ subprocess.run(['pip3', 'install', '-r', 'requirements.txt'], check=True)
121
+
122
+ has_cuda = subprocess.run(['nvcc', '--version'], capture_output=True).returncode == 0
123
+
124
+ logger.info("Building llama.cpp...")
125
+ subprocess.run(['make', 'clean'], check=True)
126
+ if has_cuda:
127
+ status.update("[bold green]Building with CUDA support...")
128
+ subprocess.run(['make', 'LLAMA_CUBLAS=1'], check=True)
129
+ else:
130
+ status.update("[bold yellow]Building without CUDA support...")
131
+ subprocess.run(['make'], check=True)
132
+
133
+ os.chdir(self.workspace)
134
+
135
+ def display_config(self) -> None:
136
+ """Displays the current configuration in a formatted table."""
137
+ table = Table(title="Configuration", show_header=True, header_style="bold magenta")
138
+ table.add_column("Setting", style="cyan")
139
+ table.add_column("Value", style="green")
140
+
141
+ table.add_row("Model ID", self.model_id)
142
+ table.add_row("Model Name", self.model_name)
143
+ table.add_row("Username", self.username or "Not provided")
144
+ table.add_row("Token", "****" if self.token else "Not provided")
145
+ table.add_row("Quantization Methods", "\n".join(
146
+ f"{method} ({self.VALID_METHODS[method]})"
147
+ for method in self.quantization_methods
148
+ ))
149
+
150
+ console.print(Panel(table))
151
+
152
+ def convert(self) -> None:
153
+ """Performs the model conversion process."""
154
+ try:
155
+ # Display banner and configuration
156
+ console.print(f"[bold green]{figlet_format('GGUF Converter')}")
157
+ self.display_config()
158
+
159
+ # Validate inputs
160
+ self.validate_inputs()
161
+
162
+ # Check dependencies
163
+ deps = self.check_dependencies()
164
+ missing = [name for name, installed in deps.items() if not installed and name != 'nvcc']
165
+ if missing:
166
+ raise ConversionError(f"Missing required dependencies: {', '.join(missing)}")
167
+
168
+ # Setup llama.cpp
169
+ self.setup_llama_cpp()
170
+
171
+ # Create and execute conversion script
172
+ script_path = self.workspace / "gguf.sh"
173
+ if not script_path.exists():
174
+ self._create_conversion_script(script_path)
175
+
176
+ # Prepare command
177
+ command = ["bash", str(script_path), "-m", self.model_id]
178
+ if self.username and self.token:
179
+ command.extend(["-u", self.username, "-t", self.token])
180
+ command.extend(["-q", ",".join(self.quantization_methods)])
181
+
182
+ # Execute conversion with progress tracking
183
+ with Progress(
184
+ SpinnerColumn(),
185
+ TextColumn("[progress.description]{task.description}"),
186
+ BarColumn(),
187
+ TaskProgressColumn(),
188
+ console=console
189
+ ) as progress:
190
+ task = progress.add_task("Converting model...", total=None)
191
+
192
+ process = subprocess.Popen(
193
+ command,
194
+ stdout=subprocess.PIPE,
195
+ stderr=subprocess.PIPE,
196
+ text=True,
197
+ bufsize=1,
198
+ universal_newlines=True
199
+ )
200
+
201
+ while True:
202
+ output = process.stdout.readline()
203
+ if output == '' and process.poll() is not None:
204
+ break
205
+ if output:
206
+ progress.update(task, description=output.strip())
207
+ logger.info(output.strip())
208
+
209
+ stderr = process.stderr.read()
210
+ if stderr:
211
+ logger.warning(stderr)
212
+
213
+ if process.returncode != 0:
214
+ raise ConversionError(f"Conversion failed with return code {process.returncode}")
215
+
216
+ progress.update(task, completed=True)
217
+
218
+ # Display success message
219
+ console.print(Panel.fit(
220
+ "[bold green]✓[/] Conversion completed successfully!\n\n"
221
+ f"[cyan]Output files can be found in: {self.workspace / self.model_name}[/]",
222
+ title="Success",
223
+ border_style="green"
224
+ ))
225
+
226
+ except Exception as e:
227
+ console.print(Panel.fit(
228
+ f"[bold red]✗[/] {str(e)}",
229
+ title="Error",
230
+ border_style="red"
231
+ ))
232
+ raise
233
+
234
+ def _create_conversion_script(self, script_path: Path) -> None:
235
+ """Creates the conversion shell script."""
236
+ script_content = """cat << "EOF"
237
+ Made with love in India
238
+ EOF
239
+
240
+ # Default values
241
+ MODEL_ID=""
242
+ USERNAME=""
243
+ TOKEN=""
244
+ QUANTIZATION_METHODS="q4_k_m,q5_k_m" # Default to "q4_k_m,q5_k_m" if not provided
245
+
246
+ # Display help/usage information
247
+ usage() {
248
+ echo "Usage: $0 -m MODEL_ID [-u USERNAME] [-t TOKEN] [-q QUANTIZATION_METHODS]"
249
+ echo
250
+ echo "Options:"
251
+ echo " -m MODEL_ID Required: Set the HF model ID"
252
+ echo " -u USERNAME Optional: Set the username"
253
+ echo " -t TOKEN Optional: Set the token"
254
+ echo " -q QUANTIZATION_METHODS Optional: Set the quantization methods (default: q4_k_m,q5_k_m)"
255
+ echo " -h Display this help and exit"
256
+ echo
257
+ }
258
+
259
+ # Parse command-line options
260
+ while getopts ":m:u:t:q:h" opt; do
261
+ case ${opt} in
262
+ m )
263
+ MODEL_ID=$OPTARG
264
+ ;;
265
+ u )
266
+ USERNAME=$OPTARG
267
+ ;;
268
+ t )
269
+ TOKEN=$OPTARG
270
+ ;;
271
+ q )
272
+ QUANTIZATION_METHODS=$OPTARG
273
+ ;;
274
+ h )
275
+ usage
276
+ exit 0
277
+ ;;
278
+ \? )
279
+ echo "Invalid Option: -$OPTARG" 1>&2
280
+ usage
281
+ exit 1
282
+ ;;
283
+ : )
284
+ echo "Invalid Option: -$OPTARG requires an argument" 1>&2
285
+ usage
286
+ exit 1
287
+ ;;
288
+ esac
289
+ done
290
+ shift $((OPTIND -1))
291
+
292
+ # Ensure MODEL_ID is provided
293
+ if [ -z "$MODEL_ID" ]; then
294
+ echo "Error: MODEL_ID is required."
295
+ usage
296
+ exit 1
297
+ fi
298
+
299
+ # # Echoing the arguments for checking
300
+ # echo "MODEL_ID: $MODEL_ID"
301
+ # echo "USERNAME: ${USERNAME:-'Not provided'}"
302
+ # echo "TOKEN: ${TOKEN:-'Not provided'}"
303
+ # echo "QUANTIZATION_METHODS: $QUANTIZATION_METHODS"
304
+
305
+ # Splitting string into an array for quantization methods, if provided
306
+ IFS=',' read -r -a QUANTIZATION_METHOD_ARRAY <<< "$QUANTIZATION_METHODS"
307
+ echo "Quantization Methods: ${QUANTIZATION_METHOD_ARRAY[@]}"
308
+
309
+ MODEL_NAME=$(echo "$MODEL_ID" | awk -F'/' '{print $NF}')
310
+
311
+
312
+ # ----------- llama.cpp setup block-----------
313
+ # Check if llama.cpp is already installed and skip the build step if it is
314
+ if [ ! -d "llama.cpp" ]; then
315
+ echo "llama.cpp not found. Cloning and setting up..."
316
+ git clone https://github.com/ggerganov/llama.cpp
317
+ cd llama.cpp && git pull
318
+ # Install required packages
319
+ pip3 install -r requirements.txt
320
+ # Build llama.cpp as it's freshly cloned
321
+ if ! command -v nvcc &> /dev/null
322
+ then
323
+ echo "nvcc could not be found, building llama without LLAMA_CUBLAS"
324
+ make clean && make
325
+ else
326
+ make clean && LLAMA_CUBLAS=1 make
327
+ fi
328
+ cd ..
329
+ else
330
+ echo "llama.cpp found. Assuming it's already built and up to date."
331
+ # Optionally, still update dependencies
332
+ # cd llama.cpp && pip3 install -r requirements.txt && cd ..
333
+ fi
334
+ # ----------- llama.cpp setup block-----------
335
+
336
+
337
+
338
+ # Download model
339
+ #todo : shall we put condition to check if model has been already downloaded? similar to autogguf?
340
+ echo "Downloading the model..."
341
+ huggingface-cli download "$MODEL_ID" --local-dir "./${MODEL_NAME}" --local-dir-use-symlinks False --revision main
342
+
343
+
344
+ # Convert to fp16
345
+ FP16="${MODEL_NAME}/${MODEL_NAME,,}.fp16.bin"
346
+ echo "Converting the model to fp16..."
347
+ python3 llama.cpp/convert_hf_to_gguf.py "$MODEL_NAME" --outtype f16 --outfile "$FP16"
348
+
349
+ # Quantize the model
350
+ echo "Quantizing the model..."
351
+ for METHOD in "${QUANTIZATION_METHOD_ARRAY[@]}"; do
352
+ QTYPE="${MODEL_NAME}/${MODEL_NAME,,}.${METHOD^^}.gguf"
353
+ ./llama.cpp/llama-quantize "$FP16" "$QTYPE" "$METHOD"
354
+ done
355
+
356
+
357
+ # Check if USERNAME and TOKEN are provided
358
+ if [[ -n "$USERNAME" && -n "$TOKEN" ]]; then
359
+
360
+ # Login to Hugging Face
361
+ echo "Logging in to Hugging Face..."
362
+ huggingface-cli login --token "$TOKEN"
363
+
364
+
365
+ # Uploading .gguf, .md files, and config.json
366
+ echo "Uploading .gguf, .md files, and config.json..."
367
+
368
+
369
+ # Define a temporary directory
370
+ TEMP_DIR="./temp_upload_dir"
371
+
372
+ # Create the temporary directory
373
+ mkdir -p "${TEMP_DIR}"
374
+
375
+ # Copy the specific files to the temporary directory
376
+ find "./${MODEL_NAME}" -type f \( -name "*.gguf" -o -name "*.md" -o -name "config.json" \) -exec cp {} "${TEMP_DIR}/" \;
377
+
378
+ # Upload the temporary directory to Hugging Face
379
+ huggingface-cli upload "${USERNAME}/${MODEL_NAME}-GGUF" "${TEMP_DIR}" --private
380
+
381
+ # Remove the temporary directory after upload
382
+ rm -rf "${TEMP_DIR}"
383
+ echo "Upload completed."
384
+ else
385
+ echo "USERNAME and TOKEN must be provided for upload."
386
+ fi
387
+
388
+ echo "Script completed."
389
+ """
390
+ script_path.write_text(script_content)
391
+ script_path.chmod(0o755)
392
+
393
+ # Initialize CLI with HAI vibes
394
+ app = CLI(
395
+ name="gguf",
396
+ help="Convert HuggingFace models to GGUF format with style! 🔥",
397
+ version="1.0.0"
398
+ )
399
+
400
+ @app.command(name="convert")
401
+ @option("-m", "--model-id", help="The HuggingFace model ID (e.g., 'OEvortex/HelpingAI-Lite-1.5T')", required=True)
402
+ @option("-u", "--username", help="Your HuggingFace username for uploads", default=None)
403
+ @option("-t", "--token", help="Your HuggingFace API token for uploads", default=None)
404
+ @option("-q", "--quantization", help="Comma-separated quantization methods", default="q4_k_m,q5_k_m")
405
+ def convert_command(model_id: str, username: Optional[str] = None,
406
+ token: Optional[str] = None, quantization: str = "q4_k_m,q5_k_m"):
407
+ """
408
+ Convert and quantize HuggingFace models to GGUF format! 🚀
409
+
410
+ Args:
411
+ model_id (str): Your model's HF ID (like 'OEvortex/HelpingAI-Lite-1.5T') 🎯
412
+ username (str, optional): Your HF username for uploads 👤
413
+ token (str, optional): Your HF API token 🔑
414
+ quantization (str): Quantization methods (default: q4_k_m,q5_k_m) 🎮
415
+
416
+ Example:
417
+ >>> python -m webscout.Extra.gguf convert \\
418
+ ... -m "OEvortex/HelpingAI-Lite-1.5T" \\
419
+ ... -q "q4_k_m,q5_k_m"
420
+ """
421
+ try:
422
+ converter = ModelConverter(
423
+ model_id=model_id,
424
+ username=username,
425
+ token=token,
426
+ quantization_methods=quantization
427
+ )
428
+ converter.convert()
429
+ except (ConversionError, ValueError) as e:
430
+ logger.error(f"Conversion failed: {str(e)}")
431
+ sys.exit(1)
432
+ except Exception as e:
433
+ logger.error(f"Unexpected error: {str(e)}")
434
+ sys.exit(1)
435
+
436
+ def main():
437
+ """Fire up the GGUF converter! 🚀"""
438
+ app.run()
439
+
440
+ if __name__ == "__main__":
441
+ main()