diff --git a/app/apps/core/forms.py b/app/apps/core/forms.py index fe2297165a55961d4cd1425e5b6f17615e6037e5..4d9ea04b6f1802c7b0be09639897413746885057 100644 --- a/app/apps/core/forms.py +++ b/app/apps/core/forms.py @@ -5,6 +5,7 @@ from PIL import Image from django import forms from django.conf import settings from django.core.validators import FileExtensionValidator, MinValueValidator, MaxValueValidator +from django.core.files.uploadedfile import TemporaryUploadedFile from django.db.models import Q from django.forms.models import inlineformset_factory from django.utils import timezone @@ -17,6 +18,8 @@ from core.models import (Project, Document, Metadata, DocumentMetadata, BlockType, LineType, AlreadyProcessingException) from users.models import User +from kraken.lib import vgsl +from kraken.lib.exceptions import KrakenInvalidModelException logger = logging.getLogger(__name__) @@ -122,6 +125,42 @@ MetadataFormSet = inlineformset_factory(Document, DocumentMetadata, extra=1, can_delete=True) +class ModelUploadForm(BootstrapFormMixin, forms.ModelForm): + name = forms.CharField() + file = forms.FileField( + validators=[FileExtensionValidator( + allowed_extensions=['mlmodel'])] + ) + + def clean_file(self): + # Early validation of the model loading + file_field = self.cleaned_data['file'] + try: + model = vgsl.TorchVGSLModel.load_model(file_field.file.name) + except KrakenInvalidModelException: + raise forms.ValidationError(_("The provided model could not be loaded.")) + self._model_job = model.model_type + if self._model_job not in ('segmentation', 'recognition'): + raise forms.ValidationError(_("Invalid model (Couldn't determine whether it's a segmentation or recognition model).")) + elif self._model_job == 'recognition' and model.seg_type == "bbox": + raise forms.ValidationError(_("eScriptorium is not compatible with bounding box models.")) + return file_field + + def clean(self): + if not getattr(self, '_model_job', None): + return super().clean() + # Update the job field on the instantiated model from the cleaned model field + if self._model_job == 'segmentation': + self.instance.job = OcrModel.MODEL_JOB_SEGMENT + elif self._model_job == 'recognition': + self.instance.job = OcrModel.MODEL_JOB_RECOGNIZE + return super().clean() + + class Meta: + model = OcrModel + fields = ('name', 'file') + + class DocumentProcessForm1(BootstrapFormMixin, forms.Form): parts = forms.CharField() @@ -142,12 +181,14 @@ class DocumentProcessForm1(BootstrapFormMixin, forms.Form): if self.document.read_direction == self.document.READ_DIRECTION_RTL: self.initial['text_direction'] = 'horizontal-rl' self.fields['binarizer'].widget.attrs['disabled'] = True - self.fields['train_model'].queryset &= self.document.ocr_models.all() - self.fields['segtrain_model'].queryset &= self.document.ocr_models.all() - self.fields['seg_model'].queryset &= self.document.ocr_models.all() - self.fields['ocr_model'].queryset &= OcrModel.objects.filter( - Q(documents=None, script=self.document.main_script) - | Q(documents=self.document)) + + # Limit querysets to models owned by the user or already linked to this document + for field in ['train_model', 'segtrain_model', 'seg_model', 'ocr_model']: + self.fields[field].queryset = self.fields[field].queryset.filter( + Q(owner=self.user) + | Q(documents=self.document) + ) + self.fields['transcription'].queryset = Transcription.objects.filter(document=self.document) def process(self): @@ -176,29 +217,12 @@ class DocumentSegmentForm(DocumentProcessForm1): ('vertical-rl', _("Vertical r2l"))) text_direction = forms.ChoiceField(initial='horizontal-lr', required=False, choices=TEXT_DIRECTION_CHOICES) - upload_model = forms.FileField(required=False, - validators=[FileExtensionValidator( - allowed_extensions=['mlmodel', 'pronn', 'clstm'])]) def clean(self): data = super().clean() model_job = OcrModel.MODEL_JOB_SEGMENT - if data.get('upload_model'): - model = OcrModel.objects.create( - owner=self.user, - name=data['upload_model'].name.rsplit('.', 1)[0], - job=model_job) - OcrModelDocument.objects.create( - document=self.parts[0].document, - ocr_model=model, - executed_on=timezone.now(), - ) - # Note: needs to save the file in a second step because the path needs the db PK - model.file = data['upload_model'] - model.save() - - elif data.get('seg_model'): + if data.get('seg_model'): model = data.get('seg_model') ocr_model_document, created = OcrModelDocument.objects.get_or_create( ocr_model=model, @@ -231,9 +255,6 @@ class DocumentTrainForm(DocumentProcessForm1): train_model = forms.ModelChoiceField(queryset=OcrModel.objects .filter(job=OcrModel.MODEL_JOB_RECOGNIZE), label=_("Model"), required=False) - upload_model = forms.FileField(required=False, - validators=[FileExtensionValidator( - allowed_extensions=['mlmodel', 'pronn', 'clstm'])]) transcription = forms.ModelChoiceField(queryset=Transcription.objects.all(), required=False) @@ -259,20 +280,6 @@ class DocumentTrainForm(DocumentProcessForm1): ocr_model_document.trained_on = timezone.now() ocr_model_document.save() - elif data.get('upload_model'): - model = OcrModel.objects.create( - owner=self.user, - name=data['upload_model'].name.rsplit('.', 1)[0], - job=model_job) - OcrModelDocument.objects.create( - document=self.parts[0].document, - ocr_model=model, - trained_on=timezone.now(), - ) - # Note: needs to save the file in a second step because the path needs the db PK - model.file = data['upload_model'] - model.save() - elif data.get('new_model'): # file will be created by the training process model = OcrModel.objects.create( @@ -305,10 +312,6 @@ class DocumentSegtrainForm(DocumentProcessForm1): segtrain_model = forms.ModelChoiceField(queryset=OcrModel.objects .filter(job=OcrModel.MODEL_JOB_SEGMENT), label=_("Model"), required=False) - upload_model = forms.FileField(required=False, - validators=[FileExtensionValidator( - allowed_extensions=['mlmodel', 'pronn', 'clstm'])]) - new_model = forms.CharField(required=False, label=_('Model name')) def clean(self): @@ -329,19 +332,6 @@ class DocumentSegtrainForm(DocumentProcessForm1): if not created: ocr_model_document.trained_on = timezone.now() ocr_model_document.save() - elif data.get('upload_model'): - model = OcrModel.objects.create( - owner=self.user, - name=data['upload_model'].name.rsplit('.', 1)[0], - job=model_job) - OcrModelDocument.objects.create( - document=self.parts[0].document, - ocr_model=model, - trained_on=timezone.now(), - ) - # Note: needs to save the file in a second step because the path needs the db PK - model.file = data['upload_model'] - model.save() elif data.get('new_model'): # file will be created by the training process @@ -372,9 +362,6 @@ class DocumentSegtrainForm(DocumentProcessForm1): class DocumentTranscribeForm(DocumentProcessForm1): - upload_model = forms.FileField(required=False, - validators=[FileExtensionValidator( - allowed_extensions=['mlmodel', 'pronn', 'clstm'])]) ocr_model = forms.ModelChoiceField(queryset=OcrModel.objects .filter(job=OcrModel.MODEL_JOB_RECOGNIZE), label=_("Model"), required=False) @@ -384,33 +371,15 @@ class DocumentTranscribeForm(DocumentProcessForm1): model_job = OcrModel.MODEL_JOB_RECOGNIZE - if data.get('upload_model'): - model = OcrModel.objects.create( - owner=self.user, - name=data['upload_model'].name.rsplit('.', 1)[0], - job=model_job) - OcrModelDocument.objects.create( - document=self.parts[0].document, - ocr_model=model, - executed_on=timezone.now(), - ) - # Note: needs to save the file in a second step because the path needs the db PK - model.file = data['upload_model'] - model.save() - - elif data.get('ocr_model'): - model = data.get('ocr_model') - ocr_model_document, created = OcrModelDocument.objects.get_or_create( - ocr_model=model, - document=self.parts[0].document, - defaults={'executed_on': timezone.now()} - ) - if not created: - ocr_model_document.executed_on = timezone.now() - ocr_model_document.save() - else: - raise forms.ValidationError( - _("Either select a name for your new model or an existing one.")) + model = data['ocr_model'] + ocr_model_document, created = OcrModelDocument.objects.get_or_create( + ocr_model=model, + document=self.parts[0].document, + defaults={'executed_on': timezone.now()} + ) + if not created: + ocr_model_document.executed_on = timezone.now() + ocr_model_document.save() data['model'] = model return data @@ -474,9 +443,6 @@ class DocumentProcessForm(BootstrapFormMixin, forms.Form): text_direction = forms.ChoiceField(initial='horizontal-lr', required=False, choices=TEXT_DIRECTION_CHOICES) # transcribe - upload_model = forms.FileField(required=False, - validators=[FileExtensionValidator( - allowed_extensions=['mlmodel', 'pronn', 'clstm'])]) ocr_model = forms.ModelChoiceField(queryset=OcrModel.objects .filter(job=OcrModel.MODEL_JOB_RECOGNIZE), label=_("Model"), required=False) @@ -506,12 +472,14 @@ class DocumentProcessForm(BootstrapFormMixin, forms.Form): if self.document.read_direction == self.document.READ_DIRECTION_RTL: self.initial['text_direction'] = 'horizontal-rl' self.fields['binarizer'].widget.attrs['disabled'] = True - self.fields['train_model'].queryset &= self.document.ocr_models.all() - self.fields['segtrain_model'].queryset &= self.document.ocr_models.all() - self.fields['seg_model'].queryset &= self.document.ocr_models.all() - self.fields['ocr_model'].queryset &= OcrModel.objects.filter( - Q(documents=None, script=self.document.main_script) - | Q(documents=self.document)) + + # Limit querysets to models owned by the user or already linked to this document + for field in ['train_model', 'segtrain_model', 'seg_model', 'ocr_model']: + self.fields[field].queryset = self.fields[field].queryset.filter( + Q(owner=self.user) + | Q(documents=self.document) + ) + self.fields['transcription'].queryset = Transcription.objects.filter(document=self.document) @cached_property @@ -575,19 +543,6 @@ class DocumentProcessForm(BootstrapFormMixin, forms.Form): if not created: ocr_model_document.trained_on = timezone.now() ocr_model_document.save() - elif data.get('upload_model'): - model = OcrModel.objects.create( - owner=self.user, - name=data['upload_model'].name.rsplit('.', 1)[0], - job=model_job) - OcrModelDocument.objects.create( - document=self.parts[0].document, - ocr_model=model, - executed_on=timezone.now(), - ) - # Note: needs to save the file in a second step because the path needs the db PK - model.file = data['upload_model'] - model.save() elif data.get('new_model'): # file will be created by the training process diff --git a/app/apps/core/urls.py b/app/apps/core/urls.py index 2420d62545807b9cf2eef5a9efe52d053ed0a1eb..1480cc68ab1f4d02e398cf28e8f541cfcfbe80c5 100644 --- a/app/apps/core/urls.py +++ b/app/apps/core/urls.py @@ -10,12 +10,14 @@ from core.views import (Home, UpdateDocument, EditPart, DocumentImages, - ModelsList, + UserModels, + DocumentModels, ModelDelete, ModelCancelTraining, PublishDocument, ShareProject, - DocumentPartsProcessAjax) + DocumentPartsProcessAjax, + ModelUpload) urlpatterns = [ path('', Home.as_view(), name='home'), @@ -33,11 +35,12 @@ urlpatterns = [ path('document/<int:pk>/part/<int:part_pk>/edit/', EditPart.as_view(), name='document-part-edit'), path('document/<int:pk>/images/', DocumentImages.as_view(), name='document-images'), - path('models/', ModelsList.as_view(), name='user-models'), + path('models/', UserModels.as_view(), name='user-models'), + path('models/new/', ModelUpload.as_view(), name='model-upload'), path('model/<int:pk>/delete/', ModelDelete.as_view(), name='model-delete'), path('model/<int:pk>/cancel_training/', ModelCancelTraining.as_view(), name='model-cancel-training'), - path('document/<int:document_pk>/models/', ModelsList.as_view(), name='document-models'), + path('document/<int:document_pk>/models/', DocumentModels.as_view(), name='document-models'), path('document/<int:pk>/publish/', PublishDocument.as_view(), name='document-publish'), path('document/<int:pk>/process/', DocumentPartsProcessAjax.as_view(), name='document-parts-process'), diff --git a/app/apps/core/views.py b/app/apps/core/views.py index d8cfd458e7ce1edf8f7b27949464e1f0a9cf1fd6..efbb3fb35c8bac7564070c1bbc2d2e04238d6280 100644 --- a/app/apps/core/views.py +++ b/app/apps/core/views.py @@ -16,7 +16,7 @@ from django.views.generic import CreateView, UpdateView, DeleteView from core.models import (Project, Document, DocumentPart, Metadata, OcrModel, AlreadyProcessingException) from core.forms import (ProjectForm, DocumentForm, MetadataFormSet, ProjectShareForm, - UploadImageForm, DocumentProcessForm) + UploadImageForm, DocumentProcessForm, ModelUploadForm) from imports.forms import ImportForm, ExportForm @@ -296,30 +296,49 @@ class EditPart(LoginRequiredMixin, DetailView): return super().dispatch(*args, **kwargs) -class ModelsList(LoginRequiredMixin, ListView): +class DocumentModels(LoginRequiredMixin, ListView): model = OcrModel - template_name = "core/models_list.html" + template_name = "core/models_list/document_models.html" http_method_names = ('get',) + paginate_by = 20 def get_queryset(self): - if 'document_pk' in self.kwargs: - try: - self.document = Document.objects.for_user(self.request.user).get(pk=self.kwargs.get('document_pk')) - except Document.DoesNotExist: - raise PermissionDenied - return self.document.ocr_models.all() - else: - self.document = None - return OcrModel.objects.filter(owner=self.request.user) + try: + self.document = Document.objects.for_user(self.request.user).get(pk=self.kwargs.get('document_pk')) + except Document.DoesNotExist: + raise PermissionDenied + return self.document.ocr_models.all() def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - if self.document: - context['document'] = self.document - context['object'] = self.document # legacy + context['document'] = self.document + context['object'] = self.document # legacy return context +class UserModels(LoginRequiredMixin, ListView): + model = OcrModel + template_name = "core/models_list/main.html" + http_method_names = ('get',) + paginate_by = 20 + + def get_queryset(self): + return OcrModel.objects.filter(owner=self.request.user) + + +class ModelUpload(LoginRequiredMixin, SuccessMessageMixin, CreateView): + model = OcrModel + form_class = ModelUploadForm + success_message = _("Model uploaded successfully!") + + def get_success_url(self): + return reverse('user-models') + + def form_valid(self, form): + form.instance.owner = self.request.user + return super().form_valid(form) + + class ModelDelete(LoginRequiredMixin, SuccessMessageMixin, DeleteView): model = OcrModel success_message = _("Model deleted successfully!") diff --git a/app/escriptorium/templates/base.html b/app/escriptorium/templates/base.html index e88a8886e2fab5c74e9993b6bf7732b6b9c89313..dbd1cd3816ff89cdff9da742500bb3e407fdc68f 100644 --- a/app/escriptorium/templates/base.html +++ b/app/escriptorium/templates/base.html @@ -65,6 +65,9 @@ <li class="nav-item"> <a class="nav-link {% block nav-proj-list-class %}{% endblock %}" href="{% url 'projects-list' %}">{% trans "My Projects" %}</a> </li> + <li class="nav-item"> + <a class="nav-link" href="{% url 'user-models' %}">{% trans "My models" %}</a> + </li> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> {% blocktrans with username=user.username %}Hello {{username}}{% endblocktrans %} diff --git a/app/escriptorium/templates/core/document_nav.html b/app/escriptorium/templates/core/document_nav.html index a0dea118aaca16d763f3d92ca547ad3d743206d3..5741aadc420cc9f5a94d754619bd8bb09d930641 100644 --- a/app/escriptorium/templates/core/document_nav.html +++ b/app/escriptorium/templates/core/document_nav.html @@ -9,11 +9,9 @@ <a href="{% if object %}{% url 'document-update' pk=document.pk %}{% endif %}" class="nav-item nav-link {% block nav-doc-active %}{% endblock %}" id="nav-doc-tab" role="tab" aria-controls="nav-doc" aria-selected="true">{% trans "Description" %}</a> <a href="{% if object %}{% url 'document-images' pk=document.pk %}{% else %}#{% endif %}" class="nav-item nav-link {% if not object %}disabled{% endif %} {% block nav-images-active %}{% endblock %}" id="nav-img-tab" role="tab" aria-controls="nav-img" aria-selected="true">{% trans "Images" %}</a> <a href="{% if document %}{% url 'document-part-edit' pk=document.pk %}{% else %}#{% endif %}" class="nav-item nav-link {% block nav-edit-active %}{% endblock %}{% if not object or not document.parts.count %}disabled{% endif %}" id="nav-edit-tab" role="tab" aria-controls="nav-doc" aria-selected="true">{% trans "Edit" %}</a> - {% if perms.core.can_train %} {% with models_count=document.ocr_models.count %} <a href="{% if document and models_count %}{% url 'document-models' document_pk=document.pk %}{% else %}#{% endif %}" class="nav-item nav-link {% if not document or not models_count %}disabled{% endif %}" id="nav-models-tab" role="tab" aria-controls="nav-doc" aria-selected="true">{% trans "Models" %}</a> {% endwith %} - {% endif %} {% block extra_nav %}<div class="nav-div nav-item ml-5 ">{{document.name}}</div>{% endblock %} </div> </nav> diff --git a/app/escriptorium/templates/core/document_part_edit.html b/app/escriptorium/templates/core/document_part_edit.html index 0cb1a7128de5f7ab355736a8fe435217f81bc1af..0c6d857774b86e3eb17907cb11366d9fe0261f87 100644 --- a/app/escriptorium/templates/core/document_part_edit.html +++ b/app/escriptorium/templates/core/document_part_edit.html @@ -13,11 +13,9 @@ <a href="{% if object %}{% url 'document-update' pk=document.pk %}{% endif %}" class="nav-item nav-link {% block nav-doc-active %}{% endblock %}" id="nav-doc-tab" role="tab" aria-controls="nav-doc" aria-selected="true">{% trans "Description" %}</a> <a href="{% if object %}{% url 'document-images' pk=document.pk %}{% else %}#{% endif %}" class="nav-item nav-link {% if not object %}disabled{% endif %} {% block nav-images-active %}{% endblock %}" id="nav-img-tab" role="tab" aria-controls="nav-img" aria-selected="true">{% trans "Images" %}</a> <a href="{% if document %}{% url 'document-part-edit' pk=document.pk %}{% else %}#{% endif %}" class="nav-item nav-link active {% if not object or not document.parts.count %}disabled{% endif %}" id="nav-edit-tab" role="tab" aria-controls="nav-doc" aria-selected="true">{% trans "Edit" %}</a> - {% if perms.core.can_train %} {% with models_count=document.ocr_models.count %} <a href="{% if document and models_count %}{% url 'document-models' document_pk=document.pk %}{% else %}#{% endif %}" class="nav-item nav-link {% if not document or not models_count %}disabled{% endif %}" id="nav-models-tab" role="tab" aria-controls="nav-doc" aria-selected="true">{% trans "Models" %}</a> {% endwith %} - {% endif %} </editor> </div> {% endblock %} diff --git a/app/escriptorium/templates/core/models_list/document_models.html b/app/escriptorium/templates/core/models_list/document_models.html new file mode 100644 index 0000000000000000000000000000000000000000..07adfa0f61443a12cad1b204b88b379faf6cd970 --- /dev/null +++ b/app/escriptorium/templates/core/models_list/document_models.html @@ -0,0 +1,9 @@ +{% extends 'core/document_nav.html' %} +{% load i18n staticfiles %} + +{% block tab_content %} + {% include 'core/models_list/table.html' %} +{% endblock %} +{% block scripts %} + {% include 'core/models_list/scripts.html' %} +{% endblock %} diff --git a/app/escriptorium/templates/core/models_list/main.html b/app/escriptorium/templates/core/models_list/main.html new file mode 100644 index 0000000000000000000000000000000000000000..674eba42ebc52579bd085bf15ee3044a4510a31b --- /dev/null +++ b/app/escriptorium/templates/core/models_list/main.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load i18n staticfiles %} + +{% block body %} +<a href="{% url 'model-upload' %}" class="btn btn-success float-sm-right">{% trans "Upload a model" %}</a> +<h2>{% trans "My Models" %}</h2> +{% include 'core/models_list/table.html' %} +{% endblock %} +{% block scripts %} + {% include 'core/models_list/scripts.html' %} +{% endblock %} diff --git a/app/escriptorium/templates/core/models_list/scripts.html b/app/escriptorium/templates/core/models_list/scripts.html new file mode 100644 index 0000000000000000000000000000000000000000..766e258e5a59601843633c29d245ba2cbce7779d --- /dev/null +++ b/app/escriptorium/templates/core/models_list/scripts.html @@ -0,0 +1,16 @@ +<script type="text/javascript"> + 'use strict'; + {% if user.onboarding %} + const ONBOARDING_PAGE = "onboarding_models"; + {% endif %} +</script> + +{{ block.super }} +<script type="text/javascript"> +'use strict'; +$(document).ready(function() { + // join the ws room + joinDocumentRoom('{{document.pk}}'); + bootModels(); +}); +</script> diff --git a/app/escriptorium/templates/core/models_list.html b/app/escriptorium/templates/core/models_list/table.html similarity index 86% rename from app/escriptorium/templates/core/models_list.html rename to app/escriptorium/templates/core/models_list/table.html index 809d1a300b64f04368efc7ed750f99286bfd5ebe..d5731aa0680ab9de6dec94af8440683d291e943e 100644 --- a/app/escriptorium/templates/core/models_list.html +++ b/app/escriptorium/templates/core/models_list/table.html @@ -1,7 +1,5 @@ -{% extends 'core/document_nav.html' %} {% load i18n staticfiles %} -{% block tab_content %} <table id="models-table" class="table table-hover"> <tr> <th class="w-50"></th> @@ -11,7 +9,7 @@ <th>{% trans "Errors" %}</th> <th>{# buttons #}</th> </tr> - {% for model in document.ocr_models.all %} + {% for model in page_obj %} <tr id="tr-{{model.pk}}" class="model-head" data-id="{{model.pk}}"> <td title="{% trans "Model name" %}">{{ model.name }}</td> <td title="{% trans "Model role" %}">{{ model.get_job_display }}</td> @@ -69,23 +67,4 @@ {% endfor %} {% endfor %} </table> -{% endblock %} - -{% block scripts %} -<script type="text/javascript"> - 'use strict'; - {% if user.onboarding %} - const ONBOARDING_PAGE = "onboarding_models"; - {% endif %} -</script> - -{{ block.super }} -<script type="text/javascript"> -'use strict'; -$(document).ready(function() { - // join the ws room - joinDocumentRoom('{{document.pk}}'); - bootModels(); -}); -</script> -{% endblock %} +{% include 'includes/pagination.html' %} diff --git a/app/escriptorium/templates/core/ocrmodel_form.html b/app/escriptorium/templates/core/ocrmodel_form.html new file mode 100644 index 0000000000000000000000000000000000000000..57efaad14500f190df13ac6f7672e80818026f88 --- /dev/null +++ b/app/escriptorium/templates/core/ocrmodel_form.html @@ -0,0 +1,26 @@ +{% extends 'base.html' %} +{% load i18n staticfiles bootstrap %} + +{% block body %} +<h2>{% trans "Upload a model" %}</h2> +<form method="post" class="inline-form" enctype="multipart/form-data" action="{% url 'model-upload' %}"> + {% csrf_token %} + {% render_field form.file %} + {% render_field form.name %} + <button type="submit" value="" class="nav-item btn btn-success">{% trans 'Upload' %}</button> +</form> +{% endblock %} +{% block scripts %} +<script type="text/javascript"> +/* Handle a basic name field auto filling */ +const fileInput = document.getElementById('id_file'); +const nameInput = document.getElementById('id_name'); +let currentFileName = ''; +fileInput.onchange = function() { + if (fileInput.files.length && (!nameInput.value || nameInput.value == currentFileName)) { + nameInput.value = fileInput.files[0].name; + currentFileName = nameInput.value; + } +}; +</script> +{% endblock %} diff --git a/app/escriptorium/templates/core/wizards/segment.html b/app/escriptorium/templates/core/wizards/segment.html index 52adbc7aab7799afea7ff328cb47290c1fc1a592..311094d11466d18a7ea14f862594c32ddb3b0924 100644 --- a/app/escriptorium/templates/core/wizards/segment.html +++ b/app/escriptorium/templates/core/wizards/segment.html @@ -8,12 +8,7 @@ {% block wizard_fields %} <div class="form-group"> - <h5>{% trans "Upload a model" %}</h5> - {% render_field process_form.upload_model class="js-proc-settings" accept=".mlmodel" %} -</div> - -<div class="form-group"> - <h5>{% trans "Or select an existing one" %}</h5> + <h5>{% trans "Select a model" %}</h5> {% render_field process_form.seg_model class="js-proc-settings" %} </div> diff --git a/app/escriptorium/templates/core/wizards/segtrain.html b/app/escriptorium/templates/core/wizards/segtrain.html index 6b279d1480b149a0567e1c868826e263e17ec8b5..40cb84a694298efd8743a8fdb1e257e31f9f5f39 100644 --- a/app/escriptorium/templates/core/wizards/segtrain.html +++ b/app/escriptorium/templates/core/wizards/segtrain.html @@ -10,10 +10,6 @@ <h5>{% trans "New model" %}</h5> {% render_field process_form.new_model class="js-proc-settings" %} </div> -<div class="form-group"> - <h5>{% trans "Or Upload a model" %}</h5> - {% render_field process_form.upload_model class="js-proc-settings" accept=".mlmodel,.clstm,.pronn" %} -</div> <div class="form-group"> <h5>{% trans "Or select an existing one" %}</h5> {% render_field process_form.segtrain_model class="js-proc-settings" %} diff --git a/app/escriptorium/templates/core/wizards/train.html b/app/escriptorium/templates/core/wizards/train.html index 458de59b479620fed26930257215e596f169c077..f96267bf4b2b5f354bfa576408dc626e616cb02c 100644 --- a/app/escriptorium/templates/core/wizards/train.html +++ b/app/escriptorium/templates/core/wizards/train.html @@ -14,12 +14,6 @@ {% render_field process_form.new_model class="js-proc-settings" %} </div> -<div class="form-group"> - <h5>{% trans "Or upload a model" %}</h5> - {% render_field process_form.upload_model class="js-proc-settings" accept=".mlmodel,.clstm,.pronn" %} - -</div> - <div class="form-group"> <h5>{% trans "Or select an existing one" %}</h5> {% render_field process_form.train_model class="js-proc-settings" %} diff --git a/app/escriptorium/templates/core/wizards/transcribe.html b/app/escriptorium/templates/core/wizards/transcribe.html index 8226fd839cf7700df62bea7b640774b1b577e820..901b318639694e985e3576a3c250e50268513ddd 100644 --- a/app/escriptorium/templates/core/wizards/transcribe.html +++ b/app/escriptorium/templates/core/wizards/transcribe.html @@ -7,12 +7,7 @@ {% block wizard_fields %} <div class="form-group"> - <h5>{% trans "Upload model" %}</h5> - {% render_field process_form.upload_model class="js-proc-settings" data_document=document.pk accept=".mlmodel,.clstm,.pronn" %} -</div> - -<div class="form-group"> - <h5>{% trans "Or use existing model" %}</h5> + <h5>{% trans "Select a model" %}</h5> {% render_field process_form.ocr_model class="js-proc-settings" data_document=document.pk %} </div> {% endblock %}