Isaacgv commited on
Commit
b6d2398
·
1 Parent(s): 2de4b7f

update project

Browse files
README.md DELETED
@@ -1,12 +0,0 @@
1
- ---
2
- title: Classification
3
- emoji: ⚡
4
- colorFrom: blue
5
- colorTo: pink
6
- sdk: gradio
7
- sdk_version: 3.23.0
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -12,70 +12,147 @@ Title : Inference With Gradio running an onnxruntime backend
12
  import os
13
 
14
  import gradio as gr
 
15
  import sys
16
 
17
  sys.path.append(".")
 
18
  from config_parser import *
19
  from inferencer import *
20
 
21
  gr.close_all()
22
 
23
 
24
- def infertace_builder():
25
- interface_list = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  logging.log(level=logging.INFO, msg=f"Building Interfaces")
 
27
  for task_number in range(0, len(tasks)):
28
- logging.log(level=logging.INFO, msg=f"Building Interface {task_number}")
29
- interface_list.append(
30
- gr.Interface(
31
- title=tasks[task_number],
32
- description=tasks_description[task_number],
33
- fn=analysis,
34
- # if tasks_name[task_number] == "Étiquetage"
35
- # else corck_screwing_analysis,
36
- allow_flagging="never",
37
- inputs=[
38
- gr.Textbox(
39
- value=f"task{task_number+1}", visible=False, interactive=False
40
- ),
41
- gr.Dropdown(
42
- tasks_products[task_number],
43
- type="value",
44
- value=tasks_products[task_number][0],
45
- label="Choix",
46
- visible=True if len(tasks_products[task_number]) > 1 else False,
47
- info="Sur quel type de produit, voulez vous lancer l'analyse ?",
48
- ),
49
- gr.Image(
50
- label="Image à analyser",
51
- shape=None,
52
- image_mode="RGB",
53
- invert_colors=False,
54
- source="upload",
55
- tool="editor",
56
- type="numpy",
57
- ),
58
- ],
59
- outputs=gr.Label(
60
- label="Résultats",
61
- ),
62
  )
63
  )
64
  logging.log(level=logging.INFO, msg=f"Interfaces ready\n")
65
- return interface_list
 
 
66
 
67
 
68
- generated_interface = infertace_builder()
69
 
70
  iface_generated = gr.TabbedInterface(
71
  interface_list=generated_interface,
72
  tab_names=tasks_name,
73
- title=title,
74
  )
75
 
76
  if __name__ == "__main__":
77
  logging.log(level=logging.INFO, msg="Starting the Gradio server...")
78
  iface_generated.launch(
79
- server_name="0.0.0.0"
80
  )
81
  logging.log(level=logging.INFO, msg="Stopping the Gradio server...")
 
12
  import os
13
 
14
  import gradio as gr
15
+
16
  import sys
17
 
18
  sys.path.append(".")
19
+
20
  from config_parser import *
21
  from inferencer import *
22
 
23
  gr.close_all()
24
 
25
 
26
+ def generate_parralel_interface(task_number, product):
27
+ logging.log(level=logging.INFO, msg=f"Entering generate_parralel_interface")
28
+ generate_parralel_interface_list = []
29
+ number_of_model = len(config["tasks"][f"task{task_number+1}"]["models"][product])
30
+ logging.log(level=logging.INFO, msg=f"Real Number of model: {number_of_model}")
31
+ for model_number in range(0, number_of_model):
32
+ logging.log(level=logging.INFO, msg=f"Building Interface for {product}")
33
+ logging.log(
34
+ level=logging.INFO, msg=f"Building Interface for sub-model n°{model_number}"
35
+ )
36
+ generate_parralel_interface_list.append(
37
+ create_interface(task_number, product, model_number)
38
+ )
39
+ generated_parralel_interface = gr.Parallel(
40
+ *generate_parralel_interface_list,
41
+ title=tasks[task_number],
42
+ description=tasks_description[task_number],
43
+ )
44
+ logging.log(level=logging.INFO, msg=f"Leaving generate_parralel_interface")
45
+ return generated_parralel_interface
46
+
47
+
48
+ def create_interface(task_number, product, model_number):
49
+ logging.log(level=logging.INFO, msg=f"Entering create_interface")
50
+ title = tasks[task_number]
51
+ description = tasks_description[task_number]
52
+ product_lists = tasks_products[task_number]
53
+ logging.log(level=logging.INFO, msg=f"Title : {title}")
54
+ logging.log(level=logging.INFO, msg=f"Description : {description}")
55
+ logging.log(level=logging.INFO, msg=f"Product list : {product_lists}")
56
+ logging.log(level=logging.INFO, msg=f"Model Number: {model_number}")
57
+
58
+ created_interface = gr.Interface(
59
+ title=title,
60
+ description=description,
61
+ fn=inferencer_arr[f"task{task_number+1}"][product][str(model_number)][
62
+ "function"
63
+ ],
64
+ # fn=lambda x: x,
65
+ allow_flagging="never",
66
+ inputs=[
67
+ gr.Textbox(
68
+ value=f"task{task_number+1}",
69
+ label="Tasks",
70
+ visible=False,
71
+ interactive=False,
72
+ ),
73
+ gr.Dropdown(
74
+ tasks_products[task_number],
75
+ type="value",
76
+ value=product,
77
+ label="Choix",
78
+ # visible=True if len(tasks_products[task_number]) > 1 else False,
79
+ visible=False,
80
+ info="Sur quel type de produit, voulez vous lancer l'analyse ?",
81
+ ),
82
+ gr.Image(
83
+ label="Image à analyser",
84
+ shape=None,
85
+ image_mode="RGB",
86
+ invert_colors=False,
87
+ source="upload",
88
+ tool="editor",
89
+ type="numpy",
90
+ ),
91
+ ],
92
+ outputs=gr.Label(
93
+ label="Résultats",
94
+ ),
95
+ )
96
+ logging.log(level=logging.INFO, msg=f"Leaving create_interface")
97
+ return created_interface
98
+
99
+
100
+ def interface_builder():
101
+ interface_builder_list = []
102
+ interface_builder_dict = {}
103
  logging.log(level=logging.INFO, msg=f"Building Interfaces")
104
+ logging.log(level=logging.INFO, msg=f"Number of task(s) : {len(tasks)}")
105
  for task_number in range(0, len(tasks)):
106
+ logging.log(level=logging.INFO, msg=f"Treating task n°{task_number+1}")
107
+ logging.log(level=logging.INFO, msg=f"Building Interface n°{task_number+1}")
108
+ interface_builder_dict[tasks[task_number]] = {}
109
+ product_list = list(config["tasks"][f"task{task_number+1}"]["models"].keys())
110
+ logging.log(level=logging.DEBUG, msg=f"Products : {product_list}")
111
+ interface_builder_product_level_list = []
112
+ for product in product_list:
113
+ logging.log(level=logging.INFO, msg=f"Product : {product}")
114
+ interface_builder_dict[tasks[task_number]][product] = []
115
+ if len(config["tasks"][f"task{task_number+1}"]["models"][product]) > 1:
116
+ generated_parralel_interface = generate_parralel_interface(
117
+ task_number, product
118
+ )
119
+ interface_builder_dict[tasks[task_number]][product].append(
120
+ generated_parralel_interface
121
+ )
122
+ interface_builder_product_level_list.append(
123
+ generated_parralel_interface
124
+ )
125
+ else:
126
+ generated_interface = create_interface(
127
+ task_number=task_number, product=product, model_number=0
128
+ )
129
+ interface_builder_dict[tasks[task_number]][product].append(
130
+ generated_interface
131
+ )
132
+ interface_builder_product_level_list.append(generated_interface)
133
+ interface_builder_list.append(
134
+ gr.TabbedInterface(
135
+ interface_list=interface_builder_product_level_list,
136
+ tab_names=product_list,
 
 
 
137
  )
138
  )
139
  logging.log(level=logging.INFO, msg=f"Interfaces ready\n")
140
+ # logging.log(level=logging.INFO, msg=f"Interfaces Dict {interface_dict}")
141
+ logging.log(level=logging.DEBUG, msg=f"Interfaces List {interface_builder_list}")
142
+ return interface_builder_list
143
 
144
 
145
+ generated_interface = interface_builder()
146
 
147
  iface_generated = gr.TabbedInterface(
148
  interface_list=generated_interface,
149
  tab_names=tasks_name,
150
+ title=f"{title} - {description}",
151
  )
152
 
153
  if __name__ == "__main__":
154
  logging.log(level=logging.INFO, msg="Starting the Gradio server...")
155
  iface_generated.launch(
156
+ server_name="0.0.0.0")
157
  )
158
  logging.log(level=logging.INFO, msg="Stopping the Gradio server...")
configtest.json → config_file/configtest.json RENAMED
File without changes
config_file/demo_full_yvesrocher.json ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "title": "YVES ROCHER",
3
+ "description": "Démonstration des algos de reconnaissance d'étiquetage/bouchage correct",
4
+ "tasks": {
5
+ "task1": {
6
+ "shortname": "Étiquetage",
7
+ "name": {
8
+ "en": "Quality Control of Labels",
9
+ "fr": "Contrôle de l'Étiquetage"
10
+ },
11
+ "description": {
12
+ "en": "Is the label in the right position ?",
13
+ "fr": "Est-ce que l'étiquette est bien positionnée ?"
14
+ },
15
+ "products": [
16
+ "497 Pure Algue 200ml",
17
+ "505 Pure Calmille 200ml",
18
+ "614 Eco Douche 100ml",
19
+ "648 Hair Care 300ml"
20
+ ],
21
+ "models": {
22
+ "497 Pure Algue 200ml": [
23
+ {
24
+ "type": "classification",
25
+ "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/po2xfZzK0KtWZUpXrFjZ/model.onnx",
26
+ "input_shape": 224,
27
+ "mean": [
28
+ 0.485,
29
+ 0.456,
30
+ 0.406
31
+ ],
32
+ "std": [
33
+ 0.229,
34
+ 0.224,
35
+ 0.225
36
+ ],
37
+ "class_names": [
38
+ "Étiquetage correct",
39
+ "Étiquetage incorrect"
40
+ ]
41
+ },
42
+ {
43
+ "type": "classification",
44
+ "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/po2xfZzK0KtWZUpXrFjZ/model.onnx",
45
+ "input_shape": 224,
46
+ "mean": [
47
+ 0.485,
48
+ 0.456,
49
+ 0.406
50
+ ],
51
+ "std": [
52
+ 0.229,
53
+ 0.224,
54
+ 0.225
55
+ ],
56
+ "class_names": [
57
+ "Étiquetage correct",
58
+ "Étiquetage incorrect"
59
+ ]
60
+ }
61
+ ],
62
+ "505 Pure Calmille 200ml": [
63
+ {
64
+ "type": "classification",
65
+ "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/po2xfZzK0KtWZUpXrFjZ/model.onnx",
66
+ "input_shape": 224,
67
+ "mean": [
68
+ 0.485,
69
+ 0.456,
70
+ 0.406
71
+ ],
72
+ "std": [
73
+ 0.229,
74
+ 0.224,
75
+ 0.225
76
+ ],
77
+ "class_names": [
78
+ "Étiquetage correct",
79
+ "Étiquetage incorrect"
80
+ ]
81
+ }
82
+ ],
83
+ "614 Eco Douche 100ml": [
84
+ {
85
+ "type": "classification",
86
+ "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/po2xfZzK0KtWZUpXrFjZ/model.onnx",
87
+ "input_shape": 224,
88
+ "mean": [
89
+ 0.485,
90
+ 0.456,
91
+ 0.406
92
+ ],
93
+ "std": [
94
+ 0.229,
95
+ 0.224,
96
+ 0.225
97
+ ],
98
+ "class_names": [
99
+ "Étiquetage correct",
100
+ "Étiquetage incorrect"
101
+ ]
102
+ }
103
+ ],
104
+ "648 Hair Care 300ml": [
105
+ {
106
+ "type": "classification",
107
+ "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/J5dAmDWboJNDouVkMVIL/model.onnx",
108
+ "input_shape": 224,
109
+ "mean": [
110
+ 0.485,
111
+ 0.456,
112
+ 0.406
113
+ ],
114
+ "std": [
115
+ 0.229,
116
+ 0.224,
117
+ 0.225
118
+ ],
119
+ "class_names": [
120
+ "Étiquetage correct",
121
+ "Étiquetage incorrect"
122
+ ]
123
+ }
124
+ ]
125
+ }
126
+ },
127
+ "task2": {
128
+ "shortname": "Bouchage",
129
+ "name": {
130
+ "en": "Quality Control of Corck Screwing",
131
+ "fr": "Contrôle du Bouchage"
132
+ },
133
+ "description": {
134
+ "en": "Is the corck in the right position ?",
135
+ "fr": "Est-ce que le bouchon est bien positionné et entièrement vissé ?"
136
+ },
137
+ "products": [
138
+ "187 Hamamelis 300ml",
139
+ "550 SVC 300ml",
140
+ "600 PN 500 ml"
141
+ ],
142
+ "models": {
143
+ "187 Hamamelis 300ml": [
144
+ {
145
+ "type": "classification",
146
+ "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/Qp6BRHBcLq7KKxqCWqmV/model.onnx",
147
+ "input_shape": 224,
148
+ "mean": [
149
+ 0.485,
150
+ 0.456,
151
+ 0.406
152
+ ],
153
+ "std": [
154
+ 0.229,
155
+ 0.224,
156
+ 0.225
157
+ ],
158
+ "class_names": [
159
+ "Bouchage correct",
160
+ "Bouchage incorrect"
161
+ ]
162
+ }
163
+ ],
164
+ "550 SVC 300ml": [
165
+ {
166
+ "type": "anomaly_detection-classification",
167
+ "path": "/Users/bastien/Downloads/model_corck_screwing.onnx",
168
+ "input_shape": 256,
169
+ "mean": [
170
+ 0.485,
171
+ 0.456,
172
+ 0.406
173
+ ],
174
+ "std": [
175
+ 0.229,
176
+ 0.224,
177
+ 0.225
178
+ ],
179
+ "class_names": [
180
+ "Bouchage correct",
181
+ "Bouchage incorrect"
182
+ ]
183
+ }
184
+ ],
185
+ "600 PN 500 ml": [
186
+ {
187
+ "type": "anomaly_detection-classification",
188
+ "path": "/Users/bastien/Downloads/model_corck_screwing.onnx",
189
+ "input_shape": 256,
190
+ "mean": [
191
+ 0.485,
192
+ 0.456,
193
+ 0.406
194
+ ],
195
+ "std": [
196
+ 0.229,
197
+ 0.224,
198
+ 0.225
199
+ ],
200
+ "class_names": [
201
+ "Bouchage correct",
202
+ "Bouchage incorrect"
203
+ ]
204
+ }
205
+ ]
206
+ }
207
+ }
208
+ }
209
+ }
config_file/demo_yvesrocher.json ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "title": "YVES ROCHER",
3
+ "description": "Démonstration des algos de reconnaissance d'étiquetage/bouchage correct",
4
+ "tasks": {
5
+ "task1": {
6
+ "shortname": "Étiquetage",
7
+ "name": {
8
+ "en": "Quality Control of Labels",
9
+ "fr": "Contrôle de l'Étiquetage"
10
+ },
11
+ "description": {
12
+ "en": "Is the label in the right position ?",
13
+ "fr": "Est-ce que l'étiquette est bien positionnée ?"
14
+ },
15
+ "products": [
16
+ "505 Pure Calmille 200ml"
17
+ ],
18
+ "models": {
19
+ "505 Pure Calmille 200ml": [
20
+ {
21
+ "type": "classification",
22
+ "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/dmeQ6Mae0HKDwkHBTdh2/model.onnx",
23
+ "input_shape": 224,
24
+ "mean": [
25
+ 0.485,
26
+ 0.456,
27
+ 0.406
28
+ ],
29
+ "std": [
30
+ 0.229,
31
+ 0.224,
32
+ 0.225
33
+ ],
34
+ "class_names": [
35
+ "Étiquetage correct",
36
+ "Étiquetage incorrect"
37
+ ]
38
+ }
39
+ ],
40
+ "648 Haire Care 300 ml": [
41
+ {
42
+ "type": "classification",
43
+ "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/uDFdeazjnSzTnIE0JVSf/model.onnx",
44
+ "input_shape": 224,
45
+ "mean": [
46
+ 0.485,
47
+ 0.456,
48
+ 0.406
49
+ ],
50
+ "std": [
51
+ 0.229,
52
+ 0.224,
53
+ 0.225
54
+ ],
55
+ "class_names": [
56
+ "Étiquetage correct",
57
+ "Étiquetage incorrect"
58
+ ]
59
+ },
60
+ {
61
+ "type": "classification",
62
+ "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/J5dAmDWboJNDouVkMVIL/model.onnx",
63
+ "input_shape": 224,
64
+ "mean": [
65
+ 0.485,
66
+ 0.456,
67
+ 0.406
68
+ ],
69
+ "std": [
70
+ 0.229,
71
+ 0.224,
72
+ 0.225
73
+ ],
74
+ "class_names": [
75
+ "Étiquetage correct",
76
+ "Étiquetage incorrect"
77
+ ]
78
+ }
79
+ ]
80
+ }
81
+ },
82
+ "task2": {
83
+ "shortname": "Bouchage",
84
+ "name": {
85
+ "en": "Quality Control of Corck Screwing",
86
+ "fr": "Contrôle du Bouchage"
87
+ },
88
+ "description": {
89
+ "en": "Is the corck in the right position ?",
90
+ "fr": "Est-ce que le bouchon est bien positionné et entièrement vissé ?"
91
+ },
92
+ "products": [
93
+ "187 Hamamelis 300ml"
94
+ ],
95
+ "models": {
96
+ "187 Hamamelis 300ml": [
97
+ {
98
+ "type": "classification",
99
+ "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/3nkoTiBxDNBzqyGtE5w8/model.onnx",
100
+ "input_shape": 224,
101
+ "mean": [
102
+ 0.485,
103
+ 0.456,
104
+ 0.406
105
+ ],
106
+ "std": [
107
+ 0.229,
108
+ 0.224,
109
+ 0.225
110
+ ],
111
+ "class_names": [
112
+ "Bouchage correct",
113
+ "Bouchage incorrect"
114
+ ]
115
+ },
116
+ {
117
+ "type": "classification",
118
+ "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/Qp6BRHBcLq7KKxqCWqmV/model.onnx",
119
+ "input_shape": 224,
120
+ "mean": [
121
+ 0.485,
122
+ 0.456,
123
+ 0.406
124
+ ],
125
+ "std": [
126
+ 0.229,
127
+ 0.224,
128
+ 0.225
129
+ ],
130
+ "class_names": [
131
+ "Bouchage correct",
132
+ "Bouchage incorrect"
133
+ ]
134
+ }
135
+ ]
136
+ }
137
+ }
138
+ }
139
+ }
config_parser.py CHANGED
@@ -15,12 +15,12 @@ import os
15
  from functools import reduce
16
 
17
  logging.basicConfig(
18
- format="%(asctime)s.%(msecs)03d %(levelname)-8s %(message)s",
19
  level=logging.INFO,
20
  datefmt="%Y%m%d-%H%M%S",
21
  )
22
 
23
- with open("demo_yvesrocher.json") as config_file:
24
  config = json.load(config_file)
25
 
26
  logging.log(level=logging.DEBUG, msg=f"Loaded config file : {json.dumps(config)}")
 
15
  from functools import reduce
16
 
17
  logging.basicConfig(
18
+ format="%(asctime)s.%(msecs)03d %(levelname)-8s [%(filename)s:%(lineno)s - %(funcName)20s() ] - %(message)s",
19
  level=logging.INFO,
20
  datefmt="%Y%m%d-%H%M%S",
21
  )
22
 
23
+ with open("config_file/demo_yvesrocher.json") as config_file:
24
  config = json.load(config_file)
25
 
26
  logging.log(level=logging.DEBUG, msg=f"Loaded config file : {json.dumps(config)}")
demo_full_yvesrocher.json DELETED
@@ -1,100 +0,0 @@
1
- {
2
- "title": "YVES ROCHER",
3
- "description": "Démonstration des algos de reconnaissance d'étiquetage/bouchage correct",
4
- "tasks": {
5
- "task1": {
6
- "shortname": "Étiquetage",
7
- "name": {
8
- "en": "Quality Control of Labels",
9
- "fr": "Contrôle de l'Étiquetage"
10
- },
11
- "description": {
12
- "en": "Is the label in the right position ?",
13
- "fr": "Est-ce que l'étiquette est bien positionnée ?"
14
- },
15
- "products":[
16
- "497 Pure Algue 200ml",
17
- "505 Pure Calmille 200ml",
18
- "614 Eco Douche 100ml",
19
- "648 Hair Care 300ml"
20
- ],
21
- "models": {
22
- "497 Pure Algue 200ml": {
23
- "type": "classification",
24
- "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/po2xfZzK0KtWZUpXrFjZ/model.onnx",
25
- "input_shape": 224,
26
- "mean": [0.485, 0.456, 0.406],
27
- "std": [0.229, 0.224, 0.225],
28
- "class_names": ["Étiquetage correct", "Étiquetage incorrect"]
29
- },
30
- "505 Pure Calmille 200ml": {
31
- "type": "classification",
32
- "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/po2xfZzK0KtWZUpXrFjZ/model.onnx",
33
- "input_shape": 224,
34
- "mean": [0.485, 0.456, 0.406],
35
- "std": [0.229, 0.224, 0.225],
36
- "class_names": ["Étiquetage correct", "Étiquetage incorrect"]
37
- },
38
- "614 Eco Douche 100ml": {
39
- "type": "classification",
40
- "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/po2xfZzK0KtWZUpXrFjZ/model.onnx",
41
- "input_shape": 224,
42
- "mean": [0.485, 0.456, 0.406],
43
- "std": [0.229, 0.224, 0.225],
44
- "class_names": ["Étiquetage correct", "Étiquetage incorrect"]
45
- },
46
- "648 Hair Care 300ml": {
47
- "type": "classification",
48
- "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/po2xfZzK0KtWZUpXrFjZ/model.onnx",
49
- "input_shape": 224,
50
- "mean": [0.485, 0.456, 0.406],
51
- "std": [0.229, 0.224, 0.225],
52
- "class_names": ["Étiquetage correct", "Étiquetage incorrect"]
53
- }
54
- }
55
- },
56
- "task2": {
57
- "shortname": "Bouchage",
58
- "name": {
59
- "en": "Quality Control of Corck Screwing",
60
- "fr": "Contrôle du Bouchage"
61
- },
62
- "description": {
63
- "en": "Is the corck in the right position ?",
64
- "fr": "Est-ce que le bouchon est bien positionné et entièrement vissé ?"
65
- },
66
- "products":[
67
- "187 Hamamelis 300ml",
68
- "550 SVC 300ml",
69
- "600 PN 500 ml"
70
- ],
71
- "models": {
72
- "187 Hamamelis 300ml":{
73
- "type": "classification",
74
- "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/Qp6BRHBcLq7KKxqCWqmV/model.onnx",
75
- "input_shape": 224,
76
- "mean": [0.485, 0.456, 0.406],
77
- "std": [0.229, 0.224, 0.225],
78
- "class_names": ["Bouchage correct", "Bouchage incorrect"]
79
- },
80
- "550 SVC 300ml": {
81
- "type": "classification",
82
- "path": "/Users/bastien/Downloads/model_corck_screwing.onnx",
83
- "input_shape": 256,
84
- "mean": [0.485, 0.456, 0.406],
85
- "std": [0.229, 0.224, 0.225],
86
- "class_names": ["Bouchage correct", "Bouchage incorrect"]
87
- },
88
- "600 PN 500 ml": {
89
- "type": "classification",
90
- "path": "/Users/bastien/Downloads/model_corck_screwing.onnx",
91
- "input_shape": 256,
92
- "mean": [0.485, 0.456, 0.406],
93
- "std": [0.229, 0.224, 0.225],
94
- "class_names": ["Bouchage correct", "Bouchage incorrect"]
95
- }
96
- }
97
- }
98
- }
99
- }
100
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
demo_yvesrocher.json DELETED
@@ -1,55 +0,0 @@
1
- {
2
- "title": "YVES ROCHER",
3
- "description": "Démonstration des algos de reconnaissance d'étiquetage/bouchage correct",
4
- "tasks": {
5
- "task1": {
6
- "shortname": "Étiquetage",
7
- "name": {
8
- "en": "Quality Control of Labels",
9
- "fr": "Contrôle de l'Étiquetage"
10
- },
11
- "description": {
12
- "en": "Is the label in the right position ?",
13
- "fr": "Est-ce que l'étiquette est bien positionnée ?"
14
- },
15
- "products":[
16
- "505 Pure Calmille 200ml"
17
- ],
18
- "models": {
19
- "505 Pure Calmille 200ml": {
20
- "type": "classification",
21
- "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/dmeQ6Mae0HKDwkHBTdh2/model.onnx",
22
- "input_shape": 224,
23
- "mean": [0.485, 0.456, 0.406],
24
- "std": [0.229, 0.224, 0.225],
25
- "class_names": ["Étiquetage correct", "Étiquetage incorrect"]
26
- }
27
- }
28
- },
29
- "task2": {
30
- "shortname": "Bouchage",
31
- "name": {
32
- "en": "Quality Control of Corck Screwing",
33
- "fr": "Contrôle du Bouchage"
34
- },
35
- "description": {
36
- "en": "Is the corck in the right position ?",
37
- "fr": "Est-ce que le bouchon est bien positionné et entièrement vissé ?"
38
- },
39
- "products":[
40
- "187 Hamamelis 300ml"
41
- ],
42
- "models": {
43
- "187 Hamamelis 300ml":{
44
- "type": "classification",
45
- "path": "https://automi-test-models.s3.eu-west-3.amazonaws.com/inference-pipeline/3nkoTiBxDNBzqyGtE5w8/model.onnx",
46
- "input_shape": 224,
47
- "mean": [0.485, 0.456, 0.406],
48
- "std": [0.229, 0.224, 0.225],
49
- "class_names": ["Bouchage correct", "Bouchage incorrect"]
50
- }
51
- }
52
- }
53
- }
54
- }
55
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inferencer.py CHANGED
@@ -15,6 +15,26 @@ import requests
15
  from config_parser import *
16
  from torchvision import transforms
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  corck_screwing_metadata = {
19
  "image_threshold": 0.9247307181358337,
20
  "pixel_threshold": 0.9247307181358337,
@@ -27,26 +47,35 @@ logging.log(level=logging.INFO, msg="Loading models...")
27
  for task in config["tasks"].keys():
28
  inferencer_arr[task] = {}
29
  r = None
30
- for model in config["tasks"][task]["models"]:
31
- product_name = model
32
- model_path = config["tasks"][task]["models"][product_name]["path"]
33
- logging.log(
34
- level=logging.INFO,
35
- msg=f"Loading labeling model for product {product_name}",
36
- )
37
- inferencer_arr[task][product_name] = {}
38
- if model_path.startswith("http"):
39
- r = requests.get(model_path, stream=True).content
40
- inferencer_arr[task][product_name][product_name] = ort.InferenceSession(
41
- r if model_path.startswith("http") else model_path
42
- )
43
- inferencer_arr[task][product_name]["input_name"] = (
44
- inferencer_arr[task][product_name][product_name].get_inputs()[0].name
45
- )
46
- inferencer_arr[task][product_name]["output_name"] = (
47
- inferencer_arr[task][product_name][product_name].get_outputs()[0].name
48
- )
49
- logging.log(level=logging.INFO, msg=f"Model for {product_name} loaded\n")
 
 
 
 
 
 
 
 
 
50
  logging.log(level=logging.INFO, msg="All models loaded...\n\n")
51
  logging.log(level=logging.DEBUG, msg=f"Inferencer Array : {inferencer_arr}")
52
 
@@ -56,40 +85,42 @@ def softmax(x):
56
  return e_x / e_x.sum(axis=0)
57
 
58
 
59
- def is_anomalous_classification(prediction, meta_data):
60
  pred_label = None
61
  pred_score = prediction.reshape(-1).max()
 
 
 
62
  if "image_threshold" in meta_data:
63
  pred_label = (
64
- config["tasks"][task]["models"][model]["class_names"][0]
65
  if (pred_score >= meta_data["image_threshold"])
66
- else config["tasks"][task]["models"][model]["class_names"][1]
67
  )
 
 
 
 
68
  return pred_label, pred_score
69
 
70
 
71
- def analysis(task, use_case, image):
72
- """
73
- Main function that process inference and return results strings
74
- Args:
75
- - task
76
- - use case
77
- - image
78
- Returns:
79
- - String including label and confidence of the model
80
- """
81
-
82
- input_image = pre_process_all(task, use_case, image)
83
- result = inference(task, use_case, input_image)
84
- logging.log(level=logging.DEBUG, msg=result)
85
- return result
86
-
87
-
88
- def pre_process_all(task, use_case, image):
89
  preprocessed_image = []
90
- input_shape = config["tasks"][task]["models"][use_case]["input_shape"]
91
- mean = config["tasks"][task]["models"][use_case]["mean"]
92
- std = config["tasks"][task]["models"][use_case]["std"]
93
  logging.log(level=logging.DEBUG, msg=f"Shape {input_shape}")
94
  logging.log(level=logging.DEBUG, msg=f"Mean {mean}")
95
  logging.log(level=logging.DEBUG, msg=f"Std {std}")
@@ -108,29 +139,47 @@ def pre_process_all(task, use_case, image):
108
  return preprocessed_image
109
 
110
 
111
- def inference(task, model, input_image):
112
  """
113
  Process inference for bottle labels
114
  Args:
115
  - task
116
- - use_case (product)
 
117
  - image
118
  Returns:
119
  - String including label and confidence of the model
120
  """
121
-
122
- prediction = inferencer_arr[task][model][model].run(
123
- [inferencer_arr[task][model]["output_name"]],
124
- {inferencer_arr[task][model]["input_name"]: input_image},
 
 
 
 
 
125
  )
126
  prediction = prediction[0].squeeze()
127
- logging.log(level=logging.INFO, msg=f"Softmaxed prediction {softmax(prediction)}")
128
- if config["tasks"][task]["models"][model]["type"] == "classification":
129
- result = f"{config['tasks'][task]['models'][model]['class_names'][np.argmax(prediction)]} avec une confiance de {str(round(softmax(prediction)[np.argmax(prediction)]*100))} %"
130
- elif task == "task2":
131
- label, score = is_anomalous_classification(prediction, corck_screwing_metadata)
 
 
 
 
 
 
 
 
 
 
 
 
132
  result = f"{label} avec une confiance de {str(round(score*100))} %"
133
  else:
134
- result = "Houston, we've got a problem"
135
  logging.log(level=logging.DEBUG, msg=result)
136
  return result
 
15
  from config_parser import *
16
  from torchvision import transforms
17
 
18
+
19
+ def make_func(model_number):
20
+ def _analysis(task, product, image):
21
+ """
22
+ Main function that process inference and return results strings
23
+ Args:
24
+ - task
25
+ - use case
26
+ - image
27
+ Returns:
28
+ - String including label and confidence of the model
29
+ """
30
+ input_image = pre_process_all(task, product, image, model_number=model_number)
31
+ result = inference(task, product, input_image, model_number=model_number)
32
+ logging.log(level=logging.DEBUG, msg=result)
33
+ return result
34
+
35
+ return _analysis
36
+
37
+
38
  corck_screwing_metadata = {
39
  "image_threshold": 0.9247307181358337,
40
  "pixel_threshold": 0.9247307181358337,
 
47
  for task in config["tasks"].keys():
48
  inferencer_arr[task] = {}
49
  r = None
50
+ for product in config["tasks"][task]["models"]:
51
+ inferencer_arr[task][product] = {}
52
+ for model_number in range(len(config["tasks"][task]["models"][product])):
53
+ model = config["tasks"][task]["models"][product][model_number]
54
+ model_path = model["path"]
55
+ logging.log(
56
+ level=logging.INFO,
57
+ msg=f"Loading model for product {product}, version {model_number}",
58
+ )
59
+ inferencer_arr[task][product][str(model_number)] = {}
60
+ if model_path.startswith("http"):
61
+ r = requests.get(model_path, stream=True).content
62
+ inferencer_arr[task][product][str(model_number)][
63
+ "model"
64
+ ] = ort.InferenceSession(r if model_path.startswith("http") else model_path)
65
+ inferencer_arr[task][product][str(model_number)]["function"] = make_func(
66
+ model_number
67
+ )
68
+ inferencer_arr[task][product][str(model_number)]["input_name"] = (
69
+ inferencer_arr[task][product][str(model_number)]["model"]
70
+ .get_inputs()[0]
71
+ .name
72
+ )
73
+ inferencer_arr[task][product][str(model_number)]["output_name"] = (
74
+ inferencer_arr[task][product][str(model_number)]["model"]
75
+ .get_outputs()[0]
76
+ .name
77
+ )
78
+ logging.log(level=logging.INFO, msg=f"Model for {product} loaded\n")
79
  logging.log(level=logging.INFO, msg="All models loaded...\n\n")
80
  logging.log(level=logging.DEBUG, msg=f"Inferencer Array : {inferencer_arr}")
81
 
 
85
  return e_x / e_x.sum(axis=0)
86
 
87
 
88
+ def is_anomalous_classification(task, product, model_number, prediction, meta_data):
89
  pred_label = None
90
  pred_score = prediction.reshape(-1).max()
91
+ logging.log(level=logging.INFO, msg=f"Task {task}")
92
+ logging.log(level=logging.INFO, msg=f"Product {product}")
93
+ class_names = config["tasks"][task]["models"][product][model_number]["class_names"]
94
  if "image_threshold" in meta_data:
95
  pred_label = (
96
+ class_names[0]
97
  if (pred_score >= meta_data["image_threshold"])
98
+ else class_names[1]
99
  )
100
+ logging.log(
101
+ level=logging.INFO,
102
+ msg=f"Predicted label {pred_label} with a confidence of {pred_score}",
103
+ )
104
  return pred_label, pred_score
105
 
106
 
107
+ def pre_process_all(task, product, image, model_number):
108
+ # model_number = model_number-1
109
+ logging.log(level=logging.INFO, msg=f"Task {task}")
110
+ logging.log(level=logging.INFO, msg=f"Product {product}")
111
+ logging.log(level=logging.INFO, msg=f"Model Number {model_number}")
112
+ logging.log(
113
+ level=logging.DEBUG,
114
+ msg=f'Product Array {config["tasks"][task]["models"][product]}',
115
+ )
116
+ logging.log(
117
+ level=logging.DEBUG,
118
+ msg=f'Model Array {config["tasks"][task]["models"][product][model_number]}',
119
+ )
 
 
 
 
 
120
  preprocessed_image = []
121
+ input_shape = config["tasks"][task]["models"][product][model_number]["input_shape"]
122
+ mean = config["tasks"][task]["models"][product][int(model_number)]["mean"]
123
+ std = config["tasks"][task]["models"][product][int(model_number)]["std"]
124
  logging.log(level=logging.DEBUG, msg=f"Shape {input_shape}")
125
  logging.log(level=logging.DEBUG, msg=f"Mean {mean}")
126
  logging.log(level=logging.DEBUG, msg=f"Std {std}")
 
139
  return preprocessed_image
140
 
141
 
142
+ def inference(task, product, input_image, model_number):
143
  """
144
  Process inference for bottle labels
145
  Args:
146
  - task
147
+ - product
148
+ - model to use (number)
149
  - image
150
  Returns:
151
  - String including label and confidence of the model
152
  """
153
+ # model_number = model_number-1
154
+ logging.log(level=logging.DEBUG, msg=f"Inferencer {inferencer_arr}")
155
+ logging.log(level=logging.INFO, msg=f"Task {task}")
156
+ logging.log(level=logging.INFO, msg=f"Product {product}")
157
+ logging.log(level=logging.INFO, msg=f"Model {model_number}")
158
+ result = "Algorithm not yet supported"
159
+ prediction = inferencer_arr[task][product][str(model_number)]["model"].run(
160
+ [inferencer_arr[task][product][str(model_number)]["output_name"]],
161
+ {inferencer_arr[task][product][str(model_number)]["input_name"]: input_image},
162
  )
163
  prediction = prediction[0].squeeze()
164
+ model_type = config["tasks"][task]["models"][product][int(model_number)]["type"]
165
+ class_names = config["tasks"][task]["models"][product][int(model_number)][
166
+ "class_names"
167
+ ]
168
+ if model_type == "classification":
169
+ logging.log(
170
+ level=logging.INFO, msg=f"Softmaxed prediction {softmax(prediction)}"
171
+ )
172
+ result = f"{class_names[np.argmax(prediction)]} avec une confiance de {str(round(softmax(prediction)[np.argmax(prediction)]*100))} %"
173
+ elif model_type == "anomaly_detection-classification":
174
+ label, score = is_anomalous_classification(
175
+ task=task,
176
+ product=product,
177
+ model_number=int(model_number),
178
+ prediction=prediction,
179
+ meta_data=corck_screwing_metadata,
180
+ )
181
  result = f"{label} avec une confiance de {str(round(score*100))} %"
182
  else:
183
+ pass
184
  logging.log(level=logging.DEBUG, msg=result)
185
  return result
poetry.lock CHANGED
@@ -630,14 +630,14 @@ files = [
630
 
631
  [[package]]
632
  name = "filelock"
633
- version = "3.10.3"
634
  description = "A platform independent file lock."
635
  category = "main"
636
  optional = false
637
  python-versions = ">=3.7"
638
  files = [
639
- {file = "filelock-3.10.3-py3-none-any.whl", hash = "sha256:99d6282f732410d44242ca02aa49835cf5473e2dd4d6734a2a785c8889dc191e"},
640
- {file = "filelock-3.10.3.tar.gz", hash = "sha256:a26bfa34d26293e04886dff13fa8dd0c8c6e1a786b723c689755fe8939297410"},
641
  ]
642
 
643
  [package.extras]
@@ -800,17 +800,6 @@ smb = ["smbprotocol"]
800
  ssh = ["paramiko"]
801
  tqdm = ["tqdm"]
802
 
803
- [[package]]
804
- name = "functools"
805
- version = "0.5"
806
- description = "Fast tools for functional programming"
807
- category = "main"
808
- optional = false
809
- python-versions = "*"
810
- files = [
811
- {file = "functools-0.5.tar.gz", hash = "sha256:596ed8999dee419c0749a41bfdd82e4697e80ea27ee01c716003ef55be9a54c5"},
812
- ]
813
-
814
  [[package]]
815
  name = "gradio"
816
  version = "3.23.0"
@@ -1229,17 +1218,6 @@ files = [
1229
  {file = "lit-16.0.0.tar.gz", hash = "sha256:3c4ac372122a1de4a88deb277b956f91b7209420a0bef683b1ab2d2b16dabe11"},
1230
  ]
1231
 
1232
- [[package]]
1233
- name = "logging"
1234
- version = "0.4.9.6"
1235
- description = "A logging module for Python"
1236
- category = "main"
1237
- optional = false
1238
- python-versions = "*"
1239
- files = [
1240
- {file = "logging-0.4.9.6.tar.gz", hash = "sha256:26f6b50773f085042d301085bd1bf5d9f3735704db9f37c1ce6d8b85c38f2417"},
1241
- ]
1242
-
1243
  [[package]]
1244
  name = "markdown-it-py"
1245
  version = "2.2.0"
@@ -3061,4 +3039,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more
3061
  [metadata]
3062
  lock-version = "2.0"
3063
  python-versions = "^3.8, <3.11"
3064
- content-hash = "ec96f879cbd998b3226a4afe86ba3fc3aa6058ce2bdcba847eeeb14abebb70b4"
 
630
 
631
  [[package]]
632
  name = "filelock"
633
+ version = "3.10.4"
634
  description = "A platform independent file lock."
635
  category = "main"
636
  optional = false
637
  python-versions = ">=3.7"
638
  files = [
639
+ {file = "filelock-3.10.4-py3-none-any.whl", hash = "sha256:6d332dc5c896f18ba93a21d987155e97c434a96d3fe4042ca70d0b3b46e3b470"},
640
+ {file = "filelock-3.10.4.tar.gz", hash = "sha256:9fc1734dbddcdcd4aaa02c160dd94db5272b92dfa859b44ec8df28e160b751f0"},
641
  ]
642
 
643
  [package.extras]
 
800
  ssh = ["paramiko"]
801
  tqdm = ["tqdm"]
802
 
 
 
 
 
 
 
 
 
 
 
 
803
  [[package]]
804
  name = "gradio"
805
  version = "3.23.0"
 
1218
  {file = "lit-16.0.0.tar.gz", hash = "sha256:3c4ac372122a1de4a88deb277b956f91b7209420a0bef683b1ab2d2b16dabe11"},
1219
  ]
1220
 
 
 
 
 
 
 
 
 
 
 
 
1221
  [[package]]
1222
  name = "markdown-it-py"
1223
  version = "2.2.0"
 
3039
  [metadata]
3040
  lock-version = "2.0"
3041
  python-versions = "^3.8, <3.11"
3042
+ content-hash = "a4f33fc4dbfcec1cb8b7c92cd33de17926044e93e0f1f11a57edfadf4406d6ca"
pyproject.toml CHANGED
@@ -7,7 +7,6 @@ authors = ["[email protected]"]
7
  [tool.poetry.dependencies]
8
  python = "^3.8, <3.11"
9
  gradio = "^3.23.0"
10
- logging = "^0.4.9.6"
11
  numpy = "^1.24.2"
12
  onnxruntime = "^1.14.1"
13
  requests = "^2.28.2"
 
7
  [tool.poetry.dependencies]
8
  python = "^3.8, <3.11"
9
  gradio = "^3.23.0"
 
10
  numpy = "^1.24.2"
11
  onnxruntime = "^1.14.1"
12
  requests = "^2.28.2"
requirements.txt CHANGED
The diff for this file is too large to render. See raw diff
 
requirements_test.txt ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==23.1.0
2
+ aiohttp==3.8.4
3
+ aiosignal==1.3.1
4
+ altair==4.2.2
5
+ anyio==3.6.2
6
+ astroid==2.15.0
7
+ async-timeout==4.0.2
8
+ attrs==22.2.0
9
+ black==23.1.0
10
+ certifi==2022.12.7
11
+ charset-normalizer==3.1.0
12
+ click==8.1.3
13
+ coloredlogs==15.0.1
14
+ configparser==5.3.0
15
+ contourpy==1.0.7
16
+ cycler==0.11.0
17
+ dill==0.3.6
18
+ entrypoints==0.4
19
+ exceptiongroup==1.1.1
20
+ fastapi==0.95.0
21
+ ffmpy==0.3.0
22
+ filelock==3.10.4
23
+ flatbuffers==23.3.3
24
+ fonttools==4.39.2
25
+ frozenlist==1.3.3
26
+ fsspec==2023.3.0
27
+ gradio==3.23.0
28
+ h11==0.14.0
29
+ httpcore==0.16.3
30
+ httpx==0.23.3
31
+ huggingface-hub==0.13.3
32
+ humanfriendly==10.0
33
+ idna==3.4
34
+ iniconfig==2.0.0
35
+ isort==5.12.0
36
+ Jinja2==3.1.2
37
+ jsonschema==4.17.3
38
+ kiwisolver==1.4.4
39
+ lazy-object-proxy==1.9.0
40
+ liccheck==0.8.3
41
+ linkify-it-py==2.0.0
42
+ markdown-it-py==2.2.0
43
+ MarkupSafe==2.1.2
44
+ matplotlib==3.7.1
45
+ mccabe==0.7.0
46
+ mdit-py-plugins==0.3.3
47
+ mdurl==0.1.2
48
+ mpmath==1.3.0
49
+ multidict==6.0.4
50
+ mypy-extensions==1.0.0
51
+ networkx==3.0
52
+ numpy==1.24.2
53
+ onnxruntime==1.14.1
54
+ orjson==3.8.8
55
+ packaging==23.0
56
+ pandas==1.5.3
57
+ pathspec==0.11.1
58
+ Pillow==9.4.0
59
+ platformdirs==3.1.1
60
+ pluggy==1.0.0
61
+ protobuf==4.22.1
62
+ pydantic==1.10.7
63
+ pydub==0.25.1
64
+ pylint==2.17.1
65
+ pyparsing==3.0.9
66
+ pyrsistent==0.19.3
67
+ pytest==7.2.2
68
+ python-dateutil==2.8.2
69
+ python-multipart==0.0.6
70
+ pytz==2022.7.1
71
+ PyYAML==6.0
72
+ requests==2.28.2
73
+ rfc3986==1.5.0
74
+ semantic-version==2.10.0
75
+ six==1.16.0
76
+ sniffio==1.3.0
77
+ starlette==0.26.1
78
+ sympy==1.11.1
79
+ toml==0.10.2
80
+ tomli==2.0.1
81
+ tomlkit==0.11.6
82
+ toolz==0.12.0
83
+ torch==2.0.0
84
+ torchvision==0.15.1
85
+ tqdm==4.65.0
86
+ typing_extensions==4.5.0
87
+ uc-micro-py==1.0.1
88
+ urllib3==1.26.15
89
+ uvicorn==0.21.1
90
+ websockets==10.4
91
+ wrapt==1.15.0
92
+ yarl==1.8.2