diff --git a/label_studio/data_export/api.py b/label_studio/data_export/api.py index c74dc9d5e096..44c9bb97894e 100644 --- a/label_studio/data_export/api.py +++ b/label_studio/data_export/api.py @@ -569,7 +569,7 @@ def get(self, request, *args, **kwargs): return response -def async_convert(converted_format_id, export_type, project, **kwargs): +def async_convert(converted_format_id, export_type, project, hostname, download_resources=False, **kwargs): with transaction.atomic(): try: converted_format = ConvertedFormat.objects.get(id=converted_format_id) @@ -583,7 +583,7 @@ def async_convert(converted_format_id, export_type, project, **kwargs): converted_format.save(update_fields=['status']) snapshot = converted_format.export - converted_file = snapshot.convert_file(export_type) + converted_file = snapshot.convert_file(export_type, download_resources=download_resources, hostname=hostname) if converted_file is None: raise ValidationError('No converted file found, probably there are no annotations in the export snapshot') md5 = Export.eval_md5(converted_file) @@ -645,6 +645,7 @@ def post(self, request, *args, **kwargs): serializer = ExportConvertSerializer(data=request.data, context={'project': snapshot.project}) serializer.is_valid(raise_exception=True) export_type = serializer.validated_data['export_type'] + download_resources = serializer.validated_data.get('download_resources') with transaction.atomic(): converted_format, created = ConvertedFormat.objects.get_or_create(export=snapshot, export_type=export_type) @@ -657,6 +658,8 @@ def post(self, request, *args, **kwargs): converted_format.id, export_type, snapshot.project, + request.build_absolute_uri('/'), + download_resources=download_resources, on_failure=set_convert_background_failure, ) return Response({'export_type': export_type, 'converted_format': converted_format.id}) diff --git a/label_studio/data_export/mixins.py b/label_studio/data_export/mixins.py index 58cfc5209990..2ef74698fa7f 100644 --- a/label_studio/data_export/mixins.py +++ b/label_studio/data_export/mixins.py @@ -137,6 +137,9 @@ def _get_export_serializer_option(serialization_options): options['context']['interpolate_key_frames'] = serialization_options['interpolate_key_frames'] if serialization_options.get('include_annotation_history') is False: options['omit'] = ['annotations.history'] + # download resources + if serialization_options.get('download_resources') is True: + options['download_resources'] = True return options def get_task_queryset(self, ids, annotation_filter_options): @@ -303,7 +306,7 @@ def run_file_exporting(self, task_filter_options=None, annotation_filter_options serialization_options=serialization_options, ) - def convert_file(self, to_format): + def convert_file(self, to_format, download_resources=False, hostname=None): with get_temp_dir() as tmp_dir: OUT = 'out' out_dir = pathlib.Path(tmp_dir) / OUT @@ -313,7 +316,10 @@ def convert_file(self, to_format): config=self.project.get_parsed_config(), project_dir=None, upload_dir=out_dir, - download_resources=False, + download_resources=download_resources, + # for downloading resource we need access to the API + access_token=self.project.organization.created_by.auth_token.key, + hostname=hostname, ) input_name = pathlib.Path(self.file.name).name input_file_path = pathlib.Path(tmp_dir) / input_name diff --git a/label_studio/data_export/serializers.py b/label_studio/data_export/serializers.py index 944d0fdf44e9..da9319e7bd71 100644 --- a/label_studio/data_export/serializers.py +++ b/label_studio/data_export/serializers.py @@ -166,6 +166,7 @@ class SerializationOption(serializers.Serializer): class ExportConvertSerializer(serializers.Serializer): export_type = serializers.CharField(help_text='Export file format.') + download_resources = serializers.BooleanField(help_text='Download resources in converter.', required=False) def validate_export_type(self, value): project = self.context.get('project') diff --git a/poetry.lock b/poetry.lock index 185ce9ddf12b..7579fd8db552 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2133,14 +2133,14 @@ testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", [[package]] name = "label-studio-sdk" -version = "1.0.9" +version = "1.0.9.dev0" description = "" optional = false python-versions = ">=3.9,<4" groups = ["main"] markers = "python_version >= \"3.12\" or python_version <= \"3.11\"" files = [ - {file = "abf1ea4207e22d3d3cdfb8f4bb12ffb4d59384e4.zip", hash = "sha256:95cda8afbbb56d11b79f8b6d34f0f20dd8d1bf7119878322fc0d7fb6c2d00a39"}, + {file = "025aaa8136465f97892adfee7aea498576e05f7a.zip", hash = "sha256:3786ff73a48fb65af1ad450cba8439c69b31a36c911cd5f6a597a88878da839d"}, ] [package.dependencies] @@ -2156,7 +2156,6 @@ numpy = ">=1.26.4,<2.0.0" pandas = ">=0.24.0" Pillow = ">=10.0.1" pydantic = ">=1.9.2" -pydantic-core = ">=2.18.2,<3.0.0" requests = ">=2.22.0" requests-mock = "1.12.1" typing_extensions = ">=4.0.0" @@ -2165,7 +2164,7 @@ xmljson = "0.2.1" [package.source] type = "url" -url = "https://github.com/HumanSignal/label-studio-sdk/archive/abf1ea4207e22d3d3cdfb8f4bb12ffb4d59384e4.zip" +url = "https://github.com/HumanSignal/label-studio-sdk/archive/025aaa8136465f97892adfee7aea498576e05f7a.zip" [[package]] name = "launchdarkly-server-sdk" @@ -3175,6 +3174,7 @@ files = [ {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"}, @@ -3791,6 +3791,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -5032,4 +5033,4 @@ uwsgi = ["pyuwsgi", "uwsgitop"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<4" -content-hash = "3eb25be02165cb9964ae5ec1f8c106ac849ec5ed77bf4d33b068b4c3e9bffcff" +content-hash = "63b670e8b1ccf8d94c34a707bdc934f79408823b6752fb3a0d6a0822e7e330f6" diff --git a/pyproject.toml b/pyproject.toml index 8f6d90b76ddb..34be602586d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -203,7 +203,7 @@ django-migration-linter = "^5.1.0" setuptools = ">=75.4.0" # Humansignal repo dependencies -label-studio-sdk = {url = "https://github.com/HumanSignal/label-studio-sdk/archive/abf1ea4207e22d3d3cdfb8f4bb12ffb4d59384e4.zip"} +label-studio-sdk = {url = "https://github.com/HumanSignal/label-studio-sdk/archive/025aaa8136465f97892adfee7aea498576e05f7a.zip"} [tool.poetry.group.test.dependencies] pytest = "7.2.2"