22import logging
33import math
44import typing
5- from typing import Any , TypedDict
65
76from django .contrib .gis .geos import GEOSGeometry
87from django .core .files .base import ContentFile
9- from geojson_pydantic import Feature
10- from geojson_pydantic .geometries import MultiPolygon , Polygon
11- from osgeo import ogr
128from pydantic import BaseModel , Field
139from pyfirebase_mapswipe import models as firebase_models
10+ from shapely import to_wkt
11+ from shapely .geometry .point import Point
1412from ulid import ULID
1513
1614from apps .common .models import AssetMimetypeEnum , AssetTypeEnum
1715from apps .project .models import Project , ProjectAsset , ProjectTask , ProjectTaskGroup , ProjectTypeEnum
1816from main .bulk_managers import BulkCreateManager
1917from project_types .base import project as base_project
20- from project_types .street .api_calls import get_image_metadata
18+ from project_types .street .api_calls import StreetRawGroupItem , get_image_metadata
2119from utils .common import create_json_dump
2220from utils .custom_options .models import CustomOption
2321
2422logger = logging .getLogger (__name__ )
2523
2624
27- class ValidFeature (Feature [Polygon | MultiPolygon , dict [str , Any ]]): ...
28-
29-
30- class StreetRawGroupItem (TypedDict ):
31- feature_ids : list [int ]
32- features : list [ValidFeature ]
33-
34-
35- class StreetMappilaryImageFilters (BaseModel ):
25+ class StreetMapilaryImageFilters (BaseModel ):
3626 is_pano : bool | None = Field (
3727 default = None ,
3828 description = "Filter for images that are panoramas." ,
@@ -66,7 +56,7 @@ class StreetMappilaryImageFilters(BaseModel):
6656class StreetProjectProperty (base_project .BaseProjectProperty ):
6757 aoi_geometry : typing .Annotated [str , Field (strict = True , pattern = r"^\d+$" )] | None = None
6858 custom_options : list [CustomOption ] | None = None
69- mappilary_image_filters : StreetMappilaryImageFilters
59+ mapilary_image_filters : StreetMapilaryImageFilters
7060
7161
7262class StreetTaskGroupProperty (base_project .BaseProjectTaskGroupProperty ): ...
@@ -84,7 +74,7 @@ class StreetProject(
8474 StreetTaskGroupProperty ,
8575 StreetTaskProperty ,
8676 StreetRawGroupItem ,
87- list [tuple [int , ValidFeature ]],
77+ list [tuple [int , Point ]],
8878 ],
8979):
9080 project_property_class = StreetProjectProperty
@@ -111,77 +101,61 @@ def validate(self) -> StreetRawGroupItem:
111101 with aoi_asset .file .open () as aoi_file :
112102 aoi_geojson = json .loads (aoi_file .read ())
113103
114- mappilary_image_filters = self .project_type_specifics .mappilary_image_filters
104+ mapilary_image_filters = self .project_type_specifics .mapilary_image_filters
115105
116- image_metadata_data = get_image_metadata (
106+ return get_image_metadata (
117107 aoi_geojson = aoi_geojson ,
118- is_pano = mappilary_image_filters .is_pano ,
119- creator_id = mappilary_image_filters .creator_id ,
120- organization_id = mappilary_image_filters .organization_id ,
121- start_time = mappilary_image_filters .start_time ,
122- end_time = mappilary_image_filters .end_time ,
123- randomize_order = mappilary_image_filters .randomize_order ,
124- sampling_threshold = mappilary_image_filters .sampling_threshold ,
125- )
126- return StreetRawGroupItem (
127- feature_ids = image_metadata_data ["ids" ],
128- features = image_metadata_data ["geometries" ],
108+ is_pano = mapilary_image_filters .is_pano ,
109+ creator_id = mapilary_image_filters .creator_id ,
110+ organization_id = mapilary_image_filters .organization_id ,
111+ start_time = mapilary_image_filters .start_time ,
112+ end_time = mapilary_image_filters .end_time ,
113+ randomize_order = mapilary_image_filters .randomize_order ,
114+ sampling_threshold = mapilary_image_filters .sampling_threshold ,
129115 )
130116
131117 @typing .override
132118 def create_tasks (
133119 self ,
134120 / ,
135121 group : ProjectTaskGroup ,
136- raw_group : list [tuple [int , ValidFeature ]],
137- previous_tasks_count : int ,
122+ raw_group : list [tuple [int , Point ]],
138123 ) -> int :
139124 """Create tasks for a group."""
140125 bulk_mgr = BulkCreateManager (chunk_size = 1000 )
141- tasks_count = previous_tasks_count
126+ tasks_count = 0
142127
143128 for f_id , feature in raw_group :
144- if feature .geometry is not None :
145- geom = ogr .CreateGeometryFromJson (
146- feature .geometry .model_dump_json (),
147- )
148-
149- if geom .GetCoordinateDimension () == 3 :
150- geom .FlattenTo2D ()
151-
152- geometry_str = geom .ExportToWkt ()
153-
154- bulk_mgr .add (
155- ProjectTask (
156- firebase_id = f"t{ tasks_count + 1 } " ,
157- task_group_id = group .pk ,
129+ geometry_str = to_wkt (feature )
130+
131+ bulk_mgr .add (
132+ ProjectTask (
133+ firebase_id = f"t{ f_id } " ,
134+ task_group_id = group .pk ,
135+ geometry = geometry_str ,
136+ project_type_specifics = self .project_task_property_class (
137+ task_id = f"t{ f_id } " ,
138+ group_id = f"g{ group .pk } " ,
158139 geometry = geometry_str ,
159- project_type_specifics = self .project_task_property_class (
160- task_id = f"t{ f_id } " ,
161- group_id = f"g{ group .pk } " ,
162- geometry = geometry_str ,
163- ).model_dump (),
164- ),
165- )
166- tasks_count += 1
140+ ).model_dump (),
141+ ),
142+ )
143+ tasks_count += 1
167144
168145 bulk_mgr .done ()
169146 return tasks_count
170147
171148 @typing .override
172149 def create_groups (self , resp : StreetRawGroupItem ):
173150 self .project .update_processing_status (Project .ProcessingStatus .GENERATING_GROUPS_AND_TASKS , True )
174- number_of_groups = math .ceil (len (resp ["feature_ids" ]) / self .project .group_size )
175-
176- # FIXME (susilnem): We can directly use the firebase_id instead of total_tasks_accumulated
177- total_tasks_accumulated : int = 0
151+ number_of_groups = math .ceil (len (resp ["ids" ]) / self .project .group_size )
178152
179153 for group_id in range (number_of_groups ):
180154 start_index = group_id * self .project .group_size
181155 end_index = start_index + self .project .group_size
182156
183- group_features = resp ["features " ][start_index :end_index ]
184- group_feature_ids = resp ["feature_ids " ][start_index :end_index ]
157+ group_features = resp ["geometries " ][start_index :end_index ]
158+ group_feature_ids = resp ["ids " ][start_index :end_index ]
185159 raw_group = list (zip (group_feature_ids , group_features , strict = True ))
186160 new_group = ProjectTaskGroup .objects .create (
187161 firebase_id = f"g{ group_id } " ,
@@ -194,9 +168,8 @@ def create_groups(self, resp: StreetRawGroupItem):
194168 )
195169
196170 # Create new tasks for this group
197- total_tasks = self .create_tasks (new_group , raw_group , total_tasks_accumulated )
171+ total_tasks = self .create_tasks (new_group , raw_group )
198172 logger .info ("Created %s tasks for group: %s" , total_tasks , new_group .pk )
199- total_tasks_accumulated += total_tasks
200173
201174 @typing .override
202175 def post_create_groups (self ):
@@ -237,7 +210,7 @@ def get_feature(task: ProjectTask):
237210 file_size = file .size ,
238211 type = AssetTypeEnum .OUTPUT ,
239212 mimetype = AssetMimetypeEnum .GEOJSON ,
240- # FIXME(tnagorra ): Maybe create a internal user like mapswipe-bot
213+ # FIXME(susilnem ): Maybe create a internal user like mapswipe-bot
241214 created_by = self .project .modified_by ,
242215 modified_by = self .project .modified_by ,
243216 )
0 commit comments