diff --git a/bothub/api/v2/repository/views.py b/bothub/api/v2/repository/views.py index ded085b5..47809c33 100644 --- a/bothub/api/v2/repository/views.py +++ b/bothub/api/v2/repository/views.py @@ -64,6 +64,7 @@ RepositoryVersionLanguage, Organization, ) +from bothub.common.usecase.repositorylog.export import ExportRepositoryLogUseCase from ..metadata import Metadata from .filters import ( @@ -1359,6 +1360,65 @@ def get_queryset(self): return super().get_queryset().sort("-created_at") +class RepositoryNLPLogExportViewSet(DocumentViewSet): + document = RepositoryNLPLogDocument + serializer_class = RepositoryNLPLogSerializer + permission_classes = [permissions.IsAuthenticated, RepositoryLogPermission] + filter_backends = [ + CompoundSearchFilterBackend, + FilteringFilterBackend, + NestedFilteringFilterBackend, + ] + pagination_class = LimitOffsetPagination + limit = settings.REPOSITORY_NLP_LOG_LIMIT + search_fields = ["text"] + filter_fields = { + "repository_uuid": "repository_uuid", + "language": "language", + "repository_version": "repository_version", + "repository_version_language": "repository_version_language", + "created_at": { + "field": "created_at", + "lookups": [LOOKUP_FILTER_RANGE, LOOKUP_QUERY_LTE, LOOKUP_QUERY_GTE], + }, + } + nested_filter_fields = { + "intent": {"field": "nlp_log.intent.name.raw", "path": "nlp_log"}, + "confidence": { + "field": "nlp_log.intent.confidence", + "path": "nlp_log", + "lookups": [LOOKUP_FILTER_RANGE, LOOKUP_QUERY_LTE, LOOKUP_QUERY_GTE], + }, + } + + def filter_queryset(self, queryset): + queryset = super().filter_queryset(queryset) + return queryset[: self.limit] + + def get_queryset(self): + params = { + "repository_uuid": self.request.query_params.get("repository_uuid", None), + "repository_version": self.request.query_params.get( + "repository_version", None + ), + "repository_version_language": self.request.query_params.get( + "repository_version_language", None + ), + } + RepositoryNLPLogFilter(params=params, user=self.request.user) + return super().get_queryset() + + def get_xlsx(self, queryset): + usecase = ExportRepositoryLogUseCase() + xlsx_response = usecase.create_xlsx_response(queryset) + return xlsx_response + + def get(self, request, *args, **kwargs): + queryset = self.filter_queryset(self.get_queryset()) + xlsx_response = self.get_xlsx(queryset) + return xlsx_response + + class RepositoryQANLPLogViewSet(DocumentViewSet): document = RepositoryQANLPLogDocument serializer_class = RepositoryQANLPLogSerializer diff --git a/bothub/api/v2/routers.py b/bothub/api/v2/routers.py index 04731378..ee2fbc04 100644 --- a/bothub/api/v2/routers.py +++ b/bothub/api/v2/routers.py @@ -59,6 +59,7 @@ RepositoryMigrateViewSet, RepositoryNLPLogReportsViewSet, RepositoryNLPLogViewSet, + RepositoryNLPLogExportViewSet, RepositoryQANLPLogViewSet, RepositoryTaskQueueViewSet, RepositoryTokenByUserViewSet, @@ -198,6 +199,7 @@ def get_lookup_regex(self, viewset, lookup_prefix=""): router.register("repository/translation-export", RepositoryTranslatedExporterViewSet) router.register("repository/version", RepositoryVersionViewSet) router.register("repository/log", RepositoryNLPLogViewSet, basename="es-repository-log") +router.register("repository/export-log", RepositoryNLPLogExportViewSet, basename="es-repository-log-export") router.register( "repository/qalog", RepositoryQANLPLogViewSet, basename="es-repository-qa-log" ) diff --git a/bothub/api/v2/translation/views.py b/bothub/api/v2/translation/views.py index d51f38bd..8dd15f06 100644 --- a/bothub/api/v2/translation/views.py +++ b/bothub/api/v2/translation/views.py @@ -181,7 +181,7 @@ def retrieve(self, request, *args, **kwargs): # pragma: no cover end=entity.end + count_entity, ) count_entity += len(entity.entity.value) + 4 - + translated = RepositoryTranslatedExample.objects.filter( original_example=example.pk, language=for_the_language ) diff --git a/bothub/common/usecase/__init__.py b/bothub/common/usecase/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bothub/common/usecase/repositorylog/__init__.py b/bothub/common/usecase/repositorylog/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bothub/common/usecase/repositorylog/export.py b/bothub/common/usecase/repositorylog/export.py new file mode 100644 index 00000000..f778fdb6 --- /dev/null +++ b/bothub/common/usecase/repositorylog/export.py @@ -0,0 +1,50 @@ +from django.http import HttpResponse + +from openpyxl import Workbook +from openpyxl.writer.excel import save_virtual_workbook + + +class ExportRepositoryLogUseCase: + + def _create_xlsx_workbook( + self, + repository_logs + ) -> Workbook: + + wb = Workbook() + ws = wb.active + + ws['A1'] = 'Text' + ws['B1'] = 'Created At' + ws['C1'] = 'Intent' + ws['D1'] = 'Confidence' + ws['E1'] = 'Entities' + ws['F1'] = 'Entities List' + + if repository_logs is None: + return wb + + row = 2 + for repository_log in repository_logs: + ws['A{}'.format(row)] = repository_log.nlp_log.text + ws['B{}'.format(row)] = repository_log.created_at + ws['C{}'.format(row)] = repository_log.nlp_log.intent.name + ws['D{}'.format(row)] = repository_log.nlp_log.intent.confidence + ws['F{}'.format(row)] = repository_log.nlp_log.entities + row += 1 + + return wb + + def create_xlsx_response( + self, + repository_logs + ) -> HttpResponse: + + wb = self._create_xlsx_workbook(repository_logs) + response = HttpResponse( + content=save_virtual_workbook(wb), + content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + response['Content-Disposition'] = 'attachment; filename=repository_logs.xlsx' + + return response diff --git a/bothub/common/usecase/repositorylog/tests/__init__.py b/bothub/common/usecase/repositorylog/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bothub/common/usecase/repositorylog/tests/test_export.py b/bothub/common/usecase/repositorylog/tests/test_export.py new file mode 100644 index 00000000..ea6082fd --- /dev/null +++ b/bothub/common/usecase/repositorylog/tests/test_export.py @@ -0,0 +1,60 @@ +import unittest +from unittest.mock import Mock +from django.http import HttpResponse +from openpyxl import Workbook +from ..export import ExportRepositoryLogUseCase + + +class TestExportRepositoryLogUseCase(unittest.TestCase): + + def setUp(self): + self.use_case = ExportRepositoryLogUseCase() + self.mock_repository_logs = [ + Mock( + nlp_log=Mock( + text='text', + intent=Mock( + name='intent', + confidence='confidence' + ), + entities='entities' + ), created_at='created_at' + ) + ] + for log in self.mock_repository_logs: + log.nlp_log.intent.name = 'intent_name' + + def test_create_xlsx_workbook(self): + # Chama a função _create_xlsx_workbook + result = self.use_case._create_xlsx_workbook(self.mock_repository_logs) + self.assertIsInstance(result, Workbook) + + def test_create_xlsx_response(self): + result = self.use_case.create_xlsx_response(self.mock_repository_logs) + self.assertIsInstance(result, HttpResponse) + self.assertEqual( + result['Content-Type'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ) + self.assertEqual( + result['Content-Disposition'], + 'attachment; filename=repository_logs.xlsx' + ) + + def test_create_xlsx_workbook_with_none(self): + + result = self.use_case._create_xlsx_workbook(None) + self.assertIsInstance(result, Workbook) + + def test_create_xlsx_response_with_none(self): + + result = self.use_case.create_xlsx_response(None) + self.assertIsInstance(result, HttpResponse) + self.assertEqual( + result['Content-Type'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ) + self.assertEqual( + result['Content-Disposition'], + 'attachment; filename=repository_logs.xlsx' + )