Skip to content
Snippets Groups Projects
Commit 05340ea7 authored by Inga Kirschnick's avatar Inga Kirschnick
Browse files

Contribution Package Spacy NLP

parent 46ba14b9
No related branches found
No related tags found
No related merge requests found
Showing
with 564 additions and 57 deletions
...@@ -5,6 +5,62 @@ ...@@ -5,6 +5,62 @@
publisher_url: 'https://github.com/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_url: 'https://github.com/explosion/spacy-models/releases/tag/de_core_news_md-3.4.0'
publishing_year: 2022 publishing_year: 2022
pipeline_name: 'de_core_news_md'
version: '3.4.0' version: '3.4.0'
compatible_service_versions: compatible_service_versions:
- '0.1.0' - '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'
...@@ -46,6 +46,18 @@ class CreateContributionBaseForm(FlaskForm): ...@@ -46,6 +46,18 @@ class CreateContributionBaseForm(FlaskForm):
) )
submit = SubmitField() submit = SubmitField()
class EditForm(CreateContributionBaseForm):
def prefill(self, model_file):
''' Pre-fill the form with data of an exististing corpus file '''
self.title.data = model_file.title
self.description.data = model_file.description
self.publisher.data = model_file.publisher
self.publishing_year.data = model_file.publishing_year
self.publisher_url.data = model_file.publisher_url
self.publishing_url.data = model_file.publishing_url
self.version.data = model_file.version
self.shared.data = model_file.shared
class TesseractOCRModelContributionForm(CreateContributionBaseForm): class TesseractOCRModelContributionForm(CreateContributionBaseForm):
tesseract_model_file = FileField( tesseract_model_file = FileField(
'File', 'File',
...@@ -67,16 +79,23 @@ class TesseractOCRModelContributionForm(CreateContributionBaseForm): ...@@ -67,16 +79,23 @@ class TesseractOCRModelContributionForm(CreateContributionBaseForm):
] ]
self.compatible_service_versions.default = '' self.compatible_service_versions.default = ''
class TesseractOCRModelEditForm(CreateContributionBaseForm): class SpacyNLPModelContributionForm(CreateContributionBaseForm):
def prefill(self, model_file): spacy_model_file = FileField(
''' Pre-fill the form with data of an exististing corpus file ''' 'File',
self.title.data = model_file.title validators=[FileRequired()]
self.description.data = model_file.description )
self.publisher.data = model_file.publisher compatible_service_versions = SelectMultipleField(
self.publishing_year.data = model_file.publishing_year 'Compatible service versions'
self.publisher_url.data = model_file.publisher_url )
self.publishing_url.data = model_file.publishing_url def validate_spacy(self, field):
self.version.data = model_file.version if field.data.mimetype != '.tar.gz':
self.shared.data = model_file.shared raise ValidationError('.tar.gz files only!')
def __init__(self, *args, **kwargs):
service_manifest = SERVICES['spacy-nlp-pipeline']
super().__init__(*args, **kwargs)
self.compatible_service_versions.choices = [('', 'Choose your option')]
self.compatible_service_versions.choices += [
(x, x) for x in service_manifest['versions'].keys()
]
self.compatible_service_versions.default = ''
from flask import abort, current_app, flash, Markup, redirect, render_template, url_for from flask import abort, current_app, flash, Markup, render_template, url_for
from flask_login import login_required, current_user from flask_login import login_required, current_user
from threading import Thread from threading import Thread
from app import db from app import db
from app.decorators import admin_required, permission_required from app.decorators import admin_required, permission_required
from app.models import TesseractOCRPipelineModel, Permission from app.models import Permission, SpaCyNLPPipelineModel, TesseractOCRPipelineModel
from . import bp from . import bp
from .forms import TesseractOCRModelContributionForm, TesseractOCRModelEditForm from .forms import TesseractOCRModelContributionForm, EditForm, SpacyNLPModelContributionForm
@bp.before_request @bp.before_request
...@@ -22,20 +22,26 @@ def contributions(): ...@@ -22,20 +22,26 @@ def contributions():
tesseract_ocr_user_models = [ tesseract_ocr_user_models = [
x for x in current_user.tesseract_ocr_pipeline_models x for x in current_user.tesseract_ocr_pipeline_models
] ]
spacy_nlp_user_models = [
x for x in current_user.spacy_nlp_pipeline_models
]
spacy_models = SpaCyNLPPipelineModel.query.all()
print(spacy_models)
return render_template( return render_template(
'contributions/contribution_overview.html.j2', 'contributions/contribution_overview.html.j2',
tesseractOCRUserModels=tesseract_ocr_user_models, tesseract_ocr_user_models=tesseract_ocr_user_models,
spacy_nlp_user_models=spacy_nlp_user_models,
userId = current_user.hashid, userId = current_user.hashid,
title='Contribution Overview' title='Contribution Overview'
) )
@bp.route('/<hashid:tesseract_ocr_pipeline_model_id>', methods=['GET', 'POST']) @bp.route('/edit-tesseract-model/<hashid:tesseract_ocr_pipeline_model_id>', methods=['GET', 'POST'])
@login_required @login_required
def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id): def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id):
tesseract_ocr_pipeline_model = TesseractOCRPipelineModel.query.get_or_404( tesseract_ocr_pipeline_model = TesseractOCRPipelineModel.query.get_or_404(
tesseract_ocr_pipeline_model_id tesseract_ocr_pipeline_model_id
) )
form = TesseractOCRModelEditForm(prefix='tesseract-ocr-model-edit-form') form = EditForm(prefix='tesseract-ocr-model-edit-form')
if form.validate_on_submit(): if form.validate_on_submit():
if tesseract_ocr_pipeline_model.title != form.title.data: if tesseract_ocr_pipeline_model.title != form.title.data:
tesseract_ocr_pipeline_model.title = form.title.data tesseract_ocr_pipeline_model.title = form.title.data
...@@ -65,7 +71,7 @@ def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id): ...@@ -65,7 +71,7 @@ def tesseract_ocr_pipeline_model(tesseract_ocr_pipeline_model_id):
title='Edit your Tesseract OCR model' title='Edit your Tesseract OCR model'
) )
@bp.route('/<hashid:tesseract_ocr_pipeline_model_id>', methods=['DELETE']) @bp.route('/edit-tesseract-model/<hashid:tesseract_ocr_pipeline_model_id>', methods=['DELETE'])
@login_required @login_required
def delete_tesseract_model(tesseract_ocr_pipeline_model_id): def delete_tesseract_model(tesseract_ocr_pipeline_model_id):
def _delete_tesseract_model(app, tesseract_ocr_pipeline_model_id): def _delete_tesseract_model(app, tesseract_ocr_pipeline_model_id):
...@@ -123,3 +129,95 @@ def add_tesseract_ocr_pipeline_model(): ...@@ -123,3 +129,95 @@ def add_tesseract_ocr_pipeline_model():
tesseract_ocr_pipeline_models=tesseract_ocr_pipeline_models, tesseract_ocr_pipeline_models=tesseract_ocr_pipeline_models,
title='Tesseract OCR Model Contribution' title='Tesseract OCR Model Contribution'
) )
@bp.route('/edit-spacy-model//<hashid:spacy_nlp_pipeline_model_id>', methods=['GET', 'POST'])
@login_required
def spacy_nlp_pipeline_model(spacy_nlp_pipeline_model_id):
spacy_nlp_pipeline_model = SpaCyNLPPipelineModel.query.get_or_404(
spacy_nlp_pipeline_model_id
)
form = EditForm(prefix='spacy-nlp-model-edit-form')
if form.validate_on_submit():
if spacy_nlp_pipeline_model.title != form.title.data:
spacy_nlp_pipeline_model.title = form.title.data
if spacy_nlp_pipeline_model.description != form.description.data:
spacy_nlp_pipeline_model.description = form.description.data
if spacy_nlp_pipeline_model.publisher != form.publisher.data:
spacy_nlp_pipeline_model.publisher = form.publisher.data
if spacy_nlp_pipeline_model.publishing_year != form.publishing_year.data:
spacy_nlp_pipeline_model.publishing_year = form.publishing_year.data
if spacy_nlp_pipeline_model.publisher_url != form.publisher_url.data:
spacy_nlp_pipeline_model.publisher_url = form.publisher_url.data
if spacy_nlp_pipeline_model.publishing_url != form.publishing_url.data:
spacy_nlp_pipeline_model.publishing_url = form.publishing_url.data
if spacy_nlp_pipeline_model.version != form.version.data:
spacy_nlp_pipeline_model.version = form.version.data
if spacy_nlp_pipeline_model.shared != form.shared.data:
spacy_nlp_pipeline_model.shared = form.shared.data
db.session.commit()
message = Markup(f'Model "<a href="contribute/{spacy_nlp_pipeline_model.hashid}">{spacy_nlp_pipeline_model.title}</a>" updated')
flash(message, category='corpus')
return {}, 201, {'Location': url_for('contributions.contributions')}
form.prefill(spacy_nlp_pipeline_model)
return render_template(
'contributions/spacy_nlp_pipeline_model.html.j2',
spacy_nlp_pipeline_model=spacy_nlp_pipeline_model,
form=form,
title='Edit your spaCy NLP model'
)
@bp.route('/edit-spacy-model/<hashid:spacy_nlp_pipeline_model_id>', methods=['DELETE'])
@login_required
def delete_spacy_model(spacy_nlp_pipeline_model_id):
def _delete_spacy_model(app, spacy_nlp_pipeline_model_id):
with app.app_context():
model = SpaCyNLPPipelineModel.query.get(spacy_nlp_pipeline_model_id)
model.delete()
db.session.commit()
model = SpaCyNLPPipelineModel.query.get_or_404(spacy_nlp_pipeline_model_id)
if not (model.user == current_user or current_user.is_administrator()):
abort(403)
thread = Thread(
target=_delete_spacy_model,
args=(current_app._get_current_object(), spacy_nlp_pipeline_model_id)
)
thread.start()
return {}, 202
@bp.route('/add-spacy-nlp-pipeline-model', methods=['GET', 'POST'])
def add_spacy_nlp_pipeline_model():
form = SpacyNLPModelContributionForm(prefix='contribute-spacy-nlp-pipeline-model-form')
if form.is_submitted():
if not form.validate():
response = {'errors': form.errors}
return response, 400
try:
spacy_nlp_model = SpaCyNLPPipelineModel.create(
form.spacy_model_file.data,
compatible_service_versions=form.compatible_service_versions.data,
description=form.description.data,
publisher=form.publisher.data,
publisher_url=form.publisher_url.data,
publishing_url=form.publishing_url.data,
publishing_year=form.publishing_year.data,
shared=form.shared.data,
title=form.title.data,
version=form.version.data,
user=current_user
)
except OSError:
abort(500)
db.session.commit()
message = Markup(f'Model "{spacy_nlp_model.title}" created')
flash(message)
return {}, 201, {'Location': url_for('contributions.contributions')}
spacy_nlp_pipeline_models = [
x for x in SpaCyNLPPipelineModel.query.all()
]
return render_template(
'contributions/contribute_spacy_nlp_models.html.j2',
form=form,
spacy_nlp_pipeline_models=spacy_nlp_pipeline_models,
title='spaCy NLP Model Contribution'
)
...@@ -520,6 +520,10 @@ class User(HashidMixin, UserMixin, db.Model): ...@@ -520,6 +520,10 @@ class User(HashidMixin, UserMixin, db.Model):
x.hashid: x.to_json(relationships=True) x.hashid: x.to_json(relationships=True)
for x in self.tesseract_ocr_pipeline_models for x in self.tesseract_ocr_pipeline_models
} }
_json['spacy_nlp_pipeline_models'] = {
x.hashid: x.to_json(relationships=True)
for x in self.spacy_nlp_pipeline_models
}
return _json return _json
class TesseractOCRPipelineModel(FileMixin, HashidMixin, db.Model): class TesseractOCRPipelineModel(FileMixin, HashidMixin, db.Model):
...@@ -643,6 +647,7 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model): ...@@ -643,6 +647,7 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model):
publisher_url = db.Column(db.String(512)) publisher_url = db.Column(db.String(512))
publishing_url = db.Column(db.String(512)) publishing_url = db.Column(db.String(512))
publishing_year = db.Column(db.Integer) publishing_year = db.Column(db.Integer)
pipeline_name = db.Column(db.String(64))
shared = db.Column(db.Boolean, default=False) shared = db.Column(db.Boolean, default=False)
# Backrefs: user: User # Backrefs: user: User
...@@ -675,6 +680,7 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model): ...@@ -675,6 +680,7 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model):
model.shared = True model.shared = True
model.title = m['title'] model.title = m['title']
model.version = m['version'] model.version = m['version']
model.pipeline_name = m['pipeline_name']
continue continue
model = SpaCyNLPPipelineModel( model = SpaCyNLPPipelineModel(
compatible_service_versions=m['compatible_service_versions'], compatible_service_versions=m['compatible_service_versions'],
...@@ -686,7 +692,8 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model): ...@@ -686,7 +692,8 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model):
shared=True, shared=True,
title=m['title'], title=m['title'],
user=nopaque_user, user=nopaque_user,
version=m['version'] version=m['version'],
pipeline_name=m['pipeline_name']
) )
db.session.add(model) db.session.add(model)
db.session.flush(objects=[model]) db.session.flush(objects=[model])
...@@ -708,6 +715,13 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model): ...@@ -708,6 +715,13 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model):
f.write(chunk) f.write(chunk)
pbar.close() pbar.close()
db.session.commit() db.session.commit()
def delete(self):
try:
os.remove(self.path)
except OSError as e:
current_app.logger.error(e)
db.session.delete(self)
def to_json(self, backrefs=False, relationships=False): def to_json(self, backrefs=False, relationships=False):
_json = { _json = {
...@@ -718,6 +732,7 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model): ...@@ -718,6 +732,7 @@ class SpaCyNLPPipelineModel(FileMixin, HashidMixin, db.Model):
'publisher_url': self.publisher_url, 'publisher_url': self.publisher_url,
'publishing_url': self.publishing_url, 'publishing_url': self.publishing_url,
'publishing_year': self.publishing_year, 'publishing_year': self.publishing_year,
'pipeline_name': self.pipeline_name,
'shared': self.shared, 'shared': self.shared,
'title': self.title, 'title': self.title,
**self.file_mixin_to_json() **self.file_mixin_to_json()
......
class SpacyNLPModelList {
constructor () {
this.elements = {
spacyNLPModelList: document.querySelector('#spacy-nlp-model-list'),
deleteButtons: document.querySelectorAll('.delete-spacy-model-button'),
editButtons: document.querySelectorAll('.edit-spacy-model-button'),
}
}
init () {
let userId = this.elements.spacyNLPModelList.dataset.userId;
for (let deleteButton of this.elements.deleteButtons) {
deleteButton.addEventListener('click', () => {this.deleteModel(deleteButton, userId);});
}
for (let editButton of this.elements.editButtons) {
editButton.addEventListener('click', () => {this.editModel(editButton);});
}
}
deleteModel(deleteButton, userId) {
return new Promise((resolve, reject) => {
let modelId = deleteButton.dataset.modelId;
let model = app.data.users[userId].spacy_nlp_pipeline_models[modelId];
let modalElement = Utils.elementFromString(
`
<div class="modal">
<div class="modal-content">
<h4>Confirm job deletion</h4>
<p>Do you really want to delete <b>${model.title}</b>? All files will be permanently deleted!</p>
</div>
<div class="modal-footer">
<a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>
<a class="action-button btn modal-close red waves-effect waves-light" data-action="confirm">Delete</a>
</div>
</div>
`
);
document.querySelector('#modals').appendChild(modalElement);
let modal = M.Modal.init(
modalElement,
{
dismissible: false,
onCloseEnd: () => {
modal.destroy();
modalElement.remove();
}
}
);
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
confirmElement.addEventListener('click', (event) => {
let modelTitle = model.title;
fetch(`/contributions/edit-spacy-model/${modelId}`, {method: 'DELETE'})
.then(
(response) => {
app.flash(`Model "${modelTitle}" marked for deletion`, 'corpus');
resolve(response);
},
(response) => {
if (response.status === 403) {app.flash('Forbidden', 'error');}
if (response.status === 404) {app.flash('Not Found', 'error');}
reject(response);
}
);
});
modal.open();
});
}
editModel(editButton) {
window.location.href = `/contributions/edit-spacy-model/${editButton.dataset.modelId}`;
}
}
...@@ -25,7 +25,6 @@ class TesseractOCRModelList { ...@@ -25,7 +25,6 @@ class TesseractOCRModelList {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let modelId = deleteButton.dataset.modelId; let modelId = deleteButton.dataset.modelId;
let model = app.data.users[userId].tesseract_ocr_pipeline_models[modelId]; let model = app.data.users[userId].tesseract_ocr_pipeline_models[modelId];
let modalElement = Utils.elementFromString( let modalElement = Utils.elementFromString(
` `
<div class="modal"> <div class="modal">
...@@ -54,7 +53,7 @@ class TesseractOCRModelList { ...@@ -54,7 +53,7 @@ class TesseractOCRModelList {
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]'); let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
confirmElement.addEventListener('click', (event) => { confirmElement.addEventListener('click', (event) => {
let modelTitle = model.title; let modelTitle = model.title;
fetch(`/contributions/${modelId}`, {method: 'DELETE'}) fetch(`/contributions/edit-tesseract-model/${modelId}`, {method: 'DELETE'})
.then( .then(
(response) => { (response) => {
app.flash(`Model "${modelTitle}" marked for deletion`, 'corpus'); app.flash(`Model "${modelTitle}" marked for deletion`, 'corpus');
...@@ -72,6 +71,6 @@ class TesseractOCRModelList { ...@@ -72,6 +71,6 @@ class TesseractOCRModelList {
} }
editModel(editButton) { editModel(editButton) {
window.location.href = `/contributions/${editButton.dataset.modelId}`; window.location.href = `/contributions/edit-tesseract-model/${editButton.dataset.modelId}`;
} }
} }
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
'js/RessourceLists/JobInputList.js', 'js/RessourceLists/JobInputList.js',
'js/RessourceLists/JobResultList.js', 'js/RessourceLists/JobResultList.js',
'js/RessourceLists/QueryResultList.js', 'js/RessourceLists/QueryResultList.js',
'js/RessourceLists/SpacyNLPModelList.js',
'js/RessourceLists/TesseractOCRModelList.js', 'js/RessourceLists/TesseractOCRModelList.js',
'js/RessourceLists/UserList.js' 'js/RessourceLists/UserList.js'
%} %}
......
...@@ -14,5 +14,18 @@ ...@@ -14,5 +14,18 @@
<li class="tab"><a href="{{ url_for('.contributions', tesseract_ocr_pipeline_model_id=nn) }}" target="_self">Contributions Overview</a></li> <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 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> <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) %}
<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">
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 %} {% endif %}
{% endset %} {% endset %}
{% extends "base.html.j2" %}
{% import "materialize/wtf.html.j2" as wtf %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12 m8 offset-m2">
<h1 id="title">{{ title }}</h1>
<p>
In order to add a new model, please fill in the form below.
</p>
<form method="POST">
<div class="card-panel">
{{ form.hidden_tag() }}
{{ wtf.render_field(form.title) }}
{{ wtf.render_field(form.description) }}
{{ wtf.render_field(form.publisher) }}
{{ wtf.render_field(form.publisher_url) }}
{{ wtf.render_field(form.publishing_url) }}
{{ wtf.render_field(form.publishing_year) }}
{{ wtf.render_field(form.shared) }}
{{ wtf.render_field(form.version) }}
{{ wtf.render_field(form.compatible_service_versions) }}
{{ wtf.render_field(form.submit, class_='width-100', material_icon='send') }}
</div>
</form>
</div>
</div>
{% endblock page_content %}
\ No newline at end of file
{% extends "base.html.j2" %}
{% import "materialize/wtf.html.j2" as wtf %}
{# {% from "contributions/_breadcrumbs.html.j2" import breadcrumbs with context %} #}
{% block main_attribs %} class="service-scheme" data-service="tesseract-ocr-pipeline"{% endblock main_attribs %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12">
<h1 id="title">{{ title }}</h1>
</div>
<div class="col s12 m3 push-m9">
<div class="center-align">
<p class="hide-on-small-only">&nbsp;</p>
<p class="hide-on-small-only">&nbsp;</p>
<a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light">
<i class="nopaque-icons service-color darken service-icon" data-service="spacy-nlp-pipeline"></i>
</a>
</div>
</div>
<div class="col s12 m9 pull-m3">
<div class="card service-color-border border-darken" data-service="spacy-nlp-pipeline" style="border-top: 10px solid;">
<div class="card-content">
<div class="row">
<div class="col s12">
<div class="card-panel z-depth-0">
<span class="card-title"><i class="left material-icons">layers</i>spaCy NLP Models</span>
<p>You can add more Tesseract OCR models using the form below. They will automatically appear in the list of usable models.</p>
<p><a href="">Edit already uploaded models</a></p>
<p><a class="modal-trigger" href="#models-modal">Information about the already existing models.</a></p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col s12">
<h2>Add a model</h2>
<div class="card">
<form class="create-contribution-form" enctype="multipart/form-data" method="POST">
<div class="card-content">
{{ form.hidden_tag() }}
<div class="row">
<div class="col s12 l5">
{{ wtf.render_field(form.spacy_model_file, accept='.tar.gz', placeholder='Choose a .tar.gz file') }}
</div>
<div class="col s12 l7">
{{ wtf.render_field(form.title, material_icon='title') }}
</div>
<div class="col s12">
{{ wtf.render_field(form.description, material_icon='description') }}
</div>
<div class="col s12 l6">
{{ wtf.render_field(form.publisher, material_icon='account_balance') }}
</div>
<div class="col s12 l6">
{{ wtf.render_field(form.publishing_year, material_icon='calendar_month') }}
</div>
<div class="col s12">
{{ wtf.render_field(form.publisher_url, material_icon='link') }}
</div>
<div class="col s12">
{{ wtf.render_field(form.publishing_url, material_icon='link') }}
</div>
<div class="col s12 l10">
{{ wtf.render_field(form.version, material_icon='apps') }}
</div>
<div class="col s12 l6">
{{ wtf.render_field(form.compatible_service_versions) }}
</div>
<div class="col s12 l6 right-align" style="padding-right:20px;">
<p></p>
<br>
{{ wtf.render_field(form.shared) }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ wtf.render_field(form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock page_content %}
{% block modals %}
{{ super() }}
<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 %}
...@@ -28,8 +28,8 @@ ...@@ -28,8 +28,8 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% if tesseractOCRUserModels|length > 0 %} {% if tesseract_ocr_user_models|length > 0 %}
{% for m in tesseractOCRUserModels %} {% for m in tesseract_ocr_user_models %}
<tr id="tesseract-ocr-pipeline-model-{{ m.hashid }}"> <tr id="tesseract-ocr-pipeline-model-{{ m.hashid }}">
<td>{{ m.title }}</td> <td>{{ m.title }}</td>
{% if m.description == '' %} {% if m.description == '' %}
...@@ -61,6 +61,58 @@ ...@@ -61,6 +61,58 @@
</div> </div>
</div> </div>
{# spaCy NLP Models #}
<div>
<h3>My spaCy NLP Pipeline Models</h3>
<p>Here you can see and edit the models that you have created. You can also create new models.</p>
<div class="row">
<div class="col s12">
<div class="card">
<div class="card-content">
<div id="spacy-nlp-model-list" data-user-id="{{ userId }}" data-user-models="{{ spacy_nlp_user_models }}">
<table>
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Biblio</th>
<th></th>
</tr>
</thead>
<tbody>
{% if spacy_nlp_user_models|length > 0 %}
{% for m in spacy_nlp_user_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>
<td class="right-align">
<a class="delete-spacy-model-button btn-floating red waves-effect waves-light" data-model-id="{{ m.hashid }}"><i class="material-icons">delete</i></a>
<a class="edit-spacy-model-button btn-floating service-color darken waves-effect waves-light" data-model-id="{{ m.hashid }}"><i class="material-icons">edit</i></a>
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="4">No models available.</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</div>
<div class="card-action right-align">
<a href="{{ url_for('contributions.add_spacy_nlp_pipeline_model') }}" class="btn waves-effect waves-light"><i class="material-icons left">add</i>Add model file</a>
</div>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -71,5 +123,7 @@ ...@@ -71,5 +123,7 @@
<script> <script>
const tesseractOCRModelList = new TesseractOCRModelList(); const tesseractOCRModelList = new TesseractOCRModelList();
tesseractOCRModelList.init(); tesseractOCRModelList.init();
const spacyNLPModelList = new SpacyNLPModelList();
spacyNLPModelList.init();
</script> </script>
{% endblock scripts %} {% endblock scripts %}
{% extends "base.html.j2" %}
{% import "materialize/wtf.html.j2" as wtf %}
{# {% from "contributions/_breadcrumbs.html.j2" import breadcrumbs with context %} #}
{% block main_attribs %} class="service-scheme" data-service="spacy-nlp-pipeline"{% endblock main_attribs %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12">
<h1 id="title">{{ title }}</h1>
</div>
<div class="col s12">
<div class="card">
<form class="create-contribution-form" enctype="multipart/form-data" method="POST">
<div class="card-content">
{{ form.hidden_tag() }}
<div class="row">
<div class="col s12 l7">
{{ wtf.render_field(form.title, material_icon='title') }}
</div>
<div class="col s12">
{{ wtf.render_field(form.description, material_icon='description') }}
</div>
<div class="col s12 l6">
{{ wtf.render_field(form.publisher, material_icon='account_balance') }}
</div>
<div class="col s12 l6">
{{ wtf.render_field(form.publishing_year, material_icon='calendar_month') }}
</div>
<div class="col s12">
{{ wtf.render_field(form.publisher_url, material_icon='link') }}
</div>
<div class="col s12">
{{ wtf.render_field(form.publishing_url, material_icon='link') }}
</div>
<div class="col s12 l10">
{{ wtf.render_field(form.version, material_icon='apps') }}
</div>
<div class="col s12 l6 right-align" style="padding-right:20px;">
<p></p>
<br>
{{ wtf.render_field(form.shared) }}
</div>
</div>
</div>
<div class="card-action right-align">
{{ wtf.render_field(form.submit, material_icon='send') }}
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock page_content %}
"""empty message
Revision ID: 721829b5dd25
Revises: 31dd42e5ea6f
Create Date: 2022-11-04 13:58:13.008301
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '721829b5dd25'
down_revision = '31dd42e5ea6f'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('spacy_nlp_pipeline_models', sa.Column('pipeline_name', sa.String(length=64), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('spacy_nlp_pipeline_models', 'pipeline_name')
# ### end Alembic commands ###
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment