Blane187/multi-diffusion
3
1"""This module should not be used directly as its API is subject to change. Instead,2use the `gr.Blocks.load()` or `gr.load()` functions."""3 4from __future__ import annotations5 6import json7import os8import re9import tempfile10import warnings11from pathlib import Path12from typing import TYPE_CHECKING, Callable13 14import httpx15import huggingface_hub16from gradio_client import Client17from gradio_client.client import Endpoint18from gradio_client.documentation import document19from packaging import version20 21import gradio22from gradio import components, external_utils, utils23from gradio.context import Context24from gradio.exceptions import (25 GradioVersionIncompatibleError,26 ModelNotFoundError,27 TooManyRequestsError,28)29from gradio.processing_utils import save_base64_to_cache, to_binary30 31if TYPE_CHECKING:32 from gradio.blocks import Blocks33 from gradio.interface import Interface34 35 36server_timeout = 60037 38 39@document()40def load(41 name: str,42 src: str | None = None,43 hf_token: str | None = None,44 alias: str | None = None,45 **kwargs,46) -> Blocks:47 """48 Constructs a demo from a Hugging Face repo. Can accept model repos (if src is "models") or Space repos (if src is "spaces"). The input49 and output components are automatically loaded from the repo. Note that if a Space is loaded, certain high-level attributes of the Blocks (e.g.50 custom `css`, `js`, and `head` attributes) will not be loaded.51 Parameters:52 name: the name of the model (e.g. "gpt2" or "facebook/bart-base") or space (e.g. "flax-community/spanish-gpt2"), can include the `src` as prefix (e.g. "models/facebook/bart-base")53 src: the source of the model: `models` or `spaces` (or leave empty if source is provided as a prefix in `name`)54 hf_token: optional access token for loading private Hugging Face Hub models or spaces. Find your token here: https://huggingface.co/settings/tokens. Warning: only provide this if you are loading a trusted private Space as it can be read by the Space you are loading.55 alias: optional string used as the name of the loaded model instead of the default name (only applies if loading a Space running Gradio 2.x)56 Returns:57 a Gradio Blocks object for the given model58 Example:59 import gradio as gr60 demo = gr.load("gradio/question-answering", src="spaces")61 demo.launch()62 """63 return load_blocks_from_repo(64 name=name, src=src, hf_token=hf_token, alias=alias, **kwargs65 )66 67 68def load_blocks_from_repo(69 name: str,70 src: str | None = None,71 hf_token: str | None = None,72 alias: str | None = None,73 **kwargs,74) -> Blocks:75 """Creates and returns a Blocks instance from a Hugging Face model or Space repo."""76 if src is None:77 # Separate the repo type (e.g. "model") from repo name (e.g. "google/vit-base-patch16-224")78 tokens = name.split("/")79 if len(tokens) <= 1:80 raise ValueError(81 "Either `src` parameter must be provided, or `name` must be formatted as {src}/{repo name}"82 )83 src = tokens[0]84 name = "/".join(tokens[1:])85 86 factory_methods: dict[str, Callable] = {87 # for each repo type, we have a method that returns the Interface given the model name & optionally an hf_token88 "huggingface": from_model,89 "models": from_model,90 "spaces": from_spaces,91 }92 if src.lower() not in factory_methods:93 raise ValueError(f"parameter: src must be one of {factory_methods.keys()}")94 95 if hf_token is not None:96 if Context.hf_token is not None and Context.hf_token != hf_token:97 warnings.warn(98 """You are loading a model/Space with a different access token than the one you used to load a previous model/Space. This is not recommended, as it may cause unexpected behavior."""99 )100 Context.hf_token = hf_token101 102 blocks: gradio.Blocks = factory_methods[src](name, hf_token, alias, **kwargs)103 return blocks104 105 106def from_model(model_name: str, hf_token: str | None, alias: str | None, **kwargs):107 model_url = f"https://huggingface.co/{model_name}"108 api_url = f"https://api-inference.huggingface.co/models/{model_name}"109 print(f"Fetching model from: {model_url}")110 111 headers = {"Authorization": f"Bearer {hf_token}"} if hf_token is not None else {}112 response = httpx.request("GET", api_url, headers=headers)113 if response.status_code != 200:114 raise ModelNotFoundError(115 f"Could not find model: {model_name}. If it is a private or gated model, please provide your Hugging Face access token (https://huggingface.co/settings/tokens) as the argument for the `hf_token` parameter."116 )117 p = response.json().get("pipeline_tag")118 119 headers["X-Wait-For-Model"] = "true"120 client = huggingface_hub.InferenceClient(121 model=model_name, headers=headers, token=hf_token, timeout=server_timeout,122 )123 124 # For tasks that are not yet supported by the InferenceClient125 GRADIO_CACHE = os.environ.get("GRADIO_TEMP_DIR") or str( # noqa: N806126 Path(tempfile.gettempdir()) / "gradio"127 )128 129 def custom_post_binary(data):130 data = to_binary({"path": data})131 response = httpx.request("POST", api_url, headers=headers, content=data)132 return save_base64_to_cache(133 external_utils.encode_to_base64(response), cache_dir=GRADIO_CACHE134 )135 136 preprocess = None137 postprocess = None138 examples = None139 140 # example model: ehcalabres/wav2vec2-lg-xlsr-en-speech-emotion-recognition141 if p == "audio-classification":142 inputs = components.Audio(type="filepath", label="Input")143 outputs = components.Label(label="Class")144 postprocess = external_utils.postprocess_label145 examples = [146 "https://gradio-builds.s3.amazonaws.com/demo-files/audio_sample.wav"147 ]148 fn = client.audio_classification149 # example model: facebook/xm_transformer_sm_all-en150 elif p == "audio-to-audio":151 inputs = components.Audio(type="filepath", label="Input")152 outputs = components.Audio(label="Output")153 examples = [154 "https://gradio-builds.s3.amazonaws.com/demo-files/audio_sample.wav"155 ]156 fn = custom_post_binary157 # example model: facebook/wav2vec2-base-960h158 elif p == "automatic-speech-recognition":159 inputs = components.Audio(type="filepath", label="Input")160 outputs = components.Textbox(label="Output")161 examples = [162 "https://gradio-builds.s3.amazonaws.com/demo-files/audio_sample.wav"163 ]164 fn = client.automatic_speech_recognition165 # example model: microsoft/DialoGPT-medium166 elif p == "conversational":167 inputs = [168 components.Textbox(render=False),169 components.State(render=False),170 ]171 outputs = [172 components.Chatbot(render=False),173 components.State(render=False),174 ]175 examples = [["Hello World"]]176 preprocess = external_utils.chatbot_preprocess177 postprocess = external_utils.chatbot_postprocess178 fn = client.conversational179 # example model: julien-c/distilbert-feature-extraction180 elif p == "feature-extraction":181 inputs = components.Textbox(label="Input")182 outputs = components.Dataframe(label="Output")183 fn = client.feature_extraction184 postprocess = utils.resolve_singleton185 # example model: distilbert/distilbert-base-uncased186 elif p == "fill-mask":187 inputs = components.Textbox(label="Input")188 outputs = components.Label(label="Classification")189 examples = [190 "Hugging Face is the AI community, working together, to [MASK] the future."191 ]192 postprocess = external_utils.postprocess_mask_tokens193 fn = client.fill_mask194 # Example: google/vit-base-patch16-224195 elif p == "image-classification":196 inputs = components.Image(type="filepath", label="Input Image")197 outputs = components.Label(label="Classification")198 postprocess = external_utils.postprocess_label199 examples = ["https://gradio-builds.s3.amazonaws.com/demo-files/cheetah-002.jpg"]200 fn = client.image_classification201 # Example: deepset/xlm-roberta-base-squad2202 elif p == "question-answering":203 inputs = [204 components.Textbox(label="Question"),205 components.Textbox(lines=7, label="Context"),206 ]207 outputs = [208 components.Textbox(label="Answer"),209 components.Label(label="Score"),210 ]211 examples = [212 [213 "What entity was responsible for the Apollo program?",214 "The Apollo program, also known as Project Apollo, was the third United States human spaceflight"215 " program carried out by the National Aeronautics and Space Administration (NASA), which accomplished"216 " landing the first humans on the Moon from 1969 to 1972.",217 ]218 ]219 postprocess = external_utils.postprocess_question_answering220 fn = client.question_answering221 # Example: facebook/bart-large-cnn222 elif p == "summarization":223 inputs = components.Textbox(label="Input")224 outputs = components.Textbox(label="Summary")225 examples = [226 [227 "The tower is 324 metres (1,063 ft) tall, about the same height as an 81-storey building, and the tallest structure in Paris. Its base is square, measuring 125 metres (410 ft) on each side. During its construction, the Eiffel Tower surpassed the Washington Monument to become the tallest man-made structure in the world, a title it held for 41 years until the Chrysler Building in New York City was finished in 1930. It was the first structure to reach a height of 300 metres. Due to the addition of a broadcasting aerial at the top of the tower in 1957, it is now taller than the Chrysler Building by 5.2 metres (17 ft). Excluding transmitters, the Eiffel Tower is the second tallest free-standing structure in France after the Millau Viaduct."228 ]229 ]230 fn = client.summarization231 # Example: distilbert-base-uncased-finetuned-sst-2-english232 elif p == "text-classification":233 inputs = components.Textbox(label="Input")234 outputs = components.Label(label="Classification")235 examples = ["I feel great"]236 postprocess = external_utils.postprocess_label237 fn = client.text_classification238 # Example: gpt2239 elif p == "text-generation":240 inputs = components.Textbox(label="Text")241 outputs = inputs242 examples = ["Once upon a time"]243 fn = external_utils.text_generation_wrapper(client)244 # Example: valhalla/t5-small-qa-qg-hl245 elif p == "text2text-generation":246 inputs = components.Textbox(label="Input")247 outputs = components.Textbox(label="Generated Text")248 examples = ["Translate English to Arabic: How are you?"]249 fn = client.text_generation250 # Example: Helsinki-NLP/opus-mt-en-ar251 elif p == "translation":252 inputs = components.Textbox(label="Input")253 outputs = components.Textbox(label="Translation")254 examples = ["Hello, how are you?"]255 fn = client.translation256 # Example: facebook/bart-large-mnli257 elif p == "zero-shot-classification":258 inputs = [259 components.Textbox(label="Input"),260 components.Textbox(label="Possible class names (" "comma-separated)"),261 components.Checkbox(label="Allow multiple true classes"),262 ]263 outputs = components.Label(label="Classification")264 postprocess = external_utils.postprocess_label265 examples = [["I feel great", "happy, sad", False]]266 fn = external_utils.zero_shot_classification_wrapper(client)267 # Example: sentence-transformers/distilbert-base-nli-stsb-mean-tokens268 elif p == "sentence-similarity":269 inputs = [270 components.Textbox(271 label="Source Sentence",272 placeholder="Enter an original sentence",273 ),274 components.Textbox(275 lines=7,276 placeholder="Sentences to compare to -- separate each sentence by a newline",277 label="Sentences to compare to",278 ),279 ]280 outputs = components.JSON(label="Similarity scores")281 examples = [["That is a happy person", "That person is very happy"]]282 fn = external_utils.sentence_similarity_wrapper(client)283 # Example: julien-c/ljspeech_tts_train_tacotron2_raw_phn_tacotron_g2p_en_no_space_train284 elif p == "text-to-speech":285 inputs = components.Textbox(label="Input")286 outputs = components.Audio(label="Audio")287 examples = ["Hello, how are you?"]288 fn = client.text_to_speech289 # example model: osanseviero/BigGAN-deep-128290 elif p == "text-to-image":291 inputs = components.Textbox(label="Input")292 outputs = components.Image(label="Output")293 examples = ["A beautiful sunset"]294 fn = client.text_to_image295 # example model: huggingface-course/bert-finetuned-ner296 elif p == "token-classification":297 inputs = components.Textbox(label="Input")298 outputs = components.HighlightedText(label="Output")299 examples = [300 "Hugging Face is a company based in Paris and New York City that acquired Gradio in 2021."301 ]302 fn = external_utils.token_classification_wrapper(client)303 # example model: impira/layoutlm-document-qa304 elif p == "document-question-answering":305 inputs = [306 components.Image(type="filepath", label="Input Document"),307 components.Textbox(label="Question"),308 ]309 postprocess = external_utils.postprocess_label310 outputs = components.Label(label="Label")311 fn = client.document_question_answering312 # example model: dandelin/vilt-b32-finetuned-vqa313 elif p == "visual-question-answering":314 inputs = [315 components.Image(type="filepath", label="Input Image"),316 components.Textbox(label="Question"),317 ]318 outputs = components.Label(label="Label")319 postprocess = external_utils.postprocess_visual_question_answering320 examples = [321 [322 "https://gradio-builds.s3.amazonaws.com/demo-files/cheetah-002.jpg",323 "What animal is in the image?",324 ]325 ]326 fn = client.visual_question_answering327 # example model: Salesforce/blip-image-captioning-base328 elif p == "image-to-text":329 inputs = components.Image(type="filepath", label="Input Image")330 outputs = components.Textbox(label="Generated Text")331 examples = ["https://gradio-builds.s3.amazonaws.com/demo-files/cheetah-002.jpg"]332 fn = client.image_to_text333 # example model: rajistics/autotrain-Adult-934630783334 elif p in ["tabular-classification", "tabular-regression"]:335 examples = external_utils.get_tabular_examples(model_name)336 col_names, examples = external_utils.cols_to_rows(examples) # type: ignore337 examples = [[examples]] if examples else None338 inputs = components.Dataframe(339 label="Input Rows",340 type="pandas",341 headers=col_names,342 col_count=(len(col_names), "fixed"),343 render=False,344 )345 outputs = components.Dataframe(346 label="Predictions", type="array", headers=["prediction"]347 )348 fn = external_utils.tabular_wrapper349 # example model: microsoft/table-transformer-detection350 elif p == "object-detection":351 inputs = components.Image(type="filepath", label="Input Image")352 outputs = components.AnnotatedImage(label="Annotations")353 fn = external_utils.object_detection_wrapper(client)354 # example model: stabilityai/stable-diffusion-xl-refiner-1.0355 elif p == "image-to-image":356 inputs = [357 components.Image(type="filepath", label="Input Image"),358 components.Textbox(label="Input"),359 ]360 outputs = components.Image(label="Output")361 examples = [362 [363 "https://gradio-builds.s3.amazonaws.com/demo-files/cheetah-002.jpg",364 "Photo of a cheetah with green eyes",365 ]366 ]367 fn = client.image_to_image368 else:369 raise ValueError(f"Unsupported pipeline type: {p}")370 371 def query_huggingface_inference_endpoints(*data, **kwargs):372 if preprocess is not None:373 data = preprocess(*data)374 data = fn(*data, **kwargs) # type: ignore375 if postprocess is not None:376 data = postprocess(data) # type: ignore377 return data378 379 query_huggingface_inference_endpoints.__name__ = alias or model_name380 381 interface_info = {382 "fn": query_huggingface_inference_endpoints,383 "inputs": inputs,384 "outputs": outputs,385 "title": model_name,386 # "examples": examples,387 }388 389 kwargs = dict(interface_info, **kwargs)390 interface = gradio.Interface(**kwargs)391 return interface392 393 394def from_spaces(395 space_name: str, hf_token: str | None, alias: str | None, **kwargs396) -> Blocks:397 client = Client(398 space_name,399 hf_token=hf_token,400 download_files=False,401 _skip_components=False,402 )403 404 space_url = f"https://huggingface.co/spaces/{space_name}"405 406 print(f"Fetching Space from: {space_url}")407 408 headers = {}409 if hf_token is not None:410 headers["Authorization"] = f"Bearer {hf_token}"411 412 iframe_url = (413 httpx.get(414 f"https://huggingface.co/api/spaces/{space_name}/host", headers=headers415 )416 .json()417 .get("host")418 )419 420 if iframe_url is None:421 raise ValueError(422 f"Could not find Space: {space_name}. If it is a private or gated Space, please provide your Hugging Face access token (https://huggingface.co/settings/tokens) as the argument for the `hf_token` parameter."423 )424 425 r = httpx.get(iframe_url, headers=headers)426 427 result = re.search(428 r"window.gradio_config = (.*?);[\s]*</script>", r.text429 ) # some basic regex to extract the config430 try:431 config = json.loads(result.group(1)) # type: ignore432 except AttributeError as ae:433 raise ValueError(f"Could not load the Space: {space_name}") from ae434 if "allow_flagging" in config: # Create an Interface for Gradio 2.x Spaces435 return from_spaces_interface(436 space_name, config, alias, hf_token, iframe_url, **kwargs437 )438 else: # Create a Blocks for Gradio 3.x Spaces439 if kwargs:440 warnings.warn(441 "You cannot override parameters for this Space by passing in kwargs. "442 "Instead, please load the Space as a function and use it to create a "443 "Blocks or Interface locally. You may find this Guide helpful: "444 "https://gradio.app/using_blocks_like_functions/"445 )446 if client.app_version < version.Version("4.0.0b14"):447 return from_spaces_blocks(space=space_name, hf_token=hf_token)448 449 450def from_spaces_blocks(space: str, hf_token: str | None) -> Blocks:451 client = Client(452 space,453 hf_token=hf_token,454 download_files=False,455 _skip_components=False,456 )457 # We set deserialize to False to avoid downloading output files from the server.458 # Instead, we serve them as URLs using the /proxy/ endpoint directly from the server.459 460 if client.app_version < version.Version("4.0.0b14"):461 raise GradioVersionIncompatibleError(462 f"Gradio version 4.x cannot load spaces with versions less than 4.x ({client.app_version})."463 "Please downgrade to version 3 to load this space."464 )465 466 # Use end_to_end_fn here to properly upload/download all files467 predict_fns = []468 for fn_index, endpoint in client.endpoints.items():469 if not isinstance(endpoint, Endpoint):470 raise TypeError(471 f"Expected endpoint to be an Endpoint, but got {type(endpoint)}"472 )473 helper = client.new_helper(fn_index)474 if endpoint.backend_fn:475 predict_fns.append(endpoint.make_end_to_end_fn(helper))476 else:477 predict_fns.append(None)478 return gradio.Blocks.from_config(client.config, predict_fns, client.src) # type: ignore479 480 481def from_spaces_interface(482 model_name: str,483 config: dict,484 alias: str | None,485 hf_token: str | None,486 iframe_url: str,487 **kwargs,488) -> Interface:489 config = external_utils.streamline_spaces_interface(config)490 api_url = f"{iframe_url}/api/predict/"491 headers = {"Content-Type": "application/json"}492 if hf_token is not None:493 headers["Authorization"] = f"Bearer {hf_token}"494 495 # The function should call the API with preprocessed data496 def fn(*data):497 data = json.dumps({"data": data})498 response = httpx.post(api_url, headers=headers, data=data) # type: ignore499 result = json.loads(response.content.decode("utf-8"))500 if "error" in result and "429" in result["error"]:501 raise TooManyRequestsError("Too many requests to the Hugging Face API")502 try:503 output = result["data"]504 except KeyError as ke:505 raise KeyError(506 f"Could not find 'data' key in response from external Space. Response received: {result}"507 ) from ke508 if (509 len(config["outputs"]) == 1510 ): # if the fn is supposed to return a single value, pop it511 output = output[0]512 if (513 len(config["outputs"]) == 1 and isinstance(output, list)514 ): # Needed to support Output.Image() returning bounding boxes as well (TODO: handle different versions of gradio since they have slightly different APIs)515 output = output[0]516 return output517 518 fn.__name__ = alias if (alias is not None) else model_name519 config["fn"] = fn520 521 kwargs = dict(config, **kwargs)522 kwargs["_api_mode"] = True523 interface = gradio.Interface(**kwargs)524 return interface525 526 527def gr_Interface_load(528 name: str,529 src: str | None = None,530 hf_token: str | None = None,531 alias: str | None = None,532 **kwargs,533) -> Blocks:534 try:535 return load_blocks_from_repo(name, src, hf_token, alias)536 except Exception as e:537 print(e)538 return gradio.Interface(lambda: None, ['text'], ['image'])539 540 541def list_uniq(l):542 return sorted(set(l), key=l.index)543 544 545def get_status(model_name: str):546 from huggingface_hub import InferenceClient547 client = InferenceClient(timeout=10)548 return client.get_model_status(model_name)549 550 551def is_loadable(model_name: str, force_gpu: bool = False):552 try:553 status = get_status(model_name)554 except Exception as e:555 print(e)556 print(f"Couldn't load {model_name}.")557 return False558 gpu_state = isinstance(status.compute_type, dict) and "gpu" in status.compute_type.keys()559 if status is None or status.state not in ["Loadable", "Loaded"] or (force_gpu and not gpu_state):560 print(f"Couldn't load {model_name}. Model state:'{status.state}', GPU:{gpu_state}")561 return status is not None and status.state in ["Loadable", "Loaded"] and (not force_gpu or gpu_state)562 563 564def find_model_list(author: str="", tags: list[str]=[], not_tag="", sort: str="last_modified", limit: int=30, force_gpu=False, check_status=False):565 from huggingface_hub import HfApi566 api = HfApi()567 default_tags = ["diffusers"]568 if not sort: sort = "last_modified"569 limit = limit * 20 if check_status and force_gpu else limit * 5570 models = []571 try:572 model_infos = api.list_models(author=author, task="text-to-image",573 tags=list_uniq(default_tags + tags), cardData=True, sort=sort, limit=limit)574 except Exception as e:575 print(f"Error: Failed to list models.")576 print(e)577 return models578 for model in model_infos:579 if not model.private and not model.gated:580 loadable = is_loadable(model.id, force_gpu) if check_status else True581 if not_tag and not_tag in model.tags or not loadable: continue582 models.append(model.id)583 if len(models) == limit: break584 return models585 