Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uses ODM Webhook for post image processing tasks #295

Merged
merged 148 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
148 commits
Select commit Hold shift + click to select a range
1f276e5
[pre-commit.ci] pre-commit autoupdate
pre-commit-ci[bot] Sep 30, 2024
62ce7ce
feat: added updated at field in task events table
Pradip-p Oct 1, 2024
79e85ce
Merge pull request #252 from hotosm/pre-commit-ci-update-config
nrjadkry Oct 1, 2024
fb5c465
fix: handle exception if project not found in db
Pradip-p Oct 1, 2024
b9a78af
feat(user-profile): pass watch on form props
Oct 1, 2024
d259bce
fix(user-profile)-#209: able to submit if the password and confirm pa…
Oct 1, 2024
9b6f57c
fix(user-profile)-#208: validation issue
Oct 1, 2024
e77a20f
feat: added updated_at field when user request, lock, unlock task
Pradip-p Oct 1, 2024
002ee20
feat: added updated_at in task details endpoint
Pradip-p Oct 1, 2024
9d0766f
fix: get superuser from user table instead of access token
Pradip-p Oct 1, 2024
24167c1
feat: update file and folder structure and rename `UserProfile` to `C…
Oct 1, 2024
74b794d
refac: remove super user from AuthUser Schemas
Pradip-p Oct 1, 2024
ba0752d
Merge pull request #253 from hotosm/feat/updated-datetime
nrjadkry Oct 1, 2024
23dd289
feat: add Breadcrumb component
Oct 1, 2024
aa3dc33
feat: replace user-profile layout component and and add new route cal…
Oct 1, 2024
52a418d
feat: added two new enums such as IMAGE_UPLOADED & IMAGE_PROCESSED
Pradip-p Oct 1, 2024
4045d43
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 1, 2024
d43b2d5
Merge pull request #254 from hotosm/feat/updated-datetime
nrjadkry Oct 1, 2024
e3a423c
fix(task-description): Remove BLOB middleware for processing result d…
Oct 1, 2024
735df24
Merge pull request #256 from hotosm/fix/remove-blob
nrjadkry Oct 1, 2024
4297042
fix: issues reslove on updated date
Pradip-p Oct 2, 2024
e85338e
feat: added change password based on old and new password
Pradip-p Oct 2, 2024
13d8ae8
feat(individual-project): post date with other data on task lock/unlock
Oct 2, 2024
e133895
feat(task-description): show task locked date
Oct 2, 2024
e23749e
Merge pull request #257 from hotosm/feat/change-password
nrjadkry Oct 2, 2024
008276b
Merge pull request #258 from hotosm/fix/remove-blob
nrjadkry Oct 2, 2024
f364c43
feat(update-profile): add BasicDetails component
Oct 2, 2024
39dd3cc
feat(update-profile): add Header component
Oct 2, 2024
ae7fba7
feat(update-profile): add OrganizationDetail component
Oct 2, 2024
6c555ed
feat(update-profile): add Password component
Oct 2, 2024
fb5cc92
feat(update-profile): add OtherDetails component
Oct 2, 2024
99da3b2
feat: add common css class main-content that gives the full screen he…
Oct 2, 2024
31fcf4d
feat(user-profile): add UpdateUserProfile component
Oct 2, 2024
e880d59
feat: remove the route `user-profile` add `complete-profile` from the…
Oct 2, 2024
4d1adf5
feat(user-profile): update basic details
Oct 2, 2024
c692906
refactor: remove user data fetching on projects page
Oct 2, 2024
1eedd82
refactor(user-profile): revalidate user details data on basic details…
Oct 2, 2024
10195fb
feat: store user details on local storage on fetch success
Oct 2, 2024
33ca871
feat(user-profile): create user profile patch service
Oct 2, 2024
22ad197
feat(user-profile): call user details api on userProfile of nav section
Oct 2, 2024
cee0890
feat(user-profile): update organization details
Oct 2, 2024
cd34d0b
feat(user-profile): update other details
Oct 2, 2024
2be552d
feat(user-profile): update password
Oct 2, 2024
86c6a7f
fix: typo
Oct 2, 2024
f686c84
fix: minor style
Oct 2, 2024
e800299
Merge branch 'develop' of github.com:hotosm/drone-tm into feat/user-p…
Oct 2, 2024
d87f2d6
fix: typo
Oct 2, 2024
b41631b
fix(ser-profile): make patch request on profile data change
Oct 2, 2024
cec7555
feat(user-profile): show error message
Oct 2, 2024
a10d813
hot-fix(user-profile): check old & new password before verify the pas…
Pradip-p Oct 2, 2024
66469eb
fix: added message if user do not sent old and new password
Pradip-p Oct 2, 2024
6c0db7f
refac: exception raise on password check
Pradip-p Oct 2, 2024
8c5f546
Merge pull request #259 from hotosm/feat/change-password
Pradip-p Oct 2, 2024
6621b75
[Merge branch 'develop' of github.com:hotosm/drone-tm into feat/user-…
Oct 2, 2024
01e5e50
feat(user-profile): redirect to complete profile page if the user not…
Oct 2, 2024
4f30c97
feat(user-profile): redirect to complete profile on google auth success
Oct 2, 2024
b33ed4d
fix(user-profile): minor UI
Oct 2, 2024
7bd0bc4
fix(user-profile): navigate to complete profile only after the profil…
Oct 2, 2024
9203dd6
fix: typo
Oct 2, 2024
c8dca57
used presigned url for map screenshot in projects endpoint
nrjadkry Oct 4, 2024
4109a1d
Merge pull request #261 from hotosm/optimize_dashboard_api
nrjadkry Oct 4, 2024
5cea65a
feat: added search features in projects read endpoit
Pradip-p Oct 4, 2024
17012de
Merge pull request #263 from hotosm/feat/search-project
nrjadkry Oct 4, 2024
a8b2aba
Merge pull request #260 from hotosm/feat/user-profile
nrjadkry Oct 4, 2024
e43edaa
Merge pull request #266 from hotosm/feat/download-orthophoto
nrjadkry Oct 4, 2024
3ba1c73
Merge pull request #265 from hotosm/feat/orthophoto-download
nrjadkry Oct 4, 2024
81d86de
fix(update-userProfile): update background color
Oct 8, 2024
a589483
feat(dashboard): show user role
Oct 8, 2024
befca95
feat: updated the task as completed after process from s3
Pradip-p Oct 8, 2024
9c7f1e8
Feat: updated pagination on list projects (#264)
Pradip-p Oct 8, 2024
475527e
feat: update task state to reflect the start of image processing
Pradip-p Oct 8, 2024
94679cb
fix: remove comment from the task update function
Pradip-p Oct 8, 2024
d633c45
fix: adjust the state based on processing...
Pradip-p Oct 8, 2024
1f7bb9e
fix: refine the state of task processing
Pradip-p Oct 8, 2024
46e3770
Feat: Updated the task as completed after process from S3 (#270)
Pradip-p Oct 8, 2024
0a59358
feat(projects): Show status on project card
Oct 8, 2024
3740f2f
feat(dashboard): update UI and pass other project details on project …
Oct 8, 2024
83ddfe3
feat: update the status of each projects on projects list endpoint
Pradip-p Oct 8, 2024
647998c
feat(dashboard): show slug on project card
Oct 8, 2024
e1cf543
fix: merge conflict
Oct 8, 2024
28ce0a6
feat: refine the status of tasks
Pradip-p Oct 8, 2024
fc9d2dd
feat(project-details): add new status on legend
Oct 8, 2024
79751fa
feat(project-details): show skeleton on project data fetching
Oct 8, 2024
62937bb
fix: reslove merge conflict project and task schema
Pradip-p Oct 8, 2024
de438ad
feat(project-details): fill different color for completed task and im…
Oct 8, 2024
7849afa
Merge pull request #271 from hotosm/feat/add-project-status
Pradip-p Oct 8, 2024
d316101
feat(project-details): show loader on table
Oct 8, 2024
3ac8981
Merge branch 'develop' of github.com:hotosm/drone-tm into feat/show-s…
Oct 8, 2024
8f55c8b
feat(dashboard): make logs table responsive
Oct 8, 2024
42bb7ef
feat: add Status chip component
Oct 8, 2024
68ab945
feat(project-dashboard): show complete status on project card
Oct 8, 2024
9cce047
feat: fill circle color code from properties on VectorLayerWithCluste…
Oct 8, 2024
bd40cc9
feat(project-description): add different color code as per project st…
Oct 8, 2024
6899671
hotfix: Update project/id to project_id in S3 image processing logic
Pradip-p Oct 9, 2024
31c52fe
Merge pull request #273 from hotosm/feat/update-completed-task
Pradip-p Oct 9, 2024
6f3d1d7
feat: reduce table height
Oct 9, 2024
75f99b8
feat(project-details): image processing status text update
Oct 9, 2024
f1596a8
fix(project-details): available tasks not showing on table
Oct 9, 2024
eaff9ac
fix: added asyncio event loop to call async update_task_state in proc…
Pradip-p Oct 9, 2024
f361b6c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 9, 2024
a26a517
Merge pull request #274 from hotosm/feat/update-completed-task
Pradip-p Oct 9, 2024
20ab8a5
Feat: Show project status and task status on map and project cards (#…
suzit-10 Oct 9, 2024
52e75fc
fix: resolve RuntimeError for missing event loop in AnyIO worker thread
Pradip-p Oct 9, 2024
1d685d9
hot-fix: minor UI issue on chip
Oct 9, 2024
775a2c9
fix: merge conflict
Oct 9, 2024
4db4150
feat: added asgiref package to convert the async to sync function
Pradip-p Oct 9, 2024
30f158e
Merge pull request #275 from hotosm/feat/update-completed-task
Pradip-p Oct 9, 2024
d2a9a6f
feat(project-description): increase opacity of task completed tasks f…
Oct 9, 2024
dfb32d7
Merge pull request #276 from hotosm/feat/show-status
suzit-10 Oct 9, 2024
dc612ee
fix: completed task status count
Pradip-p Oct 9, 2024
b421771
Merge pull request #278 from hotosm/feat/update-completed-task
Pradip-p Oct 9, 2024
f57bdc9
fix: update ongoing_task_count to count tasks in specific states of p…
Pradip-p Oct 9, 2024
8a7ce11
fix: optimize project status calculation logic & update ongoing statu…
Pradip-p Oct 9, 2024
c9f772e
fix(task-description): set height to update takeoff point button section
Oct 14, 2024
aadc06b
feat: added new assets download endpoint
Pradip-p Oct 14, 2024
839f164
fix: remove await from assets download endpoint
Pradip-p Oct 14, 2024
19c22b0
fix(task-description): set height to update takeoff point button sect…
suzit-10 Oct 14, 2024
c7df31d
feat: added users authentication
Pradip-p Oct 14, 2024
9d11b53
feat(project-dashboard): udpdate row per page options
Oct 14, 2024
464dcc3
feat(project-dashboard): update map and project card style
Oct 14, 2024
8738424
Merge branch 'feat/assets-download-url' of github.com:hotosm/drone-tm…
Oct 14, 2024
553f41b
feat(task-description): update assest information api endpoint
Oct 14, 2024
14940ad
feat(individual-project): get assets list
Oct 14, 2024
b064de0
feat(individual-project):fetch all assets and modify project details …
Oct 14, 2024
6a42ca2
Style: update rows per page and set project card column to 3 (#283)
suzit-10 Oct 14, 2024
b6bb97c
feat(individual-project):add loader
Oct 14, 2024
c5dc954
Feat: Updated endpoints(download-assets) to fetch task assets status.…
Pradip-p Oct 14, 2024
f0bbe76
fix(project-details): add `/` on api endpoint
Oct 14, 2024
bdc17fe
fix: merge conflict
Oct 14, 2024
18a114a
Merge pull request #286 from hotosm/feat/update-assets-download-url
suzit-10 Oct 14, 2024
deee39d
feat(project-description): call assets api only on contirbution tab i…
Oct 14, 2024
ed40275
Merge pull request #287 from hotosm/feat/update-assets-download-url
suzit-10 Oct 14, 2024
8ac63ff
fix: merge conflict
Oct 14, 2024
cfc9ae6
fix(backend): reslove merge conflict in pyproject.toml
Pradip-p Oct 14, 2024
def840d
fix(backend): returns values from calculations function
Pradip-p Oct 14, 2024
d959a81
fix(backend): reslove merge conflict in pyproject.toml
Pradip-p Oct 14, 2024
2c1274b
Merge pull request #289 from hotosm/fix/merge-conflict
Pradip-p Oct 14, 2024
4db47da
fix(backend): reslove merge conflict with main branch
Pradip-p Oct 14, 2024
335f409
fix: resolve merge conflict with main
Pradip-p Oct 14, 2024
baaeac1
fix: update the pdm lock file
Pradip-p Oct 14, 2024
6e14ce3
testing webhook url in odm
nrjadkry Oct 15, 2024
f648387
fix: merge conflicts
nrjadkry Oct 15, 2024
3a3302f
Merge pull request #291 from hotosm/upload_to_oam
nrjadkry Oct 15, 2024
156e190
[hotfix]: fix email notification sent to wrong person by passing corr…
Pradip-p Oct 15, 2024
6e60fb6
function to download and upload odm results to minio s3
nrjadkry Oct 15, 2024
a8aa5c4
updated odm webhook endpoint to download results and upload to s3
nrjadkry Oct 15, 2024
3a2799d
Merge pull request #294 from hotosm/upload_to_oam
nrjadkry Oct 15, 2024
ac122b4
Merge branch 'main' of github.com:hotosm/Drone-TM into develop
nrjadkry Oct 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET:-GOOGLE_CLIENT_SECRET_GOES_HERE}
GOOGLE_LOGIN_REDIRECT_URI=${GOOGLE_LOGIN_REDIRECT_URI:-http://localhost:3040}
SECRET_KEY=${SECRET_KEY:-SUPERSECRETKEY__xxxxxxxyyyyyyyyyzzzzzzz}
EXTRA_CORS_ORIGINS=${EXTRA_CORS_ORIGINS:-["http://localhost:3040"]}
BACKEND_URL=${BACKEND_URL:-http://localhost:8000}
FRONTEND_URL=${FRONTEND_URL:-http://localhost:3040}
DEBUG=${DEBUG:-True}



## SMTP CONFIG ##
SMTP_TLS=${SMTP_TLS:-True}
SMTP_SSL=${SMTP_SSL:-False}
Expand Down
2 changes: 2 additions & 0 deletions src/backend/app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ def assemble_db_connection(cls, v: Optional[str], info: ValidationInfo) -> Any:
return pg_url

FRONTEND_URL: str = "http://localhost:3040"
BACKEND_URL: str = "http://localhost:8000"

S3_ENDPOINT: str = "http://s3:9000"
S3_ACCESS_KEY: Optional[str] = ""
S3_SECRET_KEY: Optional[str] = ""
Expand Down
111 changes: 83 additions & 28 deletions src/backend/app/projects/image_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from concurrent.futures import ThreadPoolExecutor
from psycopg import Connection
from asgiref.sync import async_to_sync
from app.config import settings


class DroneImageProcessor:
Expand Down Expand Up @@ -85,7 +86,9 @@ def list_images(self, directory):
images.append(str(file))
return images

def process_new_task(self, images, name=None, options=[], progress_callback=None):
def process_new_task(
self, images, name=None, options=[], progress_callback=None, webhook=None
):
"""
Sends a set of images via the API to start processing.

Expand All @@ -100,7 +103,9 @@ def process_new_task(self, images, name=None, options=[], progress_callback=None
# FIXME: take this from the function above
opts = {"dsm": True}

task = self.node.create_task(images, opts, name, progress_callback)
task = self.node.create_task(
images, opts, name, progress_callback, webhook=webhook
)
return task

def monitor_task(self, task):
Expand All @@ -126,7 +131,7 @@ def download_results(self, task, output_path):
log.info("Download completed.")
return path

def process_images_from_s3(self, bucket_name, name=None, options=[]):
def process_images_from_s3(self, bucket_name, name=None, options=[], webhook=None):
"""
Processes images from MinIO storage.

Expand All @@ -145,35 +150,85 @@ def process_images_from_s3(self, bucket_name, name=None, options=[]):
images_list = self.list_images(temp_dir)

# Start a new processing task
task = self.process_new_task(images_list, name=name, options=options)
# Monitor task progress
self.monitor_task(task)

# Optionally, download results
output_file_path = f"/tmp/{self.project_id}"
path_to_download = self.download_results(task, output_path=output_file_path)

# Upload the results into s3
s3_path = f"projects/{self.project_id}/{self.task_id}/assets.zip"
add_file_to_bucket(bucket_name, path_to_download, s3_path)
# now update the task as completed in Db.
# Call the async function using asyncio

# Update background task status to COMPLETED
update_task_status_sync = async_to_sync(task_logic.update_task_state)
update_task_status_sync(
self.db,
self.project_id,
self.task_id,
self.user_id,
"Task completed.",
State.IMAGE_UPLOADED,
State.IMAGE_PROCESSED,
timestamp(),
task = self.process_new_task(
images_list, name=name, options=options, webhook=webhook
)

# If webhook is passed, webhook does this job.
if not webhook:
# Monitor task progress
self.monitor_task(task)

# Optionally, download results
output_file_path = f"/tmp/{self.project_id}"
path_to_download = self.download_results(
task, output_path=output_file_path
)

# Upload the results into s3
s3_path = f"projects/{self.project_id}/{self.task_id}/assets.zip"
add_file_to_bucket(bucket_name, path_to_download, s3_path)
# now update the task as completed in Db.
# Call the async function using asyncio

# Update background task status to COMPLETED
update_task_status_sync = async_to_sync(task_logic.update_task_state)
update_task_status_sync(
self.db,
self.project_id,
self.task_id,
self.user_id,
"Task completed.",
State.IMAGE_UPLOADED,
State.IMAGE_PROCESSED,
timestamp(),
)
return task

finally:
# Clean up temporary directory
shutil.rmtree(temp_dir)
pass


def download_and_upload_assets_from_odm_to_s3(
node_odm_url: str, task_id: str, dtm_project_id: uuid.UUID, dtm_task_id: uuid.UUID
):
"""
Downloads results from ODM and uploads them to S3 (Minio).

:param task_id: UUID of the ODM task.
:param dtm_project_id: UUID of the project.
:param dtm_task_id: UUID of the task.
"""
log.info(f"Starting download for task {task_id}")

# Replace with actual ODM node details and URL
node = Node.from_url(node_odm_url)

try:
# Get the task object using the task_id
task = node.get_task(task_id)

# Create a temporary directory to store the results
output_file_path = f"/tmp/{dtm_project_id}"

log.info(f"Downloading results for task {task_id} to {output_file_path}")

# Download results as a zip file
assets_path = task.download_zip(output_file_path)

# Upload the results into S3 (Minio)
s3_path = f"projects/{dtm_project_id}/{dtm_task_id}/assets.zip"
log.info(f"Uploading {output_file_path} to S3 path: {s3_path}")
add_file_to_bucket(settings.S3_BUCKET_NAME, assets_path, s3_path)

log.info(f"Assets for task {task_id} successfully uploaded to S3.")

except Exception as e:
log.error(f"Error downloading or uploading assets for task {task_id}: {e}")

finally:
# Clean up the temporary directory
shutil.rmtree(output_file_path)
log.info(f"Temporary directory {output_file_path} cleaned up.")
9 changes: 8 additions & 1 deletion src/backend/app/projects/project_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,15 @@ def process_drone_images(
{"name": "orthophoto-resolution", "value": 5},
]

webhook_url = (
f"{settings.BACKEND_URL}/api/projects/odm/webhook/{project_id}/{task_id}/"
)

processor.process_images_from_s3(
settings.S3_BUCKET_NAME, name=f"DTM-Task-{task_id}", options=options
settings.S3_BUCKET_NAME,
name=f"DTM-Task-{task_id}",
options=options,
webhook=webhook_url,
)


Expand Down
56 changes: 52 additions & 4 deletions src/backend/app/projects/project_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
Form,
Response,
BackgroundTasks,
Request,
)
from geojson_pydantic import FeatureCollection
from loguru import logger as log
from psycopg import Connection
from shapely.geometry import shape, mapping
from shapely.ops import unary_union
from app.projects import project_schemas, project_deps, project_logic
from app.projects import project_schemas, project_deps, project_logic, image_processing
from app.db import database
from app.models.enums import HTTPStatus, State
from app.s3 import s3_client
Expand Down Expand Up @@ -182,9 +183,11 @@ async def create_project(
if dem
else None
)
await project_logic.upload_file_to_s3(
project_id, image, "map_screenshot.png"
) if image else None
(
await project_logic.upload_file_to_s3(project_id, image, "map_screenshot.png")
if image
else None
)

# Update DEM and Image URLs in the database
await project_logic.update_url(db, project_id, dem_url)
Expand Down Expand Up @@ -419,3 +422,48 @@ async def get_assets_info(
return results
else:
return project_logic.get_project_info_from_s3(project.id, task_id)


@router.post(
"/odm/webhook/{dtm_project_id}/{dtm_task_id}/",
tags=["Image Processing"],
)
async def odm_webhook(
request: Request,
dtm_project_id: uuid.UUID,
dtm_task_id: uuid.UUID,
background_tasks: BackgroundTasks,
):
"""
Webhook to receive notifications from ODM processing tasks.
"""
# Try to parse the JSON body
try:
payload = await request.json()
except Exception as e:
log.error(f"Error parsing JSON: {e}")
raise HTTPException(status_code=400, detail="Invalid JSON body")

task_id = payload.get("uuid")
status = payload.get("status")

if not task_id or not status:
raise HTTPException(status_code=400, detail="Invalid webhook payload")

log.info(f"Task ID: {task_id}, Status: {status}")

# If status is 'success', download and upload assets to S3.
# 40 is the status code for success in odm
if status["code"] == 40:
# Call function to download assets from ODM and upload to S3
background_tasks.add_task(
image_processing.download_and_upload_assets_from_odm_to_s3,
settings.NODE_ODM_URL,
task_id,
dtm_project_id,
dtm_task_id,
)
elif status["code"] == 30:
# failed task
log.error(f'ODM task {task_id} failed: {status["errorMessage"]}')
return {"message": "Webhook received", "task_id": task_id}