From 033872718e12ee29904160d6114b8dafda1ab6a1 Mon Sep 17 00:00:00 2001
From: Inga Kirschnick <inga.kirschnick@uni-bielefeld.de>
Date: Tue, 8 Nov 2022 14:11:57 +0100
Subject: [PATCH] Small changes in the contribution package

---
 app/SpaCyNLPPipelineModel.defaults.yml        | 191 ++++++++++++++----
 app/contributions/forms.py                    |  12 +-
 app/services/forms.py                         |  14 +-
 app/services/routes.py                        |   5 +-
 .../contributions/_breadcrumbs.html.j2        |  26 +--
 .../contribute_spacy_nlp_models.html.j2       |   2 +-
 .../contribute_tesseract_ocr_models.html.j2   |   2 +-
 .../spacy_nlp_pipeline_model.html.j2          |   2 +-
 .../services/spacy_nlp_pipeline.html.j2       |  43 +++-
 .../services/tesseract_ocr_pipeline.html.j2   |   3 +-
 10 files changed, 230 insertions(+), 70 deletions(-)

diff --git a/app/SpaCyNLPPipelineModel.defaults.yml b/app/SpaCyNLPPipelineModel.defaults.yml
index ed4ea3bd..00031ed0 100644
--- a/app/SpaCyNLPPipelineModel.defaults.yml
+++ b/app/SpaCyNLPPipelineModel.defaults.yml
@@ -1,66 +1,177 @@
-- title: 'de_core_news_md-3.4.0'
-  description: 'German pipeline optimized for CPU. Components: tok2vec, tagger, morphologizer, parser, lemmatizer (trainable_lemmatizer), senter, ner.'
-  url: 'https://github.com/explosion/spacy-models/releases/download/de_core_news_md-3.4.0/de_core_news_md-3.4.0.tar.gz'
+- title: 'Catalan'
+  description: 'Catalan pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
+  url: 'https://github.com/explosion/spacy-models/releases/download/ca_core_news_md-3.2.0/ca_core_news_md-3.2.0.tar.gz'
   publisher: 'Explosion'
   publisher_url: 'https://github.com/explosion'
-  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/de_core_news_md-3.4.0'
-  publishing_year: 2022
+  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/ca_core_news_md-3.2.0'
+  publishing_year: 2021
+  pipeline_name: 'ca_core_news_md'
+  version: '3.2.0'
+  compatible_service_versions:
+    - '0.1.0' 
+- title: 'German'
+  description: 'German pipeline optimized for CPU. Components: tok2vec, tagger, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
+  url: 'https://github.com/explosion/spacy-models/releases/download/de_core_news_md-3.2.0/de_core_news_md-3.2.0.tar.gz'
+  publisher: 'Explosion'
+  publisher_url: 'https://github.com/explosion'
+  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/de_core_news_md-3.2.0'
+  publishing_year: 2021
   pipeline_name: 'de_core_news_md'
-  version: '3.4.0'
+  version: '3.2.0'
   compatible_service_versions:
-    - '0.1.0'
-- title: 'en_core_web_md-3.4.1'
+    - '0.1.0' 
+- title: 'Greek'
+  description: 'Greek pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
+  url: 'https://github.com/explosion/spacy-models/releases/download/el_core_news_md-3.2.0/el_core_news_md-3.2.0.tar.gz'
+  publisher: 'Explosion'
+  publisher_url: 'https://github.com/explosion'
+  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/el_core_news_md-3.2.0'
+  publishing_year: 2021
+  pipeline_name: 'el_core_news_md'
+  version: '3.2.0'
+  compatible_service_versions:
+    - '0.1.0' 
+- title: 'English'
   description: 'English pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler, lemmatizer.'
-  url: 'https://github.com/explosion/spacy-models/releases/download/en_core_web_md-3.4.1/en_core_web_md-3.4.1.tar.gz'
+  url: 'https://github.com/explosion/spacy-models/releases/download/en_core_web_md-3.2.0/en_core_web_md-3.2.0.tar.gz'
   publisher: 'Explosion'
   publisher_url: 'https://github.com/explosion'
-  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/en_core_web_md-3.4.1'
-  publishing_year: 2022
+  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/en_core_web_md-3.2.0'
+  publishing_year: 2021
   pipeline_name: 'en_core_web_md'
-  version: '3.4.1'
+  version: '3.2.0'
   compatible_service_versions:
     - '0.1.0'
-- title: 'uk_core_news_md-3.4.0'
-  description: 'Ukrainian pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
-  url: 'https://github.com/explosion/spacy-models/releases/download/uk_core_news_md-3.4.0/uk_core_news_md-3.4.0.tar.gz'
+- title: 'Spanish'
+  description: 'Spanish pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
+  url: 'https://github.com/explosion/spacy-models/releases/download/es_core_news_md-3.2.0/es_core_news_md-3.2.0.tar.gz'
   publisher: 'Explosion'
   publisher_url: 'https://github.com/explosion'
-  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/uk_core_news_md-3.4.0'
-  publishing_year: 2022
-  pipeline_name: 'uk_core_news_md'  
-  version: '3.4.0'
+  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/es_core_news_md-3.2.0'
+  publishing_year: 2021
+  pipeline_name: 'es_core_news_md'
+  version: '3.2.0'
   compatible_service_versions:
     - '0.1.0'
-- title: 'zh_core_web_md-3.4.0'
-  description: 'Chinese pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler.'
-  url: 'https://github.com/explosion/spacy-models/releases/download/zh_core_web_md-3.4.0/zh_core_web_md-3.4.0.tar.gz'
+- title: 'French'
+  description: 'French pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
+  url: 'https://github.com/explosion/spacy-models/releases/download/fr_core_news_md-3.2.0/fr_core_news_md-3.2.0.tar.gz'
   publisher: 'Explosion'
   publisher_url: 'https://github.com/explosion'
-  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/zh_core_web_md-3.4.0'
-  publishing_year: 2022
-  pipeline_name: 'zh_core_web_md'
-  version: '3.4.0'
+  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/fr_core_news_md-3.2.0'
+  publishing_year: 2021
+  pipeline_name: 'fr_core_news_md'
+  version: '3.2.0'
   compatible_service_versions:
     - '0.1.0'
-- title: 'ru_core_news_md-3.4.0'
+- title: 'Italian'
+  description: 'Italian pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
+  url: 'https://github.com/explosion/spacy-models/releases/download/it_core_news_md-3.2.0/it_core_news_md-3.2.0.tar.gz'
+  publisher: 'Explosion'
+  publisher_url: 'https://github.com/explosion'
+  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/it_core_news_md-3.2.0'
+  publishing_year: 2021
+  pipeline_name: 'it_core_news_md'
+  version: '3.2.0'
+  compatible_service_versions:
+    - '0.1.0'
+- title: 'Polish'
+  description: 'Polish pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
+  url: 'https://github.com/explosion/spacy-models/releases/download/pl_core_news_md-3.2.0/pl_core_news_md-3.2.0.tar.gz'
+  publisher: 'Explosion'
+  publisher_url: 'https://github.com/explosion'
+  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/pl_core_news_md-3.2.0'
+  publishing_year: 2021
+  pipeline_name: 'pl_core_news_md'
+  version: '3.2.0'
+  compatible_service_versions:
+    - '0.1.0'
+- title: 'Russian'
   description: 'Russian pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
-  url: 'https://github.com/explosion/spacy-models/releases/download/ru_core_news_md-3.4.0/ru_core_news_md-3.4.0.tar.gz'
+  url: 'https://github.com/explosion/spacy-models/releases/download/ru_core_news_md-3.2.0/ru_core_news_md-3.2.0.tar.gz'
   publisher: 'Explosion'
   publisher_url: 'https://github.com/explosion'
-  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/ru_core_news_md-3.4.0'
-  publishing_year: 2022
+  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/ru_core_news_md-3.2.0'
+  publishing_year: 2021
   pipeline_name: 'ru_core_news_md'
-  version: '3.4.0'
+  version: '3.2.0'
   compatible_service_versions:
     - '0.1.0'
-- title: 'la_core_cltk_sm-0.1.0'
-  description: 'Latin pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
-  url: 'https://github.com/diyclassics/latin-spacy-models/raw/main/la_core_cltk_sm/la_core_cltk_sm-0.1.0.tar.gz'
-  publisher: 'DIY Classics'
-  publisher_url: 'https://github.com/diyclassics/'
-  publishing_url: 'https://github.com/diyclassics/latin-spacy-models/tree/main/la_core_cltk_sm'
-  publishing_year: 2022
-  pipeline_name: 'la_core_cltk_sm'
-  version: '0.1.0'
+- title: 'Chinese'
+  description: 'Chinese pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler.'
+  url: 'https://github.com/explosion/spacy-models/releases/download/zh_core_web_md-3.2.0/zh_core_web_md-3.2.0.tar.gz'
+  publisher: 'Explosion'
+  publisher_url: 'https://github.com/explosion'
+  publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/zh_core_web_md-3.2.0'
+  publishing_year: 2021
+  pipeline_name: 'zh_core_web_md'
+  version: '3.2.0'
   compatible_service_versions:
     - '0.1.0'
+
+# - title: 'de_core_news_md-3.4.0'
+#   description: 'German pipeline optimized for CPU. Components: tok2vec, tagger, morphologizer, parser, lemmatizer (trainable_lemmatizer), senter, ner.'
+#   url: 'https://github.com/explosion/spacy-models/releases/download/de_core_news_md-3.4.0/de_core_news_md-3.4.0.tar.gz'
+#   publisher: 'Explosion'
+#   publisher_url: 'https://github.com/explosion'
+#   publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/de_core_news_md-3.4.0'
+#   publishing_year: 2022
+#   pipeline_name: 'de_core_news_md'
+#   version: '3.4.0'
+#   compatible_service_versions:
+#     - '0.1.0'
+# - title: 'en_core_web_md-3.4.1'
+#   description: 'English pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler, lemmatizer.'
+#   url: 'https://github.com/explosion/spacy-models/releases/download/en_core_web_md-3.4.1/en_core_web_md-3.4.1.tar.gz'
+#   publisher: 'Explosion'
+#   publisher_url: 'https://github.com/explosion'
+#   publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/en_core_web_md-3.4.1'
+#   publishing_year: 2022
+#   pipeline_name: 'en_core_web_md'
+#   version: '3.4.1'
+#   compatible_service_versions:
+#     - '0.1.0'
+# - title: 'uk_core_news_md-3.4.0'
+#   description: 'Ukrainian pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
+#   url: 'https://github.com/explosion/spacy-models/releases/download/uk_core_news_md-3.4.0/uk_core_news_md-3.4.0.tar.gz'
+#   publisher: 'Explosion'
+#   publisher_url: 'https://github.com/explosion'
+#   publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/uk_core_news_md-3.4.0'
+#   publishing_year: 2022
+#   pipeline_name: 'uk_core_news_md'  
+#   version: '3.4.0'
+#   compatible_service_versions:
+#     - '0.1.0'
+# - title: 'zh_core_web_md-3.4.0'
+#   description: 'Chinese pipeline optimized for CPU. Components: tok2vec, tagger, parser, senter, ner, attribute_ruler.'
+#   url: 'https://github.com/explosion/spacy-models/releases/download/zh_core_web_md-3.4.0/zh_core_web_md-3.4.0.tar.gz'
+#   publisher: 'Explosion'
+#   publisher_url: 'https://github.com/explosion'
+#   publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/zh_core_web_md-3.4.0'
+#   publishing_year: 2022
+#   pipeline_name: 'zh_core_web_md'
+#   version: '3.4.0'
+#   compatible_service_versions:
+#     - '0.1.0'
+# - title: 'ru_core_news_md-3.4.0'
+#   description: 'Russian pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
+#   url: 'https://github.com/explosion/spacy-models/releases/download/ru_core_news_md-3.4.0/ru_core_news_md-3.4.0.tar.gz'
+#   publisher: 'Explosion'
+#   publisher_url: 'https://github.com/explosion'
+#   publishing_url: 'https://github.com/explosion/spacy-models/releases/tag/ru_core_news_md-3.4.0'
+#   publishing_year: 2022
+#   pipeline_name: 'ru_core_news_md'
+#   version: '3.4.0'
+#   compatible_service_versions:
+#     - '0.1.0'
+# - title: 'la_core_cltk_sm-0.1.0'
+#   description: 'Latin pipeline optimized for CPU. Components: tok2vec, morphologizer, parser, senter, ner, attribute_ruler, lemmatizer.'
+#   url: 'https://github.com/diyclassics/latin-spacy-models/raw/main/la_core_cltk_sm/la_core_cltk_sm-0.1.0.tar.gz'
+#   publisher: 'DIY Classics'
+#   publisher_url: 'https://github.com/diyclassics/'
+#   publishing_url: 'https://github.com/diyclassics/latin-spacy-models/tree/main/la_core_cltk_sm'
+#   publishing_year: 2022
+#   pipeline_name: 'la_core_cltk_sm'
+#   version: '0.1.0'
+#   compatible_service_versions:
+#     - '0.1.0'
diff --git a/app/contributions/forms.py b/app/contributions/forms.py
index dcdfaea8..c0611e17 100644
--- a/app/contributions/forms.py
+++ b/app/contributions/forms.py
@@ -1,4 +1,4 @@
-from xml.dom import ValidationErr
+from flask import current_app
 from flask_wtf import FlaskForm
 from flask_wtf.file import FileField, FileRequired
 from wtforms import (
@@ -66,8 +66,9 @@ class TesseractOCRModelContributionForm(CreateContributionBaseForm):
     compatible_service_versions = SelectMultipleField(
         'Compatible service versions'
     )
-    def validate_traineddata(self, field):
-        if field.data.mimetype != '.traineddata':
+    def validate_tesseract_model_file(self, field):
+        current_app.logger.warning(field.data.filename)
+        if not field.data.filename.lower().endswith('.traineddata'):
             raise ValidationError('traineddata files only!')
 
     def __init__(self, *args, **kwargs):
@@ -87,8 +88,9 @@ class SpacyNLPModelContributionForm(CreateContributionBaseForm):
     compatible_service_versions = SelectMultipleField(
         'Compatible service versions'
     )
-    def validate_spacy(self, field):
-        if field.data.mimetype != '.tar.gz':
+    def validate_spacy_model_file(self, field):
+        current_app.logger.warning(field.data.filename)
+        if not field.data.filename.lower().endswith('.tar.gz'):
             raise ValidationError('.tar.gz files only!')
 
     def __init__(self, *args, **kwargs):
diff --git a/app/services/forms.py b/app/services/forms.py
index 5c0af906..134e9456 100644
--- a/app/services/forms.py
+++ b/app/services/forms.py
@@ -10,7 +10,7 @@ from wtforms import (
     ValidationError
 )
 from wtforms.validators import InputRequired, Length
-from app.models import TesseractOCRPipelineModel
+from app.models import TesseractOCRPipelineModel, SpaCyNLPPipelineModel
 from . import SERVICES
 
 
@@ -73,11 +73,11 @@ class CreateTesseractOCRPipelineJobForm(CreateJobBaseForm):
                 if 'disabled' in self.binarization.render_kw:
                     del self.binarization.render_kw['disabled']
         models = [
-            x for x in TesseractOCRPipelineModel.query.filter().all()
+            x for x in TesseractOCRPipelineModel.query.order_by(TesseractOCRPipelineModel.title).all()
             if version in x.compatible_service_versions and (x.shared == True or x.user == current_user)
         ]
         self.model.choices = [('', 'Choose your option')]
-        self.model.choices += [(x.hashid, x.title) for x in models]
+        self.model.choices += [(x.hashid, f'{x.title} [{x.version}]') for x in models]
         self.model.default = ''
         self.version.choices = [(x, x) for x in service_manifest['versions']]
         self.version.data = version
@@ -127,7 +127,7 @@ class CreateSpacyNLPPipelineJobForm(CreateJobBaseForm):
     encoding_detection = BooleanField('Encoding detection', render_kw={'disabled': True})
     txt = FileField('File', validators=[FileRequired()])
     model = SelectField('Model', validators=[InputRequired()])
-
+    
     def validate_encoding_detection(self, field):
         service_info = SERVICES['spacy-nlp-pipeline']['versions'][self.version.data]
         if field.data:
@@ -153,8 +153,12 @@ class CreateSpacyNLPPipelineJobForm(CreateJobBaseForm):
             if 'encoding_detection' in service_info['methods']:
                 if 'disabled' in self.encoding_detection.render_kw:
                     del self.encoding_detection.render_kw['disabled']
+        models = [
+            x for x in SpaCyNLPPipelineModel.query.order_by(SpaCyNLPPipelineModel.title).all()
+            if version in x.compatible_service_versions and (x.shared == True or x.user == current_user)
+        ]
         self.model.choices = [('', 'Choose your option')]
-        self.model.choices += [(x, y) for x, y in service_info['models'].items()]  # noqa
+        self.model.choices += [(x.hashid, f'{x.title} [{x.version}]') for x in models]
         self.model.default = ''
         self.version.choices = [(x, x) for x in service_manifest['versions']]
         self.version.data = version
diff --git a/app/services/routes.py b/app/services/routes.py
index b34d0619..4bfca9bb 100644
--- a/app/services/routes.py
+++ b/app/services/routes.py
@@ -6,7 +6,8 @@ from app.models import (
     Job,
     JobInput,
     JobStatus,
-    TesseractOCRPipelineModel
+    TesseractOCRPipelineModel,
+    SpaCyNLPPipelineModel
 )
 from . import bp, SERVICES
 from .forms import (
@@ -172,6 +173,7 @@ def spacy_nlp_pipeline():
     if version not in service_manifest['versions']:
         abort(404)
     form = CreateSpacyNLPPipelineJobForm(prefix='create-job-form', version=version)
+    spacy_nlp_pipeline_models = SpaCyNLPPipelineModel.query.all()
     if form.is_submitted():
         if not form.validate():
             response = {'errors': form.errors}
@@ -202,6 +204,7 @@ def spacy_nlp_pipeline():
     return render_template(
         'services/spacy_nlp_pipeline.html.j2',
         form=form,
+        spacy_nlp_pipeline_models=spacy_nlp_pipeline_models,
         title=service_manifest['name']
     )
 
diff --git a/app/templates/contributions/_breadcrumbs.html.j2 b/app/templates/contributions/_breadcrumbs.html.j2
index 4ccfad3b..327d0578 100644
--- a/app/templates/contributions/_breadcrumbs.html.j2
+++ b/app/templates/contributions/_breadcrumbs.html.j2
@@ -2,30 +2,30 @@
 <li class="tab disabled"><i class="material-icons">navigate_next</i></li>
 {% if request.path == url_for('.contributions') %}
 <li class="tab"><a class="active" href="{{ url_for('.contributions') }}" target="_self">Contributions Overview</a></li>
-{% elif request.path == url_for('.tesseract_ocr_pipeline_model', tesseract_ocr_pipeline_model_id=tesseract_ocr_pipeline_model.id) %}
+
+{% elif request.path == url_for('.add_tesseract_ocr_pipeline_model') %}
+<li class="tab"><a href="{{ url_for('.contributions') }}" target="_self">Contributions Overview</a></li>
+<li class="tab disabled"><i class="material-icons">navigate_next</i></li>
+<li class="tab"><a class="active" href="{{ url_for('.add_tesseract_ocr_pipeline_model') }}" target="_self">{{ title }}</a></li>
+{% elif request.path == url_for('.add_spacy_nlp_pipeline_model') %}
+<li class="tab"><a href="{{ url_for('.contributions') }}" target="_self">Contributions Overview</a></li>
+<li class="tab disabled"><i class="material-icons">navigate_next</i></li>
+<li class="tab"><a class="active" href="{{ url_for('.add_spacy_nlp_pipeline_model') }}" target="_self">{{ title }}</a></li>
+{% elif tesseract_ocr_pipeline_model and request.path == url_for('.tesseract_ocr_pipeline_model', tesseract_ocr_pipeline_model_id=tesseract_ocr_pipeline_model.id) %}
 <li class="tab"><a href="{{ url_for('.contributions') }}" target="_self">Contributions Overview</a></li>
 <li class="tab disabled"><i class="material-icons">navigate_next</i></li>
 <li class="tab">
-  <a class="active" href="{{ url_for('.tesseract_ocr_pipeline_model', tesseract_ocr_pipeline_model_id=tesseract_ocr_pipeline_model.hashid) }}" target="_self">
+  <a class="active" href="{{ url_for('.tesseract_ocr_pipeline_model', tesseract_ocr_pipeline_model_id=tesseract_ocr_pipeline_model.id) }}" target="_self">
     Edit {{ tesseract_ocr_pipeline_model.title }}
   </a>
 </li>
-{% elif request.path == url_for('.add_tesseract_ocr_pipeline_model, tesseract_ocr_pipeline_model=nn') %}
-<li class="tab"><a href="{{ url_for('.contributions', tesseract_ocr_pipeline_model_id=nn) }}" target="_self">Contributions Overview</a></li>
-<li class="tab disabled"><i class="material-icons">navigate_next</i></li>
-<li class="tab"><a class="active" href="{{ url_for('.add_tesseract_ocr_pipeline_model') }}" target="_self">{{ title }}</a></li>
-
-{% elif request.path == url_for('.spacy_nlp_pipeline_model', spacy_nlp_pipeline_model_id=spacy_nlp_pipeline_model.id) %}
+{% elif spacy_nlp_pipeline_model and request.path == url_for('.spacy_nlp_pipeline_model', spacy_nlp_pipeline_model_id=spacy_nlp_pipeline_model.id) %}
 <li class="tab"><a href="{{ url_for('.contributions') }}" target="_self">Contributions Overview</a></li>
 <li class="tab disabled"><i class="material-icons">navigate_next</i></li>
 <li class="tab">
-  <a class="active" href="{{ url_for('.spacy_nlp_pipeline_model', spacy_nlp_pipeline_model_id=spacy_nlp_pipeline_model.hashid) }}" target="_self">
+  <a class="active" href="{{ url_for('.spacy_nlp_pipeline_model', spacy_nlp_pipeline_model_id=spacy_nlp_pipeline_model.id) }}" target="_self">
     Edit {{ spacy_nlp_pipeline_model.title }}
   </a>
 </li>
-{% elif request.path == url_for('.add_spacy_nlp_pipeline_model, spacy_nlp_pipeline_model=nn') %}
-<li class="tab"><a href="{{ url_for('.contributions', spacy_nlp_pipeline_model_id=nn) }}" target="_self">Contributions Overview</a></li>
-<li class="tab disabled"><i class="material-icons">navigate_next</i></li>
-<li class="tab"><a class="active" href="{{ url_for('.add_spacy_nlp_pipeline_model') }}" target="_self">{{ title }}</a></li>
 {% endif %}
 {% endset %}
diff --git a/app/templates/contributions/contribute_spacy_nlp_models.html.j2 b/app/templates/contributions/contribute_spacy_nlp_models.html.j2
index 97475c40..b5ab9b0d 100644
--- a/app/templates/contributions/contribute_spacy_nlp_models.html.j2
+++ b/app/templates/contributions/contribute_spacy_nlp_models.html.j2
@@ -1,6 +1,6 @@
 {% extends "base.html.j2" %}
 {% import "materialize/wtf.html.j2" as wtf %}
-{# {% from "contributions/_breadcrumbs.html.j2" import breadcrumbs with context %} #}
+{% from "contributions/_breadcrumbs.html.j2" import breadcrumbs with context %}
 
 {% block main_attribs %} class="service-scheme" data-service="tesseract-ocr-pipeline"{% endblock main_attribs %}
 
diff --git a/app/templates/contributions/contribute_tesseract_ocr_models.html.j2 b/app/templates/contributions/contribute_tesseract_ocr_models.html.j2
index d7c8bd41..1e50585a 100644
--- a/app/templates/contributions/contribute_tesseract_ocr_models.html.j2
+++ b/app/templates/contributions/contribute_tesseract_ocr_models.html.j2
@@ -1,6 +1,6 @@
 {% extends "base.html.j2" %}
 {% import "materialize/wtf.html.j2" as wtf %}
-{# {% from "contributions/_breadcrumbs.html.j2" import breadcrumbs with context %} #}
+{% from "contributions/_breadcrumbs.html.j2" import breadcrumbs with context %}
 
 {% block main_attribs %} class="service-scheme" data-service="tesseract-ocr-pipeline"{% endblock main_attribs %}
 
diff --git a/app/templates/contributions/spacy_nlp_pipeline_model.html.j2 b/app/templates/contributions/spacy_nlp_pipeline_model.html.j2
index 04d7506f..82fd6862 100644
--- a/app/templates/contributions/spacy_nlp_pipeline_model.html.j2
+++ b/app/templates/contributions/spacy_nlp_pipeline_model.html.j2
@@ -1,6 +1,6 @@
 {% extends "base.html.j2" %}
 {% import "materialize/wtf.html.j2" as wtf %}
-{# {% from "contributions/_breadcrumbs.html.j2" import breadcrumbs with context %} #}
+{% from "contributions/_breadcrumbs.html.j2" import breadcrumbs with context %}
 
 {% block main_attribs %} class="service-scheme" data-service="spacy-nlp-pipeline"{% endblock main_attribs %}
 
diff --git a/app/templates/services/spacy_nlp_pipeline.html.j2 b/app/templates/services/spacy_nlp_pipeline.html.j2
index 37f70210..5ad1e97a 100644
--- a/app/templates/services/spacy_nlp_pipeline.html.j2
+++ b/app/templates/services/spacy_nlp_pipeline.html.j2
@@ -70,8 +70,16 @@
               <div class="col s12 l5">
                 {{ wtf.render_field(form.txt, accept='text/plain', placeholder='Choose a plain text file') }}
               </div>
-              <div class="col s12 l4">
-                {{ wtf.render_field(form.model, material_icon='language') }}
+             <div class="col s12 l4">
+                <div class="input-field">
+                  <i class="material-icons prefix">language</i>
+                  {{ form.model() }}
+                  {{ form.model.label }}
+                  <span class="helper-text">
+                    <a class="modal-trigger tooltipped" href="#models-modal" data-position="bottom" data-tooltip="See more information about models"><i class="material-icons" style="color:#0064A3;">help_outline</i></a>
+                    <a class="tooltipped" href="{{ url_for('contributions.add_spacy_nlp_pipeline_model') }}" data-position="bottom" data-tooltip="Add your own spaCy NLP models"><i class="material-icons" style="color:#0064A3">new_label</i></a>
+                  </span>
+                </div>
               </div>
               <div class="col s12 l3">
                 {{ wtf.render_field(form.version, material_icon='apps') }}
@@ -122,4 +130,35 @@
     <a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a>
   </div>
 </div>
+
+<div id="models-modal" class="modal">
+  <div class="modal-content">
+    <h4>spaCy NLP Pipeline models</h4>
+    <table>
+      <thead>
+        <tr>
+          <th>Title</th>
+          <th>Description</th>
+          <th>Biblio</th>
+        </tr>
+      </thead>
+      <tbody>
+        {% for m in spacy_nlp_pipeline_models %}
+        <tr id="spacy-nlp-pipeline-model-{{ m.hashid }}">
+          <td>{{ m.title }}</td>
+          {% if m.description == '' %}
+          <td>Description is not available.</td>
+          {% else %}
+          <td>{{ m.description }}</td>
+          {% endif %}
+          <td><a href="{{ m.publisher_url }}">{{ m.publisher }}</a> ({{ m.publishing_year }}), {{ m.title }} {{ m.version}}, <a href="{{ m.publishing_url }}">{{ m.publishing_url }}</a></td>
+        </tr>
+        {% endfor %}
+      </tbody>
+    </table>
+  </div>
+  <div class="modal-footer">
+    <a href="#!" class="modal-close waves-effect waves-light btn">Close</a>
+  </div>
+</div>
 {% endblock modals %}
diff --git a/app/templates/services/tesseract_ocr_pipeline.html.j2 b/app/templates/services/tesseract_ocr_pipeline.html.j2
index 982265bc..b66e968b 100644
--- a/app/templates/services/tesseract_ocr_pipeline.html.j2
+++ b/app/templates/services/tesseract_ocr_pipeline.html.j2
@@ -58,7 +58,8 @@
                   {{ form.model() }}
                   {{ form.model.label }}
                   <span class="helper-text">
-                    <a class="modal-trigger" href="#models-modal">More details about models</a>
+                    <a class="modal-trigger tooltipped" href="#models-modal" data-position="bottom" data-tooltip="See more information about models"><i class="material-icons" style="color:#00A58B;">help_outline</i></a>
+                    <a class="tooltipped" href="{{ url_for('contributions.add_tesseract_ocr_pipeline_model') }}" data-position="bottom" data-tooltip="Add your own Tesseract OCR models"><i class="material-icons" style="color:#00A58B">new_label</i></a>
                   </span>
                   {% for error in form.model.errors %}
                   <span class="helper-text error-color-text">{{ error }}</span>
-- 
GitLab