Spaces:
Build error
Build error
| from typing import List | |
| import numpy as np | |
| import requests | |
| import gradio as gr | |
| import time | |
| import os | |
| from huggingface_hub import ( | |
| create_repo, | |
| get_full_repo_name, | |
| upload_file, | |
| ) | |
| class SpaceBuilder: | |
| error_message = None | |
| url = None | |
| def split_space_names(cls, names: str) -> List[str]: | |
| """ | |
| Splits and filters the given space_names. | |
| :param names: space names | |
| :return: Name List | |
| """ | |
| name_list = names.split("\n") | |
| filtered_list = [] | |
| for name in name_list: | |
| if not (name == "" or name.isspace()): | |
| name = name.replace(" ", "") | |
| filtered_list.append(name) | |
| return filtered_list | |
| def file_as_a_string(cls, name_list: List[str], title: str, description: str) -> str: | |
| """ | |
| Returns the file that is going to be created in the new space as string. | |
| :param name_list: list of space names | |
| :param title: title | |
| :param description: description | |
| :return: file as a string | |
| """ | |
| return ( | |
| f"import gradio as gr" | |
| f"\nname_list = {name_list}" | |
| f"\ninterfaces = [gr.Interface.load(name) for name in name_list]" | |
| f"\ngr.mix.Parallel(*interfaces, title=\"{title}\", description=\"{description}\").launch()" | |
| ) | |
| def control_input_and_output_types( | |
| cls, interface_list: List["gr.Interface"] | |
| ) -> bool: | |
| """ | |
| Controls whether if input and output types of the given interfaces are the same. | |
| :param interface_list: list of interfaces | |
| :return: True if all input and output types are the same | |
| """ | |
| first_input_types = [ | |
| type(input) for input in interface_list[0].input_components | |
| ] | |
| first_output_types = [ | |
| type(output) for output in interface_list[0].output_components | |
| ] | |
| for interface in interface_list: | |
| interface_input_types = [ | |
| type(input) for input in interface.input_components | |
| ] | |
| if not np.all( | |
| interface_input_types == first_input_types | |
| ): # Vectorize the comparison and don't use double for loop | |
| cls.error_message = "Provided space input types are different" | |
| return False | |
| interface_output_types = [ | |
| type(output) for output in interface.output_components | |
| ] | |
| if not np.all(interface_output_types == first_output_types): | |
| cls.error_message = "Provided space output types are different" | |
| return False | |
| return True | |
| def check_space_name_availability(cls, hf_token: str, space_name: str) -> bool: | |
| """ | |
| Check whether if the space_name is currently used. | |
| :param hf_token: hugging_face token | |
| :param space_name: | |
| :return: True if the space_name is available | |
| """ | |
| try: | |
| repo_name = get_full_repo_name(model_id=space_name, token=hf_token) | |
| except Exception as ex: | |
| print(ex) | |
| cls.error_message = "You have given an incorrect HuggingFace token" | |
| return False | |
| try: | |
| url = f"https://huggingface.co/spaces/{repo_name}" | |
| response = requests.get(url) | |
| if response.status_code == 200: | |
| cls.error_message = f"The {repo_name} is already used." | |
| return False | |
| else: | |
| print(f"The space name {repo_name} is available") | |
| return True | |
| except Exception as ex: | |
| print(ex) | |
| cls.error_message = "Can not send a request to https://huggingface.co" | |
| return False | |
| def load_and_check_spaces(cls, names: str) -> bool: | |
| """ | |
| Loads given space inputs as interfaces and checks whether if they are loadable. | |
| :param names: Input space names | |
| :return: True if check is successful | |
| """ | |
| name_list = cls.split_space_names(names) | |
| try: | |
| # We could gather these interfaces in parallel if gradio was supporting async gathering. It will probably be possible after the migration to the FastAPI is completed. | |
| interfaces = [gr.Interface.load(name) for name in name_list] | |
| except Exception as ex: | |
| print(ex) | |
| cls.error_message = ( | |
| f"One of the given space cannot be loaded to gradio, sorry for the inconvenience. " | |
| f"\nPlease use different input space names!" | |
| ) | |
| return False | |
| if not cls.control_input_and_output_types(interfaces): | |
| return False | |
| else: | |
| print("Loaded and checked input spaces, great it works!") | |
| return True | |
| def create_space(cls, input_space_names: str, target_space_name: str, hf_token: str, title: str, description: str) -> bool: | |
| """ | |
| Creates the target space with the given space names. | |
| :param input_space_names: Input space name_list | |
| :param target_space_name: Target space_name | |
| :param hf_token: HuggingFace Write Token | |
| :param title: Target Interface Title | |
| :param description: Target Interface Description | |
| :return: True if success | |
| """ | |
| name_list = cls.split_space_names(input_space_names) | |
| try: | |
| create_repo(name=target_space_name, token=hf_token, repo_type="space", space_sdk="gradio") | |
| except Exception as ex: | |
| print(ex) | |
| cls.error_message = "Please provide a correct space name as Only regular characters and '-', '_', '.' accepted. '--' and '..' are forbidden. '-' and '.' cannot start or end the name." | |
| return False | |
| repo_name = get_full_repo_name(model_id=target_space_name, token=hf_token) | |
| try: | |
| file_string = cls.file_as_a_string(name_list, title, description) | |
| temp_file = open("temp_file.txt", "w") | |
| temp_file.write(file_string) | |
| temp_file.close() | |
| except Exception as ex: | |
| print(ex) | |
| cls.error_message = "An exception occurred during temporary file writing" | |
| return False | |
| # Sleep a little bit otherwise the interface might not build at the space after uploading a file | |
| time.sleep(1) | |
| try: | |
| file_url = upload_file( | |
| path_or_fileobj="temp_file.txt", | |
| path_in_repo="app.py", | |
| repo_id=repo_name, | |
| repo_type="space", | |
| token=hf_token, | |
| ) | |
| cls.url = f"https://huggingface.co/spaces/{repo_name}" | |
| return True | |
| except Exception as ex: | |
| print(ex) | |
| cls.error_message = ( | |
| "An exception occurred during writing app.py to the target space" | |
| ) | |
| return False | |
| def build_space( | |
| model_or_space_names: str, hf_token: str, target_space_name: str, interface_title: str, interface_description: str | |
| ) -> str: | |
| """ | |
| Creates a space with given input spaces. | |
| :param model_or_space_names: Multiple model or space names split with new lines | |
| :param hf_token: HuggingFace token | |
| :param target_space_name: Target Space Name | |
| :param interface_title: Target Interface Title | |
| :param interface_description: Target Interface Description | |
| :return: | |
| """ | |
| if ( | |
| model_or_space_names== "" or model_or_space_names.isspace() | |
| or target_space_name == "" or target_space_name.isspace() | |
| or interface_title == "" or interface_title.isspace() | |
| or interface_description == "" or interface_description.isspace() | |
| ): | |
| return "Please fill all the inputs" | |
| if hf_token == "" or hf_token.isspace(): | |
| hf_token = os.environ['HF_SELF_TOKEN'] | |
| if not SpaceBuilder.check_space_name_availability(hf_token=hf_token, space_name=target_space_name): | |
| return SpaceBuilder.error_message | |
| if not SpaceBuilder.load_and_check_spaces(names=model_or_space_names): | |
| return SpaceBuilder.error_message | |
| if not SpaceBuilder.create_space(input_space_names=model_or_space_names, target_space_name=target_space_name, hf_token=hf_token, title=interface_title, description=interface_description): | |
| return SpaceBuilder.error_message | |
| url = SpaceBuilder.url | |
| return f"<a href={url}>{url}</a>" | |
| if __name__ == "__main__": | |
| print(f"Gradio Version: {gr.__version__}") | |
| iface = gr.Interface( | |
| fn=SpaceBuilder.build_space, | |
| inputs=[ | |
| gr.inputs.Textbox( | |
| lines=4, | |
| placeholder=( | |
| f"Drop model and space links at each line and I will create a new space comparing them. Usage examples:" | |
| f"\nspaces/onnx/GPT-2" | |
| f"\nmodels/gpt2-large" | |
| f"\nmodels/gpt2" | |
| ), | |
| ), | |
| gr.inputs.Textbox(lines=1, placeholder="HuggingFace Write Token"), | |
| gr.inputs.Textbox(lines=1, placeholder="Name for the target space, ie. space-building-space"), | |
| gr.inputs.Textbox(lines=1, placeholder="Title for the target space interface, ie. Title"), | |
| gr.inputs.Textbox(lines=1, placeholder="Description for the target space interface, ie. Description"), | |
| ], | |
| title="Model Comparator Space Builder", | |
| description="Welcome onboard 🤗, I can create a comparative space which will compare the models and/or spaces you provide to me. You can get your HF Write Token from [here](https://huggingface.co/settings/tokens). If you leave HF Token input empty, the space will release under the author's account, [farukozderim](https://huggingface.co/farukozderim). Finally, you can publish spaces as a clone of other spaces if you provide just a single model or space. Have fun :)", | |
| outputs=gr.outputs.HTML(label="URL"), | |
| examples= [ | |
| ["spaces/onnx/GPT-2 \nmodels/gpt2-large \nmodels/EleutherAI/gpt-j-6B", "", "example-name", "example-title", "example-description"] | |
| ,["spaces/onnx/GPT-2", "", "clone-space", "example-title", "example-description"] | |
| ], | |
| ) | |
| iface.launch() | |