learning-loop-node 0.8.5__tar.gz → 0.8.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of learning-loop-node might be problematic. Click here for more details.

Files changed (87) hide show
  1. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/PKG-INFO +16 -14
  2. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/README.md +12 -10
  3. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/data_exchanger.py +16 -2
  4. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/detector_logic.py +1 -1
  5. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/detector_node.py +7 -2
  6. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/inbox_filter/cam_observation_history.py +2 -1
  7. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_downloader.py +24 -1
  8. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/trainer_logic.py +3 -3
  9. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/pyproject.toml +5 -5
  10. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/__init__.py +0 -0
  11. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/annotation/__init__.py +0 -0
  12. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/annotation/annotator_logic.py +0 -0
  13. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/annotation/annotator_node.py +0 -0
  14. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/annotation/tests/test_annotator_node.py +0 -0
  15. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/conftest.py +0 -0
  16. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/converter/__init__.py +0 -0
  17. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/converter/converter_logic.py +0 -0
  18. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/converter/converter_node.py +0 -0
  19. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/converter/tests/test_converter.py +0 -0
  20. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/data_classes/__init__.py +0 -0
  21. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/data_classes/annotations.py +0 -0
  22. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/data_classes/detections.py +0 -0
  23. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/data_classes/general.py +0 -0
  24. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/data_classes/socket_response.py +0 -0
  25. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/data_classes/training.py +0 -0
  26. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/__init__.py +0 -0
  27. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/inbox_filter/__init__.py +0 -0
  28. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/inbox_filter/relevance_filter.py +0 -0
  29. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/inbox_filter/tests/test_observation.py +0 -0
  30. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/inbox_filter/tests/test_relevance_group.py +0 -0
  31. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/inbox_filter/tests/test_unexpected_observations_count.py +0 -0
  32. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/outbox.py +0 -0
  33. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/rest/__init__.py +0 -0
  34. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/rest/backdoor_controls.py +0 -0
  35. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/rest/detect.py +0 -0
  36. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/rest/operation_mode.py +0 -0
  37. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/rest/upload.py +0 -0
  38. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/__init__.py +0 -0
  39. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/conftest.py +0 -0
  40. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/test.jpg +0 -0
  41. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/test_client_communication.py +0 -0
  42. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/test_outbox.py +0 -0
  43. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/test_relevance_filter.py +0 -0
  44. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/detector/tests/testing_detector.py +0 -0
  45. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/examples/novelty_score_updater.py +0 -0
  46. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/globals.py +0 -0
  47. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/helpers/__init__.py +0 -0
  48. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/helpers/environment_reader.py +0 -0
  49. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/helpers/gdrive_downloader.py +0 -0
  50. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/helpers/log_conf.py +0 -0
  51. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/helpers/misc.py +0 -0
  52. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/loop_communication.py +0 -0
  53. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/node.py +0 -0
  54. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/pytest.ini +0 -0
  55. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/tests/__init__.py +0 -0
  56. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/tests/conftest.py +0 -0
  57. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_data/file_1.txt +0 -0
  58. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_data/file_2.txt +0 -0
  59. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_data/model.json +0 -0
  60. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_data_classes.py +0 -0
  61. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_executor.py +0 -0
  62. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_helper.py +0 -0
  63. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/tests/test_learning_loop_node.py +0 -0
  64. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/__init__.py +0 -0
  65. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/downloader.py +0 -0
  66. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/executor.py +0 -0
  67. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/io_helpers.py +0 -0
  68. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/rest/__init__.py +0 -0
  69. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/rest/backdoor_controls.py +0 -0
  70. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/rest/controls.py +0 -0
  71. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/__init__.py +0 -0
  72. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/conftest.py +0 -0
  73. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/state_helper.py +0 -0
  74. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/__init__.py +0 -0
  75. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_cleanup.py +0 -0
  76. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_detecting.py +0 -0
  77. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_download_train_model.py +0 -0
  78. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_prepare.py +0 -0
  79. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_sync_confusion_matrix.py +0 -0
  80. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_train.py +0 -0
  81. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_upload_detections.py +0 -0
  82. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/states/test_state_upload_model.py +0 -0
  83. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/test_errors.py +0 -0
  84. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/test_trainer_states.py +0 -0
  85. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/tests/testing_trainer_logic.py +0 -0
  86. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/trainer_node.py +0 -0
  87. {learning_loop_node-0.8.5 → learning_loop_node-0.8.7}/learning_loop_node/trainer/training_syncronizer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: learning-loop-node
3
- Version: 0.8.5
3
+ Version: 0.8.7
4
4
  Summary: Python Library for Nodes which connect to the Zauberzeug Learning Loop
5
5
  Home-page: https://github.com/zauberzeug/learning_loop_node
6
6
  License: MIT
@@ -18,8 +18,8 @@ Requires-Dist: aiofiles (>=0.7.0,<0.8.0)
18
18
  Requires-Dist: aiohttp (>=3.8.4,<4.0.0)
19
19
  Requires-Dist: async_generator (>=1.10,<2.0)
20
20
  Requires-Dist: dacite (>=1.8.1,<2.0.0)
21
- Requires-Dist: fastapi (>=0.70.1,<0.71.0)
22
- Requires-Dist: fastapi-socketio (>=0.0.6,<0.0.7)
21
+ Requires-Dist: fastapi (>=0.93,<1.0.0)
22
+ Requires-Dist: fastapi-socketio (>=0.0.10,<0.0.11)
23
23
  Requires-Dist: fastapi-utils (>=0.2.1,<0.3.0)
24
24
  Requires-Dist: httpx (>=0.24.1,<0.25.0)
25
25
  Requires-Dist: icecream (>=2.1.0,<3.0.0)
@@ -33,7 +33,7 @@ Requires-Dist: python-socketio (>=5.7.2,<6.0.0)
33
33
  Requires-Dist: requests (>=2.25.1,<3.0.0)
34
34
  Requires-Dist: simplejson (>=3.17.2,<4.0.0)
35
35
  Requires-Dist: tqdm (>=4.63.0,<5.0.0)
36
- Requires-Dist: uvicorn (>=0.13.3,<0.14.0)
36
+ Requires-Dist: uvicorn[standard] (>=0.22.0,<0.23.0)
37
37
  Requires-Dist: werkzeug (>=2.0.1,<3.0.0)
38
38
  Project-URL: Repository, https://github.com/zauberzeug/learning_loop_node
39
39
  Description-Content-Type: text/markdown
@@ -57,16 +57,18 @@ To start a node you have to implement the logic by inheriting from the correspon
57
57
 
58
58
  You can configure connection to our Learning Loop by specifying the following environment variables before starting:
59
59
 
60
- | Name | Alias | Purpose | Required by |
61
- | ---------------------- | ------------ | ------------------------------------------------- | -------------------- |
62
- | LOOP_HOST | HOST | Learning Loop address (e.g. learning-loop.ai) | all |
63
- | LOOP_USERNAME | USERNAME | Learning Loop user name | all besides Detector |
64
- | LOOP_PASSWORD | PASSWORD | Learning Loop password | all besides Detector |
65
- | LOOP_ORGANIZATION | ORGANIZATION | Organization name | Detector |
66
- | LOOP_PROJECT | PROJECT | Project name | Detector |
67
- | INFERENCE_BATCH_SIZE | - | Batch size of trainer when calculating detections | Trainer (opt.) |
68
- | RESTART_AFTER_TRAINING | - | Restart the trainer after training (set to 1) | Trainer (opt.) |
69
- | KEEP_OLD_TRAININGS | - | Do not delete old trainings (set to 1) | Trainer (opt.) |
60
+ | Name | Alias | Purpose | Required by |
61
+ | ----------------------- | ------------ | ------------------------------------------------------------ | -------------------- |
62
+ | LOOP_HOST | HOST | Learning Loop address (e.g. learning-loop.ai) | all |
63
+ | LOOP_USERNAME | USERNAME | Learning Loop user name | all besides Detector |
64
+ | LOOP_PASSWORD | PASSWORD | Learning Loop password | all besides Detector |
65
+ | LOOP_ORGANIZATION | ORGANIZATION | Organization name | Detector |
66
+ | LOOP_PROJECT | PROJECT | Project name | Detector |
67
+ | MIN_UNCERTAIN_THRESHOLD | PROJECT | smallest confidence (float) at which auto-upload will happen | Detector |
68
+ | MAX_UNCERTAIN_THRESHOLD | PROJECT | largest confidence (float) at which auto-upload will happen | Detector |
69
+ | INFERENCE_BATCH_SIZE | - | Batch size of trainer when calculating detections | Trainer (opt.) |
70
+ | RESTART_AFTER_TRAINING | - | Restart the trainer after training (set to 1) | Trainer (opt.) |
71
+ | KEEP_OLD_TRAININGS | - | Do not delete old trainings (set to 1) | Trainer (opt.) |
70
72
 
71
73
  #### Testing
72
74
 
@@ -17,16 +17,18 @@ To start a node you have to implement the logic by inheriting from the correspon
17
17
 
18
18
  You can configure connection to our Learning Loop by specifying the following environment variables before starting:
19
19
 
20
- | Name | Alias | Purpose | Required by |
21
- | ---------------------- | ------------ | ------------------------------------------------- | -------------------- |
22
- | LOOP_HOST | HOST | Learning Loop address (e.g. learning-loop.ai) | all |
23
- | LOOP_USERNAME | USERNAME | Learning Loop user name | all besides Detector |
24
- | LOOP_PASSWORD | PASSWORD | Learning Loop password | all besides Detector |
25
- | LOOP_ORGANIZATION | ORGANIZATION | Organization name | Detector |
26
- | LOOP_PROJECT | PROJECT | Project name | Detector |
27
- | INFERENCE_BATCH_SIZE | - | Batch size of trainer when calculating detections | Trainer (opt.) |
28
- | RESTART_AFTER_TRAINING | - | Restart the trainer after training (set to 1) | Trainer (opt.) |
29
- | KEEP_OLD_TRAININGS | - | Do not delete old trainings (set to 1) | Trainer (opt.) |
20
+ | Name | Alias | Purpose | Required by |
21
+ | ----------------------- | ------------ | ------------------------------------------------------------ | -------------------- |
22
+ | LOOP_HOST | HOST | Learning Loop address (e.g. learning-loop.ai) | all |
23
+ | LOOP_USERNAME | USERNAME | Learning Loop user name | all besides Detector |
24
+ | LOOP_PASSWORD | PASSWORD | Learning Loop password | all besides Detector |
25
+ | LOOP_ORGANIZATION | ORGANIZATION | Organization name | Detector |
26
+ | LOOP_PROJECT | PROJECT | Project name | Detector |
27
+ | MIN_UNCERTAIN_THRESHOLD | PROJECT | smallest confidence (float) at which auto-upload will happen | Detector |
28
+ | MAX_UNCERTAIN_THRESHOLD | PROJECT | largest confidence (float) at which auto-upload will happen | Detector |
29
+ | INFERENCE_BATCH_SIZE | - | Batch size of trainer when calculating detections | Trainer (opt.) |
30
+ | RESTART_AFTER_TRAINING | - | Restart the trainer after training (set to 1) | Trainer (opt.) |
31
+ | KEEP_OLD_TRAININGS | - | Do not delete old trainings (set to 1) | Trainer (opt.) |
30
32
 
31
33
  #### Testing
32
34
 
@@ -59,10 +59,23 @@ class DataExchanger():
59
59
  logging.warning('context was not set yet')
60
60
  return
61
61
 
62
+ await self.delete_corrupt_images(image_folder)
62
63
  new_image_ids = await asyncio.get_event_loop().run_in_executor(None, DataExchanger.filter_existing_images, image_ids, image_folder)
63
64
  paths, ids = create_resource_paths(self.context.organization, self.context.project, new_image_ids)
64
65
  await self._download_images(paths, ids, image_folder)
65
66
 
67
+ @staticmethod
68
+ async def delete_corrupt_images(image_folder: str) -> None:
69
+ logging.info('deleting corrupt images')
70
+ n_deleted = 0
71
+ for image in glob(f'{image_folder}/*.jpg'):
72
+ if not await DataExchanger.is_valid_image(image):
73
+ logging.debug(f' deleting image {image}')
74
+ os.remove(image)
75
+ n_deleted += 1
76
+
77
+ logging.info(f'deleted {n_deleted} images')
78
+
66
79
  @staticmethod
67
80
  def filter_existing_images(all_image_ids, image_folder) -> List[str]:
68
81
  logging.info(f'### Going to filter {len(all_image_ids)} images ids')
@@ -131,8 +144,9 @@ class DataExchanger():
131
144
  if not await self.is_valid_image(filename):
132
145
  os.remove(filename)
133
146
 
134
- async def is_valid_image(self, filename: str) -> bool:
135
- if not os.path.isfile(filename):
147
+ @staticmethod
148
+ async def is_valid_image(filename: str) -> bool:
149
+ if not os.path.isfile(filename) or os.path.getsize(filename) == 0:
136
150
  return False
137
151
  if not check_jpeg:
138
152
  return True
@@ -46,7 +46,7 @@ class DetectorLogic():
46
46
 
47
47
  @abstractmethod
48
48
  def init(self):
49
- """Initialize the model. Note that `model_info` is available as `self.model_info`"""
49
+ """Called when a (new) model was loaded. Initialize the model. Model information available via `self.model_info`"""
50
50
 
51
51
  @abstractmethod
52
52
  def evaluate(self, image: np.ndarray) -> Detections:
@@ -142,10 +142,13 @@ class DetectorNode(Node):
142
142
 
143
143
  detection_data = data.get('detections', {})
144
144
  if detection_data and self.detector_logic.is_initialized:
145
- detections = from_dict(data_class=Detections, data=detection_data)
145
+ try:
146
+ detections = from_dict(data_class=Detections, data=detection_data)
147
+ except Exception as e:
148
+ self.log.exception('could not parse detections')
149
+ return {'error': str(e)}
146
150
  detections = self.add_category_id_to_detections(self.detector_logic.model_info, detections)
147
151
  else:
148
- print(f'No detections: {detection_data}', flush=True)
149
152
  detections = Detections()
150
153
 
151
154
  tags = data.get('tags', [])
@@ -292,6 +295,8 @@ class DetectorNode(Node):
292
295
  self.log.error('could not reload app')
293
296
 
294
297
  async def get_detections(self, raw_image: np.ndarray, camera_id: Optional[str], tags: List[str], autoupload: Optional[str] = None) -> Optional[Dict]:
298
+ """Note: raw_image is a numpy array of type uint8, but not in the correrct shape!
299
+ It can be converted e.g. using cv2.imdecode(raw_image, cv2.IMREAD_COLOR)"""
295
300
  loop = asyncio.get_event_loop()
296
301
  detections: Detections = await loop.run_in_executor(None, self.detector_logic.evaluate, raw_image)
297
302
 
@@ -1,3 +1,4 @@
1
+ import os
1
2
  from typing import List, Union
2
3
 
3
4
  from learning_loop_node.data_classes import (BoxDetection,
@@ -39,7 +40,7 @@ class CamObservationHistory:
39
40
  continue
40
41
 
41
42
  self.recent_observations.append(Observation(detection))
42
- if 0.3 <= detection.confidence <= 0.6:
43
+ if float(os.environ.get('MIN_UNCERTAIN_THRESHOLD', '0.3')) <= detection.confidence <= float(os.environ.get('MAX_UNCERTAIN_THRESHOLD', '0.6')):
43
44
  causes.add('uncertain')
44
45
 
45
46
  return list(causes)
@@ -1,5 +1,8 @@
1
+ import os
2
+ import shutil
3
+
1
4
  from learning_loop_node.data_classes import Context
2
- from learning_loop_node.data_exchanger import DataExchanger
5
+ from learning_loop_node.data_exchanger import DataExchanger, check_jpeg
3
6
  from learning_loop_node.globals import GLOBALS
4
7
 
5
8
  from . import test_helper
@@ -46,3 +49,23 @@ async def test_download_training_data(data_exchanger: DataExchanger):
46
49
  image_ids = await data_exchanger.fetch_image_ids()
47
50
  image_data = await data_exchanger.download_images_data(image_ids)
48
51
  assert len(image_data) == 3
52
+
53
+
54
+ async def test_removal_of_corrupted_images(data_exchanger: DataExchanger):
55
+ image_ids = await data_exchanger.fetch_image_ids()
56
+
57
+ shutil.rmtree('/tmp/img_folder', ignore_errors=True)
58
+ os.makedirs('/tmp/img_folder', exist_ok=True)
59
+ await data_exchanger.download_images(image_ids, '/tmp/img_folder')
60
+ num_images = len(os.listdir('/tmp/img_folder'))
61
+
62
+ # Generate two corrupted images
63
+ with open('/tmp/img_folder/c0.jpg', 'w') as f:
64
+ f.write('')
65
+ with open('/tmp/img_folder/c1.jpg', 'w') as f:
66
+ f.write('I am no image')
67
+
68
+ await data_exchanger.delete_corrupt_images('/tmp/img_folder')
69
+
70
+ assert len(os.listdir('/tmp/img_folder')) == num_images if check_jpeg else num_images - 1
71
+ shutil.rmtree('/tmp/img_folder', ignore_errors=True)
@@ -54,8 +54,8 @@ class TrainerLogic():
54
54
  self._training: Optional[Training] = None
55
55
  self._active_training_io: Optional[ActiveTrainingIO] = None
56
56
  self._node: Optional[TrainerNode] = None
57
- self.restart_after_training = bool(int(os.environ.get('RESTART_AFTER_TRAINING', '0')))
58
- self.keep_old_trainings = bool(int(os.environ.get('KEEP_OLD_TRAININGS', '0')))
57
+ self.restart_after_training = os.environ.get('RESTART_AFTER_TRAINING', 'FALSE').lower() in ['true', '1']
58
+ self.keep_old_trainings = os.environ.get('KEEP_OLD_TRAININGS', 'FALSE').lower() in ['true', '1']
59
59
  self.inference_batch_size = int(os.environ.get('INFERENCE_BATCH_SIZE', '10'))
60
60
  logging.info(f'INFERENCE_BATCH_SIZE: {self.inference_batch_size}')
61
61
 
@@ -335,7 +335,7 @@ class TrainerLogic():
335
335
  try:
336
336
  new_model_id = await self._upload_model_return_new_id(self.training.context)
337
337
  if new_model_id is None:
338
- raise Exception('could not upload model')
338
+ raise Exception('could not upload model - maybe training failed')
339
339
  assert new_model_id is not None, 'uploaded_model must be set'
340
340
  logging.info(f'successfully uploaded model and received new model id: {new_model_id}')
341
341
  self.training.model_id_for_detecting = new_model_id
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "learning_loop_node"
3
- version = "v0.8.5"
3
+ version = "v0.8.7"
4
4
  description = "Python Library for Nodes which connect to the Zauberzeug Learning Loop"
5
5
  authors = ["Zauberzeug GmbH <info@zauberzeug.com>"]
6
6
  license = "MIT"
@@ -9,12 +9,12 @@ repository = "https://github.com/zauberzeug/learning_loop_node"
9
9
 
10
10
  [tool.poetry.dependencies]
11
11
  python = "^3.8"
12
+ fastapi = ">=0.93,<1.0.0"
13
+ fastapi-socketio = "^0.0.10"
14
+ uvicorn = {extras = ["standard"], version = "^0.22.0"}
15
+ fastapi-utils = "^0.2.1"
12
16
  requests = "^2.25.1"
13
17
  python-socketio = "^5.7.2"
14
- fastapi-socketio = "^0.0.6"
15
- fastapi = "^0.70.1"
16
- uvicorn = "^0.13.3"
17
- fastapi-utils = "^0.2.1"
18
18
  simplejson = "^3.17.2"
19
19
  icecream = "^2.1.0"
20
20
  aiofiles = "^0.7.0"