ankstoo commited on
Commit
499b1cd
·
1 Parent(s): 38ea214
Files changed (8) hide show
  1. app.py +21 -14
  2. data.py +11 -0
  3. data_experiments.py +55 -0
  4. data_photos.py +87 -0
  5. experiments.jsonl +0 -0
  6. llm_messages_v1.py +75 -0
  7. llm_messages_v2.py +68 -0
  8. llm_messages_v3.py +73 -0
app.py CHANGED
@@ -22,6 +22,8 @@ from transformers import (
22
  )
23
  from transformers.image_utils import load_image
24
 
 
 
25
  # Constants for text generation
26
  MAX_MAX_NEW_TOKENS = 2048
27
  DEFAULT_MAX_NEW_TOKENS = 1024
@@ -103,11 +105,16 @@ def process_image(
103
  yield buffer, buffer
104
 
105
 
106
- # Define examples for image and video inference
107
- image_examples = [
108
- ["Jsonify Data.", "images/1.jpg"],
109
- ["Explain the pie-chart in detail.", "images/2.jpg"]
110
- ]
 
 
 
 
 
111
 
112
  css = """
113
  .submit-btn {
@@ -129,12 +136,18 @@ with gr.Blocks(css=css, theme="bethecloud/storj_theme") as demo:
129
  gr.Markdown("# **Experiments photo moderation**")
130
  with gr.Row():
131
  with gr.Column():
 
 
 
 
 
132
  image_query = gr.Textbox(label="Query Input", placeholder="Enter your query here...")
133
  image_upload = gr.Image(type="pil", label="Image")
134
  image_submit = gr.Button("Submit", elem_classes="submit-btn")
135
- gr.Examples(
136
- examples=image_examples,
137
- inputs=[image_query, image_upload]
 
138
  )
139
  with gr.Accordion("Advanced options", open=False):
140
  max_new_tokens = gr.Slider(label="Max new tokens", minimum=1, maximum=MAX_MAX_NEW_TOKENS, step=1, value=DEFAULT_MAX_NEW_TOKENS)
@@ -150,12 +163,6 @@ with gr.Blocks(css=css, theme="bethecloud/storj_theme") as demo:
150
 
151
  with gr.Accordion("(Result.md)", open=False):
152
  markdown_output = gr.Markdown()
153
-
154
- model_choice = gr.Radio(
155
- choices=["Qwen2.5-VL-7B-Instruct", "Qwen2.5-VL-3B-Instruct"],
156
- label="Select Model",
157
- value="Qwen2.5-VL-7B-Instruct"
158
- )
159
 
160
  image_submit.click(
161
  fn=process_image,
 
22
  )
23
  from transformers.image_utils import load_image
24
 
25
+ from data_experiments import filter_experiments
26
+
27
  # Constants for text generation
28
  MAX_MAX_NEW_TOKENS = 2048
29
  DEFAULT_MAX_NEW_TOKENS = 1024
 
105
  yield buffer, buffer
106
 
107
 
108
+ experiments_to_select = filter_experiments(
109
+ product_id="chemistry",
110
+ )
111
+ experiments_to_select = sorted(experiments_to_select, key=lambda x: x["id"])
112
+
113
+ def format_experiment_dropdown_title(experiment: dict) -> str:
114
+ id = str(experiment["id"])
115
+ title = experiment.get("title", "")
116
+ product = experiment.get("product_id", "")
117
+ return f"{id}. {title} ({product})"
118
 
119
  css = """
120
  .submit-btn {
 
136
  gr.Markdown("# **Experiments photo moderation**")
137
  with gr.Row():
138
  with gr.Column():
139
+ gr.Dropdown(
140
+ choices=[(format_experiment_dropdown_title(exp), exp["id"]) for exp in experiments_to_select],
141
+ value=None,
142
+ label="Select Experiment",
143
+ )
144
  image_query = gr.Textbox(label="Query Input", placeholder="Enter your query here...")
145
  image_upload = gr.Image(type="pil", label="Image")
146
  image_submit = gr.Button("Submit", elem_classes="submit-btn")
147
+ model_choice = gr.Radio(
148
+ choices=["Qwen2.5-VL-7B-Instruct", "Qwen2.5-VL-3B-Instruct"],
149
+ label="Select Model",
150
+ value="Qwen2.5-VL-7B-Instruct"
151
  )
152
  with gr.Accordion("Advanced options", open=False):
153
  max_new_tokens = gr.Slider(label="Max new tokens", minimum=1, maximum=MAX_MAX_NEW_TOKENS, step=1, value=DEFAULT_MAX_NEW_TOKENS)
 
163
 
164
  with gr.Accordion("(Result.md)", open=False):
165
  markdown_output = gr.Markdown()
 
 
 
 
 
 
166
 
167
  image_submit.click(
168
  fn=process_image,
data.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+ def load_jsonl(file_path) -> list[dict]:
4
+ result = []
5
+ with open(file_path, 'r', encoding='utf-8') as file:
6
+ for line in file:
7
+ if not line.strip() or line.startswith('#') or line.startswith('//'):
8
+ continue
9
+ json_line = json.loads(line)
10
+ result.append(json_line)
11
+ return result
data_experiments.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Union
2
+ from collections import defaultdict
3
+
4
+ from data import load_jsonl
5
+
6
+
7
+ all_experiments = load_jsonl('experiments.jsonl')
8
+
9
+ experiment_ids_by_product_id = defaultdict(list)
10
+ for experiment in all_experiments:
11
+ product_id = experiment.get('product_id')
12
+ if product_id is not None:
13
+ experiment_ids_by_product_id[product_id].append(experiment["id"])
14
+
15
+
16
+ def get_experiment_by_id(experiment_id: int) -> Union[dict, None]:
17
+ for experiment in all_experiments:
18
+ if experiment['id'] == experiment_id:
19
+ return experiment
20
+ return None
21
+
22
+
23
+ def filter_experiments(
24
+ experiments: Union[list[dict], None] = None,
25
+ product_id: Union[str, list[str], None] = None,
26
+ experiment_id: Union[int, list[int], None] = None,
27
+ ) -> list[dict]:
28
+ filtered_experiments = experiments
29
+ if filtered_experiments is None:
30
+ filtered_experiments = all_experiments
31
+ if product_id is not None:
32
+ if isinstance(product_id, str):
33
+ product_id = {product_id}
34
+ filtered_experiments = [exp for exp in filtered_experiments if exp.get('product_id') in product_id]
35
+ if experiment_id is not None:
36
+ if isinstance(experiment_id, int):
37
+ experiment_id = {experiment_id}
38
+ filtered_experiments = [exp for exp in filtered_experiments if exp['id'] in experiment_id]
39
+ return filtered_experiments
40
+
41
+
42
+ def get_experiment(
43
+ experiments: Union[list[dict], None] = None,
44
+ product_id: Union[str, list[str], None] = None,
45
+ experiment_id: Union[int, None] = None,
46
+ ) -> Union[dict, None]:
47
+ filtered_experiments = filter_experiments(
48
+ experiments=experiments,
49
+ product_id=product_id,
50
+ experiment_id=experiment_id
51
+ )
52
+ if filtered_experiments:
53
+ return filtered_experiments[0]
54
+ else:
55
+ return None
data_photos.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Union
2
+ from enum import Enum
3
+
4
+ from data import load_jsonl
5
+ from data_experiments import experiment_ids_by_product_id
6
+
7
+ class PhotoModerationState(Enum):
8
+ INAPPROPRIATE = "inappropriate"
9
+ SAFE = "safe"
10
+ SAFE_FOR_SHARING = "safe_for_sharing"
11
+ UNKNOWN = "unknown"
12
+
13
+ class PhotoApprovalState(Enum):
14
+ APPROVED = "approved"
15
+ FAILED = "failed"
16
+ SUPERSEDED = "superseded"
17
+ UNKNOWN = "unknown"
18
+
19
+ all_photos = load_jsonl('mobile_photo_uploads_2.jsonl')
20
+
21
+ def get_photo_by_id(photo_id: str) -> Union[dict, None]:
22
+ for photo in all_photos:
23
+ if photo['uid'] == photo_id:
24
+ return photo
25
+ return None
26
+
27
+ def get_photo_url(photo: dict) -> str:
28
+ uid = photo['uid']
29
+ url = f'https://res.cloudinary.com/mel-science/image/upload/c_limit,w_1024,h_1024/v1/dotcomprodmobup/{uid}.jpg'
30
+ return url
31
+
32
+ def filter_photos(
33
+ photos: Union[list[dict], None] = None,
34
+ experiment_id: Union[int, list[int], None] = None,
35
+ product_id: Union[str, list[str], None] = None,
36
+ uid: Union[str, set[str], None] = None,
37
+ is_sharing_requested: Union[bool, None] = None,
38
+ moderation_state: Union[set[PhotoModerationState], None] = None,
39
+ approval_state: Union[set[PhotoApprovalState], None] = None,
40
+ ) -> list[dict]:
41
+ filtered_photos = photos
42
+ if filtered_photos is None:
43
+ filtered_photos = all_photos
44
+ if experiment_id is not None:
45
+ if isinstance(experiment_id, int):
46
+ experiment_id = {experiment_id}
47
+ filtered_photos = [photo for photo in filtered_photos if int(photo.get('experiment_id')) in experiment_id]
48
+ if product_id is not None:
49
+ if isinstance(product_id, str):
50
+ product_id = {product_id}
51
+ product_experiment_ids = set()
52
+ for id in product_id:
53
+ product_experiment_ids.update(experiment_ids_by_product_id.get(id, []))
54
+ filtered_photos = [photo for photo in filtered_photos if int(photo.get('experiment_id')) in product_experiment_ids]
55
+ if uid is not None:
56
+ if isinstance(uid, str):
57
+ uid = {uid}
58
+ filtered_photos = [photo for photo in filtered_photos if photo.get('uid') in uid]
59
+ if is_sharing_requested is not None:
60
+ filtered_photos = [photo for photo in filtered_photos if photo.get('is_sharing_requested') == str(is_sharing_requested)]
61
+ if moderation_state is not None:
62
+ values = {state.value for state in moderation_state}
63
+ filtered_photos = [photo for photo in filtered_photos if photo.get('moderation_state') in values]
64
+ if approval_state is not None:
65
+ values = {state.value for state in approval_state}
66
+ filtered_photos = [photo for photo in filtered_photos if photo.get('approval_state') in values]
67
+ return filtered_photos
68
+
69
+ def get_photo(
70
+ photos: Union[list[dict], None] = None,
71
+ experiment_id: Union[int, None] = None,
72
+ uid: Union[str, set[str], None] = None,
73
+ is_sharing_requested: Union[bool, None] = None,
74
+ moderation_state: Union[set[PhotoModerationState], None] = None,
75
+ approval_state: Union[set[PhotoApprovalState], None] = None,
76
+ ) -> Union[dict, None]:
77
+ filtered_photos = filter_photos(
78
+ photos=photos,
79
+ experiment_id=experiment_id,
80
+ uid=uid,
81
+ is_sharing_requested=is_sharing_requested,
82
+ moderation_state=moderation_state,
83
+ approval_state=approval_state,
84
+ )
85
+ if not filtered_photos:
86
+ return None
87
+ return filtered_photos[0]
experiments.jsonl ADDED
The diff for this file is too large to render. See raw diff
 
llm_messages_v1.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
2
+
3
+ from data import get_photo_url
4
+
5
+ def format_experiment(experiment: dict) -> str:
6
+ lines = []
7
+
8
+ lines.append(f"Experiment: {experiment['title']}")
9
+ lines.append(f"Description: {experiment['short_description']}")
10
+
11
+ experiment_steps = experiment.get('steps', [])
12
+ if experiment_steps:
13
+ lines.append("Steps:")
14
+ step_index = 1
15
+ for step in experiment_steps:
16
+ step_text = step.get('text', '').strip()
17
+ if step_text:
18
+ lines.append(f" {step_index}. {step_text}")
19
+ step_index += 1
20
+
21
+ experiment_result = experiment.get('expected_result', "").strip()
22
+ if experiment_result:
23
+ lines.append(f"Expected result: {experiment_result}")
24
+
25
+ combined = "\n".join(lines)
26
+ return combined
27
+
28
+
29
+ def format_system_message(experiment: dict) -> SystemMessage:
30
+ lines = []
31
+ lines.append("You are a photo moderation assistant for science experiments.")
32
+ lines.append("Your task is to determine if the provided photo is a succeful result of the experiment, completed setup or user is on the right way to result. And doesn't contain any inappropriate content. Or not.")
33
+ lines.append("")
34
+ lines.append("Here is the experiment details:")
35
+ experiment_text = format_experiment(experiment)
36
+ lines.append(experiment_text)
37
+
38
+ combined = "\n".join(lines)
39
+ return SystemMessage(content=combined)
40
+
41
+ def format_human_message(experiment: dict, photo: dict) -> HumanMessage:
42
+ lines = []
43
+ lines.append("Here is the photo to check")
44
+ # lines.append("Please analyze the photo and determine if it is a successful result of the experiment, completed setup or user is on the right way to result. And doesn't contain any inappropriate content.")
45
+ lines.append("Result options:")
46
+ lines.append("- `approved`: photo is a successful result of the experiment")
47
+ lines.append("- `partial`: photo is something closed to the experiment, but it is not a final successful result (e.g. not all steps are completed, or parts of result are not visible)")
48
+ # lines.append("- `inappropriate`: photo contains inappropriate content (including faces of children)")
49
+ lines.append("- `failed`: photo is not a successful result of the experiment, but doesn't contain inappropriate content")
50
+ # lines.append("Please analyze the photo and determine if it is a successful result of the experiment.")
51
+ lines.append("Answer in the following format:")
52
+ lines.append("```json")
53
+ lines.append('{"result": "approved" | "partial" | "failed", "reason": "your reason for the decision"}')
54
+ lines.append("```")
55
+ combined = "\n".join(lines)
56
+ photo_url = get_photo_url(photo)
57
+ return HumanMessage(content=[
58
+ {"type": "text", "text": combined},
59
+ {"type": "image_url", "image_url": {"url": photo_url}}
60
+ ])
61
+
62
+ def format_ai_message(experiment: dict, photo: dict) -> AIMessage:
63
+ is_approved = photo.get('approval_state', 'unknown') == 'approved'
64
+ result = "approved" if is_approved else "failed"
65
+ reason = photo.get('review_comment', '').strip()
66
+
67
+ lines = []
68
+ lines.append("```json")
69
+ lines.append("{" + f'"result": "{result}", "reason": "{reason}"' + "}")
70
+ lines.append("```")
71
+ combined = "\n".join(lines)
72
+
73
+ return AIMessage(content=[
74
+ {"type": "text", "text": combined},
75
+ ])
llm_messages_v2.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
2
+
3
+ from data import get_photo_url
4
+
5
+ def format_experiment(experiment: dict) -> str:
6
+ lines = []
7
+
8
+ lines.append(f"Experiment: {experiment['title']}")
9
+ lines.append(f"Description: {experiment['short_description']}")
10
+
11
+ experiment_steps = experiment.get('steps', [])
12
+ if experiment_steps:
13
+ lines.append("Steps:")
14
+ step_index = 1
15
+ for step in experiment_steps:
16
+ step_text = step.get('text', '').strip()
17
+ if step_text:
18
+ lines.append(f" {step_index}. {step_text}")
19
+ step_index += 1
20
+
21
+ experiment_result = experiment.get('expected_result', "").strip()
22
+ if experiment_result:
23
+ lines.append(f"Expected result: {experiment_result}")
24
+
25
+ combined = "\n".join(lines)
26
+ return combined
27
+
28
+
29
+ def format_system_message(experiment: dict) -> SystemMessage:
30
+ lines = []
31
+ lines.append("You are a photo moderation assistant for science experiments.")
32
+ lines.append("Your task is to determine if the provided photo is a succeful result of the experiment, completed setup or user is on the right way to result. And doesn't contain any inappropriate content. Or not.")
33
+ # lines.append("")
34
+ # lines.append("Here is the experiment details:")
35
+ # experiment_text = format_experiment(experiment)
36
+ # lines.append(experiment_text)
37
+
38
+ combined = "\n".join(lines)
39
+ return SystemMessage(content=combined)
40
+
41
+ def format_human_message(experiment: dict, photo: dict) -> HumanMessage:
42
+ lines = []
43
+ # lines.append("Here is the photo to check")
44
+ # lines.append("Please analyze the photo and determine if it is a successful result of the experiment.")
45
+ lines.append("Answer in the following format:")
46
+ lines.append("```json")
47
+ lines.append('{"result": "approved" | "failed"}')
48
+ lines.append("```")
49
+ combined = "\n".join(lines)
50
+ photo_url = get_photo_url(photo)
51
+ return HumanMessage(content=[
52
+ {"type": "text", "text": combined},
53
+ {"type": "image_url", "image_url": {"url": photo_url}}
54
+ ])
55
+
56
+ def format_ai_message(experiment: dict, photo: dict) -> AIMessage:
57
+ is_approved = photo.get('approval_state', 'unknown') == 'approved'
58
+ result = "approved" if is_approved else "failed"
59
+
60
+ lines = []
61
+ lines.append("```json")
62
+ lines.append("{" + f'"result": "{result}"' + "}")
63
+ lines.append("```")
64
+ combined = "\n".join(lines)
65
+
66
+ return AIMessage(content=[
67
+ {"type": "text", "text": combined},
68
+ ])
llm_messages_v3.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
2
+
3
+ from data import get_photo_url
4
+
5
+ def format_experiment(experiment: dict) -> str:
6
+ lines = []
7
+
8
+ lines.append(f"Experiment: {experiment['title']}")
9
+ lines.append(f"Description: {experiment['short_description']}")
10
+
11
+ experiment_steps = experiment.get('steps', [])
12
+ if experiment_steps:
13
+ lines.append("Steps:")
14
+ step_index = 1
15
+ for step in experiment_steps:
16
+ step_text = step.get('text', '').strip()
17
+ if step_text:
18
+ lines.append(f" {step_index}. {step_text}")
19
+ step_index += 1
20
+
21
+ experiment_result = experiment.get('expected_result', "").strip()
22
+ if experiment_result:
23
+ lines.append(f"Expected result: {experiment_result}")
24
+
25
+ combined = "\n".join(lines)
26
+ return combined
27
+
28
+
29
+ def format_system_message(experiment: dict) -> SystemMessage:
30
+ lines = []
31
+ lines.append("You are a photo moderation assistant for science experiments.")
32
+ lines.append("Your task is to determine if the provided photo is a succeful result of the experiment, completed setup or user is on the right way to result. And doesn't contain any inappropriate content. Or not.")
33
+ # lines.append("")
34
+ # lines.append("Here is the experiment details:")
35
+ # experiment_text = format_experiment(experiment)
36
+ # lines.append(experiment_text)
37
+
38
+ combined = "\n".join(lines)
39
+ return SystemMessage(content=combined)
40
+
41
+ def format_human_message(experiment: dict, photo: dict) -> HumanMessage:
42
+ lines = []
43
+
44
+ lines.append("Here is the experiment details:")
45
+ experiment_text = format_experiment(experiment)
46
+ lines.append(experiment_text)
47
+ lines.append("")
48
+
49
+ lines.append("Your task is to determine if the provided photo is a succeful result of the experiment, completed setup or user is on the right way to result. And doesn't contain any inappropriate content. Or not.")
50
+ lines.append("Answer in the following format:")
51
+ lines.append("```json")
52
+ lines.append('{"result": "approved" | "failed"}')
53
+ lines.append("```")
54
+ combined = "\n".join(lines)
55
+ photo_url = get_photo_url(photo)
56
+ return HumanMessage(content=[
57
+ {"type": "text", "text": combined},
58
+ {"type": "image_url", "image_url": {"url": photo_url}}
59
+ ])
60
+
61
+ def format_ai_message(experiment: dict, photo: dict) -> AIMessage:
62
+ is_approved = photo.get('approval_state', 'unknown') == 'approved'
63
+ result = "approved" if is_approved else "failed"
64
+
65
+ lines = []
66
+ lines.append("```json")
67
+ lines.append("{" + f'"result": "{result}"' + "}")
68
+ lines.append("```")
69
+ combined = "\n".join(lines)
70
+
71
+ return AIMessage(content=[
72
+ {"type": "text", "text": combined},
73
+ ])