gr8monk3ys commited on
Commit
efcf320
·
verified ·
1 Parent(s): 3c904ad

Sync card and scripts from the monorepo

Browse files
Files changed (4) hide show
  1. README.md +11 -23
  2. app.py +41 -162
  3. core.py +180 -0
  4. requirements.txt +2 -2
README.md CHANGED
@@ -4,27 +4,19 @@ emoji: 🎯
4
  colorFrom: yellow
5
  colorTo: red
6
  sdk: gradio
7
- sdk_version: 5.50.0
8
  python_version: "3.10"
9
  app_file: app.py
10
  pinned: false
11
  license: mit
12
  short_description: Find the perfect HuggingFace model for your task
13
- tags:
14
- - recommendation
15
- - model-discovery
16
- - beginner-friendly
17
- models:
18
- - facebook/bart-large-cnn
19
- - deepset/roberta-base-squad2
20
- - BAAI/bge-small-en-v1.5
21
- - cardiffnlp/twitter-roberta-base-sentiment-latest
22
- - black-forest-labs/FLUX.1-schnell
23
  ---
24
 
25
  # Model Selector
26
 
27
- Find the perfect HuggingFace model for your task. Answer a few simple questions and get personalized recommendations with ready-to-use code examples.
 
 
28
 
29
  ## Features
30
 
@@ -47,10 +39,9 @@ Find the perfect HuggingFace model for your task. Answer a few simple questions
47
 
48
  ### Ready-to-Use Code
49
  Every recommendation includes:
50
- - Working Python code example
51
- - Direct link to the model
52
- - License information
53
- - Size/speed tradeoffs
54
 
55
  ## How to Use
56
 
@@ -62,13 +53,10 @@ Every recommendation includes:
62
 
63
  ## Example Output
64
 
65
- For "Text Generation" with "Small" size preference:
66
-
67
- | Rank | Model | Size | License |
68
- |------|-------|------|---------|
69
- | 1 | microsoft/phi-3-mini | 3.8B | MIT |
70
- | 2 | Qwen/Qwen2.5-3B-Instruct | 3B | Apache |
71
- | 3 | mistralai/Mistral-7B | 7B | Apache |
72
 
73
  ## Quick Reference
74
 
 
4
  colorFrom: yellow
5
  colorTo: red
6
  sdk: gradio
7
+ sdk_version: 5.31.0
8
  python_version: "3.10"
9
  app_file: app.py
10
  pinned: false
11
  license: mit
12
  short_description: Find the perfect HuggingFace model for your task
 
 
 
 
 
 
 
 
 
 
13
  ---
14
 
15
  # Model Selector
16
 
17
+ Find the perfect HuggingFace model for your task. Answer a few simple questions and get recommendations with ready-to-use code examples.
18
+
19
+ Recommendations are fetched **live from the HuggingFace Hub** (top models for the task, ranked by downloads). If the Hub can't be reached (offline or rate-limited), the app falls back to a curated shortlist so it always returns something useful.
20
 
21
  ## Features
22
 
 
39
 
40
  ### Ready-to-Use Code
41
  Every recommendation includes:
42
+ - Working Python code example for the task
43
+ - Direct link to the model on the Hub
44
+ - Live download/like counts (or size/license for curated fallback picks)
 
45
 
46
  ## How to Use
47
 
 
53
 
54
  ## Example Output
55
 
56
+ For "Text Generation", the app lists the current top models on the Hub with
57
+ their live download and like counts, a link, and a ready-to-run `transformers`
58
+ snippet for the top pick. (Size filtering applies to the curated fallback;
59
+ live results are ranked by popularity.)
 
 
 
60
 
61
  ## Quick Reference
62
 
app.py CHANGED
@@ -5,8 +5,13 @@ Answer a few questions and get personalized model recommendations.
5
  """
6
 
7
  import gradio as gr
8
- from huggingface_hub import HfApi, list_models
9
- from typing import Optional
 
 
 
 
 
10
 
11
  # ---------------------------------------------------------------------------
12
  # Task Categories and Model Recommendations
@@ -33,7 +38,6 @@ TASKS = {
33
  {"name": "distilbert-base-uncased-finetuned-sst-2-english", "size": "67M", "license": "apache-2.0"},
34
  {"name": "cardiffnlp/twitter-roberta-base-sentiment-latest", "size": "125M", "license": "mit"},
35
  {"name": "facebook/bart-large-mnli", "size": "400M", "license": "mit"},
36
- {"name": "MoritzLaworoutedistilbert-base-uncased-sentiment", "size": "67M", "license": "apache-2.0"},
37
  ]
38
  },
39
  "Question Answering": {
@@ -126,181 +130,56 @@ TASKS = {
126
  },
127
  }
128
 
129
- SIZE_PREFERENCES = {
130
- "Tiny (< 100M)": {"min": 0, "max": 100},
131
- "Small (100M - 500M)": {"min": 100, "max": 500},
132
- "Medium (500M - 2B)": {"min": 500, "max": 2000},
133
- "Large (2B - 10B)": {"min": 2000, "max": 10000},
134
- "Any size": {"min": 0, "max": 100000},
135
- }
136
-
137
  # ---------------------------------------------------------------------------
138
- # Core Functions
139
  # ---------------------------------------------------------------------------
140
 
141
- def get_recommendations(
142
- task: str,
143
- size_pref: str,
144
- priority: str,
145
- use_case: str
146
- ) -> tuple[str, str]:
147
- """Get model recommendations based on user preferences."""
148
-
149
  if task not in TASKS:
150
  return "Please select a task.", ""
151
 
152
  task_info = TASKS[task]
153
- models = task_info["top_models"]
154
-
155
- # Filter by size if preference is set
156
- size_range = SIZE_PREFERENCES.get(size_pref, SIZE_PREFERENCES["Any size"])
157
-
158
- def parse_size(size_str):
159
- """Parse size string to millions."""
160
- size_str = size_str.upper()
161
- if 'B' in size_str:
162
- return float(size_str.replace('B', '')) * 1000
163
- elif 'M' in size_str:
164
- return float(size_str.replace('M', ''))
165
- return 0
166
-
167
- if size_pref != "Any size":
168
- models = [m for m in models if size_range["min"] <= parse_size(m["size"]) <= size_range["max"]]
169
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  if not models:
171
  return "No models match your size preference. Try 'Any size'.", ""
172
-
173
- # Sort by priority
174
- if priority == "Smallest/Fastest":
175
- models = sorted(models, key=lambda x: parse_size(x["size"]))
176
- elif priority == "Most Popular":
177
- # Keep original order (already sorted by popularity)
178
- pass
179
- elif priority == "Best Quality":
180
- # Larger models tend to be higher quality
181
- models = sorted(models, key=lambda x: parse_size(x["size"]), reverse=True)
182
-
183
- # Build recommendation output
184
- recs = []
185
- recs.append(f"## Recommendations for: {task}\n")
186
- recs.append(f"*{task_info['description']}*\n")
187
-
188
- if use_case:
189
- recs.append(f"**Your use case:** {use_case}\n")
190
-
191
- recs.append("---\n")
192
-
193
  for i, model in enumerate(models[:4], 1):
194
  recs.append(f"### {i}. {model['name']}")
195
  recs.append(f"- **Size:** {model['size']} parameters")
196
  recs.append(f"- **License:** {model['license']}")
197
  recs.append(f"- **Link:** [View on HuggingFace](https://huggingface.co/{model['name']})")
198
  recs.append("")
199
-
200
- # Build code example
201
- code = generate_code_example(task, models[0] if models else None)
202
-
203
- return "\n".join(recs), code
204
-
205
-
206
- def generate_code_example(task: str, model: Optional[dict]) -> str:
207
- """Generate code example for using the recommended model."""
208
-
209
- if not model:
210
- return ""
211
-
212
- model_name = model["name"]
213
-
214
- code_templates = {
215
- "Text Generation": f'''```python
216
- from transformers import pipeline
217
-
218
- generator = pipeline("text-generation", model="{model_name}")
219
-
220
- result = generator(
221
- "Write a story about a robot:",
222
- max_length=100,
223
- num_return_sequences=1
224
- )
225
- print(result[0]["generated_text"])
226
- ```''',
227
-
228
- "Text Classification": f'''```python
229
- from transformers import pipeline
230
-
231
- classifier = pipeline("text-classification", model="{model_name}")
232
-
233
- result = classifier("I love this product! It's amazing!")
234
- print(result) # [{{'label': 'POSITIVE', 'score': 0.99}}]
235
- ```''',
236
-
237
- "Question Answering": f'''```python
238
- from transformers import pipeline
239
-
240
- qa = pipeline("question-answering", model="{model_name}")
241
-
242
- result = qa(
243
- question="What is the capital of France?",
244
- context="France is a country in Europe. Paris is its capital city."
245
- )
246
- print(result["answer"]) # Paris
247
- ```''',
248
-
249
- "Translation": f'''```python
250
- from transformers import pipeline
251
-
252
- translator = pipeline("translation", model="{model_name}")
253
-
254
- result = translator("Hello, how are you?")
255
- print(result[0]["translation_text"])
256
- ```''',
257
-
258
- "Summarization": f'''```python
259
- from transformers import pipeline
260
-
261
- summarizer = pipeline("summarization", model="{model_name}")
262
-
263
- long_text = """Your long article text here..."""
264
- result = summarizer(long_text, max_length=130, min_length=30)
265
- print(result[0]["summary_text"])
266
- ```''',
267
-
268
- "Image Classification": f'''```python
269
- from transformers import pipeline
270
-
271
- classifier = pipeline("image-classification", model="{model_name}")
272
-
273
- result = classifier("path/to/image.jpg")
274
- print(result) # [{{'label': 'cat', 'score': 0.95}}]
275
- ```''',
276
-
277
- "Speech Recognition": f'''```python
278
- from transformers import pipeline
279
-
280
- transcriber = pipeline("automatic-speech-recognition", model="{model_name}")
281
-
282
- result = transcriber("audio.mp3")
283
- print(result["text"])
284
- ```''',
285
-
286
- "Embeddings": f'''```python
287
- from sentence_transformers import SentenceTransformer
288
-
289
- model = SentenceTransformer("{model_name}")
290
-
291
- sentences = ["This is a sentence", "This is another sentence"]
292
- embeddings = model.encode(sentences)
293
- print(embeddings.shape) # (2, 384)
294
- ```''',
295
- }
296
-
297
- return code_templates.get(task, f'''```python
298
- from transformers import pipeline
299
-
300
- pipe = pipeline("{TASKS[task]['id']}", model="{model_name}")
301
- result = pipe("Your input here")
302
- print(result)
303
- ```''')
304
 
305
 
306
  # ---------------------------------------------------------------------------
 
5
  """
6
 
7
  import gradio as gr
8
+
9
+ from core import (
10
+ SIZE_PREFERENCES,
11
+ fetch_live_models,
12
+ generate_code_example,
13
+ rank_curated,
14
+ )
15
 
16
  # ---------------------------------------------------------------------------
17
  # Task Categories and Model Recommendations
 
38
  {"name": "distilbert-base-uncased-finetuned-sst-2-english", "size": "67M", "license": "apache-2.0"},
39
  {"name": "cardiffnlp/twitter-roberta-base-sentiment-latest", "size": "125M", "license": "mit"},
40
  {"name": "facebook/bart-large-mnli", "size": "400M", "license": "mit"},
 
41
  ]
42
  },
43
  "Question Answering": {
 
130
  },
131
  }
132
 
 
 
 
 
 
 
 
 
133
  # ---------------------------------------------------------------------------
134
+ # Recommendation logic
135
  # ---------------------------------------------------------------------------
136
 
137
+ def get_recommendations(task: str, size_pref: str, priority: str, use_case: str) -> tuple[str, str]:
138
+ """Recommend models for a task, querying the Hub live with a curated fallback."""
 
 
 
 
 
 
139
  if task not in TASKS:
140
  return "Please select a task.", ""
141
 
142
  task_info = TASKS[task]
143
+ task_id = task_info["id"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
 
145
+ header = [
146
+ f"## Recommendations for: {task}\n",
147
+ f"*{task_info['description']}*\n",
148
+ ]
149
+ if use_case:
150
+ header.append(f"**Your use case:** {use_case}\n")
151
+
152
+ # 1) Try a live query against the HuggingFace Hub.
153
+ live = fetch_live_models(task_id, limit=8)
154
+ if live:
155
+ if priority == "Best Quality":
156
+ live = sorted(live, key=lambda m: m["likes"], reverse=True)
157
+ recs = header + ["_Live from the HuggingFace Hub, sorted by downloads._\n"]
158
+ if size_pref != "Any size":
159
+ recs.append(
160
+ "> Size filtering applies to the curated fallback; live results "
161
+ "are ranked by popularity.\n"
162
+ )
163
+ recs.append("---\n")
164
+ for i, m in enumerate(live[:5], 1):
165
+ recs.append(f"### {i}. {m['name']}")
166
+ recs.append(f"- **Downloads:** {m['downloads']:,} | **Likes:** {m['likes']:,}")
167
+ recs.append(f"- **Link:** [View on HuggingFace](https://huggingface.co/{m['name']})")
168
+ recs.append("")
169
+ return "\n".join(recs), generate_code_example(task, task_id, live[0]["name"])
170
+
171
+ # 2) Fall back to the curated list (e.g. when offline or rate-limited).
172
+ models = rank_curated(task_info["top_models"], size_pref, priority)
173
  if not models:
174
  return "No models match your size preference. Try 'Any size'.", ""
175
+ recs = header + ["_Curated picks (live Hub query unavailable right now)._\n", "---\n"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  for i, model in enumerate(models[:4], 1):
177
  recs.append(f"### {i}. {model['name']}")
178
  recs.append(f"- **Size:** {model['size']} parameters")
179
  recs.append(f"- **License:** {model['license']}")
180
  recs.append(f"- **Link:** [View on HuggingFace](https://huggingface.co/{model['name']})")
181
  recs.append("")
182
+ return "\n".join(recs), generate_code_example(task, task_id, models[0]["name"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
 
184
 
185
  # ---------------------------------------------------------------------------
core.py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Pure logic for the model selector (no Gradio import) so it is unit-testable.
2
+
3
+ The live Hub query is isolated in :func:`fetch_live_models` with a lazy
4
+ ``huggingface_hub`` import and an injectable ``lister`` for testing, and it
5
+ fails soft (returns ``None``) so the UI can fall back to a curated list.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import re
11
+ from typing import Optional
12
+
13
+ SIZE_PREFERENCES = {
14
+ "Tiny (< 100M)": {"min": 0, "max": 100},
15
+ "Small (100M - 500M)": {"min": 100, "max": 500},
16
+ "Medium (500M - 2B)": {"min": 500, "max": 2000},
17
+ "Large (2B - 10B)": {"min": 2000, "max": 10000},
18
+ "Any size": {"min": 0, "max": 100000},
19
+ }
20
+
21
+
22
+ def parse_size(size_str: str) -> float:
23
+ """Parse a parameter-count string like '7B', '67M', '1.5B' to millions.
24
+
25
+ Returns 0.0 for unparseable input rather than guessing.
26
+ """
27
+ if not size_str:
28
+ return 0.0
29
+ s = str(size_str).strip().upper().replace(",", "")
30
+ match = re.match(r"([0-9]*\.?[0-9]+)\s*([BMK]?)", s)
31
+ if not match:
32
+ return 0.0
33
+ val = float(match.group(1))
34
+ unit = match.group(2)
35
+ if unit == "B":
36
+ return val * 1000.0
37
+ if unit == "K":
38
+ return val / 1000.0
39
+ return val # 'M' or unspecified -> already millions
40
+
41
+
42
+ def rank_curated(models: list[dict], size_pref: str, priority: str) -> list[dict]:
43
+ """Filter curated models by size preference and order them by priority."""
44
+ size_range = SIZE_PREFERENCES.get(size_pref, SIZE_PREFERENCES["Any size"])
45
+ if size_pref != "Any size":
46
+ models = [
47
+ m
48
+ for m in models
49
+ if size_range["min"] <= parse_size(m["size"]) <= size_range["max"]
50
+ ]
51
+ if priority == "Smallest/Fastest":
52
+ models = sorted(models, key=lambda x: parse_size(x["size"]))
53
+ elif priority == "Best Quality":
54
+ models = sorted(models, key=lambda x: parse_size(x["size"]), reverse=True)
55
+ # "Most Popular" keeps the curated order.
56
+ return models
57
+
58
+
59
+ def fetch_live_models(
60
+ task_id: str, limit: int = 8, lister=None
61
+ ) -> Optional[list[dict]]:
62
+ """Return live top models for a pipeline task from the Hub.
63
+
64
+ Sorted by downloads (desc). Returns ``None`` on any failure so callers can
65
+ fall back to a curated list. ``lister`` is injectable for testing.
66
+ """
67
+ try:
68
+ if lister is None:
69
+ from huggingface_hub import list_models as lister
70
+ results = lister(filter=task_id, sort="downloads", direction=-1, limit=limit)
71
+ out = []
72
+ for m in results:
73
+ name = getattr(m, "id", None) or getattr(m, "modelId", None)
74
+ if not name:
75
+ continue
76
+ out.append(
77
+ {
78
+ "name": name,
79
+ "downloads": int(getattr(m, "downloads", 0) or 0),
80
+ "likes": int(getattr(m, "likes", 0) or 0),
81
+ }
82
+ )
83
+ return out or None
84
+ except Exception:
85
+ return None
86
+
87
+
88
+ def generate_code_example(
89
+ task_label: str, task_id: str, model_name: Optional[str]
90
+ ) -> str:
91
+ """Generate a code snippet for using the recommended model."""
92
+ if not model_name:
93
+ return ""
94
+
95
+ code_templates = {
96
+ "Text Generation": f'''```python
97
+ from transformers import pipeline
98
+
99
+ generator = pipeline("text-generation", model="{model_name}")
100
+
101
+ result = generator(
102
+ "Write a story about a robot:",
103
+ max_length=100,
104
+ num_return_sequences=1
105
+ )
106
+ print(result[0]["generated_text"])
107
+ ```''',
108
+ "Text Classification": f'''```python
109
+ from transformers import pipeline
110
+
111
+ classifier = pipeline("text-classification", model="{model_name}")
112
+
113
+ result = classifier("I love this product! It's amazing!")
114
+ print(result) # [{{'label': 'POSITIVE', 'score': 0.99}}]
115
+ ```''',
116
+ "Question Answering": f'''```python
117
+ from transformers import pipeline
118
+
119
+ qa = pipeline("question-answering", model="{model_name}")
120
+
121
+ result = qa(
122
+ question="What is the capital of France?",
123
+ context="France is a country in Europe. Paris is its capital city."
124
+ )
125
+ print(result["answer"]) # Paris
126
+ ```''',
127
+ "Translation": f'''```python
128
+ from transformers import pipeline
129
+
130
+ translator = pipeline("translation", model="{model_name}")
131
+
132
+ result = translator("Hello, how are you?")
133
+ print(result[0]["translation_text"])
134
+ ```''',
135
+ "Summarization": f'''```python
136
+ from transformers import pipeline
137
+
138
+ summarizer = pipeline("summarization", model="{model_name}")
139
+
140
+ long_text = """Your long article text here..."""
141
+ result = summarizer(long_text, max_length=130, min_length=30)
142
+ print(result[0]["summary_text"])
143
+ ```''',
144
+ "Image Classification": f'''```python
145
+ from transformers import pipeline
146
+
147
+ classifier = pipeline("image-classification", model="{model_name}")
148
+
149
+ result = classifier("path/to/image.jpg")
150
+ print(result) # [{{'label': 'cat', 'score': 0.95}}]
151
+ ```''',
152
+ "Speech Recognition": f'''```python
153
+ from transformers import pipeline
154
+
155
+ transcriber = pipeline("automatic-speech-recognition", model="{model_name}")
156
+
157
+ result = transcriber("audio.mp3")
158
+ print(result["text"])
159
+ ```''',
160
+ "Embeddings": f'''```python
161
+ from sentence_transformers import SentenceTransformer
162
+
163
+ model = SentenceTransformer("{model_name}")
164
+
165
+ sentences = ["This is a sentence", "This is another sentence"]
166
+ embeddings = model.encode(sentences)
167
+ print(embeddings.shape) # (2, 384)
168
+ ```''',
169
+ }
170
+
171
+ return code_templates.get(
172
+ task_label,
173
+ f'''```python
174
+ from transformers import pipeline
175
+
176
+ pipe = pipeline("{task_id}", model="{model_name}")
177
+ result = pipe("Your input here")
178
+ print(result)
179
+ ```''',
180
+ )
requirements.txt CHANGED
@@ -1,2 +1,2 @@
1
- gradio>=5.31.0
2
- huggingface_hub>=0.20.0
 
1
+ gradio>=5.31.0,<6.0.0
2
+ huggingface_hub>=0.20.0,<1.0.0