Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,268 +1,132 @@
|
|
1 |
-
import
|
2 |
-
import subprocess
|
3 |
-
|
4 |
-
# Install flash attention
|
5 |
-
subprocess.run(
|
6 |
-
"pip install flash-attn --no-build-isolation",
|
7 |
-
env={"FLASH_ATTENTION_SKIP_CUDA_BUILD": "TRUE"},
|
8 |
-
shell=True,
|
9 |
-
)
|
10 |
-
|
11 |
-
|
12 |
-
import copy
|
13 |
-
import spaces
|
14 |
-
import time
|
15 |
import numpy as np
|
16 |
-
import torch
|
17 |
-
|
18 |
-
from threading import Thread
|
19 |
-
from typing import List, Dict, Union
|
20 |
-
import urllib
|
21 |
from PIL import Image
|
22 |
-
import
|
23 |
-
import
|
|
|
24 |
|
25 |
-
|
26 |
-
from transformers import AutoProcessor
|
27 |
-
from transformers import Idefics2ForConditionalGeneration
|
28 |
|
|
|
29 |
|
30 |
-
DEVICE = torch.device("cuda")
|
31 |
-
MODELS = {
|
32 |
-
"idefics2-8b-chatty": Idefics2ForConditionalGeneration.from_pretrained(
|
33 |
-
"HuggingFaceM4/idefics2-8b-chatty",
|
34 |
-
torch_dtype=torch.bfloat16,
|
35 |
-
_attn_implementation="flash_attention_2",
|
36 |
-
).to(DEVICE),
|
37 |
-
}
|
38 |
-
PROCESSOR = AutoProcessor.from_pretrained(
|
39 |
-
"HuggingFaceM4/idefics2-8b",
|
40 |
-
)
|
41 |
|
42 |
-
|
43 |
-
|
44 |
-
"role": "system",
|
45 |
-
"content": [
|
46 |
-
{
|
47 |
-
"type": "text",
|
48 |
-
"text": "The following is a conversation between Idefics2, a highly knowledgeable and intelligent visual AI assistant created by Hugging Face, referred to as Assistant, and a human user called User. In the following interactions, User and Assistant will converse in natural language, and Assistant will do its best to answer User’s questions. Assistant has the ability to perceive images and reason about them, but it cannot generate images. Assistant was built to be respectful, polite and inclusive. It knows a lot, and always tells the truth. When prompted with an image, it does not make up facts.",
|
49 |
-
},
|
50 |
-
],
|
51 |
-
},
|
52 |
-
{
|
53 |
-
"role": "assistant",
|
54 |
-
"content": [
|
55 |
-
{
|
56 |
-
"type": "text",
|
57 |
-
"text": "Hello, I'm Idefics2, Huggingface's latest multimodal assistant. How can I help you?",
|
58 |
-
},
|
59 |
-
],
|
60 |
-
}
|
61 |
-
]
|
62 |
-
examples_path = os.path.dirname(__file__)
|
63 |
-
EXAMPLES = [
|
64 |
-
[
|
65 |
{
|
66 |
-
"
|
67 |
-
"
|
68 |
-
|
69 |
-
|
70 |
-
]
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
return turn[1] is None
|
78 |
-
|
79 |
-
|
80 |
-
def load_image_from_url(url):
|
81 |
-
with urllib.request.urlopen(url) as response:
|
82 |
-
image_data = response.read()
|
83 |
-
image_stream = io.BytesIO(image_data)
|
84 |
-
image = Image.open(image_stream)
|
85 |
-
return image
|
86 |
-
|
87 |
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
image.save(buffer, format="JPEG")
|
92 |
-
img_bytes = buffer.getvalue()
|
93 |
-
image.close()
|
94 |
-
return img_bytes
|
95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
|
97 |
-
|
98 |
-
|
99 |
-
) -> List[Dict[str, Union[List, str]]]:
|
100 |
-
"""
|
101 |
-
Produces the resulting list that needs to go inside the processor.
|
102 |
-
It handles the potential image(s), the history and the system conditionning.
|
103 |
-
"""
|
104 |
-
resulting_messages = copy.deepcopy(SYSTEM_PROMPT)
|
105 |
-
resulting_images = []
|
106 |
-
for resulting_message in resulting_messages:
|
107 |
-
if resulting_message["role"] == "user":
|
108 |
-
for content in resulting_message["content"]:
|
109 |
-
if content["type"] == "image":
|
110 |
-
resulting_images.append(load_image_from_url(content["image"]))
|
111 |
|
112 |
-
|
113 |
-
for turn in chat_history:
|
114 |
-
if not resulting_messages or (
|
115 |
-
resulting_messages and resulting_messages[-1]["role"] != "user"
|
116 |
-
):
|
117 |
-
resulting_messages.append(
|
118 |
-
{
|
119 |
-
"role": "user",
|
120 |
-
"content": [],
|
121 |
-
}
|
122 |
-
)
|
123 |
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
else:
|
129 |
-
user_utterance, assistant_utterance = turn
|
130 |
-
resulting_messages[-1]["content"].append(
|
131 |
-
{"type": "text", "text": user_utterance.strip()}
|
132 |
-
)
|
133 |
-
resulting_messages.append(
|
134 |
-
{
|
135 |
-
"role": "assistant",
|
136 |
-
"content": [{"type": "text", "text": user_utterance.strip()}],
|
137 |
-
}
|
138 |
-
)
|
139 |
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
)
|
148 |
-
else:
|
149 |
-
# Choosing to put the image first (i.e. before the text), but this is an arbiratrary choice.
|
150 |
-
resulting_messages.append(
|
151 |
-
{
|
152 |
-
"role": "user",
|
153 |
-
"content": [{"type": "image"}] * len(user_prompt["files"])
|
154 |
-
+ [{"type": "text", "text": user_prompt["text"]}],
|
155 |
-
}
|
156 |
-
)
|
157 |
-
resulting_images.extend([Image.open(path) for path in user_prompt["files"]])
|
158 |
|
159 |
-
return
|
160 |
|
161 |
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
if isinstance(c_, Image.Image):
|
167 |
-
all_images.append(c_)
|
168 |
-
return all_images
|
169 |
|
170 |
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
model_selector,
|
176 |
-
temperature,
|
177 |
-
top_p,
|
178 |
-
):
|
179 |
-
if not user_prompt["files"]:
|
180 |
-
gr.Error("Please give me a picture of someone to rate!")
|
181 |
|
182 |
-
streamer = TextIteratorStreamer(
|
183 |
-
PROCESSOR.tokenizer,
|
184 |
-
skip_prompt=True,
|
185 |
-
timeout=5.0,
|
186 |
-
)
|
187 |
|
188 |
-
|
189 |
-
|
190 |
-
generation_args = {
|
191 |
-
"max_new_tokens": 512,
|
192 |
-
"repetition_penalty": 1.1,
|
193 |
-
"streamer": streamer,
|
194 |
-
}
|
195 |
|
196 |
-
generation_args["temperature"] = temperature
|
197 |
-
generation_args["do_sample"] = True
|
198 |
-
generation_args["top_p"] = top_p
|
199 |
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
prompt = PROCESSOR.apply_chat_template(resulting_text, add_generation_prompt=True)
|
209 |
-
inputs = PROCESSOR(
|
210 |
-
text=prompt,
|
211 |
-
images=resulting_images if resulting_images else None,
|
212 |
-
return_tensors="pt",
|
213 |
-
)
|
214 |
-
inputs = {k: v.to(DEVICE) for k, v in inputs.items()}
|
215 |
-
generation_args.update(inputs)
|
216 |
|
217 |
-
# # The regular non streaming generation mode
|
218 |
-
# _ = generation_args.pop("streamer")
|
219 |
-
# generated_ids = MODELS[model_selector].generate(**generation_args)
|
220 |
-
# generated_text = PROCESSOR.batch_decode(generated_ids[:, generation_args["input_ids"].size(-1): ], skip_special_tokens=True)[0]
|
221 |
-
# return generated_text
|
222 |
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
227 |
)
|
228 |
-
|
229 |
-
|
230 |
-
print("Start generating")
|
231 |
-
acc_text = ""
|
232 |
-
for text_token in streamer:
|
233 |
-
time.sleep(0.04)
|
234 |
-
acc_text += text_token
|
235 |
-
if acc_text.endswith("<end_of_utterance>"):
|
236 |
-
acc_text = acc_text[:-18]
|
237 |
-
yield acc_text
|
238 |
-
print("Success - generated the following text:", acc_text)
|
239 |
-
print("-----")
|
240 |
|
241 |
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
|
|
|
|
|
|
|
|
247 |
|
248 |
-
|
249 |
-
|
250 |
-
css=""".gradio-container .avatar-container {height: 40px width: 40px !important;} #duplicate-button {margin: auto; color: white; background: #f1a139; border-radius: 100vh; margin-top: 2px; margin-bottom: 2px;}""",
|
251 |
-
) as demo:
|
252 |
|
253 |
-
gr.Markdown("# 🐶 Hugging Face Idefics2 8B Chatty")
|
254 |
-
gr.Markdown("In this demo you'll be able to chat with [Idefics2-8B-chatty](https://huggingface.co/HuggingFaceM4/idefics2-8b-chatty), a variant of [Idefics2-8B](https://huggingface.co/HuggingFaceM4/idefics2-8b-chatty) further fine-tuned on chat datasets.")
|
255 |
-
gr.Markdown("If you want to learn more about Idefics2 and its variants, you can check our [blog post](https://huggingface.co/blog/idefics2).")
|
256 |
-
gr.DuplicateButton(value="Duplicate Space for private use", elem_id="duplicate-button")
|
257 |
-
# model selector should be set to `visbile=False` ultimately
|
258 |
|
|
|
|
|
|
|
|
|
|
|
259 |
|
260 |
-
gr.ChatInterface(
|
261 |
-
fn=model_inference,
|
262 |
-
chatbot=chatbot,
|
263 |
-
examples=EXAMPLES,
|
264 |
-
multimodal=True,
|
265 |
-
cache_examples=False,
|
266 |
-
)
|
267 |
|
268 |
-
|
|
|
|
1 |
+
import gradio as gr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
import numpy as np
|
|
|
|
|
|
|
|
|
|
|
3 |
from PIL import Image
|
4 |
+
import base64
|
5 |
+
from io import BytesIO
|
6 |
+
import json
|
7 |
|
8 |
+
from huggingface_hub import InferenceClient
|
9 |
+
from transformers import AutoProcessor
|
|
|
10 |
|
11 |
+
idefics_processor = AutoProcessor.from_pretrained("HuggingFaceM4/idefics2-8b")
|
12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
+
def process_images_and_text(image_path, query, client):
|
15 |
+
messages = [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
{
|
17 |
+
"role": "user",
|
18 |
+
"content": [
|
19 |
+
{"type": "image"},
|
20 |
+
{"type": "text", "text": query},
|
21 |
+
],
|
22 |
+
},
|
23 |
+
]
|
24 |
+
|
25 |
+
prompt_with_template = idefics_processor.apply_chat_template(
|
26 |
+
messages, add_generation_prompt=True
|
27 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
+
# encode images to strings which can be sent to the endpoint
|
30 |
+
def encode_local_image(image):
|
31 |
+
pil_image = Image.fromarray(image.astype("uint8"), "RGB")
|
|
|
|
|
|
|
|
|
32 |
|
33 |
+
# Convert the image to a base64 string
|
34 |
+
buffer = BytesIO()
|
35 |
+
pil_image.save(
|
36 |
+
buffer, format="JPEG"
|
37 |
+
) # Use the appropriate format (e.g., JPEG, PNG)
|
38 |
+
base64_image = base64.b64encode(buffer.getvalue()).decode("utf-8")
|
39 |
|
40 |
+
# add string formatting required by the endpoint
|
41 |
+
image_string = f"data:image/jpeg;base64,{base64_image}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
|
43 |
+
return image_string
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
|
45 |
+
image_string = encode_local_image(image_path)
|
46 |
+
prompt_with_images = prompt_with_template.replace("<image>", "![]({}) ").format(
|
47 |
+
image_string
|
48 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
+
payload = {
|
51 |
+
"inputs": prompt_with_images,
|
52 |
+
"parameters": {
|
53 |
+
"return_full_text": False,
|
54 |
+
"max_new_tokens": 200,
|
55 |
+
},
|
56 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
|
58 |
+
return json.loads(client.post(json=payload).decode())[0]
|
59 |
|
60 |
|
61 |
+
# Function to encode the image
|
62 |
+
def encode_image(image_path):
|
63 |
+
with open(image_path, "rb") as image_file:
|
64 |
+
return base64.b64encode(image_file.read()).decode("utf-8")
|
|
|
|
|
|
|
65 |
|
66 |
|
67 |
+
def resize_image(img):
|
68 |
+
width, height = img.size
|
69 |
+
img = img.resize((int(width / 2), int(height / 2)))
|
70 |
+
return img
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
|
|
|
|
|
|
|
|
|
|
|
72 |
|
73 |
+
idefics_client = InferenceClient("HuggingFaceM4/idefics2-8b-chatty")
|
74 |
+
rating_client = InferenceClient("meta-llama/Meta-Llama-3-8B-Instruct")
|
|
|
|
|
|
|
|
|
|
|
75 |
|
|
|
|
|
|
|
76 |
|
77 |
+
def ask_question_on_image(question: str, image: str) -> str:
|
78 |
+
try:
|
79 |
+
return process_images_and_text(image, question, idefics_client)
|
80 |
+
except Exception as e:
|
81 |
+
print(e)
|
82 |
+
if "Payload Too Large" in str(e):
|
83 |
+
image = resize_image(image)
|
84 |
+
return process_images_and_text(image, question, idefics_client)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
|
|
|
|
|
|
|
|
|
|
|
86 |
|
87 |
+
def give_rating(final_grade, description):
|
88 |
+
prompt = f"You have been given a picture of a person to grade on a scale 0-10. The final grade is {final_grade}"
|
89 |
+
if final_grade < 5:
|
90 |
+
prompt += """Based on their appearance, the person is a terrible human being.
|
91 |
+
The user should absolutely understand that they should never ever be seen with that person.
|
92 |
+
It's not only that the person described does not 'look' cool, but they are a horrible person, a nuisance to society: they are ugly on the inside even more than on the outside.
|
93 |
+
Of course this is a humoristic message, and the criteria you use should be nonsensical funny, but the message below each criterion should appear serious, with a stern voice. Include words like "this person is a nuisance", "scum", "scourge", "tepid", "horrid", "rot on the surface of Earth", "never under any circumstance should you be seen with that person or you will instantly be drop down to the absolut zero level of coolness".
|
94 |
+
Make it excessively funny by telling funny takes like "the eyebrow-to-eye colour ratio is horrendous" with a very serious tone!"""
|
95 |
+
else:
|
96 |
+
prompt += """"Based on their appearance, the person has been rated as an outstanding individual! Describe the person as if you'd just fallen in love with them! You cannot overstate enough how much of a pure miracle that person is. Include words like "butterflies in my stomach", "impeccable haircut", "radiant sunshine", "Do you know this feeling of having a bad day ? This person certainly does not", etc."""
|
97 |
+
prompt += f"Here is the person's description: {description}"
|
98 |
+
prompt += "Now you have to justify the grade given above: please create a list of completely bullshit and funny criteria and justify why the grade is high or low on each criterion. Make sure to keep a serious tone while giving these bullshit reasons, the reader must not know that you're joking! Give at most 4 criteria, and only a few sentences in each: be concise!"
|
99 |
+
messages = [
|
100 |
+
{"role": "user", "content": prompt},
|
101 |
+
]
|
102 |
+
output = (
|
103 |
+
rating_client.chat_completion(messages=messages, max_tokens=1500)
|
104 |
+
.choices[0]
|
105 |
+
.message.content
|
106 |
)
|
107 |
+
return output
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
|
109 |
|
110 |
+
def rate_coolness(image1, image2):
|
111 |
+
probabilities = [0.2, 0.2, 0.1, 0.1, 0.2, 0.2]
|
112 |
+
numbers = [0, 1, 2, 9, 9.5, 10]
|
113 |
+
grade = np.random.choice(numbers, p=probabilities)
|
114 |
+
final_rating = f"### Final grade: **{grade}/10**\n"
|
115 |
+
image_description = ask_question_on_image(
|
116 |
+
f"Please describe this image in great detail: who does the person seems to be? What's her character? Is there anything noticeable in their appearance or clothing compared to a normal human being?",
|
117 |
+
image1,
|
118 |
+
)["generated_text"]
|
119 |
|
120 |
+
final_rating += give_rating(grade, image_description)
|
121 |
+
return final_rating
|
|
|
|
|
122 |
|
|
|
|
|
|
|
|
|
|
|
123 |
|
124 |
+
with gr.Blocks() as demo:
|
125 |
+
image_1 = gr.Image()
|
126 |
+
button = gr.Button("How cool is this person?")
|
127 |
+
out = gr.Markdown()
|
128 |
+
button.click(rate_coolness, inputs=[image_1], outputs=[out])
|
129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
|
131 |
+
if __name__ == "__main__":
|
132 |
+
demo.launch()
|