jenbenarye commited on
Commit
d062581
·
2 Parent(s): 35d154e a3f1359

Merge branch 'main' of https://github.com/jenbenarye/feel

Browse files
Files changed (1) hide show
  1. app/app.py +158 -62
app/app.py CHANGED
@@ -14,37 +14,65 @@ from huggingface_hub import InferenceClient
14
  from pandas import DataFrame
15
 
16
  LANGUAGES: dict[str, str] = {
17
- "English": "You are a helpful assistant that speaks English.",
18
- "Spanish": "Tu eres un asistente útil que habla español.",
19
- "Hebrew": "אתה עוזר טוב שמפגש בעברית.",
20
- "Dutch": "Je bent een handige assistent die Nederlands spreekt.",
21
- "Italian": "Tu sei un assistente utile che parla italiano.",
22
- "French": "Tu es un assistant utile qui parle français.",
23
- "German": "Du bist ein hilfreicher Assistent, der Deutsch spricht.",
24
- "Portuguese": "Você é um assistente útil que fala português.",
25
- "Russian": "Ты полезный помощник, который говорит по-русски.",
26
- "Chinese": "你是一个有用的助手,会说中文。",
27
- "Japanese": "あなたは役立つ助け役で、日本語を話します。",
28
- "Korean": "당신은 유용한 도우미이며 한국어를 말합니다.",
29
  }
30
 
31
- client = InferenceClient(
32
- token=os.getenv("HF_TOKEN"),
33
- model=(
34
- os.getenv("MODEL", "meta-llama/Llama-3.2-11B-Vision-Instruct")
35
- if not os.getenv("BASE_URL")
36
- else None
37
- ),
38
- base_url=os.getenv("BASE_URL"),
39
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
 
42
  def add_user_message(history, message):
43
- for x in message["files"]:
44
- history.append({"role": "user", "content": {"path": x}})
45
- if message["text"] is not None:
46
- history.append({"role": "user", "content": message["text"]})
47
- return history, gr.MultimodalTextbox(value=None, interactive=False)
 
 
 
48
 
49
 
50
  def format_system_message(language: str, history: list):
@@ -128,7 +156,11 @@ def _process_rating(rating) -> int:
128
 
129
 
130
  def add_fake_like_data(
131
- history: list, session_id: str, language: str, liked: bool = False
 
 
 
 
132
  ) -> None:
133
  data = {
134
  "index": len(history) - 1,
@@ -138,17 +170,25 @@ def add_fake_like_data(
138
  _, dataframe = wrangle_like_data(
139
  gr.LikeData(target=None, data=data), history.copy()
140
  )
141
- submit_conversation(dataframe, session_id, language)
 
 
 
 
 
142
 
143
 
144
- def respond_system_message(
145
- history: list, temperature: Optional[float] = None, seed: Optional[int] = None
 
 
 
146
  ) -> list: # -> list:
147
  """Respond to the user message with a system message
148
 
149
  Return the history with the new message"""
150
  messages = format_history_as_messages(history)
151
- response = client.chat.completions.create(
152
  messages=messages,
153
  max_tokens=2000,
154
  stream=False,
@@ -187,7 +227,11 @@ def wrangle_like_data(x: gr.LikeData, history) -> DataFrame:
187
  if isinstance(message, gr.ChatMessage):
188
  message = message.__dict__
189
  if idx == liked_index:
190
- message["metadata"] = {"title": "liked" if x.liked else "disliked"}
 
 
 
 
191
  if not isinstance(message["metadata"], dict):
192
  message["metadata"] = message["metadata"].__dict__
193
  rating = message["metadata"].get("title")
@@ -221,7 +265,12 @@ def wrangle_like_data(x: gr.LikeData, history) -> DataFrame:
221
 
222
 
223
  def wrangle_edit_data(
224
- x: gr.EditData, history: list, dataframe: DataFrame, session_id: str, language: str
 
 
 
 
 
225
  ) -> list:
226
  """Edit the conversation and add negative feedback if assistant message is edited, otherwise regenerate the message
227
 
@@ -237,20 +286,41 @@ def wrangle_edit_data(
237
 
238
  if history[index]["role"] == "user":
239
  # Add feedback on original and corrected message
240
- add_fake_like_data(history[: index + 2], session_id, language, liked=True)
241
  add_fake_like_data(
242
- history[: index + 1] + [original_message], session_id, language
 
 
 
 
243
  )
244
- history = respond_system_message(
245
- history[: index + 1],
 
 
 
 
 
 
 
246
  temperature=random.randint(1, 100) / 100,
247
  seed=random.randint(0, 1000000),
248
  )
249
  return history
250
  else:
251
  # Add feedback on original and corrected message
252
- add_fake_like_data(history[: index + 1], session_id, language, liked=True)
253
- add_fake_like_data(history[:index] + [original_message], session_id, language)
 
 
 
 
 
 
 
 
 
 
 
254
  history = history[: index + 1]
255
  # add chosen and rejected options
256
  history[-1]["options"] = [
@@ -261,23 +331,34 @@ def wrangle_edit_data(
261
 
262
 
263
  def wrangle_retry_data(
264
- x: gr.RetryData, history: list, dataframe: DataFrame, session_id: str, language: str
 
 
 
 
 
265
  ) -> list:
266
  """Respond to the user message with a system message and add negative feedback on the original message
267
 
268
  Return the history with the new message"""
269
- add_fake_like_data(history, session_id, language)
 
 
 
 
 
270
 
271
  # Return the history without a new message
272
- history = respond_system_message(
273
- history[:-1],
 
274
  temperature=random.randint(1, 100) / 100,
275
  seed=random.randint(0, 1000000),
276
  )
277
  return history, update_dataframe(dataframe, history)
278
 
279
 
280
- def submit_conversation(dataframe, session_id, language):
281
  """ "Submit the conversation to dataset repo"""
282
  if dataframe.empty or len(dataframe) < 2:
283
  gr.Info("No feedback to submit.")
@@ -290,11 +371,10 @@ def submit_conversation(dataframe, session_id, language):
290
  "conversation": conversation,
291
  "timestamp": datetime.now().isoformat(),
292
  "session_id": session_id,
293
- "conversation_id": str(uuid.uuid4()),
294
  "language": language,
295
  }
296
  save_feedback(input_object=conversation_data)
297
- gr.Info("Submitted your feedback!")
298
  return (gr.Dataframe(value=None, interactive=False), [])
299
 
300
 
@@ -320,7 +400,9 @@ with gr.Blocks(css=css) as demo:
320
 
321
  with gr.Accordion("Explanation") as explanation:
322
  gr.Markdown(f"""
323
- FeeL is a collaboration between Hugging Face and MIT. It is a community-driven project to provide a real-time feedback loop for VLMs, where your feedback is continuously used to train the model. The [dataset](https://huggingface.co/datasets/{scheduler.repo_id}) and [code](https://github.com/huggingface/feel) are public.
 
 
324
 
325
  Start by selecting your language, chat with the model with text and images and provide feedback in different ways.
326
 
@@ -328,7 +410,7 @@ with gr.Blocks(css=css) as demo:
328
  - 👍/👎 Like or dislike a message
329
  - 🔄 Regenerate a message
330
 
331
- Some feedback is automatically submitted allowing you to continue chatting, but you can also submit and reset the conversation by clicking "💾 Submit conversation" (under the chat) or trash the conversation by clicking "🗑️" (upper right corner).
332
  """)
333
  language = gr.Dropdown(
334
  choices=list(LANGUAGES.keys()), label="Language", interactive=True
@@ -340,6 +422,12 @@ with gr.Blocks(css=css) as demo:
340
  visible=False,
341
  )
342
 
 
 
 
 
 
 
343
  chatbot = gr.Chatbot(
344
  elem_id="chatbot",
345
  editable="all",
@@ -354,19 +442,17 @@ with gr.Blocks(css=css) as demo:
354
  feedback_options=["Like", "Dislike"],
355
  )
356
 
357
- chat_input = gr.MultimodalTextbox(
358
  interactive=True,
359
- file_count="multiple",
360
  placeholder="Enter message or upload file...",
361
  show_label=False,
362
  submit_btn=True,
363
  )
364
 
365
- dataframe = gr.Dataframe(wrap=True, label="Collected feedback")
 
366
 
367
- submit_btn = gr.Button(
368
- value="💾 Submit conversation",
369
- )
370
 
371
  ##############################
372
  # Deal with feedback
@@ -382,34 +468,46 @@ with gr.Blocks(css=css) as demo:
382
  fn=add_user_message,
383
  inputs=[chatbot, chat_input],
384
  outputs=[chatbot, chat_input],
385
- ).then(respond_system_message, chatbot, chatbot, api_name="bot_response").then(
386
  lambda: gr.Textbox(interactive=True), None, [chat_input]
387
- ).then(update_dataframe, inputs=[dataframe, chatbot], outputs=[dataframe])
 
 
 
388
 
389
  chatbot.like(
390
  fn=wrangle_like_data,
391
  inputs=[chatbot],
392
  outputs=[chatbot, dataframe],
393
  like_user_message=False,
 
 
 
394
  )
395
 
396
  chatbot.retry(
397
  fn=wrangle_retry_data,
398
- inputs=[chatbot, dataframe, session_id, language],
399
  outputs=[chatbot, dataframe],
400
  )
401
 
402
  chatbot.edit(
403
  fn=wrangle_edit_data,
404
- inputs=[chatbot, dataframe, session_id, language],
405
  outputs=[chatbot],
406
  ).then(update_dataframe, inputs=[dataframe, chatbot], outputs=[dataframe])
407
 
408
- submit_btn.click(
 
409
  fn=submit_conversation,
410
- inputs=[dataframe, session_id, language],
411
  outputs=[dataframe, chatbot],
 
 
 
 
412
  )
 
413
  demo.load(
414
  lambda: str(uuid.uuid4()),
415
  inputs=[],
@@ -417,5 +515,3 @@ with gr.Blocks(css=css) as demo:
417
  )
418
 
419
  demo.launch()
420
-
421
- # /private/var/folders/9t/msy700h16jz3q35qvg4z1ln40000gn/T/gradio/a5013b9763ad9f2192254540fee226539fbcd1382cbc2317b916aef469bb01b9/Screenshot 2025-01-13 at 08.02.26.png
 
14
  from pandas import DataFrame
15
 
16
  LANGUAGES: dict[str, str] = {
17
+ "English": "You are a helpful assistant. Always respond to requests in fluent and natural English, regardless of the language used by the user.",
18
+ "Dutch": "Je bent een behulpzame assistent die uitsluitend in het Nederlands communiceert. Beantwoord alle vragen en verzoeken in vloeiend en natuurlijk Nederlands, ongeacht de taal waarin de gebruiker schrijft.",
19
+ "Italian": "Sei un assistente utile e rispondi sempre in italiano in modo naturale e fluente, indipendentemente dalla lingua utilizzata dall'utente.",
20
+ "Spanish": "Eres un asistente útil que siempre responde en español de manera fluida y natural, independientemente del idioma utilizado por el usuario.",
21
+ "French": "Tu es un assistant utile qui répond toujours en français de manière fluide et naturelle, quelle que soit la langue utilisée par l'utilisateur.",
22
+ "German": "Du bist ein hilfreicher Assistent, der stets auf Deutsch in einer natürlichen und fließenden Weise antwortet, unabhängig von der Sprache des Benutzers.",
23
+ "Portuguese": "Você é um assistente útil que sempre responde em português de forma natural e fluente, independentemente do idioma utilizado pelo usuário.",
24
+ "Russian": "Ты полезный помощник, который всегда отвечает на русском языке плавно и естественно, независимо от языка пользователя.",
25
+ "Chinese": "你是一个有用的助手,总是用流畅自然的中文回答问题,无论用户使用哪种语言。",
26
+ "Japanese": "あなたは役に立つアシスタントであり、常に流暢で自然な日本語で応答します。ユーザーが使用する言語に関係なく、日本語で対応してください。",
27
+ "Korean": "당신은 유용한 도우미이며, 항상 유창하고 자연스러운 한국어로 응답합니다. 사용자가 어떤 언어를 사용하든 한국어로 대답하세요.",
 
28
  }
29
 
30
+
31
+ BASE_MODEL = os.getenv("MODEL", "meta-llama/Llama-3.2-11B-Vision-Instruct")
32
+
33
+
34
+ def create_inference_client(
35
+ model: Optional[str] = None, base_url: Optional[str] = None
36
+ ) -> InferenceClient:
37
+ """Create an InferenceClient instance with the given model or environment settings.
38
+
39
+ Args:
40
+ model: Optional model identifier to use. If not provided, will use environment settings.
41
+
42
+ Returns:
43
+ InferenceClient: Configured client instance
44
+ """
45
+ return InferenceClient(
46
+ token=os.getenv("HF_TOKEN"),
47
+ model=model if model else (BASE_MODEL if not base_url else None),
48
+ base_url=base_url,
49
+ )
50
+
51
+
52
+ LANGUAGES_TO_CLIENT = {
53
+ "English": create_inference_client(),
54
+ "Dutch": create_inference_client(),
55
+ "Italian": create_inference_client(),
56
+ "Spanish": create_inference_client(),
57
+ "French": create_inference_client(),
58
+ "German": create_inference_client(),
59
+ "Portuguese": create_inference_client(),
60
+ "Russian": create_inference_client(),
61
+ "Chinese": create_inference_client(),
62
+ "Japanese": create_inference_client(),
63
+ "Korean": create_inference_client(),
64
+ }
65
 
66
 
67
  def add_user_message(history, message):
68
+ if isinstance(message, dict) and "files" in message:
69
+ for x in message["files"]:
70
+ history.append({"role": "user", "content": {"path": x}})
71
+ if message["text"] is not None:
72
+ history.append({"role": "user", "content": message["text"]})
73
+ else:
74
+ history.append({"role": "user", "content": message})
75
+ return history, gr.Textbox(value=None, interactive=False)
76
 
77
 
78
  def format_system_message(language: str, history: list):
 
156
 
157
 
158
  def add_fake_like_data(
159
+ history: list,
160
+ conversation_id: str,
161
+ session_id: str,
162
+ language: str,
163
+ liked: bool = False,
164
  ) -> None:
165
  data = {
166
  "index": len(history) - 1,
 
170
  _, dataframe = wrangle_like_data(
171
  gr.LikeData(target=None, data=data), history.copy()
172
  )
173
+ submit_conversation(
174
+ dataframe=dataframe,
175
+ conversation_id=conversation_id,
176
+ session_id=session_id,
177
+ language=language,
178
+ )
179
 
180
 
181
+ def respond(
182
+ history: list,
183
+ language: str,
184
+ temperature: Optional[float] = None,
185
+ seed: Optional[int] = None,
186
  ) -> list: # -> list:
187
  """Respond to the user message with a system message
188
 
189
  Return the history with the new message"""
190
  messages = format_history_as_messages(history)
191
+ response = LANGUAGES_TO_CLIENT[language].chat.completions.create(
192
  messages=messages,
193
  max_tokens=2000,
194
  stream=False,
 
227
  if isinstance(message, gr.ChatMessage):
228
  message = message.__dict__
229
  if idx == liked_index:
230
+ if x.liked is True:
231
+ message["metadata"] = {"title": "liked"}
232
+ elif x.liked is False:
233
+ message["metadata"] = {"title": "disliked"}
234
+
235
  if not isinstance(message["metadata"], dict):
236
  message["metadata"] = message["metadata"].__dict__
237
  rating = message["metadata"].get("title")
 
265
 
266
 
267
  def wrangle_edit_data(
268
+ x: gr.EditData,
269
+ history: list,
270
+ dataframe: DataFrame,
271
+ conversation_id: str,
272
+ session_id: str,
273
+ language: str,
274
  ) -> list:
275
  """Edit the conversation and add negative feedback if assistant message is edited, otherwise regenerate the message
276
 
 
286
 
287
  if history[index]["role"] == "user":
288
  # Add feedback on original and corrected message
 
289
  add_fake_like_data(
290
+ history=history[: index + 2],
291
+ conversation_id=conversation_id,
292
+ session_id=session_id,
293
+ language=language,
294
+ liked=True,
295
  )
296
+ add_fake_like_data(
297
+ history=history[: index + 1] + [original_message],
298
+ conversation_id=conversation_id,
299
+ session_id=session_id,
300
+ language=language,
301
+ )
302
+ history = respond(
303
+ history=history[: index + 1],
304
+ language=language,
305
  temperature=random.randint(1, 100) / 100,
306
  seed=random.randint(0, 1000000),
307
  )
308
  return history
309
  else:
310
  # Add feedback on original and corrected message
311
+ add_fake_like_data(
312
+ history=history[: index + 1],
313
+ conversation_id=conversation_id,
314
+ session_id=session_id,
315
+ language=language,
316
+ liked=True,
317
+ )
318
+ add_fake_like_data(
319
+ history=history[:index] + [original_message],
320
+ conversation_id=conversation_id,
321
+ session_id=session_id,
322
+ language=language,
323
+ )
324
  history = history[: index + 1]
325
  # add chosen and rejected options
326
  history[-1]["options"] = [
 
331
 
332
 
333
  def wrangle_retry_data(
334
+ x: gr.RetryData,
335
+ history: list,
336
+ dataframe: DataFrame,
337
+ conversation_id: str,
338
+ session_id: str,
339
+ language: str,
340
  ) -> list:
341
  """Respond to the user message with a system message and add negative feedback on the original message
342
 
343
  Return the history with the new message"""
344
+ add_fake_like_data(
345
+ history=history,
346
+ conversation_id=conversation_id,
347
+ session_id=session_id,
348
+ language=language,
349
+ )
350
 
351
  # Return the history without a new message
352
+ history = respond(
353
+ history=history[:-1],
354
+ language=language,
355
  temperature=random.randint(1, 100) / 100,
356
  seed=random.randint(0, 1000000),
357
  )
358
  return history, update_dataframe(dataframe, history)
359
 
360
 
361
+ def submit_conversation(dataframe, conversation_id, session_id, language):
362
  """ "Submit the conversation to dataset repo"""
363
  if dataframe.empty or len(dataframe) < 2:
364
  gr.Info("No feedback to submit.")
 
371
  "conversation": conversation,
372
  "timestamp": datetime.now().isoformat(),
373
  "session_id": session_id,
374
+ "conversation_id": conversation_id,
375
  "language": language,
376
  }
377
  save_feedback(input_object=conversation_data)
 
378
  return (gr.Dataframe(value=None, interactive=False), [])
379
 
380
 
 
400
 
401
  with gr.Accordion("Explanation") as explanation:
402
  gr.Markdown(f"""
403
+ FeeL is a collaboration between Hugging Face and MIT.
404
+ It is a community-driven project to provide a real-time feedback loop for VLMs, where your feedback is continuously used to fine-tune the underlying models.
405
+ The [dataset](https://huggingface.co/datasets/{scheduler.repo_id}), [code](https://github.com/huggingface/feel) and [models](https://huggingface.co/collections/feel-fl/feel-models-67a9b6ef0fdd554315e295e8) are public.
406
 
407
  Start by selecting your language, chat with the model with text and images and provide feedback in different ways.
408
 
 
410
  - 👍/👎 Like or dislike a message
411
  - 🔄 Regenerate a message
412
 
413
+ Feedback is automatically submitted allowing you to continue chatting, but you can also submit and reset the conversation by clicking "💾 Submit conversation" (under the chat) or trash the conversation by clicking "🗑️" (upper right corner).
414
  """)
415
  language = gr.Dropdown(
416
  choices=list(LANGUAGES.keys()), label="Language", interactive=True
 
422
  visible=False,
423
  )
424
 
425
+ conversation_id = gr.Textbox(
426
+ interactive=False,
427
+ value=str(uuid.uuid4()),
428
+ visible=False,
429
+ )
430
+
431
  chatbot = gr.Chatbot(
432
  elem_id="chatbot",
433
  editable="all",
 
442
  feedback_options=["Like", "Dislike"],
443
  )
444
 
445
+ chat_input = gr.Textbox(
446
  interactive=True,
 
447
  placeholder="Enter message or upload file...",
448
  show_label=False,
449
  submit_btn=True,
450
  )
451
 
452
+ with gr.Accordion("Collected feedback", open=False):
453
+ dataframe = gr.Dataframe(wrap=True, label="Collected feedback")
454
 
455
+ submit_btn = gr.Button(value="💾 Submit conversation", visible=False)
 
 
456
 
457
  ##############################
458
  # Deal with feedback
 
468
  fn=add_user_message,
469
  inputs=[chatbot, chat_input],
470
  outputs=[chatbot, chat_input],
471
+ ).then(respond, inputs=[chatbot, language], outputs=[chatbot]).then(
472
  lambda: gr.Textbox(interactive=True), None, [chat_input]
473
+ ).then(update_dataframe, inputs=[dataframe, chatbot], outputs=[dataframe]).then(
474
+ submit_conversation,
475
+ inputs=[dataframe, conversation_id, session_id, language],
476
+ )
477
 
478
  chatbot.like(
479
  fn=wrangle_like_data,
480
  inputs=[chatbot],
481
  outputs=[chatbot, dataframe],
482
  like_user_message=False,
483
+ ).then(
484
+ submit_conversation,
485
+ inputs=[dataframe, conversation_id, session_id, language],
486
  )
487
 
488
  chatbot.retry(
489
  fn=wrangle_retry_data,
490
+ inputs=[chatbot, dataframe, conversation_id, session_id, language],
491
  outputs=[chatbot, dataframe],
492
  )
493
 
494
  chatbot.edit(
495
  fn=wrangle_edit_data,
496
+ inputs=[chatbot, dataframe, conversation_id, session_id, language],
497
  outputs=[chatbot],
498
  ).then(update_dataframe, inputs=[dataframe, chatbot], outputs=[dataframe])
499
 
500
+ gr.on(
501
+ triggers=[submit_btn.click, chatbot.clear],
502
  fn=submit_conversation,
503
+ inputs=[dataframe, conversation_id, session_id, language],
504
  outputs=[dataframe, chatbot],
505
+ ).then(
506
+ fn=lambda x: str(uuid.uuid4()),
507
+ inputs=[conversation_id],
508
+ outputs=[conversation_id],
509
  )
510
+
511
  demo.load(
512
  lambda: str(uuid.uuid4()),
513
  inputs=[],
 
515
  )
516
 
517
  demo.launch()