Commit
•
ad1cd58
0
Parent(s):
Duplicate from hysts/space-that-creates-model-demo-space
Browse filesCo-authored-by: hysts <hysts@users.noreply.huggingface.co>
- .gitattributes +31 -0
- .pre-commit-config.yaml +45 -0
- .style.yapf +5 -0
- README.md +13 -0
- app.py +173 -0
- assets/template.py +36 -0
.gitattributes
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
5 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
6 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
7 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
8 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
9 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
10 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
11 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
12 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
13 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
14 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
15 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
16 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
17 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
18 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
20 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
21 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
22 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
23 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
24 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
25 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
26 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
27 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
28 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
29 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
30 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
31 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
.pre-commit-config.yaml
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
repos:
|
2 |
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
3 |
+
rev: v4.2.0
|
4 |
+
hooks:
|
5 |
+
- id: check-executables-have-shebangs
|
6 |
+
- id: check-json
|
7 |
+
- id: check-merge-conflict
|
8 |
+
- id: check-shebang-scripts-are-executable
|
9 |
+
- id: check-toml
|
10 |
+
- id: check-yaml
|
11 |
+
- id: double-quote-string-fixer
|
12 |
+
- id: end-of-file-fixer
|
13 |
+
- id: mixed-line-ending
|
14 |
+
args: ['--fix=lf']
|
15 |
+
- id: requirements-txt-fixer
|
16 |
+
- id: trailing-whitespace
|
17 |
+
- repo: https://github.com/myint/docformatter
|
18 |
+
rev: v1.4
|
19 |
+
hooks:
|
20 |
+
- id: docformatter
|
21 |
+
args: ['--in-place']
|
22 |
+
- repo: https://github.com/pycqa/isort
|
23 |
+
rev: 5.10.1
|
24 |
+
hooks:
|
25 |
+
- id: isort
|
26 |
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
27 |
+
rev: v0.812
|
28 |
+
hooks:
|
29 |
+
- id: mypy
|
30 |
+
args: ['--ignore-missing-imports']
|
31 |
+
- repo: https://github.com/google/yapf
|
32 |
+
rev: v0.32.0
|
33 |
+
hooks:
|
34 |
+
- id: yapf
|
35 |
+
args: ['--parallel', '--in-place']
|
36 |
+
- repo: https://github.com/kynan/nbstripout
|
37 |
+
rev: 0.5.0
|
38 |
+
hooks:
|
39 |
+
- id: nbstripout
|
40 |
+
args: ['--extra-keys', 'metadata.interpreter metadata.kernelspec cell.metadata.pycharm']
|
41 |
+
- repo: https://github.com/nbQA-dev/nbQA
|
42 |
+
rev: 1.3.1
|
43 |
+
hooks:
|
44 |
+
- id: nbqa-isort
|
45 |
+
- id: nbqa-yapf
|
.style.yapf
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[style]
|
2 |
+
based_on_style = pep8
|
3 |
+
blank_line_before_nested_class_or_def = false
|
4 |
+
spaces_before_comment = 2
|
5 |
+
split_before_logical_operator = true
|
README.md
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
title: Space That Creates Model Demo Space
|
3 |
+
emoji: 🐠
|
4 |
+
colorFrom: yellow
|
5 |
+
colorTo: yellow
|
6 |
+
sdk: gradio
|
7 |
+
sdk_version: 3.1.6
|
8 |
+
app_file: app.py
|
9 |
+
pinned: false
|
10 |
+
duplicated_from: hysts/space-that-creates-model-demo-space
|
11 |
+
---
|
12 |
+
|
13 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
ADDED
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python
|
2 |
+
|
3 |
+
from __future__ import annotations
|
4 |
+
|
5 |
+
import shutil
|
6 |
+
import tempfile
|
7 |
+
|
8 |
+
import gradio as gr
|
9 |
+
from huggingface_hub import HfApi
|
10 |
+
|
11 |
+
title = 'Model Demo Creation'
|
12 |
+
description = '''
|
13 |
+
With this Space, you can create a demo Space for models that are loadable with `gradio.Interface.load` in [Model Hub](https://huggingface.co/models).
|
14 |
+
The Space will be created under your account and private.
|
15 |
+
You need a token with write permission (See: https://huggingface.co/settings/tokens).
|
16 |
+
|
17 |
+
You can specify multiple model names by listing them separated by commas.
|
18 |
+
If you specify multiple model names, the resulting Space will show all the outputs of those models side by side for the given inputs.
|
19 |
+
'''
|
20 |
+
article = ''
|
21 |
+
examples = [
|
22 |
+
[
|
23 |
+
'resnet-50',
|
24 |
+
'microsoft/resnet-50',
|
25 |
+
'',
|
26 |
+
'Demo for microsoft/resnet-50',
|
27 |
+
'',
|
28 |
+
'',
|
29 |
+
],
|
30 |
+
[
|
31 |
+
'compare-image-classification-models',
|
32 |
+
'google/vit-base-patch16-224, microsoft/resnet-50',
|
33 |
+
'',
|
34 |
+
'Compare Image Classification Models',
|
35 |
+
'',
|
36 |
+
'',
|
37 |
+
],
|
38 |
+
[
|
39 |
+
'compare-text-generation-models',
|
40 |
+
'EleutherAI/gpt-j-6B, EleutherAI/gpt-neo-1.3B',
|
41 |
+
'',
|
42 |
+
'Compare Text Generation Models',
|
43 |
+
'',
|
44 |
+
'',
|
45 |
+
],
|
46 |
+
]
|
47 |
+
|
48 |
+
api = HfApi()
|
49 |
+
|
50 |
+
|
51 |
+
def check_if_model_exists(model_name: str) -> bool:
|
52 |
+
return any(info.modelId == model_name
|
53 |
+
for info in api.list_models(search=model_name))
|
54 |
+
|
55 |
+
|
56 |
+
def check_if_model_loadable(model_name: str) -> bool:
|
57 |
+
try:
|
58 |
+
gr.Interface.load(model_name, src='models')
|
59 |
+
except Exception:
|
60 |
+
return False
|
61 |
+
return True
|
62 |
+
|
63 |
+
|
64 |
+
def get_model_io_types(
|
65 |
+
model_name: str) -> tuple[tuple[str, ...], tuple[str, ...]]:
|
66 |
+
iface = gr.Interface.load(model_name, src='models')
|
67 |
+
inputs = tuple(map(str, iface.input_components))
|
68 |
+
outputs = tuple(map(str, iface.output_components))
|
69 |
+
return inputs, outputs
|
70 |
+
|
71 |
+
|
72 |
+
def check_if_model_io_is_consistent(model_names: list[str]) -> bool:
|
73 |
+
if len(model_names) == 1:
|
74 |
+
return True
|
75 |
+
|
76 |
+
inputs0, outputs0 = get_model_io_types(model_names[0])
|
77 |
+
for name in model_names[1:]:
|
78 |
+
inputs, outputs = get_model_io_types(name)
|
79 |
+
if inputs != inputs0 or outputs != outputs0:
|
80 |
+
return False
|
81 |
+
return True
|
82 |
+
|
83 |
+
|
84 |
+
def save_space_info(dirname: str, filename: str, content: str) -> None:
|
85 |
+
with open(f'{dirname}/{filename}', 'w') as f:
|
86 |
+
f.write(content)
|
87 |
+
|
88 |
+
|
89 |
+
def run(space_name: str, model_names_str: str, hf_token: str, title: str,
|
90 |
+
description: str, article: str) -> str:
|
91 |
+
if space_name == '':
|
92 |
+
return 'Space Name must be specified.'
|
93 |
+
if model_names_str == '':
|
94 |
+
return 'Model Names must be specified.'
|
95 |
+
if hf_token == '':
|
96 |
+
return 'Hugging Face Token must be specified.'
|
97 |
+
|
98 |
+
model_names = [name.strip() for name in model_names_str.split(',')]
|
99 |
+
model_names_str = '\n'.join(model_names)
|
100 |
+
|
101 |
+
missing_models = [
|
102 |
+
name for name in model_names if not check_if_model_exists(name)
|
103 |
+
]
|
104 |
+
if len(missing_models) > 0:
|
105 |
+
message = 'The following models were not found: '
|
106 |
+
for model_name in missing_models:
|
107 |
+
message += f'\n{model_name}'
|
108 |
+
return message
|
109 |
+
|
110 |
+
non_loadable_models = [
|
111 |
+
name for name in model_names if not check_if_model_loadable(name)
|
112 |
+
]
|
113 |
+
if len(non_loadable_models) > 0:
|
114 |
+
message = 'The following models are not loadable with gradio.Interface.load: '
|
115 |
+
for model_name in non_loadable_models:
|
116 |
+
message += f'\n{model_name}'
|
117 |
+
return message
|
118 |
+
|
119 |
+
if not check_if_model_io_is_consistent(model_names):
|
120 |
+
return 'The inputs and outputs of each model must be the same.'
|
121 |
+
|
122 |
+
user_name = api.whoami(token=hf_token)['name']
|
123 |
+
repo_id = f'{user_name}/{space_name}'
|
124 |
+
try:
|
125 |
+
space_url = api.create_repo(repo_id=repo_id,
|
126 |
+
repo_type='space',
|
127 |
+
private=True,
|
128 |
+
token=hf_token,
|
129 |
+
space_sdk='gradio')
|
130 |
+
except Exception as e:
|
131 |
+
return str(e)
|
132 |
+
|
133 |
+
with tempfile.TemporaryDirectory() as temp_dir:
|
134 |
+
shutil.copy('assets/template.py', f'{temp_dir}/app.py')
|
135 |
+
save_space_info(temp_dir, 'TITLE', title)
|
136 |
+
save_space_info(temp_dir, 'DESCRIPTION', description)
|
137 |
+
save_space_info(temp_dir, 'ARTICLE', article)
|
138 |
+
save_space_info(temp_dir, 'MODEL_NAMES', model_names_str)
|
139 |
+
api.upload_folder(repo_id=repo_id,
|
140 |
+
folder_path=temp_dir,
|
141 |
+
path_in_repo='.',
|
142 |
+
token=hf_token,
|
143 |
+
repo_type='space')
|
144 |
+
|
145 |
+
return f'Successfully created: {space_url}'
|
146 |
+
|
147 |
+
|
148 |
+
gr.Interface(
|
149 |
+
fn=run,
|
150 |
+
inputs=[
|
151 |
+
gr.Textbox(
|
152 |
+
label='Space Name',
|
153 |
+
placeholder=
|
154 |
+
'e.g. demo-resnet-50. The Space will be created under your account and private.'
|
155 |
+
),
|
156 |
+
gr.Textbox(label='Model Names',
|
157 |
+
placeholder='e.g. microsoft/resnet-50'),
|
158 |
+
gr.Textbox(
|
159 |
+
label='Hugging Face Token',
|
160 |
+
placeholder=
|
161 |
+
'This should be a token with write permission. See: https://huggingface.co/settings/tokens'
|
162 |
+
),
|
163 |
+
gr.Textbox(label='Title (Optional)'),
|
164 |
+
gr.Textbox(label='Description (Optional)'),
|
165 |
+
gr.Textbox(label='Article (Optional)'),
|
166 |
+
],
|
167 |
+
outputs=gr.Textbox(label='Output'),
|
168 |
+
title=title,
|
169 |
+
description=description,
|
170 |
+
article=article,
|
171 |
+
examples=examples,
|
172 |
+
cache_examples=False,
|
173 |
+
).launch(enable_queue=True, share=False)
|
assets/template.py
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python
|
2 |
+
|
3 |
+
from __future__ import annotations
|
4 |
+
|
5 |
+
import gradio as gr
|
6 |
+
|
7 |
+
|
8 |
+
def read_info(file_name: str) -> str:
|
9 |
+
with open(file_name) as f:
|
10 |
+
content = f.read()
|
11 |
+
return content
|
12 |
+
|
13 |
+
|
14 |
+
def load_model(model_name: str) -> gr.Interface:
|
15 |
+
iface = gr.Interface.load(model_name, src='models')
|
16 |
+
for component in iface.output_components:
|
17 |
+
component.label = f'{component.label} ({model_name})'
|
18 |
+
return iface
|
19 |
+
|
20 |
+
|
21 |
+
def load_models(model_names: list[str]) -> list[gr.Interface]:
|
22 |
+
return [load_model(name) for name in model_names]
|
23 |
+
|
24 |
+
|
25 |
+
title = read_info('TITLE')
|
26 |
+
description = read_info('DESCRIPTION')
|
27 |
+
article = read_info('ARTICLE')
|
28 |
+
model_names = read_info('MODEL_NAMES').split('\n')
|
29 |
+
|
30 |
+
interfaces = load_models(model_names)
|
31 |
+
gr.Parallel(
|
32 |
+
*interfaces,
|
33 |
+
title=title,
|
34 |
+
description=description,
|
35 |
+
article=article,
|
36 |
+
).launch()
|