ReallyFloppyPenguin commited on
Commit
fc10172
Β·
verified Β·
1 Parent(s): e5d9709

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +372 -0
app.py ADDED
@@ -0,0 +1,372 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import json
4
+ import re
5
+ import time
6
+ from typing import List, Dict, Tuple, Optional
7
+ from urllib.parse import quote
8
+
9
+ class GGUFModelFinder:
10
+ def __init__(self):
11
+ self.popular_gguf_creators = [
12
+ "TheBloke",
13
+ "bartowski",
14
+ "mradermacher",
15
+ "microsoft",
16
+ "QuantFactory",
17
+ "lmstudio-ai",
18
+ "huggingface",
19
+ "mlabonne",
20
+ "NousResearch",
21
+ "MaziyarPanahi"
22
+ ]
23
+
24
+ self.api_base = "https://huggingface.co/api"
25
+ self.headers = {
26
+ "User-Agent": "GGUF-Model-Finder/1.0"
27
+ }
28
+
29
+ def clean_model_name(self, model_name: str) -> str:
30
+ """Clean and normalize model name for better searching"""
31
+ # Remove common prefixes and suffixes
32
+ cleaned = model_name.strip()
33
+
34
+ # Remove author/organization prefix if present
35
+ if "/" in cleaned:
36
+ cleaned = cleaned.split("/")[-1]
37
+
38
+ # Remove common suffixes
39
+ suffixes_to_remove = [
40
+ "-GGUF", "-gguf", "-GPTQ", "-gptq", "-AWQ", "-awq",
41
+ "-HF", "-hf", "-chat", "-instruct", "-base", "-v1",
42
+ "-v2", "-v3", "-uncensored", "-finetune"
43
+ ]
44
+
45
+ for suffix in suffixes_to_remove:
46
+ if cleaned.lower().endswith(suffix.lower()):
47
+ cleaned = cleaned[:-len(suffix)]
48
+
49
+ return cleaned.strip()
50
+
51
+ def search_models(self, query: str, author: str = None, limit: int = 20) -> List[Dict]:
52
+ """Search for models using HuggingFace API"""
53
+ try:
54
+ search_url = f"{self.api_base}/models"
55
+ params = {
56
+ "search": query,
57
+ "filter": "gguf",
58
+ "limit": limit,
59
+ "sort": "downloads"
60
+ }
61
+
62
+ if author:
63
+ params["author"] = author
64
+
65
+ response = requests.get(search_url, params=params, headers=self.headers, timeout=10)
66
+
67
+ if response.status_code == 200:
68
+ return response.json()
69
+ else:
70
+ return []
71
+ except Exception as e:
72
+ print(f"Error searching models: {e}")
73
+ return []
74
+
75
+ def search_gguf_variants(self, model_name: str) -> List[Dict]:
76
+ """Search for GGUF variants of a given model"""
77
+ cleaned_name = self.clean_model_name(model_name)
78
+ all_results = []
79
+
80
+ # Search with different query variations
81
+ search_terms = [
82
+ cleaned_name,
83
+ f"{cleaned_name} GGUF",
84
+ f"{cleaned_name}-GGUF",
85
+ f"{cleaned_name}_GGUF"
86
+ ]
87
+
88
+ # Search through popular GGUF creators
89
+ for creator in self.popular_gguf_creators:
90
+ for term in search_terms:
91
+ results = self.search_models(term, author=creator, limit=10)
92
+ all_results.extend(results)
93
+ time.sleep(0.1) # Rate limiting
94
+
95
+ # Also search generally without author filter
96
+ for term in search_terms:
97
+ results = self.search_models(term, limit=15)
98
+ all_results.extend(results)
99
+ time.sleep(0.1)
100
+
101
+ # Remove duplicates and filter relevant results
102
+ seen_ids = set()
103
+ filtered_results = []
104
+
105
+ for model in all_results:
106
+ model_id = model.get('id', '')
107
+ if model_id not in seen_ids and 'gguf' in model_id.lower():
108
+ seen_ids.add(model_id)
109
+
110
+ # Check if model name is relevant
111
+ model_name_clean = self.clean_model_name(model_id)
112
+ if self.is_relevant_match(cleaned_name, model_name_clean):
113
+ filtered_results.append(model)
114
+
115
+ # Sort by downloads (descending)
116
+ filtered_results.sort(key=lambda x: x.get('downloads', 0), reverse=True)
117
+
118
+ return filtered_results[:20] # Return top 20 results
119
+
120
+ def is_relevant_match(self, original: str, candidate: str) -> bool:
121
+ """Check if candidate model is a relevant match for original"""
122
+ original_lower = original.lower()
123
+ candidate_lower = candidate.lower()
124
+
125
+ # Direct substring match
126
+ if original_lower in candidate_lower or candidate_lower in original_lower:
127
+ return True
128
+
129
+ # Check word overlap
130
+ original_words = set(re.findall(r'\w+', original_lower))
131
+ candidate_words = set(re.findall(r'\w+', candidate_lower))
132
+
133
+ # If most words overlap, it's likely a match
134
+ if len(original_words) > 0:
135
+ overlap_ratio = len(original_words.intersection(candidate_words)) / len(original_words)
136
+ return overlap_ratio >= 0.6
137
+
138
+ return False
139
+
140
+ def get_model_details(self, model_id: str) -> Dict:
141
+ """Get detailed information about a specific model"""
142
+ try:
143
+ url = f"{self.api_base}/models/{model_id}"
144
+ response = requests.get(url, headers=self.headers, timeout=10)
145
+
146
+ if response.status_code == 200:
147
+ return response.json()
148
+ return {}
149
+ except Exception as e:
150
+ print(f"Error getting model details: {e}")
151
+ return {}
152
+
153
+ def format_model_info(self, model: Dict) -> str:
154
+ """Format model information for display"""
155
+ model_id = model.get('id', 'Unknown')
156
+ downloads = model.get('downloads', 0)
157
+ likes = model.get('likes', 0)
158
+ updated = model.get('lastModified', 'Unknown')
159
+
160
+ # Format the date
161
+ if updated != 'Unknown':
162
+ try:
163
+ from datetime import datetime
164
+ date_obj = datetime.fromisoformat(updated.replace('Z', '+00:00'))
165
+ updated = date_obj.strftime('%Y-%m-%d')
166
+ except:
167
+ pass
168
+
169
+ # Get model size info if available
170
+ size_info = ""
171
+ if 'siblings' in model:
172
+ total_size = 0
173
+ file_count = 0
174
+ for sibling in model['siblings']:
175
+ if sibling.get('rfilename', '').endswith('.gguf'):
176
+ file_count += 1
177
+ if 'size' in sibling:
178
+ total_size += sibling['size']
179
+
180
+ if total_size > 0:
181
+ size_gb = total_size / (1024**3)
182
+ size_info = f" | Size: {size_gb:.1f}GB ({file_count} GGUF files)"
183
+
184
+ model_url = f"https://huggingface.co/{model_id}"
185
+
186
+ return f"""
187
+ **[{model_id}]({model_url})**
188
+ - Downloads: {downloads:,} | Likes: {likes} | Updated: {updated}{size_info}
189
+ """
190
+
191
+ def find_gguf_models(model_name: str, progress=gr.Progress()) -> Tuple[str, str]:
192
+ """Main function to find GGUF models"""
193
+ if not model_name.strip():
194
+ return "Please enter a model name to search for.", ""
195
+
196
+ progress(0.1, desc="Initializing search...")
197
+
198
+ finder = GGUFModelFinder()
199
+
200
+ progress(0.3, desc="Searching for GGUF variants...")
201
+ results = finder.search_gguf_variants(model_name)
202
+
203
+ progress(0.8, desc="Formatting results...")
204
+
205
+ if not results:
206
+ no_results = f"""
207
+ # No GGUF Models Found 😞
208
+
209
+ Could not find any GGUF variants for **{model_name}**.
210
+
211
+ ## Suggestions:
212
+ 1. **Check the spelling** of the model name
213
+ 2. **Try a simpler name** (e.g., just "llama-2-7b" instead of "meta-llama/Llama-2-7b-chat-hf")
214
+ 3. **Search manually** on [Hugging Face](https://huggingface.co/models?other=gguf) with the GGUF filter
215
+ 4. **Check popular GGUF creators**:
216
+ - [TheBloke](https://huggingface.co/TheBloke)
217
+ - [bartowski](https://huggingface.co/bartowski)
218
+ - [mradermacher](https://huggingface.co/mradermacher)
219
+ - [QuantFactory](https://huggingface.co/QuantFactory)
220
+
221
+ The model you're looking for might not have been converted to GGUF format yet, or might be available under a different name.
222
+ """
223
+ return no_results, ""
224
+
225
+ # Create main results
226
+ results_md = f"""
227
+ # GGUF Models Found for "{model_name}" 🎯
228
+
229
+ Found **{len(results)}** GGUF variant(s):
230
+
231
+ """
232
+
233
+ for i, model in enumerate(results, 1):
234
+ results_md += f"{i}. {finder.format_model_info(model)}\n"
235
+
236
+ # Create additional info
237
+ additional_info = f"""
238
+ ## πŸ“‹ What is GGUF?
239
+
240
+ GGUF (GPT-Generated Unified Format) is a file format for storing models for inference with GGML and llama.cpp. It's designed to be fast to load and save, and to be extensible.
241
+
242
+ ## πŸ”§ How to Use These Models
243
+
244
+ ### With llama.cpp:
245
+ ```bash
246
+ ./main -m model.gguf -p "Your prompt here"
247
+ ```
248
+
249
+ ### With Ollama:
250
+ ```bash
251
+ ollama create mymodel -f Modelfile
252
+ ollama run mymodel
253
+ ```
254
+
255
+ ### With Python (llama-cpp-python):
256
+ ```python
257
+ from llama_cpp import Llama
258
+
259
+ llm = Llama(model_path="model.gguf")
260
+ output = llm("Your prompt here")
261
+ ```
262
+
263
+ ## πŸ’‘ Tips for Choosing a Model
264
+
265
+ - **Q4_K_M**: Good balance of quality and size
266
+ - **Q5_K_M**: Higher quality, larger size
267
+ - **Q6_K**: Even higher quality, larger size
268
+ - **Q8_0**: Highest quality, largest size
269
+
270
+ Lower numbers = smaller file size but lower quality
271
+ Higher numbers = larger file size but higher quality
272
+
273
+ ## 🌟 Popular GGUF Model Creators
274
+
275
+ The results above are from trusted model quantizers who regularly convert popular models to GGUF format.
276
+ """
277
+
278
+ progress(1.0, desc="Complete!")
279
+
280
+ return results_md, additional_info
281
+
282
+ # Create the Gradio interface
283
+ def create_interface():
284
+ with gr.Blocks(
285
+ title="GGUF Model Finder",
286
+ theme=gr.themes.Soft(),
287
+ css="""
288
+ .container { max-width: 1200px; margin: auto; }
289
+ .header { text-align: center; margin: 20px 0; }
290
+ .search-box { margin: 20px 0; }
291
+ """
292
+ ) as iface:
293
+
294
+ gr.HTML("""
295
+ <div class="header">
296
+ <h1>πŸ” GGUF Model Finder</h1>
297
+ <p>Find GGUF (quantized) versions of your favorite language models for local inference</p>
298
+ </div>
299
+ """)
300
+
301
+ with gr.Row():
302
+ with gr.Column(scale=3):
303
+ model_input = gr.Textbox(
304
+ label="Model Name",
305
+ placeholder="e.g., llama-2-7b, mistral-7b, codellama-34b, deepseek-coder-6.7b",
306
+ info="Enter the name of the model you want to find GGUF versions for",
307
+ lines=1
308
+ )
309
+
310
+ with gr.Column(scale=1):
311
+ search_btn = gr.Button("πŸ” Search GGUF Models", variant="primary", size="lg")
312
+
313
+ gr.HTML("""
314
+ <div style="margin: 20px 0; padding: 15px; background-color: #f0f0f0; border-radius: 8px;">
315
+ <strong>πŸ’‘ Quick Examples:</strong><br>
316
+ β€’ <code>llama-2-7b</code> - Meta's Llama 2 7B model<br>
317
+ β€’ <code>mistral-7b</code> - Mistral AI's 7B model<br>
318
+ β€’ <code>codellama-34b</code> - Code Llama 34B model<br>
319
+ β€’ <code>neural-chat-7b</code> - Intel's Neural Chat model<br>
320
+ β€’ <code>deepseek-coder</code> - DeepSeek Coder model
321
+ </div>
322
+ """)
323
+
324
+ with gr.Row():
325
+ with gr.Column(scale=2):
326
+ results_output = gr.Markdown(
327
+ label="Search Results",
328
+ value="Enter a model name above and click 'Search GGUF Models' to find quantized versions.",
329
+ height=400
330
+ )
331
+
332
+ with gr.Column(scale=1):
333
+ info_output = gr.Markdown(
334
+ label="Additional Information",
335
+ value="",
336
+ height=400
337
+ )
338
+
339
+ # Event handlers
340
+ search_btn.click(
341
+ fn=find_gguf_models,
342
+ inputs=[model_input],
343
+ outputs=[results_output, info_output],
344
+ show_progress=True
345
+ )
346
+
347
+ model_input.submit(
348
+ fn=find_gguf_models,
349
+ inputs=[model_input],
350
+ outputs=[results_output, info_output],
351
+ show_progress=True
352
+ )
353
+
354
+ gr.HTML("""
355
+ <div style="margin-top: 30px; text-align: center; color: #666;">
356
+ <p>Made with ❀️ using Gradio | Data from <a href="https://huggingface.co">Hugging Face</a></p>
357
+ <p>GGUF format by the <a href="https://github.com/ggerganov/llama.cpp">llama.cpp</a> team</p>
358
+ </div>
359
+ """)
360
+
361
+ return iface
362
+
363
+ if __name__ == "__main__":
364
+ # Create and launch the interface
365
+ demo = create_interface()
366
+ demo.launch(
367
+ server_name="0.0.0.0",
368
+ server_port=7860,
369
+ share=True,
370
+ show_error=True,
371
+ show_tips=True
372
+ )