+
+ filtered_lines.append(f'{label_label}: {label}')
+ with open(features, 'w') as f:
+ f.writelines(line + '\n' for line in filtered_lines)
+ if config.config['ml_quick_label_use_skip_lists']:
+ skip_list.add(image)
+ print(f'Wrote {len(labeled_features)} labels.')
+
+
+def quick_label(helper: QuickLabelHelper) -> None:
+ '''Pass your QuickLabelHelper implementing class to this function and
+ it will allow users to label examples and persist them to disk.
+
+ '''
+ skip_list = _maybe_read_skip_list()
+
+ # Ask helper for an initial set of files.
+ images = helper.get_candidate_files()
+ if len(images) == 0:
+ logger.warning('No images files to operate on.')
+ return
+ logger.info('There are %d starting candidate images.', len(images))
+
+ # Filter out any that can't be converted to features or already have a
+ # label (unless they used --ml_qukck_label_overwrite_labels).
+ filtered_images = _filter_images(images, skip_list, helper)
+ if len(filtered_images) == 0:
+ logger.warning('No image files to operate on (post filter).')
+ return
+ logger.info('There are %d candidate images post filtering.', len(filtered_images))
+
+ # Allow the user to label the non-filtered images one by one.
+ labeled_features: Dict[Tuple[str, str], str] = {}
+ cursor = 0
+ while True:
+ assert 0 <= cursor < len(filtered_images)
+
+ image = filtered_images[cursor][0]
+ assert os.path.exists(image)
+ features = filtered_images[cursor][1]
+ assert features and os.path.exists(features)
+
+ # Render the features, image and prompt.
+ _make_prompt(helper, cursor, len(filtered_images), image, features, labeled_features)
+ try:
+ # Did they want everything labelled the same?
+ label_everything = helper.get_everything_label()
+ if label_everything:
+ labeled_features[(image, features)] = label_everything
+ filtered_images.remove((image, features))
+ if len(filtered_images) == 0:
+ print('Nothing more to label.')
+ break
+ if cursor >= len(filtered_images):
+ cursor -= 1
+
+ # Otherwise ask about each individual example.