VikasQblocks commited on
Commit
c5c1856
1 Parent(s): 0acc369

Add gradio app and monsterapi v2 client for SD Comparison gradio app.

Browse files
Files changed (2) hide show
  1. MonsterAPIClient.py +178 -0
  2. app.py +89 -0
MonsterAPIClient.py ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #MonsterAPIClient.py
2
+
3
+ """
4
+ Monster API Python client to connect to LLM models on monsterapi
5
+
6
+ Base URL: https://api.monsterapi.ai/v1/generate/{model}
7
+
8
+ Available models:
9
+ -----------------
10
+
11
+ LLMs:
12
+ 1. falcon-7b-instruct
13
+ 2. falcon-40b-instruct
14
+ 3. mpt-30B-instruct
15
+ 4. mpt-7b-instruct
16
+ 5. openllama-13b-base
17
+ 6. llama2-7b-chat
18
+
19
+ Text to Image:
20
+ 1. stable-diffusion v1.5
21
+ 2. stable-diffusion XL V1.0
22
+
23
+ """
24
+ import os
25
+ import time
26
+ import logging
27
+ import requests
28
+ from requests_toolbelt.multipart.encoder import MultipartEncoder
29
+
30
+ from typing import Optional, Literal, Union, List, Dict
31
+ from pydantic import BaseModel, Field
32
+
33
+ logging.basicConfig(level=logging.INFO)
34
+ logger = logging.getLogger(__name__)
35
+
36
+
37
+ class LLMInputModel1(BaseModel):
38
+ """
39
+ Supports Following models: Falcon-40B-instruct, Falcon-7B-instruct, openllama-13b-base, llama2-7b-chat
40
+
41
+ prompt string Prompt is a textual instruction for the model to produce an output. Required
42
+ top_k integer Top-k sampling helps improve quality by removing the tail and making it less likely to go off topic. Optional
43
+ (Default: 40)
44
+ top_p float Top-p sampling helps generate more diverse and creative text by considering a broader range of tokens. Optional
45
+ (Default: 1.0)
46
+ temp float The temperature influences the randomness of the next token predictions. Optional
47
+ (Default: 0.98)
48
+ max_length integer The maximum length of the generated text. Optional
49
+ (Default: 256)
50
+ repetition_penalty float The model uses this penalty to discourage the repetition of tokens in the output. Optional
51
+ (Default: 1.2)
52
+ beam_size integer The beam size for beam search. A larger beam size results in better quality output, but slower generation times. Optional
53
+ (Default: 1)
54
+ """
55
+ prompt: str
56
+ top_k: int = 40
57
+ top_p: float = Field(0.9, ge=0., le=1.)
58
+ temp: float = Field(0.98, ge=0., le=1.)
59
+ max_length: int = 256
60
+ repetition_penalty: float = 1.2
61
+ beam_size: int = 1
62
+
63
+
64
+ class LLMInputModel2(BaseModel):
65
+ """
66
+ Supports Following models: MPT-30B-instruct, MPT-7B-instruct
67
+
68
+ prompt: string Instruction is a textual command for the model to produce an output. Required
69
+ top_k integer Top-k sampling helps improve quality by removing the tail and making it less likely to go off topic. Optional
70
+ (Default: 40)
71
+ top_p float Top-p sampling helps generate more diverse and creative text by considering a broader range of tokens. Optional
72
+ Allowed Range: 0 - 1
73
+ (Default: 1.0)
74
+ temp float Temperature is a parameter that controls the randomness of the model's output. The higher the temperature, the more random the output. Optional
75
+ (Default: 0.98)
76
+ max_length integer Maximum length of the generated output. Optional
77
+ (Default: 256)
78
+ """
79
+ prompt: str
80
+ top_k: int = 40
81
+ top_p: float = Field(0.9, ge=0., le=1.)
82
+ temp: float = Field(0.98, ge=0., le=1.)
83
+ max_length: int = 256
84
+
85
+ class SDInputModel(BaseModel):
86
+ """
87
+ Support following models: text2img, text2img-sdxl
88
+
89
+ prompt: string Your input text prompt Required
90
+ negprompt: string Negative text prompt Optional
91
+ samples: integer No. of images to be generated. Allowed range: 1-4 Optional
92
+ (Default: 1)
93
+ steps: integer Sampling steps per image. Allowed range 30-500 Optional
94
+ (Default: 30)
95
+ aspect_ratio: string. Allowed values: square, landscape, portrait Optional
96
+ (Default: square)
97
+ guidance_scale: float. Prompt guidance scale Optional
98
+ (Default: 7.5)
99
+ seed: integer Random number used to initialize the image generation. Optional
100
+ (Default: random)
101
+ """
102
+ prompt: str
103
+ negprompt: Optional[str] = ""
104
+ samples: Optional[int] = Field(1, ge=1, le=4)
105
+ steps: Optional[int] = Field(30, ge=30, le=500)
106
+ aspect_ratio: Optional[Literal['square', 'landscape', 'portrait']] = 'square'
107
+ guidance_scale: Optional[float] = 7.5
108
+ seed: Optional[int] = None
109
+
110
+
111
+ MODELS_TO_DATAMODEL = {
112
+ 'falcon-7b-instruct': LLMInputModel1,
113
+ 'falcon-40b-instruct': LLMInputModel1,
114
+ 'mpt-30B-instruct': LLMInputModel2,
115
+ 'mpt-7b-instruct': LLMInputModel2,
116
+ 'openllama-13b-base': LLMInputModel1,
117
+ 'llama2-7b-chat': LLMInputModel1,
118
+ "sdxl-base": SDInputModel,
119
+ "txt2img": SDInputModel
120
+ }
121
+
122
+
123
+ class MClient():
124
+ def __init__(self):
125
+ self.boundary = '---011000010111000001101001'
126
+ self.auth_token = os.environ.get('MONSTER_API_KEY')
127
+ self.headers = {
128
+ "accept": "application/json",
129
+ "content-type": f"multipart/form-data; boundary={self.boundary}",
130
+ 'Authorization': 'Bearer ' + self.auth_token}
131
+ self.base_url = 'https://api.monsterapi.ai/v1'
132
+ self.models_to_data_model = MODELS_TO_DATAMODEL
133
+ self.mock = os.environ.get('MOCK_Runner', "False").lower() == "true"
134
+
135
+ def get_response(self, model:Literal['falcon-7b-instruct', 'falcon-40b-instruct', 'mpt-30B-instruct', 'mpt-7b-instruct', 'openllama-13b-base', 'llama2-7b-chat'],
136
+ data: dict):
137
+
138
+ if model not in self.models_to_data_model:
139
+ raise ValueError(f"Invalid model: {model}!")
140
+
141
+ dataModel = self.models_to_data_model[model](**data)
142
+ url = f"{self.base_url}/generate/{model}"
143
+ data = dataModel.dict()
144
+ logger.info(f"Calling Monster API with url: {url}, with payload: {data}")
145
+
146
+ # convert all values into string
147
+ for key, value in data.items():
148
+ data[key] = str(value)
149
+ multipart_data = MultipartEncoder(fields=data, boundary=self.boundary)
150
+ response = requests.post(url, headers=self.headers, data=multipart_data)
151
+ response.raise_for_status()
152
+ return response.json()
153
+
154
+ def get_status(self, process_id):
155
+ # /v1/status/{process_id}
156
+ url = f"{self.base_url}/status/{process_id}"
157
+ response = requests.get(url, headers=self.headers)
158
+ response.raise_for_status()
159
+ return response.json()
160
+
161
+ def wait_and_get_result(self, process_id, timeout=100):
162
+ start_time = time.time()
163
+ while True:
164
+ elapsed_time = time.time() - start_time
165
+
166
+ if elapsed_time >= timeout:
167
+ raise TimeoutError(f"Process {process_id} timed out after {timeout} seconds.")
168
+
169
+ status = self.get_status(process_id)
170
+ if status['status'].lower() == 'completed':
171
+ return status['result']
172
+ elif status['status'].lower() == 'failed':
173
+ raise RuntimeError(f"Process {process_id} failed! {status}")
174
+ else:
175
+ if self.mock:
176
+ return 100 * "Mock Output!"
177
+ logger.info(f"Process {process_id} is still running, status is {status['status']}. Waiting ...")
178
+ time.sleep(0.01)
app.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ import gradio as gr
3
+ import requests
4
+ from concurrent.futures import ThreadPoolExecutor
5
+ from MonsterAPIClient import MClient
6
+ from typing import Tuple
7
+
8
+ client = MClient()
9
+
10
+ def generate_model_output(model: str, input_text: str, neg_prompt: str, samples: int, steps: int,
11
+ aspect_ratio: str, guidance_scale: float, random_seed: str) -> str:
12
+ """
13
+ Generate output from a specific model.
14
+
15
+ Parameters:
16
+ model (str): The name of the model.
17
+ input_text (str): Your input text prompt.
18
+ neg_prompt (str): Negative text prompt.
19
+ samples (int): No. of images to be generated.
20
+ steps (int): Sampling steps per image.
21
+ aspect_ratio (str): Aspect ratio of the generated image.
22
+ guidance_scale (float): Prompt guidance scale.
23
+ random_seed (str): Random number used to initialize the image generation.
24
+
25
+ Returns:
26
+ str: The generated output text or image URL.
27
+ """
28
+ try:
29
+ response = client.get_response(model, {
30
+ "prompt": input_text,
31
+ "negprompt": neg_prompt,
32
+ "samples": samples,
33
+ "steps": steps,
34
+ "aspect_ratio": aspect_ratio,
35
+ "guidance_scale": guidance_scale,
36
+ "seed": random_seed,
37
+ })
38
+ output = client.wait_and_get_result(response['process_id'])
39
+ if 'output' in output:
40
+ return output['output']
41
+ else:
42
+ return "No output available."
43
+ except Exception as e:
44
+ return f"Error occurred: {str(e)}"
45
+
46
+ def generate_output(input_text: str, neg_prompt: str, samples: int, steps: int,
47
+ aspect_ratio: str, guidance_scale: float, random_seed: str):
48
+ with ThreadPoolExecutor() as executor:
49
+ # Schedule the function calls asynchronously
50
+ future_sdxl_base = executor.submit(generate_model_output, 'sdxl-base', input_text, neg_prompt, samples, steps,
51
+ aspect_ratio, guidance_scale, random_seed)
52
+ future_txt2img = executor.submit(generate_model_output, 'txt2img', input_text, neg_prompt, samples, steps,
53
+ aspect_ratio, guidance_scale, random_seed)
54
+
55
+ # Get the results from the completed futures
56
+ sdxl_base_output = future_sdxl_base.result()
57
+ txt2img_output = future_txt2img.result()
58
+
59
+ return [sdxl_base_output, txt2img_output]
60
+
61
+ # Function to stitch
62
+
63
+
64
+ input_components = [
65
+ gr.inputs.Textbox(label="Input Prompt"),
66
+ gr.inputs.Textbox(label="Negative Prompt"),
67
+ gr.inputs.Slider(label="No. of Images to Generate", minimum=1, maximum=3, default=1),
68
+ gr.inputs.Slider(label="Sampling Steps per Image", minimum=30, maximum=40, default=30),
69
+ gr.inputs.Dropdown(label="Aspect Ratio", choices=["square", "landscape", "portrait"], default="square"),
70
+ gr.inputs.Slider(label="Prompt Guidance Scale", minimum=0.1, maximum=20.0, default=7.5),
71
+ gr.inputs.Textbox(label="Random Seed", default=random.randint(0, 1000000)),
72
+ ]
73
+
74
+ output_component_sdxl_base = gr.Gallery(label="Stable Diffusion V2.0 Output", type="pil", container = True)
75
+ output_component_txt2img = gr.Gallery(label="Stable Diffusion V1.5 Output", type="pil", container = True)
76
+
77
+ interface = gr.Interface(
78
+ fn=generate_output,
79
+ inputs=input_components,
80
+ outputs=[output_component_sdxl_base, output_component_txt2img],
81
+ live=False,
82
+ capture_session=True,
83
+ title="Stable Diffusion Evaluation powered by MonsterAPI",
84
+ description="""This HuggingFace Space has been designed to help you compare the outputs between Stable-Diffusion V1.5 vs V2.0. These models are hosted on [MonsterAPI](https://monsterapi.ai/?utm_source=llm-evaluation&utm_medium=referral) - An AI infrastructure platform built for easily accessing AI models via scalable APIs and [finetuning LLMs](https://docs.monsterapi.ai/fine-tune-a-large-language-model-llm) at very low cost with our no-code implementation. MonsterAPI is powered by our low cost and highly scalable GPU computing platform - [Q Blocks](https://www.qblocks.cloud?utm_source=llm-evaluation&utm_medium=referral). These LLMs are accessible via scalable REST APIs. Checkout our [API documentation](https://documenter.getpostman.com/view/13759598/2s8ZDVZ3Yi) to integrate them in your AI powered applications.""",
85
+ css="body {background-color: black}"
86
+ )
87
+
88
+ # Launch the Gradio app
89
+ interface.launch()