Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/workflows/ecr-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ on:
push:
branches:
- dev
workflow_dispatch:

name: DEV ECS build & deployment

Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/ecr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ on:
branches:
- main
workflow_dispatch:
branches:
- main

name: PRODUCTION ECS build & deployment

Expand Down
2 changes: 1 addition & 1 deletion mcserver/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class SessionAdmin(admin.ModelAdmin):
'public',
'created_at', 'updated_at', 'server',
'status', 'status_changed',
'trashed', 'trashed_at',
'trashed', 'trashed_at', 'isMono',
)
raw_id_fields = ('user', 'subject')
search_fields = ['id', 'user__username', "subject__name"]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.22 on 2025-06-05 21:23

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('mcserver', '0039_merge_20241008_1623'),
]

operations = [
migrations.AddField(
model_name='session',
name='is_mono',
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name='subject',
name='sex_at_birth',
field=models.CharField(blank=True, choices=[('woman', 'Female'), ('man', 'Male'), ('intersect', 'Intersex'), ('not-listed', 'Not Listed'), ('prefer-not-respond', 'Prefer Not to Respond')], max_length=20, null=True),
),
]
17 changes: 17 additions & 0 deletions mcserver/migrations/0041_remove_session_is_mono.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.22 on 2025-06-05 23:28

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('mcserver', '0040_session_is_mono_alter_subject_sex_at_birth'),
]

operations = [
migrations.RemoveField(
model_name='session',
name='is_mono',
),
]
18 changes: 18 additions & 0 deletions mcserver/migrations/0042_session_ismono.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.22 on 2025-06-06 16:03

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('mcserver', '0041_remove_session_is_mono'),
]

operations = [
migrations.AddField(
model_name='session',
name='isMono',
field=models.BooleanField(default=False),
),
]
18 changes: 18 additions & 0 deletions mcserver/migrations/0043_alter_session_ismono.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.22 on 2025-06-06 16:50

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('mcserver', '0042_session_ismono'),
]

operations = [
migrations.AlterField(
model_name='session',
name='isMono',
field=models.BooleanField(db_index=True, default=False),
),
]
23 changes: 23 additions & 0 deletions mcserver/migrations/0044_auto_20250606_1629.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 3.1.14 on 2025-06-06 22:29

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('mcserver', '0043_alter_session_ismono'),
]

operations = [
migrations.AlterField(
model_name='analysisresult',
name='status',
field=models.IntegerField(choices=[(100, 'Continue'), (101, 'Switching Protocols'), (102, 'Processing'), (200, 'OK'), (201, 'Created'), (202, 'Accepted'), (203, 'Non-Authoritative Information'), (204, 'No Content'), (205, 'Reset Content'), (206, 'Partial Content'), (207, 'Multi-Status'), (208, 'Already Reported'), (226, 'IM Used'), (300, 'Multiple Choices'), (301, 'Moved Permanently'), (302, 'Found'), (303, 'See Other'), (304, 'Not Modified'), (305, 'Use Proxy'), (307, 'Temporary Redirect'), (308, 'Permanent Redirect'), (400, 'Bad Request'), (401, 'Unauthorized'), (402, 'Payment Required'), (403, 'Forbidden'), (404, 'Not Found'), (405, 'Method Not Allowed'), (406, 'Not Acceptable'), (407, 'Proxy Authentication Required'), (408, 'Request Timeout'), (409, 'Conflict'), (410, 'Gone'), (411, 'Length Required'), (412, 'Precondition Failed'), (413, 'Request Entity Too Large'), (414, 'Request-URI Too Long'), (415, 'Unsupported Media Type'), (416, 'Requested Range Not Satisfiable'), (417, 'Expectation Failed'), (421, 'Misdirected Request'), (422, 'Unprocessable Entity'), (423, 'Locked'), (424, 'Failed Dependency'), (426, 'Upgrade Required'), (428, 'Precondition Required'), (429, 'Too Many Requests'), (431, 'Request Header Fields Too Large'), (500, 'Internal Server Error'), (501, 'Not Implemented'), (502, 'Bad Gateway'), (503, 'Service Unavailable'), (504, 'Gateway Timeout'), (505, 'HTTP Version Not Supported'), (506, 'Variant Also Negotiates'), (507, 'Insufficient Storage'), (508, 'Loop Detected'), (510, 'Not Extended'), (511, 'Network Authentication Required')], default=200, help_text='Status code function responsed with.', verbose_name='Status'),
),
migrations.AlterField(
model_name='trial',
name='updated_at',
field=models.DateTimeField(auto_now=True, db_index=True),
),
]
4 changes: 3 additions & 1 deletion mcserver/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ class Session(models.Model):

trashed = models.BooleanField(default=False)
trashed_at = models.DateTimeField(blank=True, null=True)

isMono = models.BooleanField(default=False, db_index=True)

class Meta:
ordering = ['-created_at']
Expand Down Expand Up @@ -107,7 +109,7 @@ class Trial(models.Model):
name = models.CharField(max_length=64, null=True)
meta = models.JSONField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
updated_at = models.DateTimeField(auto_now=True)
updated_at = models.DateTimeField(auto_now=True, db_index=True)
server = models.GenericIPAddressField(null=True, blank=True)
is_docker = models.BooleanField(null=True, blank=True)
hostname = models.CharField(max_length=64, null=True, blank=True)
Expand Down
13 changes: 9 additions & 4 deletions mcserver/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,14 +201,16 @@ def session_name(self, session):
return str(session.id).split("-")[0]

def get_sessionName(self, session):
return session.meta.get("sessionName", "") if session.meta else ""
if hasattr(session, 'meta') and session.meta:
return session.meta.get("sessionName", "")
return ""

class Meta:
model = Session
fields = [
'id', 'user', 'public', 'name', 'sessionName',
'qrcode', 'meta', 'trials', 'server',
'subject',
'subject', 'isMono',
'created_at', 'updated_at',
'trashed', 'trashed_at', 'trials_count', 'trashed_trials_count',
]
Expand All @@ -226,7 +228,7 @@ class Meta:
fields = [
'id', 'user', 'public', 'name', 'sessionName',
'qrcode', 'meta', 'trials', 'server',
'subject',
'subject', 'isMono',
'created_at', 'updated_at',
'trashed', 'trashed_at', 'trials_count', 'trashed_trials_count',
]
Expand Down Expand Up @@ -254,7 +256,9 @@ def session_name(self, session):
return str(session.id).split("-")[0]

def get_sessionName(self, session):
return session.meta.get("sessionName", "")
if hasattr(session, 'meta') and session.meta:
return session.meta.get("sessionName", "")
return ""


class SessionStatusSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -431,3 +435,4 @@ class AnalysisDashboardSerializer(serializers.ModelSerializer):
class Meta:
model = AnalysisDashboard
fields = ('id', 'title', 'function', 'template', 'layout')

38 changes: 29 additions & 9 deletions mcserver/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,12 @@ def get_n_calibrated_cameras(self, request, pk):
calibration_trials = session.trial_set.filter(name="calibration")
last_calibration_trial_num_videos = 0

if session.isMono:
return Response({
'error_message': error_message,
'data': 1
})

# Check if there is a calibration trial. If not, it must be in a parent session.
loop_counter = 0
while not calibration_trials and session.meta.get('sessionWithCalibration') and loop_counter < 100:
Expand Down Expand Up @@ -389,9 +395,10 @@ def valid(self, request):
sessions = sessions.filter(subject=subject)

# A session is valid only if at least one trial is the "neutral" trial and its status is "done".
# OR if it is a monocular session, which doesn't require a neutral trial.
for session in sessions:
trials = Trial.objects.filter(session__exact=session, name__exact="neutral")
if trials.count() < 1:
if trials.count() < 1 and not session.isMono:
sessions = sessions.exclude(id__exact=session.id)

# Sort by
Expand Down Expand Up @@ -1016,6 +1023,10 @@ def set_metadata(self, request, pk):
"posemodel": request.GET.get("subject_pose_model",""),
}

if "isMono" in request.GET:
session.isMono = request.GET.get("isMono", "").lower() == 'true'


if "settings_framerate" in request.GET:
session.meta["settings"] = {
"framerate": request.GET.get("settings_framerate",""),
Expand Down Expand Up @@ -1460,16 +1471,22 @@ def dequeue(self, request):
try:
ip = get_client_ip(request)

workerType = self.request.query_params.get('workerType')
workerType = self.request.query_params.get('workerType', 'all')
isMonoQuery = self.request.query_params.get('isMono', 'False')



# find trials with some videos not uploaded
not_uploaded = Video.objects.filter(video='',
updated_at__gte=datetime.now() + timedelta(minutes=-15)).values_list("trial__id", flat=True)


print(not_uploaded)

uploaded_trials = Trial.objects.exclude(id__in=not_uploaded)
# uploaded_trials = Trial.objects.all()
if isMonoQuery == 'False':
uploaded_trials = Trial.objects.filter(updated_at__gte=datetime.now() + timedelta(days=-7)).exclude(
id__in=not_uploaded).exclude(session__isMono=True)
else:
uploaded_trials = Trial.objects.filter(updated_at__gte=datetime.now() + timedelta(days=-7)).exclude(
id__in=not_uploaded).filter(session__isMono=True)

if workerType != 'dynamic':
# Priority for 'calibration' and 'neutral'
Expand Down Expand Up @@ -1501,7 +1518,10 @@ def dequeue(self, request):
raise Http404

# prioritize admin and priority group trials (priority group doesn't exist yet, but should have same priv. as user)
trialsPrioritized = trials.filter(session__user__groups__name__in=["admin","priority"])
trialsPrioritized = trials.filter(session__user__groups__name__in=["admin"])
# if no admin trials, go to priority group trials
if trialsPrioritized.count() == 0:
trialsPrioritized = trials.filter(session__user__groups__name__in=["priority"])
# if not priority trials, go to normal trials
if trialsPrioritized.count() == 0:
trialsPrioritized = trials
Expand Down Expand Up @@ -1532,7 +1552,7 @@ def dequeue(self, request):
raise APIException(_('trial_dequeue_error'))

return Response(serializer.data)

@action(detail=False, permission_classes=[((IsAdmin | IsBackend))])
def get_trials_with_status(self, request):
"""
Expand Down Expand Up @@ -2575,4 +2595,4 @@ def data(self, request, pk):
return Response(dashboard.get_available_data())

return Response(dashboard.get_available_data(
only_public=True, subject_id=request.GET.get('subject_id'), share_token=request.GET.get('share_token')))
only_public=True, subject_id=request.GET.get('subject_id'), share_token=request.GET.get('share_token')))
Loading