endoreg-db 0.8.1__py3-none-any.whl → 0.8.2.1__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/helpers/download_segmentation_model.py +31 -0
- endoreg_db/migrations/0003_add_center_display_name.py +30 -0
- endoreg_db/models/administration/center/center.py +7 -1
- endoreg_db/models/media/pdf/raw_pdf.py +31 -26
- endoreg_db/models/media/video/create_from_file.py +26 -4
- endoreg_db/models/media/video/pipe_1.py +13 -1
- endoreg_db/models/media/video/video_file.py +36 -13
- endoreg_db/models/media/video/video_file_anonymize.py +2 -1
- endoreg_db/models/media/video/video_file_frames/_manage_frame_range.py +12 -0
- endoreg_db/models/media/video/video_file_io.py +4 -2
- endoreg_db/models/metadata/video_meta.py +2 -2
- endoreg_db/serializers/anonymization.py +3 -0
- endoreg_db/services/pdf_import.py +131 -45
- endoreg_db/services/video_import.py +427 -128
- endoreg_db/urls/__init__.py +0 -2
- endoreg_db/urls/media.py +201 -4
- endoreg_db/urls/report.py +0 -30
- endoreg_db/urls/sensitive_meta.py +0 -36
- endoreg_db/urls/video.py +30 -88
- endoreg_db/utils/paths.py +2 -10
- endoreg_db/utils/video/ffmpeg_wrapper.py +67 -4
- endoreg_db/views/anonymization/validate.py +76 -32
- endoreg_db/views/media/__init__.py +38 -2
- endoreg_db/views/media/pdf_media.py +1 -1
- endoreg_db/views/media/segments.py +71 -0
- endoreg_db/views/media/sensitive_metadata.py +314 -0
- endoreg_db/views/media/video_segments.py +596 -0
- endoreg_db/views/pdf/reimport.py +18 -8
- endoreg_db/views/video/__init__.py +0 -8
- endoreg_db/views/video/correction.py +34 -32
- endoreg_db/views/video/reimport.py +15 -12
- endoreg_db/views/video/video_stream.py +168 -50
- {endoreg_db-0.8.1.dist-info → endoreg_db-0.8.2.1.dist-info}/METADATA +2 -2
- {endoreg_db-0.8.1.dist-info → endoreg_db-0.8.2.1.dist-info}/RECORD +47 -43
- endoreg_db/views/video/media/__init__.py +0 -23
- /endoreg_db/{urls/pdf.py → config/__init__.py} +0 -0
- /endoreg_db/views/video/{media/task_status.py → task_status.py} +0 -0
- /endoreg_db/views/video/{media/video_analyze.py → video_analyze.py} +0 -0
- /endoreg_db/views/video/{media/video_apply_mask.py → video_apply_mask.py} +0 -0
- /endoreg_db/views/video/{media/video_correction.py → video_correction.py} +0 -0
- /endoreg_db/views/video/{media/video_download_processed.py → video_download_processed.py} +0 -0
- /endoreg_db/views/video/{media/video_media.py → video_media.py} +0 -0
- /endoreg_db/views/video/{media/video_meta.py → video_meta.py} +0 -0
- /endoreg_db/views/video/{media/video_processing_history.py → video_processing_history.py} +0 -0
- /endoreg_db/views/video/{media/video_remove_frames.py → video_remove_frames.py} +0 -0
- /endoreg_db/views/video/{media/video_reprocess.py → video_reprocess.py} +0 -0
- {endoreg_db-0.8.1.dist-info → endoreg_db-0.8.2.1.dist-info}/WHEEL +0 -0
- {endoreg_db-0.8.1.dist-info → endoreg_db-0.8.2.1.dist-info}/licenses/LICENSE +0 -0
endoreg_db/urls/__init__.py
CHANGED
|
@@ -25,7 +25,6 @@ from .label_video_segments import url_patterns as label_video_segments_url_patte
|
|
|
25
25
|
from .label_video_segment_validate import url_patterns as label_video_segment_validate_url_patterns
|
|
26
26
|
# TODO Phase 1.2: Implement VideoMediaView and PDFMediaView before enabling
|
|
27
27
|
# from .media import urlpatterns as media_url_patterns
|
|
28
|
-
from .sensitive_meta import urlpatterns as pdf_url_patterns
|
|
29
28
|
from .report import url_patterns as report_url_patterns
|
|
30
29
|
from .upload import urlpatterns as upload_url_patterns
|
|
31
30
|
from .video import url_patterns as video_url_patterns
|
|
@@ -43,7 +42,6 @@ api_urls += label_video_segments_url_patterns
|
|
|
43
42
|
api_urls += label_video_segment_validate_url_patterns # Neue Validierungs-Endpunkte
|
|
44
43
|
# Phase 1.2: Enable media_url_patterns ✅ IMPLEMENTED
|
|
45
44
|
api_urls += media_url_patterns
|
|
46
|
-
api_urls += pdf_url_patterns
|
|
47
45
|
api_urls += report_url_patterns
|
|
48
46
|
api_urls += upload_url_patterns
|
|
49
47
|
api_urls += video_url_patterns
|
endoreg_db/urls/media.py
CHANGED
|
@@ -2,11 +2,35 @@ from django.urls import path
|
|
|
2
2
|
|
|
3
3
|
from endoreg_db.views.media import (
|
|
4
4
|
VideoMediaView,
|
|
5
|
-
|
|
5
|
+
PdfMediaView, # Alias to avoid conflict with legacy pdf.PDFMediaView
|
|
6
|
+
video_segments_by_pk,
|
|
7
|
+
video_segments_collection,
|
|
8
|
+
video_segments_by_video,
|
|
9
|
+
video_segment_detail,
|
|
10
|
+
video_segments_stats,
|
|
11
|
+
video_segment_validate,
|
|
12
|
+
video_segments_validate_bulk,
|
|
13
|
+
video_segments_validation_status,
|
|
14
|
+
video_sensitive_metadata,
|
|
15
|
+
video_sensitive_metadata_verify,
|
|
16
|
+
pdf_sensitive_metadata,
|
|
17
|
+
pdf_sensitive_metadata_verify,
|
|
18
|
+
sensitive_metadata_list,
|
|
19
|
+
pdf_sensitive_metadata_list,
|
|
6
20
|
)
|
|
7
21
|
from endoreg_db.views import (
|
|
8
22
|
VideoStreamView,
|
|
9
23
|
)
|
|
24
|
+
from endoreg_db.views.pdf.reimport import PdfReimportView
|
|
25
|
+
from endoreg_db.views.video.reimport import VideoReimportView
|
|
26
|
+
from endoreg_db.views.video.correction import (
|
|
27
|
+
VideoReprocessView,
|
|
28
|
+
VideoMetadataView,
|
|
29
|
+
VideoProcessingHistoryView,
|
|
30
|
+
VideoAnalyzeView,
|
|
31
|
+
VideoApplyMaskView,
|
|
32
|
+
VideoRemoveFramesView,
|
|
33
|
+
)
|
|
10
34
|
# ---------------------------------------------------------------------------------------
|
|
11
35
|
# ANNOTATION API ENDPOINTS
|
|
12
36
|
#
|
|
@@ -23,10 +47,183 @@ urlpatterns = [
|
|
|
23
47
|
path("media/videos/<int:pk>/", VideoStreamView.as_view(), name="video-detail-stream"), # Support ?type= params
|
|
24
48
|
path("media/videos/<int:pk>/details/", VideoMediaView.as_view(), name="video-detail"), # JSON metadata
|
|
25
49
|
path("media/videos/<int:pk>/stream/", VideoStreamView.as_view(), name="video-stream"), # Legacy support
|
|
50
|
+
|
|
51
|
+
# Video Re-import API endpoint (modern media framework)
|
|
52
|
+
# POST /api/media/videos/<int:pk>/reimport/
|
|
53
|
+
# Re-imports a video file to regenerate metadata when OCR failed or data is incomplete
|
|
54
|
+
path("media/videos/<int:pk>/reimport/", VideoReimportView.as_view(), name="video-reimport"),
|
|
55
|
+
|
|
56
|
+
# ---------------------------------------------------------------------------------------
|
|
57
|
+
# VIDEO CORRECTION API ENDPOINTS (Modern Media Framework - October 14, 2025)
|
|
58
|
+
#
|
|
59
|
+
# All video correction endpoints migrated to unified /api/media/videos/<pk>/ pattern
|
|
60
|
+
# These endpoints enable video correction workflows (Phase 1.1):
|
|
61
|
+
# - Analysis: Detect sensitive frames using MiniCPM-o 2.6 or OCR+LLM
|
|
62
|
+
# - Masking: Apply device-specific masks or custom ROI masks
|
|
63
|
+
# - Frame Removal: Remove sensitive frames from videos
|
|
64
|
+
# - Reprocessing: Re-run entire anonymization pipeline
|
|
65
|
+
# - Metadata: View analysis results
|
|
66
|
+
# - History: Track all correction operations
|
|
67
|
+
# ---------------------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
# Video Metadata API
|
|
70
|
+
# GET /api/media/videos/<int:pk>/metadata/
|
|
71
|
+
# Returns analysis results (sensitive frame count, ratio, frame IDs)
|
|
72
|
+
path("media/videos/<int:pk>/metadata/", VideoMetadataView.as_view(), name="video-metadata"),
|
|
73
|
+
|
|
74
|
+
# Video Processing History API
|
|
75
|
+
# GET /api/media/videos/<int:pk>/processing-history/
|
|
76
|
+
# Returns history of all processing operations (masking, frame removal, analysis)
|
|
77
|
+
path("media/videos/<int:pk>/processing-history/", VideoProcessingHistoryView.as_view(), name="video-processing-history"),
|
|
78
|
+
|
|
79
|
+
# Video Analysis API
|
|
80
|
+
# POST /api/media/videos/<int:pk>/analyze/
|
|
81
|
+
# Analyzes video for sensitive frames using MiniCPM-o 2.6 or OCR+LLM
|
|
82
|
+
# Body: { detection_method: 'minicpm'|'ocr_llm'|'hybrid', sample_interval: 30 }
|
|
83
|
+
path("media/videos/<int:pk>/analyze/", VideoAnalyzeView.as_view(), name="video-analyze"),
|
|
84
|
+
|
|
85
|
+
# Video Masking API
|
|
86
|
+
# POST /api/media/videos/<int:pk>/apply-mask/
|
|
87
|
+
# Applies device mask or custom ROI mask to video
|
|
88
|
+
# Body: { mask_type: 'device'|'custom', device_name: 'olympus', roi: {...} }
|
|
89
|
+
path("media/videos/<int:pk>/apply-mask/", VideoApplyMaskView.as_view(), name="video-apply-mask"),
|
|
90
|
+
|
|
91
|
+
# Video Frame Removal API
|
|
92
|
+
# POST /api/media/videos/<int:pk>/remove-frames/
|
|
93
|
+
# Removes specified frames from video
|
|
94
|
+
# Body: { frame_list: [10,20,30] OR frame_ranges: '10-20,30' OR detection_method: 'automatic' }
|
|
95
|
+
path("media/videos/<int:pk>/remove-frames/", VideoRemoveFramesView.as_view(), name="video-remove-frames"),
|
|
96
|
+
|
|
97
|
+
# Video Reprocess API endpoint (modern media framework)
|
|
98
|
+
# POST /api/media/videos/<int:pk>/reprocess/
|
|
99
|
+
# Re-runs entire anonymization pipeline for a video (correction workflow)
|
|
100
|
+
path("media/videos/<int:pk>/reprocess/", VideoReprocessView.as_view(), name="video-reprocess"),
|
|
101
|
+
|
|
102
|
+
# ---------------------------------------------------------------------------------------
|
|
103
|
+
# VIDEO SEGMENT API ENDPOINTS (Modern Media Framework - October 14, 2025)
|
|
104
|
+
#
|
|
105
|
+
# Unified segment management endpoints replacing legacy /api/video-segments/
|
|
106
|
+
# Collection: GET/POST all segments across videos
|
|
107
|
+
# Video-scoped: GET/POST segments for specific video
|
|
108
|
+
# Detail: GET/PATCH/DELETE individual segment
|
|
109
|
+
# ---------------------------------------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
# Video Segments Collection API
|
|
112
|
+
# GET/POST /api/media/videos/segments/
|
|
113
|
+
# List all video segments across videos or create new segment
|
|
114
|
+
path("media/videos/segments/", video_segments_collection, name="video-segments-collection"),
|
|
115
|
+
|
|
116
|
+
# Video Segments Stats API
|
|
117
|
+
# GET /api/media/videos/segments/stats/
|
|
118
|
+
# Get statistics about video segments
|
|
119
|
+
path("media/videos/segments/stats/", video_segments_stats, name="video-segments-stats"),
|
|
120
|
+
|
|
121
|
+
# Video-Specific Segments API
|
|
122
|
+
# GET/POST /api/media/videos/<int:pk>/segments/
|
|
123
|
+
# List segments for specific video or create segment for video
|
|
124
|
+
path("media/videos/<int:pk>/segments/", video_segments_by_video, name="video-segments-by-video"),
|
|
125
|
+
|
|
126
|
+
# Segment Detail API
|
|
127
|
+
# GET /api/media/videos/<int:pk>/segments/<int:segment_id>/
|
|
128
|
+
# PATCH /api/media/videos/<int:pk>/segments/<int:segment_id>/
|
|
129
|
+
# DELETE /api/media/videos/<int:pk>/segments/<int:segment_id>/
|
|
130
|
+
# Manages individual segment operations
|
|
131
|
+
path("media/videos/<int:pk>/segments/<int:segment_id>/", video_segment_detail, name="video-segment-detail"),
|
|
132
|
+
|
|
133
|
+
# ---------------------------------------------------------------------------------------
|
|
134
|
+
# VIDEO SEGMENT VALIDATION API ENDPOINTS (Modern Media Framework - October 14, 2025)
|
|
135
|
+
#
|
|
136
|
+
# Unified validation endpoints replacing legacy /api/label-video-segment/*/validate/
|
|
137
|
+
# Single: POST validate individual segment
|
|
138
|
+
# Bulk: POST validate multiple segments
|
|
139
|
+
# Status: GET/POST validation status for all segments
|
|
140
|
+
# ---------------------------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
# Single Segment Validation API
|
|
143
|
+
# POST /api/media/videos/<int:pk>/segments/<int:segment_id>/validate/
|
|
144
|
+
# Validates a single video segment
|
|
145
|
+
# Body: { "is_validated": true, "notes": "..." }
|
|
146
|
+
path("media/videos/<int:pk>/segments/<int:segment_id>/validate/", video_segment_validate, name="video-segment-validate"),
|
|
147
|
+
|
|
148
|
+
# Bulk Segment Validation API
|
|
149
|
+
# POST /api/media/videos/<int:pk>/segments/validate-bulk/
|
|
150
|
+
# Validates multiple segments at once
|
|
151
|
+
# Body: { "segment_ids": [1,2,3], "is_validated": true, "notes": "..." }
|
|
152
|
+
path("media/videos/<int:pk>/segments/validate-bulk/", video_segments_validate_bulk, name="video-segments-validate-bulk"),
|
|
153
|
+
|
|
154
|
+
# Segment Validation Status API
|
|
155
|
+
# GET /api/media/videos/<int:pk>/segments/validation-status/
|
|
156
|
+
# Returns validation statistics for all segments
|
|
157
|
+
# POST /api/media/videos/<int:pk>/segments/validation-status/
|
|
158
|
+
# Marks all segments (or filtered by label) as validated
|
|
159
|
+
# Body: { "label_name": "polyp", "notes": "..." }
|
|
160
|
+
path("media/videos/<int:pk>/segments/validation-status/", video_segments_validation_status, name="video-segments-validation-status"),
|
|
161
|
+
|
|
162
|
+
# ---------------------------------------------------------------------------------------
|
|
163
|
+
# SENSITIVE METADATA ENDPOINTS (Modern Media Framework)
|
|
164
|
+
# ---------------------------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
# Video Sensitive Metadata (Resource-Scoped)
|
|
167
|
+
# GET/PATCH /api/media/videos/<pk>/sensitive-metadata/
|
|
168
|
+
# Get or update sensitive patient data for a video
|
|
169
|
+
path(
|
|
170
|
+
"media/videos/<int:pk>/sensitive-metadata/",
|
|
171
|
+
video_sensitive_metadata,
|
|
172
|
+
name="video-sensitive-metadata"
|
|
173
|
+
),
|
|
174
|
+
|
|
175
|
+
# POST /api/media/videos/<pk>/sensitive-metadata/verify/
|
|
176
|
+
# Update verification state (dob_verified, names_verified)
|
|
177
|
+
path(
|
|
178
|
+
"media/videos/<int:pk>/sensitive-metadata/verify/",
|
|
179
|
+
video_sensitive_metadata_verify,
|
|
180
|
+
name="video-sensitive-metadata-verify"
|
|
181
|
+
),
|
|
182
|
+
|
|
183
|
+
# PDF Sensitive Metadata (Resource-Scoped)
|
|
184
|
+
# GET/PATCH /api/media/pdfs/<pk>/sensitive-metadata/
|
|
185
|
+
# Get or update sensitive patient data for a PDF
|
|
186
|
+
path(
|
|
187
|
+
"media/pdfs/<int:pk>/sensitive-metadata/",
|
|
188
|
+
pdf_sensitive_metadata,
|
|
189
|
+
name="pdf-sensitive-metadata"
|
|
190
|
+
),
|
|
191
|
+
|
|
192
|
+
# POST /api/media/pdfs/<pk>/sensitive-metadata/verify/
|
|
193
|
+
# Update verification state (dob_verified, names_verified)
|
|
194
|
+
path(
|
|
195
|
+
"media/pdfs/<int:pk>/sensitive-metadata/verify/",
|
|
196
|
+
pdf_sensitive_metadata_verify,
|
|
197
|
+
name="pdf-sensitive-metadata-verify"
|
|
198
|
+
),
|
|
199
|
+
|
|
200
|
+
# List Endpoints (Collection-Level)
|
|
201
|
+
# GET /api/media/sensitive-metadata/
|
|
202
|
+
# List all sensitive metadata (combined PDFs and Videos)
|
|
203
|
+
# Supports filtering: ?content_type=pdf|video&verified=true&search=name
|
|
204
|
+
path(
|
|
205
|
+
"media/sensitive-metadata/",
|
|
206
|
+
sensitive_metadata_list,
|
|
207
|
+
name="sensitive-metadata-list"
|
|
208
|
+
),
|
|
209
|
+
|
|
210
|
+
# GET /api/media/pdfs/sensitive-metadata/
|
|
211
|
+
# List sensitive metadata for PDFs only
|
|
212
|
+
# Replaces legacy /api/pdf/sensitivemeta/list/
|
|
213
|
+
path(
|
|
214
|
+
"media/pdfs/sensitive-metadata/",
|
|
215
|
+
pdf_sensitive_metadata_list,
|
|
216
|
+
name="pdf-sensitive-metadata-list"
|
|
217
|
+
),
|
|
26
218
|
|
|
27
219
|
# PDF media endpoints
|
|
28
|
-
path("media/pdfs/",
|
|
29
|
-
path("media/pdfs/<int:pk>/",
|
|
30
|
-
path("media/pdfs/<int:pk>/stream/",
|
|
220
|
+
path("media/pdfs/", PdfMediaView.as_view(), name="pdf-list"),
|
|
221
|
+
path("media/pdfs/<int:pk>/", PdfMediaView.as_view(), name="pdf-detail"),
|
|
222
|
+
path("media/pdfs/<int:pk>/stream/", PdfMediaView.as_view(), name="pdf-stream"),
|
|
223
|
+
|
|
224
|
+
# PDF Re-import API endpoint (modern media framework)
|
|
225
|
+
# POST /api/media/pdfs/<int:pk>/reimport/
|
|
226
|
+
# Re-imports a PDF file to regenerate metadata when OCR failed or data is incomplete
|
|
227
|
+
path("media/pdfs/<int:pk>/reimport/", PdfReimportView.as_view(), name="pdf-reimport"),
|
|
31
228
|
]
|
|
32
229
|
# ---------------------------------------------------------------------------------------
|
endoreg_db/urls/report.py
CHANGED
|
@@ -2,10 +2,7 @@ from django.urls import path
|
|
|
2
2
|
from endoreg_db.views import (
|
|
3
3
|
ReportListView,
|
|
4
4
|
ReportWithSecureUrlView,
|
|
5
|
-
SecureFileUrlView,
|
|
6
5
|
ReportFileMetadataView,
|
|
7
|
-
SecureFileServingView,
|
|
8
|
-
validate_secure_url,
|
|
9
6
|
)
|
|
10
7
|
|
|
11
8
|
url_patterns = [ # ---------------------------------------------------------------------------------------
|
|
@@ -40,16 +37,6 @@ url_patterns = [ # ------------------------------------------------------
|
|
|
40
37
|
name='report_with_secure_url'
|
|
41
38
|
),
|
|
42
39
|
|
|
43
|
-
# API-Endpunkt für manuelle sichere URL-Generierung
|
|
44
|
-
# POST /api/secure-file-urls/
|
|
45
|
-
# Body: {"report_id": 123, "file_type": "pdf"}
|
|
46
|
-
# Generiert eine neue sichere URL für einen bestehenden Report
|
|
47
|
-
path(
|
|
48
|
-
'secure-file-urls/',
|
|
49
|
-
SecureFileUrlView.as_view(),
|
|
50
|
-
name='generate_secure_file_url'
|
|
51
|
-
),
|
|
52
|
-
|
|
53
40
|
# API-Endpunkt für Report-Datei-Metadaten
|
|
54
41
|
# GET /api/reports/{report_id}/file-metadata/
|
|
55
42
|
# Gibt Datei-Metadaten zurück (Größe, Typ, Datum, etc.)
|
|
@@ -58,21 +45,4 @@ url_patterns = [ # ------------------------------------------------------
|
|
|
58
45
|
ReportFileMetadataView.as_view(),
|
|
59
46
|
name='report_file_metadata'
|
|
60
47
|
),
|
|
61
|
-
|
|
62
|
-
# Sichere Datei-Serving-Endpunkt mit Token-Validierung
|
|
63
|
-
# GET /api/reports/{report_id}/secure-file/?token={token}
|
|
64
|
-
# Serviert die tatsächliche Datei über eine sichere, tokenbasierte URL
|
|
65
|
-
path(
|
|
66
|
-
'reports/<int:report_id>/secure-file/',
|
|
67
|
-
SecureFileServingView.as_view(),
|
|
68
|
-
name='secure_file_serving'
|
|
69
|
-
),
|
|
70
|
-
# URL-Validierungs-Endpunkt
|
|
71
|
-
# GET /api/validate-secure-url/?url={url}
|
|
72
|
-
# Validiert, ob eine sichere URL noch gültig ist
|
|
73
|
-
path(
|
|
74
|
-
'validate-secure-url/',
|
|
75
|
-
validate_secure_url,
|
|
76
|
-
name='validate_secure_url'
|
|
77
|
-
),
|
|
78
48
|
]
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
from django.urls import path
|
|
2
|
-
|
|
3
|
-
# Prefer explicit imports to avoid relying on parent __init__ exports
|
|
4
|
-
from endoreg_db.views import (
|
|
5
|
-
SensitiveMetaDetailView,
|
|
6
|
-
SensitiveMetaVerificationView,
|
|
7
|
-
SensitiveMetaListView,
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
urlpatterns = [
|
|
11
|
-
|
|
12
|
-
# Sensitive Meta Detail API
|
|
13
|
-
path(
|
|
14
|
-
'pdf/sensitivemeta/<int:sensitive_meta_id>/',
|
|
15
|
-
SensitiveMetaDetailView.as_view(),
|
|
16
|
-
name='sensitive_meta_detail'
|
|
17
|
-
),
|
|
18
|
-
# Alternative endpoint for query parameter access (backward compatibility)
|
|
19
|
-
path(
|
|
20
|
-
'pdf/sensitivemeta/',
|
|
21
|
-
SensitiveMetaDetailView.as_view(),
|
|
22
|
-
name='sensitive_meta_query'
|
|
23
|
-
),
|
|
24
|
-
|
|
25
|
-
# Sensitive Meta Verification API
|
|
26
|
-
path(
|
|
27
|
-
'pdf/sensitivemeta/verify/',
|
|
28
|
-
SensitiveMetaVerificationView.as_view(),
|
|
29
|
-
name='sensitive_meta_verify'),
|
|
30
|
-
|
|
31
|
-
# Sensitive Meta List API
|
|
32
|
-
path(
|
|
33
|
-
'pdf/sensitivemeta/list/',
|
|
34
|
-
SensitiveMetaListView.as_view(),
|
|
35
|
-
name='sensitive_meta_list'),
|
|
36
|
-
]
|
endoreg_db/urls/video.py
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
from django.urls import path
|
|
2
2
|
|
|
3
3
|
from endoreg_db.views import (
|
|
4
|
-
VideoReimportView,
|
|
5
4
|
SensitiveMetaDetailView,
|
|
6
5
|
VideoLabelView,
|
|
7
|
-
VideoStreamView
|
|
8
|
-
# Video Correction Views
|
|
9
|
-
VideoMetadataView,
|
|
10
|
-
VideoProcessingHistoryView,
|
|
11
|
-
VideoAnalyzeView,
|
|
12
|
-
VideoApplyMaskView,
|
|
13
|
-
VideoRemoveFramesView,
|
|
14
|
-
VideoReprocessView,
|
|
6
|
+
# Note: VideoStreamView moved to modern media framework. See: endoreg_db/urls/media.py
|
|
7
|
+
# Note: All Video Correction Views moved to modern media framework. See: endoreg_db/urls/media.py
|
|
15
8
|
)
|
|
16
9
|
|
|
17
10
|
url_patterns = [
|
|
@@ -24,23 +17,22 @@ url_patterns = [
|
|
|
24
17
|
name='video_label_segments'
|
|
25
18
|
),
|
|
26
19
|
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
20
|
+
# ---------------------------------------------------------------------------------------
|
|
21
|
+
# VIDEO STREAMING - MOVED TO MODERN MEDIA FRAMEWORK
|
|
22
|
+
#
|
|
23
|
+
# Video streaming endpoint has been migrated to the media framework
|
|
24
|
+
# as of October 14, 2025. Please use the new endpoints:
|
|
25
|
+
#
|
|
26
|
+
# OLD → NEW:
|
|
27
|
+
# GET /api/videostream/<pk>/ → GET /api/media/videos/<pk>/
|
|
28
|
+
# GET /api/videostream/<pk>/ → GET /api/media/videos/<pk>/stream/
|
|
29
|
+
#
|
|
30
|
+
# See: endoreg_db/urls/media.py for new URL registrations
|
|
31
|
+
# ---------------------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
# Note: Video Re-import moved to modern media framework
|
|
34
|
+
# See: endoreg_db/urls/media.py - POST /api/media/videos/<int:pk>/reimport/
|
|
35
35
|
|
|
36
|
-
# Video Re-import API endpoint
|
|
37
|
-
# POST /api/video/<int:video_id>/reimport/
|
|
38
|
-
# Re-imports a video file to regenerate metadata when OCR failed or data is incomplete
|
|
39
|
-
path(
|
|
40
|
-
'video/<int:video_id>/reimport/',
|
|
41
|
-
VideoReimportView.as_view(),
|
|
42
|
-
name='video_reimport'
|
|
43
|
-
),
|
|
44
36
|
# Video Sensitive Meta endpoints (for video anonymization)
|
|
45
37
|
# GET /api/video/sensitivemeta/<int:sensitive_meta_id>/
|
|
46
38
|
# PATCH /api/video/sensitivemeta/<int:sensitive_meta_id>/
|
|
@@ -51,69 +43,19 @@ url_patterns = [
|
|
|
51
43
|
),
|
|
52
44
|
|
|
53
45
|
# ---------------------------------------------------------------------------------------
|
|
54
|
-
# VIDEO CORRECTION API ENDPOINTS
|
|
46
|
+
# VIDEO CORRECTION API ENDPOINTS - MOVED TO MODERN MEDIA FRAMEWORK
|
|
47
|
+
#
|
|
48
|
+
# All video correction endpoints have been migrated to the modern media framework
|
|
49
|
+
# as of October 14, 2025. Please use the new endpoints:
|
|
50
|
+
#
|
|
51
|
+
# OLD → NEW:
|
|
52
|
+
# GET /api/video-metadata/<id>/ → GET /api/media/videos/<pk>/metadata/
|
|
53
|
+
# GET /api/video-processing-history/<id>/ → GET /api/media/videos/<pk>/processing-history/
|
|
54
|
+
# POST /api/video-analyze/<id>/ → POST /api/media/videos/<pk>/analyze/
|
|
55
|
+
# POST /api/video-apply-mask/<id>/ → POST /api/media/videos/<pk>/apply-mask/
|
|
56
|
+
# POST /api/video-remove-frames/<id>/ → POST /api/media/videos/<pk>/remove-frames/
|
|
57
|
+
# POST /api/video-reprocess/<id>/ → POST /api/media/videos/<pk>/reprocess/
|
|
55
58
|
#
|
|
56
|
-
#
|
|
57
|
-
# - Analysis: Detect sensitive frames using MiniCPM-o 2.6 or OCR+LLM
|
|
58
|
-
# - Masking: Apply device-specific masks or custom ROI masks
|
|
59
|
-
# - Frame Removal: Remove sensitive frames from videos
|
|
60
|
-
# - Processing History: Track all correction operations
|
|
59
|
+
# See: endoreg_db/urls/media.py for new URL registrations
|
|
61
60
|
# ---------------------------------------------------------------------------------------
|
|
62
|
-
|
|
63
|
-
# Video Metadata API
|
|
64
|
-
# GET /api/video-metadata/<int:id>/
|
|
65
|
-
# Returns analysis results (sensitive frame count, ratio, frame IDs)
|
|
66
|
-
path(
|
|
67
|
-
'video-metadata/<int:id>/',
|
|
68
|
-
VideoMetadataView.as_view(),
|
|
69
|
-
name='video_metadata'
|
|
70
|
-
),
|
|
71
|
-
|
|
72
|
-
# Video Processing History API
|
|
73
|
-
# GET /api/video-processing-history/<int:id>/
|
|
74
|
-
# Returns history of all processing operations (masking, frame removal, analysis)
|
|
75
|
-
path(
|
|
76
|
-
'video-processing-history/<int:id>/',
|
|
77
|
-
VideoProcessingHistoryView.as_view(),
|
|
78
|
-
name='video_processing_history'
|
|
79
|
-
),
|
|
80
|
-
|
|
81
|
-
# Video Analysis API
|
|
82
|
-
# POST /api/video-analyze/<int:id>/
|
|
83
|
-
# Analyzes video for sensitive frames using MiniCPM-o 2.6 or OCR+LLM
|
|
84
|
-
# Body: { detection_method: 'minicpm'|'ocr_llm'|'hybrid', sample_interval: 30 }
|
|
85
|
-
path(
|
|
86
|
-
'video-analyze/<int:id>/',
|
|
87
|
-
VideoAnalyzeView.as_view(),
|
|
88
|
-
name='video_analyze'
|
|
89
|
-
),
|
|
90
|
-
|
|
91
|
-
# Video Masking API
|
|
92
|
-
# POST /api/video-apply-mask/<int:id>/
|
|
93
|
-
# Applies device mask or custom ROI mask to video
|
|
94
|
-
# Body: { mask_type: 'device'|'custom', device_name: 'olympus', roi: {...} }
|
|
95
|
-
path(
|
|
96
|
-
'video-apply-mask/<int:id>/',
|
|
97
|
-
VideoApplyMaskView.as_view(),
|
|
98
|
-
name='video_apply_mask'
|
|
99
|
-
),
|
|
100
|
-
|
|
101
|
-
# Frame Removal API
|
|
102
|
-
# POST /api/video-remove-frames/<int:id>/
|
|
103
|
-
# Removes specified frames from video
|
|
104
|
-
# Body: { frame_list: [10,20,30] OR frame_ranges: '10-20,30' OR detection_method: 'automatic' }
|
|
105
|
-
path(
|
|
106
|
-
'video-remove-frames/<int:id>/',
|
|
107
|
-
VideoRemoveFramesView.as_view(),
|
|
108
|
-
name='video_remove_frames'
|
|
109
|
-
),
|
|
110
|
-
|
|
111
|
-
# Video Reprocessing API
|
|
112
|
-
# POST /api/video-reprocess/<int:id>/
|
|
113
|
-
# Re-runs entire anonymization pipeline for a video
|
|
114
|
-
path(
|
|
115
|
-
'video-reprocess/<int:id>/',
|
|
116
|
-
VideoReprocessView.as_view(),
|
|
117
|
-
name='video_reprocess'
|
|
118
|
-
),
|
|
119
61
|
]
|
endoreg_db/utils/paths.py
CHANGED
|
@@ -8,19 +8,12 @@ It provides a unified dictionary 'data_paths' for accessing all path objects.
|
|
|
8
8
|
from logging import getLogger
|
|
9
9
|
logger = getLogger(__name__)
|
|
10
10
|
|
|
11
|
-
import os
|
|
12
11
|
from pathlib import Path
|
|
13
12
|
from typing import Dict
|
|
14
|
-
import dotenv
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
if not os.environ.get("PYTEST_CURRENT_TEST"):
|
|
18
|
-
dotenv.load_dotenv()
|
|
19
|
-
else:
|
|
20
|
-
logger.debug("Skipping .env load under pytest")
|
|
14
|
+
from endoreg_db.config.env import env_path
|
|
21
15
|
|
|
22
|
-
|
|
23
|
-
STORAGE_DIR = Path(os.getenv("STORAGE_DIR"))
|
|
16
|
+
STORAGE_DIR = env_path("STORAGE_DIR", "storage")
|
|
24
17
|
|
|
25
18
|
# Resolve STORAGE_DIR from env or default under BASE_DIR
|
|
26
19
|
#def _resolve_storage_dir() -> Path:
|
|
@@ -36,7 +29,6 @@ STORAGE_DIR = Path(os.getenv("STORAGE_DIR"))
|
|
|
36
29
|
STORAGE_DIR.mkdir(parents=True, exist_ok=True)
|
|
37
30
|
|
|
38
31
|
PREFIX_RAW = "raw_"
|
|
39
|
-
STORAGE_DIR_NAME = "data"
|
|
40
32
|
IMPORT_DIR_NAME = "import"
|
|
41
33
|
EXPORT_DIR_NAME = "export"
|
|
42
34
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import os
|
|
1
2
|
import subprocess
|
|
2
3
|
import json
|
|
3
4
|
import logging
|
|
5
|
+
from functools import lru_cache
|
|
4
6
|
from pathlib import Path
|
|
5
7
|
from typing import List, Dict, Optional, Tuple
|
|
6
8
|
import cv2
|
|
@@ -13,6 +15,67 @@ logger = logging.getLogger("ffmpeg_wrapper")
|
|
|
13
15
|
_nvenc_available = None
|
|
14
16
|
_preferred_encoder = None
|
|
15
17
|
|
|
18
|
+
|
|
19
|
+
@lru_cache(maxsize=1)
|
|
20
|
+
def _resolve_ffmpeg_executable() -> Optional[str]:
|
|
21
|
+
"""Locate the ffmpeg executable using multiple discovery strategies."""
|
|
22
|
+
# 1) Explicit overrides via env vars
|
|
23
|
+
env_candidates = [
|
|
24
|
+
os.environ.get("FFMPEG_EXECUTABLE"),
|
|
25
|
+
os.environ.get("FFMPEG_BINARY"),
|
|
26
|
+
os.environ.get("FFMPEG_PATH"),
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
# 2) Django settings overrides (if Django is configured)
|
|
30
|
+
try:
|
|
31
|
+
from django.conf import settings # type: ignore
|
|
32
|
+
|
|
33
|
+
env_candidates.extend(
|
|
34
|
+
getattr(settings, attr)
|
|
35
|
+
for attr in ("FFMPEG_EXECUTABLE", "FFMPEG_BINARY", "FFMPEG_PATH")
|
|
36
|
+
if hasattr(settings, attr)
|
|
37
|
+
)
|
|
38
|
+
except Exception:
|
|
39
|
+
# Django might not be configured for every consumer
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
# Normalize and verify explicit candidates
|
|
43
|
+
for candidate in env_candidates:
|
|
44
|
+
if not candidate:
|
|
45
|
+
continue
|
|
46
|
+
candidate_path = Path(candidate)
|
|
47
|
+
if candidate_path.is_dir():
|
|
48
|
+
candidate_path = candidate_path / "ffmpeg"
|
|
49
|
+
if candidate_path.exists() and os.access(candidate_path, os.X_OK):
|
|
50
|
+
logger.debug("Using ffmpeg executable override at %s", candidate_path)
|
|
51
|
+
return str(candidate_path)
|
|
52
|
+
|
|
53
|
+
# 3) PATH lookup (shutil.which)
|
|
54
|
+
via_path = shutil.which("ffmpeg")
|
|
55
|
+
if via_path:
|
|
56
|
+
return via_path
|
|
57
|
+
|
|
58
|
+
# 4) Common fallback locations (useful for Nix-based environments)
|
|
59
|
+
nix_store = Path("/nix/store")
|
|
60
|
+
if nix_store.exists():
|
|
61
|
+
patterns = (
|
|
62
|
+
"*-ffmpeg-*/bin/ffmpeg",
|
|
63
|
+
"*-ffmpeg-headless-*/bin/ffmpeg",
|
|
64
|
+
"*-ffmpeg-headless*/bin/ffmpeg",
|
|
65
|
+
)
|
|
66
|
+
for pattern in patterns:
|
|
67
|
+
matches = sorted(nix_store.glob(pattern))
|
|
68
|
+
if matches:
|
|
69
|
+
logger.debug("Discovered ffmpeg in nix store at %s", matches[-1])
|
|
70
|
+
return str(matches[-1])
|
|
71
|
+
|
|
72
|
+
# 5) Final fallback to standard Unix locations
|
|
73
|
+
for fallback in (Path("/usr/bin/ffmpeg"), Path("/usr/local/bin/ffmpeg")):
|
|
74
|
+
if fallback.exists() and os.access(fallback, os.X_OK):
|
|
75
|
+
return str(fallback)
|
|
76
|
+
|
|
77
|
+
return None
|
|
78
|
+
|
|
16
79
|
def _detect_nvenc_support() -> bool:
|
|
17
80
|
"""
|
|
18
81
|
Detect if NVIDIA NVENC hardware acceleration is available.
|
|
@@ -163,7 +226,7 @@ def is_ffmpeg_available() -> bool:
|
|
|
163
226
|
Returns:
|
|
164
227
|
True if FFmpeg is found in the PATH; otherwise, False.
|
|
165
228
|
"""
|
|
166
|
-
return
|
|
229
|
+
return _resolve_ffmpeg_executable() is not None
|
|
167
230
|
|
|
168
231
|
def check_ffmpeg_availability():
|
|
169
232
|
"""
|
|
@@ -607,8 +670,8 @@ def extract_frames(
|
|
|
607
670
|
Returns:
|
|
608
671
|
A list of Path objects for the extracted frames.
|
|
609
672
|
"""
|
|
610
|
-
#
|
|
611
|
-
ffmpeg_executable =
|
|
673
|
+
# Resolve ffmpeg executable with multiple fallbacks
|
|
674
|
+
ffmpeg_executable = _resolve_ffmpeg_executable()
|
|
612
675
|
if not ffmpeg_executable:
|
|
613
676
|
error_msg = "ffmpeg command not found. Ensure FFmpeg is installed and in the system's PATH."
|
|
614
677
|
logger.error(error_msg)
|
|
@@ -691,7 +754,7 @@ def extract_frame_range(
|
|
|
691
754
|
logger.warning("extract_frame_range called with start_frame (%d) >= end_frame (%d). No frames to extract.", start_frame, end_frame)
|
|
692
755
|
return []
|
|
693
756
|
|
|
694
|
-
ffmpeg_executable =
|
|
757
|
+
ffmpeg_executable = _resolve_ffmpeg_executable()
|
|
695
758
|
if not ffmpeg_executable:
|
|
696
759
|
error_msg = "ffmpeg command not found. Ensure FFmpeg is installed and in the system's PATH."
|
|
697
760
|
logger.error(error_msg)
|