m-ric HF staff commited on
Commit
a9e81c4
1 Parent(s): 66a4acc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +100 -236
app.py CHANGED
@@ -1,268 +1,132 @@
1
- import os
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 io
23
- import datasets
 
24
 
25
- import gradio as gr
26
- from transformers import AutoProcessor, TextIteratorStreamer
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
- SYSTEM_PROMPT = [
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
- "text": "For 2024, the interest expense is twice what it was in 2014, and the long-term debt is 10% higher than its 2015 level. Can you calculate the combined total of the interest and long-term debt for 2024?",
67
- "files": [f"{examples_path}/example_images/mmmu_example_2.png"],
68
- }
69
- ],
70
- ]
71
-
72
- BOT_AVATAR = "IDEFICS_logo.png"
73
-
74
-
75
- # Chatbot utils
76
- def turn_is_pure_media(turn):
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
- def img_to_bytes(image_path):
89
- image = Image.open(image_path).convert(mode='RGB')
90
- buffer = io.BytesIO()
91
- image.save(buffer, format="JPEG")
92
- img_bytes = buffer.getvalue()
93
- image.close()
94
- return img_bytes
95
 
 
 
 
 
 
 
96
 
97
- def format_user_prompt_with_im_history_and_system_conditioning(
98
- user_prompt, chat_history
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
- # Format history
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
- if turn_is_pure_media(turn):
125
- media = turn[0][0]
126
- resulting_messages[-1]["content"].append({"type": "image"})
127
- resulting_images.append(Image.open(media))
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
- # Format current input
141
- if not user_prompt["files"]:
142
- resulting_messages.append(
143
- {
144
- "role": "user",
145
- "content": [{"type": "text", "text": user_prompt["text"]}],
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 resulting_messages, resulting_images
160
 
161
 
162
- def extract_images_from_msg_list(msg_list):
163
- all_images = []
164
- for msg in msg_list:
165
- for c_ in msg["content"]:
166
- if isinstance(c_, Image.Image):
167
- all_images.append(c_)
168
- return all_images
169
 
170
 
171
- @spaces.GPU(duration=180)
172
- def model_inference(
173
- user_prompt,
174
- chat_history,
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
- # Common parameters to all decoding strategies
189
- # This documentation is useful to read: https://huggingface.co/docs/transformers/main/en/generation_strategies
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
- # Creating model inputs
201
- (
202
- resulting_text,
203
- resulting_images,
204
- ) = format_user_prompt_with_im_history_and_system_conditioning(
205
- user_prompt=user_prompt,
206
- chat_history=chat_history,
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
- # The streaming generation mode
224
- thread = Thread(
225
- target=MODELS[model_selector].generate,
226
- kwargs=generation_args,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  )
228
- thread.start()
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
- chatbot = gr.Chatbot(
243
- label="Idefics2-Chatty",
244
- avatar_images=[None, BOT_AVATAR],
245
- height=450,
246
- )
 
 
 
 
247
 
248
- with gr.Blocks(
249
- fill_height=True,
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
- demo.launch()
 
 
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()