33from typing import TYPE_CHECKING
44
55if TYPE_CHECKING :
6- from ami .ml .models import ProcessingService # , ProjectPipelineConfig
6+ from ami .ml .models import ProcessingService , ProjectPipelineConfig
7+ from ami .jobs .models import Job
78
89import collections
910import dataclasses
4041 ClassificationResponse ,
4142 DetectionResponse ,
4243 PipelineRequest ,
44+ PipelineRequestConfigParameters ,
4345 PipelineResultsResponse ,
4446 SourceImageRequest ,
4547 SourceImageResponse ,
@@ -98,7 +100,7 @@ def filter_processed_images(
98100 )
99101 # log all algorithms that are in the pipeline but not in the detection
100102 missing_algos = pipeline_algorithm_ids - detection_algorithm_ids
101- task_logger .info (f"Image #{ image .pk } needs classification by pipeline's algorithms: { missing_algos } " )
103+ task_logger .debug (f"Image #{ image .pk } needs classification by pipeline's algorithms: { missing_algos } " )
102104 yield image
103105 else :
104106 # If all detections have been classified by the pipeline, skip the image
@@ -162,9 +164,6 @@ def process_images(
162164) -> PipelineResultsResponse :
163165 """
164166 Process images using ML pipeline API.
165-
166- @TODO find a home for this function.
167- @TODO break into task chunks.
168167 """
169168 job = None
170169 task_logger = logger
@@ -201,29 +200,11 @@ def process_images(
201200 if url
202201 ]
203202
204- if project_id :
205- try :
206- config = pipeline .project_pipeline_configs .get (project_id = project_id ).config
207- task_logger .info (
208- f"Sending pipeline request using { config } from the project-pipeline config "
209- f"for Pipeline { pipeline } and Project id { project_id } ."
210- )
211- except pipeline .project_pipeline_configs .model .DoesNotExist as e :
212- task_logger .error (
213- f"Error getting the project-pipeline config for Pipeline { pipeline } "
214- f"and Project id { project_id } : { e } "
215- )
216- config = {}
217- task_logger .info (
218- "Using empty config when sending pipeline request since no project-pipeline config "
219- f"was found for Pipeline { pipeline } and Project id { project_id } "
220- )
221- else :
222- config = {}
223- task_logger .info (
224- "Using empty config when sending pipeline request "
225- f"since no project id was provided for Pipeline { pipeline } "
226- )
203+ if not project_id :
204+ task_logger .warning (f"Pipeline { pipeline } is not associated with a project" )
205+
206+ config = pipeline .get_config (project_id = project_id )
207+ task_logger .info (f"Using pipeline config: { config } " )
227208
228209 request_data = PipelineRequest (
229210 pipeline = pipeline .slug ,
@@ -914,7 +895,7 @@ class Pipeline(BaseModel):
914895 description = models .TextField (blank = True )
915896 version = models .IntegerField (default = 1 )
916897 version_name = models .CharField (max_length = 255 , blank = True )
917- # @TODO the algorithms list be retrieved by querying the pipeline endpoint
898+ # @TODO the algorithms attribute is not currently used. Review for removal.
918899 algorithms = models .ManyToManyField ("ml.Algorithm" , related_name = "pipelines" )
919900 stages : list [PipelineStage ] = SchemaField (
920901 default = default_stages ,
@@ -926,8 +907,18 @@ class Pipeline(BaseModel):
926907 projects = models .ManyToManyField (
927908 "main.Project" , related_name = "pipelines" , blank = True , through = "ml.ProjectPipelineConfig"
928909 )
910+ default_config : PipelineRequestConfigParameters = SchemaField (
911+ schema = PipelineRequestConfigParameters ,
912+ default = dict ,
913+ help_text = (
914+ "The default configuration for the pipeline. "
915+ "Used by both the job sending images to the pipeline "
916+ "and the processing service."
917+ ),
918+ )
929919 processing_services : models .QuerySet [ProcessingService ]
930- # project_pipeline_configs: models.QuerySet[ProjectPipelineConfig]
920+ project_pipeline_configs : models .QuerySet [ProjectPipelineConfig ]
921+ jobs : models .QuerySet [Job ]
931922
932923 class Meta :
933924 ordering = ["name" , "version" ]
@@ -939,6 +930,26 @@ class Meta:
939930 def __str__ (self ):
940931 return f'#{ self .pk } "{ self .name } " ({ self .slug } ) v{ self .version } '
941932
933+ def get_config (self , project_id : int | None = None ) -> PipelineRequestConfigParameters :
934+ """
935+ Get the configuration for the pipeline request.
936+
937+ This will be the same as pipeline.default_config, but if a project ID is provided,
938+ the project's pipeline config will be used to override the default config.
939+ """
940+ config = self .default_config
941+ if project_id :
942+ try :
943+ project_pipeline_config = self .project_pipeline_configs .get (project_id = project_id )
944+ if project_pipeline_config .config :
945+ config .update (project_pipeline_config .config )
946+ logger .debug (
947+ f"Using ProjectPipelineConfig for Pipeline { self } and Project #{ project_id } :" f"config: { config } "
948+ )
949+ except self .project_pipeline_configs .model .DoesNotExist as e :
950+ logger .warning (f"No project-pipeline config for Pipeline { self } " f"and Project #{ project_id } : { e } " )
951+ return config
952+
942953 def collect_images (
943954 self ,
944955 collection : SourceImageCollection | None = None ,
0 commit comments