1
1
import logging
2
2
import os
3
3
import time
4
+ from functools import partial
4
5
from io import BufferedReader , BytesIO
5
6
from typing import Callable , Optional , Union
6
7
@@ -304,9 +305,20 @@ def submit_image_query( # noqa: PLR0913 # pylint: disable=too-many-arguments, t
304
305
Any pixel format will get converted to JPEG at high quality before sending to service.
305
306
:type image: str or bytes or Image.Image or BytesIO or BufferedReader or np.ndarray
306
307
307
- :param wait: How long to wait (in seconds) for a confident answer.
308
+ :param wait: How long to poll (in seconds) for a confident answer. This is a client-side timeout .
308
309
:type wait: float
309
310
311
+ :param patience_time: How long to wait (in seconds) for a confident answer for this image query.
312
+ The longer the patience_time, the more likely Groundlight will arrive at a confident answer.
313
+ Within patience_time, Groundlight will update ML predictions based on stronger findings,
314
+ and, additionally, Groundlight will prioritize human review of the image query if necessary.
315
+ This is a soft server-side timeout. If not set, use the detector's patience_time.
316
+ :type patience_time: float
317
+
318
+ :param confidence_threshold: The confidence threshold to wait for.
319
+ If not set, use the detector's confidence threshold.
320
+ :type confidence_threshold: float
321
+
310
322
:param human_review: If `None` or `DEFAULT`, send the image query for human review
311
323
only if the ML prediction is not confident.
312
324
If set to `ALWAYS`, always send the image query for human review.
@@ -375,8 +387,10 @@ def ask_confident(
375
387
confidence_threshold : Optional [float ] = None ,
376
388
wait : Optional [float ] = None ,
377
389
) -> ImageQuery :
378
- """Evaluates an image with Groundlight waiting until an answer above the confidence threshold
379
- of the detector is reached or the wait period has passed.
390
+ """
391
+ Evaluates an image with Groundlight waiting until an answer above the confidence threshold
392
+ of the detector is reached or the wait period has passed.
393
+
380
394
:param detector: the Detector object, or string id of a detector like `det_12345`
381
395
:type detector: Detector or str
382
396
@@ -405,6 +419,8 @@ def ask_confident(
405
419
image ,
406
420
confidence_threshold = confidence_threshold ,
407
421
wait = wait ,
422
+ patience_time = wait ,
423
+ human_review = None ,
408
424
)
409
425
410
426
def ask_ml (
@@ -413,7 +429,9 @@ def ask_ml(
413
429
image : Union [str , bytes , Image .Image , BytesIO , BufferedReader , np .ndarray ],
414
430
wait : Optional [float ] = None ,
415
431
) -> ImageQuery :
416
- """Evaluates an image with Groundlight, getting the first answer Groundlight can provide.
432
+ """
433
+ Evaluates an image with Groundlight, getting the first answer Groundlight can provide.
434
+
417
435
:param detector: the Detector object, or string id of a detector like `det_12345`
418
436
:type detector: Detector or str
419
437
@@ -443,12 +461,13 @@ def ask_ml(
443
461
wait = self .DEFAULT_WAIT if wait is None else wait
444
462
return self .wait_for_ml_result (iq , timeout_sec = wait )
445
463
446
- def ask_async (
464
+ def ask_async ( # noqa: PLR0913 # pylint: disable=too-many-arguments
447
465
self ,
448
466
detector : Union [Detector , str ],
449
467
image : Union [str , bytes , Image .Image , BytesIO , BufferedReader , np .ndarray ],
468
+ patience_time : Optional [float ] = None ,
469
+ confidence_threshold : Optional [float ] = None ,
450
470
human_review : Optional [str ] = None ,
451
- inspection_id : Optional [str ] = None ,
452
471
) -> ImageQuery :
453
472
"""
454
473
Convenience method for submitting an `ImageQuery` asynchronously. This is equivalent to calling
@@ -469,6 +488,17 @@ def ask_async(
469
488
470
489
:type image: str or bytes or Image.Image or BytesIO or BufferedReader or np.ndarray
471
490
491
+ :param patience_time: How long to wait (in seconds) for a confident answer for this image query.
492
+ The longer the patience_time, the more likely Groundlight will arrive at a confident answer.
493
+ Within patience_time, Groundlight will update ML predictions based on stronger findings,
494
+ and, additionally, Groundlight will prioritize human review of the image query if necessary.
495
+ This is a soft server-side timeout. If not set, use the detector's patience_time.
496
+ :type patience_time: float
497
+
498
+ :param confidence_threshold: The confidence threshold to wait for.
499
+ If not set, use the detector's confidence threshold.
500
+ :type confidence_threshold: float
501
+
472
502
:param human_review: If `None` or `DEFAULT`, send the image query for human review
473
503
only if the ML prediction is not confident.
474
504
If set to `ALWAYS`, always send the image query for human review.
@@ -500,26 +530,34 @@ def ask_async(
500
530
assert image_query.id is not None
501
531
502
532
# Do not attempt to access the result of this query as the result for all async queries
503
- # will be None. Your result is being computed asynchronously and will be available
504
- # later
533
+ # will be None. Your result is being computed asynchronously and will be available later
505
534
assert image_query.result is None
506
535
507
- # retrieve the result later or on another machine by calling gl.get_image_query ()
508
- # with the id of the image_query above
509
- image_query = gl.get_image_query (image_query.id)
536
+ # retrieve the result later or on another machine by calling gl.wait_for_confident_result ()
537
+ # with the id of the image_query above. This will block until the result is available.
538
+ image_query = gl.wait_for_confident_result (image_query.id)
510
539
511
540
# now the result will be available for your use
512
541
assert image_query.result is not None
513
542
543
+ # alternatively, you can check if the result is available (without blocking) by calling
544
+ # gl.get_image_query() with the id of the image_query above.
545
+ image_query = gl.get_image_query(image_query.id)
514
546
"""
515
547
return self .submit_image_query (
516
- detector , image , wait = 0 , human_review = human_review , want_async = True , inspection_id = inspection_id
548
+ detector ,
549
+ image ,
550
+ wait = 0 ,
551
+ patience_time = patience_time ,
552
+ confidence_threshold = confidence_threshold ,
553
+ human_review = human_review ,
554
+ want_async = True ,
517
555
)
518
556
519
557
def wait_for_confident_result (
520
558
self ,
521
559
image_query : Union [ImageQuery , str ],
522
- confidence_threshold : float ,
560
+ confidence_threshold : Optional [ float ] = None ,
523
561
timeout_sec : float = 30.0 ,
524
562
) -> ImageQuery :
525
563
"""
@@ -529,7 +567,8 @@ def wait_for_confident_result(
529
567
:param image_query: An ImageQuery object to poll
530
568
:type image_query: ImageQuery or str
531
569
532
- :param confidence_threshold: The minimum confidence level required to return before the timeout.
570
+ :param confidence_threshold: The confidence threshold to wait for.
571
+ If not set, use the detector's confidence threshold.
533
572
:type confidence_threshold: float
534
573
535
574
:param timeout_sec: The maximum number of seconds to wait.
@@ -538,10 +577,12 @@ def wait_for_confident_result(
538
577
:return: ImageQuery
539
578
:rtype: ImageQuery
540
579
"""
580
+ if confidence_threshold is None :
581
+ if isinstance (image_query , str ):
582
+ image_query = self .get_image_query (image_query )
583
+ confidence_threshold = self .get_detector (image_query .detector_id ).confidence_threshold
541
584
542
- def confidence_above_thresh (iq ):
543
- return iq_is_confident (iq , confidence_threshold = confidence_threshold )
544
-
585
+ confidence_above_thresh = partial (iq_is_confident , confidence_threshold = confidence_threshold )
545
586
return self ._wait_for_result (image_query , condition = confidence_above_thresh , timeout_sec = timeout_sec )
546
587
547
588
def wait_for_ml_result (self , image_query : Union [ImageQuery , str ], timeout_sec : float = 30.0 ) -> ImageQuery :
@@ -551,9 +592,6 @@ def wait_for_ml_result(self, image_query: Union[ImageQuery, str], timeout_sec: f
551
592
:param image_query: An ImageQuery object to poll
552
593
:type image_query: ImageQuery or str
553
594
554
- :param confidence_threshold: The minimum confidence level required to return before the timeout.
555
- :type confidence_threshold: float
556
-
557
595
:param timeout_sec: The maximum number of seconds to wait.
558
596
:type timeout_sec: float
559
597
@@ -623,6 +661,7 @@ def add_label(self, image_query: Union[ImageQuery, str], label: Union[Label, str
623
661
else :
624
662
image_query_id = str (image_query )
625
663
# Some old imagequery id's started with "chk_"
664
+ # TODO: handle iqe_ for image_queries returned from edge endpoints
626
665
if not image_query_id .startswith (("chk_" , "iq_" )):
627
666
raise ValueError (f"Invalid image query id { image_query_id } " )
628
667
api_label = convert_display_label_to_internal (image_query_id , label )
0 commit comments