endoreg-db 0.6.1__py3-none-any.whl → 0.6.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/data/distribution/numeric/data.yaml +1 -1
- endoreg_db/mermaid/Overall_flow_patient_finding_intervention.md +10 -0
- endoreg_db/mermaid/anonymized_image_annotation.md +20 -0
- endoreg_db/mermaid/binary_classification_annotation.md +50 -0
- endoreg_db/mermaid/classification.md +8 -0
- endoreg_db/mermaid/examination.md +8 -0
- endoreg_db/mermaid/findings.md +7 -0
- endoreg_db/mermaid/image_classification.md +28 -0
- endoreg_db/mermaid/interventions.md +8 -0
- endoreg_db/mermaid/morphology.md +8 -0
- endoreg_db/mermaid/patient_creation.md +14 -0
- endoreg_db/mermaid/video_segmentation_annotation.md +17 -0
- endoreg_db/models/ai_model/ai_model.py +1 -1
- endoreg_db/models/ai_model/model_meta.py +1 -1
- endoreg_db/models/data_file/base_classes/utils.py +1 -1
- endoreg_db/serializers/raw_pdf_anony_text_validation.py +137 -0
- endoreg_db/serializers/raw_pdf_meta_validation.py +223 -0
- endoreg_db/serializers/raw_video_meta_validation.py +163 -1
- endoreg_db/serializers/video_segmentation.py +207 -112
- endoreg_db/urls.py +110 -11
- endoreg_db/views/raw_pdf_anony_text_validation_views.py +95 -0
- endoreg_db/views/raw_pdf_meta_validation_views.py +111 -0
- endoreg_db/views/raw_video_meta_validation_views.py +128 -18
- endoreg_db/views/video_segmentation_views.py +28 -11
- {endoreg_db-0.6.1.dist-info → endoreg_db-0.6.3.dist-info}/METADATA +11 -1
- {endoreg_db-0.6.1.dist-info → endoreg_db-0.6.3.dist-info}/RECORD +28 -13
- {endoreg_db-0.6.1.dist-info → endoreg_db-0.6.3.dist-info}/WHEEL +0 -0
- {endoreg_db-0.6.1.dist-info → endoreg_db-0.6.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,13 +1,175 @@
|
|
|
1
|
+
from pathlib import Path
|
|
1
2
|
from rest_framework import serializers
|
|
3
|
+
from django.conf import settings
|
|
2
4
|
from ..models import RawVideoFile, SensitiveMeta
|
|
5
|
+
import cv2
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
3
8
|
|
|
4
9
|
class VideoFileForMetaSerializer(serializers.ModelSerializer):
|
|
5
10
|
"""
|
|
6
11
|
Serializer to fetch video metadata along with linked `SensitiveMeta` details.
|
|
12
|
+
Ensures that Vue.js can properly access and play videos.
|
|
7
13
|
"""
|
|
8
14
|
|
|
15
|
+
# Fetch patient name and DOB from `SensitiveMeta` table
|
|
9
16
|
patient_first_name = serializers.CharField(source="sensitive_meta.patient_first_name", read_only=True)
|
|
17
|
+
patient_last_name = serializers.CharField(source="sensitive_meta.patient_last_name", read_only=True)
|
|
18
|
+
patient_dob = serializers.CharField(source="sensitive_meta.patient_dob", read_only=True)
|
|
19
|
+
examination_date = serializers.CharField(source="sensitive_meta.examination_date", read_only=True)
|
|
20
|
+
|
|
21
|
+
duration = serializers.SerializerMethodField()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# `video_url` generates the full URL where Vue.js can fetch & play the video
|
|
25
|
+
video_url = serializers.SerializerMethodField()
|
|
26
|
+
|
|
27
|
+
# `full_video_path` dynamically constructs the absolute path using MEDIA_ROOT
|
|
28
|
+
full_video_path = serializers.SerializerMethodField()
|
|
29
|
+
|
|
30
|
+
file = serializers.SerializerMethodField()
|
|
10
31
|
|
|
11
32
|
class Meta:
|
|
12
33
|
model = RawVideoFile
|
|
13
|
-
fields = ['id', 'original_file_name', 'file', '
|
|
34
|
+
fields = ['id', 'original_file_name', 'file', 'video_url', 'full_video_path',
|
|
35
|
+
'sensitive_meta_id', 'patient_first_name', 'patient_last_name', 'patient_dob', 'examination_date','duration']
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
def get_next_video(last_id=None):
|
|
39
|
+
"""
|
|
40
|
+
Fetches the first or next available video.
|
|
41
|
+
Returns a model instance if found, else returns None.
|
|
42
|
+
"""
|
|
43
|
+
query_filter = {} if last_id is None else {"id__gt": int(last_id)}
|
|
44
|
+
|
|
45
|
+
# Get next available video
|
|
46
|
+
video_entry = RawVideoFile.objects.select_related("sensitive_meta").filter(**query_filter).order_by('id').first()
|
|
47
|
+
|
|
48
|
+
return video_entry # Always return model instance or None
|
|
49
|
+
|
|
50
|
+
def get_video_url(self, obj):
|
|
51
|
+
"""
|
|
52
|
+
Generates the full URL where Vue.js can fetch and stream the video.
|
|
53
|
+
"""
|
|
54
|
+
request = self.context.get('request')
|
|
55
|
+
if request and obj.file:
|
|
56
|
+
print("---------------------------:",obj.file)
|
|
57
|
+
return request.build_absolute_uri(f"/api/video/{obj.id}/") # Generates full URL
|
|
58
|
+
return None # Return None instead of an error dictionary
|
|
59
|
+
|
|
60
|
+
def get_file(self, obj):
|
|
61
|
+
"""
|
|
62
|
+
Returns only the relative file path, without `/media/`.
|
|
63
|
+
"""
|
|
64
|
+
if not obj.file:
|
|
65
|
+
return None # No file associated
|
|
66
|
+
|
|
67
|
+
video_relative_path = str(obj.file.name).strip()
|
|
68
|
+
return video_relative_path if video_relative_path else None # Avoids errors if the file path is empty
|
|
69
|
+
|
|
70
|
+
def get_full_video_path(self, obj):
|
|
71
|
+
"""
|
|
72
|
+
Constructs the full absolute file path using `settings.MEDIA_ROOT`
|
|
73
|
+
and the `file` field from the database.
|
|
74
|
+
"""
|
|
75
|
+
if not obj.file:
|
|
76
|
+
return None # No file associated
|
|
77
|
+
|
|
78
|
+
video_relative_path = str(obj.file.name).strip()
|
|
79
|
+
full_path = Path(settings.MEDIA_ROOT) / video_relative_path
|
|
80
|
+
|
|
81
|
+
return str(full_path) if full_path.exists() else None # Return path or None if not found
|
|
82
|
+
|
|
83
|
+
def get_duration(self, obj):
|
|
84
|
+
"""
|
|
85
|
+
Returns the total duration of the video in seconds.
|
|
86
|
+
- If stored in the database, use it.
|
|
87
|
+
- Otherwise, calculate dynamically using OpenCV.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
# Step 1: Check if the `duration` field is already stored in the database.
|
|
91
|
+
if hasattr(obj, "duration") and obj.duration:
|
|
92
|
+
return obj.duration # If duration exists in the database, return it immediately.
|
|
93
|
+
|
|
94
|
+
# Step 2: Get the actual video file path
|
|
95
|
+
video_path = obj.file.path if obj.file else None # Extracts the file path if it exists
|
|
96
|
+
|
|
97
|
+
# Step 3: Validate if the file exists
|
|
98
|
+
if not video_path or not Path(video_path).exists():
|
|
99
|
+
return None # Return None if the file path is invalid or missing
|
|
100
|
+
|
|
101
|
+
# Step 4: Open the video file using OpenCV
|
|
102
|
+
cap = cv2.VideoCapture(video_path) # Load the video file
|
|
103
|
+
|
|
104
|
+
if not cap.isOpened():
|
|
105
|
+
return None # If OpenCV fails to open the video, return None (invalid or corrupted file)
|
|
106
|
+
|
|
107
|
+
# Step 5: Extract FPS (Frames Per Second)
|
|
108
|
+
fps = cap.get(cv2.CAP_PROP_FPS) # Get the number of frames per second
|
|
109
|
+
print("here is the fps------------", fps) # Debugging print to check FPS value
|
|
110
|
+
|
|
111
|
+
# Step 6: Get Total Number of Frames
|
|
112
|
+
total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT) # Get the total number of frames in the video
|
|
113
|
+
|
|
114
|
+
# Step 7: Release the video file from OpenCV memory
|
|
115
|
+
cap.release() # Free up system memory
|
|
116
|
+
|
|
117
|
+
# Step 8: Calculate and Return Video Duration
|
|
118
|
+
return round(total_frames / fps, 2) if fps > 0 else None # Divide frames by FPS to get duration (seconds)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class SensitiveMetaUpdateSerializer(serializers.ModelSerializer):
|
|
124
|
+
"""
|
|
125
|
+
Serializer to update patient information in the `SensitiveMeta` table.
|
|
126
|
+
Handles validation and saves the data directly in the serializer.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
sensitive_meta_id = serializers.IntegerField(write_only=True) # Needed for lookup but not included in response
|
|
130
|
+
|
|
131
|
+
class Meta:
|
|
132
|
+
model = SensitiveMeta
|
|
133
|
+
fields = ['sensitive_meta_id', 'patient_first_name', 'patient_last_name', 'patient_dob', 'examination_date']
|
|
134
|
+
|
|
135
|
+
def validate(self, data):
|
|
136
|
+
"""
|
|
137
|
+
Validate input data before updating.
|
|
138
|
+
"""
|
|
139
|
+
errors = {}
|
|
140
|
+
|
|
141
|
+
# Ensure the SensitiveMeta ID exists
|
|
142
|
+
sensitive_meta_id = data.get("sensitive_meta_id")
|
|
143
|
+
if not SensitiveMeta.objects.filter(id=sensitive_meta_id).exists():
|
|
144
|
+
raise serializers.ValidationError({"sensitive_meta_id": "SensitiveMeta entry not found."})
|
|
145
|
+
|
|
146
|
+
# Validate each field separately
|
|
147
|
+
if 'patient_first_name' in data and (data['patient_first_name'] is None or data['patient_first_name'].strip() == ""):
|
|
148
|
+
errors['patient_first_name'] = "First name cannot be empty."
|
|
149
|
+
|
|
150
|
+
if 'patient_last_name' in data and (data['patient_last_name'] is None or data['patient_last_name'].strip() == ""):
|
|
151
|
+
errors['patient_last_name'] = "Last name cannot be empty."
|
|
152
|
+
|
|
153
|
+
if 'patient_dob' in data and not data['patient_dob']:
|
|
154
|
+
errors['patient_dob'] = "Date of birth is required."
|
|
155
|
+
|
|
156
|
+
if 'examination_date' in data and not data['examination_date']:
|
|
157
|
+
errors['examination_date'] = "Examination date is required."
|
|
158
|
+
|
|
159
|
+
if errors:
|
|
160
|
+
raise serializers.ValidationError(errors) # Raise errors before saving
|
|
161
|
+
|
|
162
|
+
return data
|
|
163
|
+
|
|
164
|
+
def update(self, instance, validated_data):
|
|
165
|
+
"""
|
|
166
|
+
Update the SensitiveMeta entry directly inside the serializer.
|
|
167
|
+
"""
|
|
168
|
+
# Remove `sensitive_meta_id` before updating
|
|
169
|
+
validated_data.pop("sensitive_meta_id", None)
|
|
170
|
+
|
|
171
|
+
for attr, value in validated_data.items():
|
|
172
|
+
setattr(instance, attr, value) # Set attributes dynamically
|
|
173
|
+
|
|
174
|
+
instance.save() # Save changes
|
|
175
|
+
return instance # Return updated instance
|