marduk191 commited on
Commit
a92cd29
·
1 Parent(s): 3080918
Files changed (3) hide show
  1. app.py +159 -0
  2. config.json +61 -0
  3. static/style.css +269 -0
app.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import os
4
+ from pathlib import Path
5
+
6
+ def load_config():
7
+ """Load configuration from config.json"""
8
+ config_path = Path(__file__).parent / "config.json"
9
+ with open(config_path, 'r', encoding='utf-8') as f:
10
+ return json.load(f)
11
+
12
+ def get_custom_css():
13
+ """Load custom CSS if available"""
14
+ css_path = Path(__file__).parent / "static" / "style.css"
15
+ if css_path.exists():
16
+ with open(css_path, 'r', encoding='utf-8') as f:
17
+ return f.read()
18
+ return ""
19
+
20
+ def create_category_card(category):
21
+ """Create HTML for a category card"""
22
+ return f"""
23
+ <div class="category-card">
24
+ <div class="category-icon">{category['icon']}</div>
25
+ <h3>{category['name']}</h3>
26
+ <p>{category['description']}</p>
27
+ </div>
28
+ """
29
+
30
+ def create_model_card(item, item_type="model"):
31
+ """Create HTML for a model or dataset card"""
32
+ tags_html = " ".join([f'<span class="tag">{tag}</span>' for tag in item.get('tags', [])])
33
+
34
+ links = []
35
+ if item.get('repo'):
36
+ links.append(f'<a href="https://huggingface.co/{item["repo"]}" target="_blank" class="card-link">🤗 View on HF</a>')
37
+ if item.get('demo_url'):
38
+ links.append(f'<a href="{item["demo_url"]}" target="_blank" class="card-link">🚀 Demo</a>')
39
+ if item.get('paper_url'):
40
+ links.append(f'<a href="{item["paper_url"]}" target="_blank" class="card-link">📄 Paper</a>')
41
+
42
+ links_html = " ".join(links)
43
+
44
+ size_info = f'<div class="card-size">{item["size"]}</div>' if item.get('size') else ''
45
+
46
+ return f"""
47
+ <div class="item-card">
48
+ <h3>{item['name']}</h3>
49
+ <p class="card-description">{item.get('description', '')}</p>
50
+ {size_info}
51
+ <div class="card-tags">{tags_html}</div>
52
+ <div class="card-links">{links_html}</div>
53
+ </div>
54
+ """
55
+
56
+ def create_header(config):
57
+ """Create site header"""
58
+ site = config['site']
59
+ social_links = []
60
+
61
+ if site['social_links'].get('github'):
62
+ social_links.append(f'<a href="{site["social_links"]["github"]}" target="_blank">GitHub</a>')
63
+ if site['social_links'].get('twitter'):
64
+ social_links.append(f'<a href="{site["social_links"]["twitter"]}" target="_blank">Twitter</a>')
65
+ if site['social_links'].get('linkedin'):
66
+ social_links.append(f'<a href="{site["social_links"]["linkedin"]}" target="_blank">LinkedIn</a>')
67
+
68
+ social_html = " · ".join(social_links) if social_links else ""
69
+
70
+ return f"""
71
+ <div class="site-header">
72
+ <h1>{site['title']}</h1>
73
+ <p class="site-description">{site['description']}</p>
74
+ <p class="site-author">by {site['author']}</p>
75
+ <div class="social-links">{social_html}</div>
76
+ </div>
77
+ """
78
+
79
+ def create_category_section(config, category_id):
80
+ """Create a section showing items from a specific category"""
81
+ models = [m for m in config.get('models', []) if m.get('category') == category_id]
82
+ datasets = [d for d in config.get('datasets', []) if d.get('category') == category_id]
83
+
84
+ html = "<div class='items-grid'>"
85
+
86
+ for model in models:
87
+ html += create_model_card(model, "model")
88
+
89
+ for dataset in datasets:
90
+ html += create_model_card(dataset, "dataset")
91
+
92
+ html += "</div>"
93
+
94
+ if not models and not datasets:
95
+ html = "<p class='no-items'>No items in this category yet.</p>"
96
+
97
+ return html
98
+
99
+ def build_interface():
100
+ """Build the Gradio interface"""
101
+ config = load_config()
102
+ custom_css = get_custom_css()
103
+
104
+ with gr.Blocks(
105
+ title=config['site']['title'],
106
+ css=custom_css,
107
+ theme=gr.themes.Soft(primary_hue="indigo")
108
+ ) as demo:
109
+
110
+ # Header
111
+ gr.HTML(create_header(config))
112
+
113
+ # Categories Overview
114
+ gr.Markdown("## 📂 Categories", elem_classes="section-title")
115
+
116
+ categories_html = "<div class='categories-grid'>"
117
+ for category in config['categories']:
118
+ categories_html += create_category_card(category)
119
+ categories_html += "</div>"
120
+
121
+ gr.HTML(categories_html)
122
+
123
+ # Create tabs for each category
124
+ with gr.Tabs():
125
+ for category in config['categories']:
126
+ with gr.Tab(f"{category['icon']} {category['name']}"):
127
+ gr.Markdown(f"### {category['description']}")
128
+ category_html = create_category_section(config, category['id'])
129
+ gr.HTML(category_html)
130
+
131
+ # All items tab
132
+ with gr.Tab("🌐 All Items"):
133
+ gr.Markdown("### All Models and Datasets")
134
+ all_html = "<div class='items-grid'>"
135
+
136
+ for model in config.get('models', []):
137
+ all_html += create_model_card(model, "model")
138
+
139
+ for dataset in config.get('datasets', []):
140
+ all_html += create_model_card(dataset, "dataset")
141
+
142
+ all_html += "</div>"
143
+ gr.HTML(all_html)
144
+
145
+ # Footer
146
+ gr.Markdown("""
147
+ ---
148
+ <div style="text-align: center; color: #666; padding: 20px;">
149
+ Built with <a href="https://github.com/marduk191/hf_site_builder" target="_blank">HF Site Builder</a> |
150
+ Powered by <a href="https://gradio.app" target="_blank">Gradio</a> &
151
+ <a href="https://huggingface.co/spaces" target="_blank">Hugging Face Spaces</a>
152
+ </div>
153
+ """)
154
+
155
+ return demo
156
+
157
+ if __name__ == "__main__":
158
+ demo = build_interface()
159
+ demo.launch()
config.json ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "site": {
3
+ "title": "My AI Model Hub",
4
+ "description": "Explore my collection of AI models and datasets",
5
+ "author": "Your Name",
6
+ "theme_color": "#4F46E5",
7
+ "header_image": null,
8
+ "social_links": {
9
+ "github": "",
10
+ "twitter": "",
11
+ "linkedin": ""
12
+ }
13
+ },
14
+ "categories": [
15
+ {
16
+ "id": "nlp",
17
+ "name": "Natural Language Processing",
18
+ "icon": "💬",
19
+ "description": "Models for text understanding and generation"
20
+ },
21
+ {
22
+ "id": "vision",
23
+ "name": "Computer Vision",
24
+ "icon": "👁️",
25
+ "description": "Image and video processing models"
26
+ },
27
+ {
28
+ "id": "audio",
29
+ "name": "Audio Processing",
30
+ "icon": "🎵",
31
+ "description": "Speech and sound analysis models"
32
+ },
33
+ {
34
+ "id": "datasets",
35
+ "name": "Datasets",
36
+ "icon": "📊",
37
+ "description": "Curated datasets for training and evaluation"
38
+ }
39
+ ],
40
+ "models": [
41
+ {
42
+ "name": "Example Text Classifier",
43
+ "repo": "username/model-name",
44
+ "category": "nlp",
45
+ "description": "A fine-tuned model for text classification",
46
+ "tags": ["classification", "bert", "nlp"],
47
+ "demo_url": null,
48
+ "paper_url": null
49
+ }
50
+ ],
51
+ "datasets": [
52
+ {
53
+ "name": "Example Dataset",
54
+ "repo": "username/dataset-name",
55
+ "category": "datasets",
56
+ "description": "A curated dataset for specific tasks",
57
+ "tags": ["text", "classification"],
58
+ "size": "100K samples"
59
+ }
60
+ ]
61
+ }
static/style.css ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Modern styling for HF Site Builder */
2
+
3
+ :root {
4
+ --primary-color: #4F46E5;
5
+ --secondary-color: #7C3AED;
6
+ --accent-color: #EC4899;
7
+ --text-color: #1F2937;
8
+ --text-light: #6B7280;
9
+ --bg-color: #F9FAFB;
10
+ --card-bg: #FFFFFF;
11
+ --border-color: #E5E7EB;
12
+ --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
13
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
14
+ }
15
+
16
+ /* Global Styles */
17
+ body {
18
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
19
+ color: var(--text-color);
20
+ }
21
+
22
+ /* Site Header */
23
+ .site-header {
24
+ text-align: center;
25
+ padding: 3rem 2rem;
26
+ background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
27
+ color: white;
28
+ border-radius: 12px;
29
+ margin-bottom: 2rem;
30
+ box-shadow: var(--shadow-lg);
31
+ }
32
+
33
+ .site-header h1 {
34
+ font-size: 2.5rem;
35
+ font-weight: 800;
36
+ margin-bottom: 0.5rem;
37
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
38
+ }
39
+
40
+ .site-description {
41
+ font-size: 1.25rem;
42
+ margin-bottom: 0.5rem;
43
+ opacity: 0.95;
44
+ }
45
+
46
+ .site-author {
47
+ font-size: 1rem;
48
+ opacity: 0.85;
49
+ margin-bottom: 1rem;
50
+ }
51
+
52
+ .social-links {
53
+ margin-top: 1rem;
54
+ }
55
+
56
+ .social-links a {
57
+ color: white;
58
+ text-decoration: none;
59
+ margin: 0 0.5rem;
60
+ opacity: 0.9;
61
+ transition: opacity 0.2s;
62
+ font-weight: 500;
63
+ }
64
+
65
+ .social-links a:hover {
66
+ opacity: 1;
67
+ text-decoration: underline;
68
+ }
69
+
70
+ /* Section Titles */
71
+ .section-title {
72
+ font-size: 1.75rem;
73
+ font-weight: 700;
74
+ margin-top: 2rem;
75
+ margin-bottom: 1.5rem;
76
+ color: var(--text-color);
77
+ }
78
+
79
+ /* Categories Grid */
80
+ .categories-grid {
81
+ display: grid;
82
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
83
+ gap: 1.5rem;
84
+ margin: 2rem 0;
85
+ }
86
+
87
+ .category-card {
88
+ background: var(--card-bg);
89
+ border: 2px solid var(--border-color);
90
+ border-radius: 12px;
91
+ padding: 2rem;
92
+ text-align: center;
93
+ transition: all 0.3s ease;
94
+ box-shadow: var(--shadow);
95
+ }
96
+
97
+ .category-card:hover {
98
+ transform: translateY(-4px);
99
+ box-shadow: var(--shadow-lg);
100
+ border-color: var(--primary-color);
101
+ }
102
+
103
+ .category-icon {
104
+ font-size: 3rem;
105
+ margin-bottom: 1rem;
106
+ }
107
+
108
+ .category-card h3 {
109
+ font-size: 1.25rem;
110
+ font-weight: 700;
111
+ margin-bottom: 0.5rem;
112
+ color: var(--text-color);
113
+ }
114
+
115
+ .category-card p {
116
+ color: var(--text-light);
117
+ font-size: 0.95rem;
118
+ line-height: 1.5;
119
+ }
120
+
121
+ /* Items Grid */
122
+ .items-grid {
123
+ display: grid;
124
+ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
125
+ gap: 1.5rem;
126
+ margin: 2rem 0;
127
+ }
128
+
129
+ .item-card {
130
+ background: var(--card-bg);
131
+ border: 1px solid var(--border-color);
132
+ border-radius: 12px;
133
+ padding: 1.5rem;
134
+ transition: all 0.3s ease;
135
+ box-shadow: var(--shadow);
136
+ display: flex;
137
+ flex-direction: column;
138
+ }
139
+
140
+ .item-card:hover {
141
+ transform: translateY(-4px);
142
+ box-shadow: var(--shadow-lg);
143
+ border-color: var(--primary-color);
144
+ }
145
+
146
+ .item-card h3 {
147
+ font-size: 1.25rem;
148
+ font-weight: 700;
149
+ margin-bottom: 0.75rem;
150
+ color: var(--text-color);
151
+ }
152
+
153
+ .card-description {
154
+ color: var(--text-light);
155
+ font-size: 0.95rem;
156
+ line-height: 1.6;
157
+ margin-bottom: 1rem;
158
+ flex-grow: 1;
159
+ }
160
+
161
+ .card-size {
162
+ display: inline-block;
163
+ background: var(--bg-color);
164
+ color: var(--text-light);
165
+ padding: 0.25rem 0.75rem;
166
+ border-radius: 6px;
167
+ font-size: 0.85rem;
168
+ font-weight: 600;
169
+ margin-bottom: 0.75rem;
170
+ }
171
+
172
+ .card-tags {
173
+ display: flex;
174
+ flex-wrap: wrap;
175
+ gap: 0.5rem;
176
+ margin-bottom: 1rem;
177
+ }
178
+
179
+ .tag {
180
+ display: inline-block;
181
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
182
+ color: white;
183
+ padding: 0.25rem 0.75rem;
184
+ border-radius: 6px;
185
+ font-size: 0.8rem;
186
+ font-weight: 600;
187
+ }
188
+
189
+ .card-links {
190
+ display: flex;
191
+ flex-wrap: wrap;
192
+ gap: 0.75rem;
193
+ margin-top: auto;
194
+ padding-top: 1rem;
195
+ border-top: 1px solid var(--border-color);
196
+ }
197
+
198
+ .card-link {
199
+ display: inline-flex;
200
+ align-items: center;
201
+ padding: 0.5rem 1rem;
202
+ background: var(--primary-color);
203
+ color: white;
204
+ text-decoration: none;
205
+ border-radius: 8px;
206
+ font-size: 0.9rem;
207
+ font-weight: 600;
208
+ transition: all 0.2s ease;
209
+ }
210
+
211
+ .card-link:hover {
212
+ background: var(--secondary-color);
213
+ transform: scale(1.05);
214
+ text-decoration: none;
215
+ }
216
+
217
+ .no-items {
218
+ text-align: center;
219
+ color: var(--text-light);
220
+ font-size: 1.1rem;
221
+ padding: 3rem;
222
+ background: var(--bg-color);
223
+ border-radius: 8px;
224
+ margin: 2rem 0;
225
+ }
226
+
227
+ /* Tabs Styling */
228
+ .tabs {
229
+ margin-top: 2rem;
230
+ }
231
+
232
+ /* Responsive Design */
233
+ @media (max-width: 768px) {
234
+ .site-header h1 {
235
+ font-size: 2rem;
236
+ }
237
+
238
+ .site-description {
239
+ font-size: 1.1rem;
240
+ }
241
+
242
+ .categories-grid,
243
+ .items-grid {
244
+ grid-template-columns: 1fr;
245
+ }
246
+
247
+ .category-card,
248
+ .item-card {
249
+ padding: 1.5rem;
250
+ }
251
+ }
252
+
253
+ /* Custom Scrollbar */
254
+ ::-webkit-scrollbar {
255
+ width: 10px;
256
+ }
257
+
258
+ ::-webkit-scrollbar-track {
259
+ background: var(--bg-color);
260
+ }
261
+
262
+ ::-webkit-scrollbar-thumb {
263
+ background: var(--primary-color);
264
+ border-radius: 5px;
265
+ }
266
+
267
+ ::-webkit-scrollbar-thumb:hover {
268
+ background: var(--secondary-color);
269
+ }