Skip to content

Commit

Permalink
Merge pull request #1289 from Signbank/stc_source_1266
Browse files Browse the repository at this point in the history
Added sentence source model and video trimming #1266 #1277
  • Loading branch information
susanodd committed Jul 11, 2024
2 parents db16f09 + d7793eb commit da651ab
Show file tree
Hide file tree
Showing 12 changed files with 342 additions and 52 deletions.
2 changes: 1 addition & 1 deletion media/js/process_annotated_eaf_files.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ $(document).ready(function () {
$('#eaffile').change(function () {
var formData = new FormData();
formData.append('eaffile', $('#eaffile')[0].files[0]); // Add the file input to the FormData object
formData.append('check_gloss_label', [$('#check_gloss_label').val()]); // Add the gloss label to check in checkbox
formData.append('check_gloss_label', [$('#check-gloss-label').val()]); // Add the gloss label to check in checkbox
formData.append('csrfmiddlewaretoken', $('input[name=csrfmiddlewaretoken]').val()); // Include the CSRF token in the FormData object
formData.append('dataset', $('#dataset').val()); // add the dataset to the formdata

Expand Down
7 changes: 6 additions & 1 deletion signbank/dictionary/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,10 @@ class ExampleSentenceTranslationAdmin(admin.ModelAdmin):
search_fields = ['text']
list_filter = ['language']

class AnnotatedSentenceSourceAdmin(admin.ModelAdmin):
list_display = ("name", "source", "url", "dataset")
search_fields = ['name']
list_filter = ['dataset']

class AffiliationAdmin(admin.ModelAdmin):
list_display = ("name", )
Expand Down Expand Up @@ -1408,4 +1412,5 @@ class AffiliatedUserAdmin(admin.ModelAdmin):
admin.site.register(GlossSense, GlossSenseAdmin)
admin.site.register(Sense, SenseAdmin)
admin.site.register(ExampleSentence, ExampleSentenceAdmin)
admin.site.register(ExampleSentenceTranslation, ExampleSentenceTranslationAdmin)
admin.site.register(ExampleSentenceTranslation, ExampleSentenceTranslationAdmin)
admin.site.register(AnnotatedSentenceSource, AnnotatedSentenceSourceAdmin)
24 changes: 24 additions & 0 deletions signbank/dictionary/migrations/0083_annotatedsentencesource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.2.10 on 2024-07-10 13:06

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('dictionary', '0082_signbankapitoken_remove_userprofile_api_token_and_more'),
]

operations = [
migrations.CreateModel(
name='AnnotatedSentenceSource',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('source', models.TextField()),
('url', models.TextField(blank=True)),
('dataset', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dictionary.dataset')),
],
),
]
51 changes: 44 additions & 7 deletions signbank/dictionary/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3881,7 +3881,7 @@ def has_contexts(self):
return True
return False

def add_annotations(self, annotations, gloss):
def add_annotations(self, annotations, gloss, start_cut=-1, end_cut=-1):
"""Add annotations to the annotated sentence"""
dataset = gloss.lemma.dataset

Expand All @@ -3902,7 +3902,29 @@ def add_annotations(self, annotations, gloss):
repr = False
if annotation[1] == "1":
repr = True
AnnotatedGloss.objects.create(gloss=annotationIdGlossTranslation.gloss, annotatedsentence=self, isRepresentative=repr, starttime=annotation[2], endtime=annotation[3])

starttime = int(annotation[2])
endtime = int(annotation[3])

excluded = False
if start_cut >= 0 and end_cut >= 0:
# If completely outside of the cut, exclude it
if starttime >= end_cut or endtime <= 0:
excluded = True
elif (min(endtime, end_cut) - max(starttime, start_cut)) < 100:
excluded = True
# If the annotation is partially outside the cut, make it fit
elif starttime < start_cut and endtime > start_cut and endtime < end_cut:
starttime = start_cut
elif starttime >= start_cut and starttime < end_cut and endtime > end_cut:
endtime = end_cut
elif starttime < start_cut and endtime > end_cut:
starttime = start_cut
endtime = end_cut
starttime = starttime - start_cut
endtime = endtime - start_cut
if not excluded:
AnnotatedGloss.objects.create(gloss=annotationIdGlossTranslation.gloss, annotatedsentence=self, isRepresentative=repr, starttime=starttime, endtime=endtime)

def get_annotated_glosses_list(self):
annotated_glosses = []
Expand Down Expand Up @@ -3990,17 +4012,32 @@ def has_video(self):

return self.get_video() not in ['', None]

def add_video(self, user, videofile, eaffile, corpus):
def add_video(self, user, videofile, eaffile, source):
"""Add a video to the annotated sentence"""
from signbank.video.models import AnnotatedVideo

annotatedVideo = AnnotatedVideo.objects.create(annotatedsentence=self, videofile=videofile, eaffile=eaffile)

annotatedVideo.corpus = corpus
annotatedVideo.source = source
annotatedVideo.save()

return annotatedVideo


def __str__(self):
return " | ".join(self.get_annotatedstc_translations())
return " | ".join(self.get_annotatedstc_translations())

class AnnotatedSentenceSource(models.Model):
"""A source to choose for a sentence"""
name = models.CharField(max_length=200)
source = models.TextField()
url = models.TextField(blank=True)
dataset = models.ForeignKey(Dataset, on_delete=models.CASCADE)

def __str__(self):
return self.source

def get_absolute_url(self):
from urllib.parse import urlparse
parsed_url = urlparse(self.url)
if not parsed_url.scheme:
return 'http://' + self.url
return self.url
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<input type='hidden' name='redirect' value='{{PREFIX_URL}}/dictionary/gloss/{{gloss.id}}'>
<input type='hidden' name='object_id' value='{{gloss.id}}'>
<input type='hidden' name='object_type' value='annotated_video'>
<input type='hidden' id='check_gloss_label' value='{{annotationidgloss}}'>
<input type='hidden' id='check-gloss-label' value='{{annotationidgloss}}'>
<input type='hidden' id='dataset' value='{{gloss.lemma.dataset.acronym}}'>
<table id="staffops">
<tr>
Expand Down Expand Up @@ -65,8 +65,13 @@
<input type='hidden' name='translations' id='translations-hidden' value=''>

<br><br>
{% trans "From corpus:" %}
<input style="width:100%" id="corpus_name" name="corpus_name" value="" maxlength="100" type="text"/>
{% trans "Source:" %}
<select name="source_id">
<option value="">{% trans "-" %}</option>
{% for source in annotated_sentence_sources %}
<option value="{{ source.id }}">{{ source.name }}</option>
{% endfor %}
</select>

<br><br>
<input class='btn btn-primary' type='submit' value='Upload' />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@

{% get_obj_perms request.user for gloss.lemma.dataset as "dataset_perms" %}
{% if "change_dataset" in dataset_perms %}
<div class='editform', style="width:500px">
<div class='editform', style="width:1000px">
<fieldset>
<legend>{% trans "Edit Annotated Sentence" %}</legend>

{% trans "For the following gloss:" %} {{annotationidgloss}}<br><br>

{% trans "For the following sentence:" %}<br>
{% url 'dictionary:protected_media' '' as protected_media_url %}
<video id="sentenceVideo" controls width="500px">
<video id="sentence-video" controls width="700px">
<source src="{{ protected_media_url }}/{{ annotated_sentence.annotatedvideo.videofile }}" type="video/mp4">
</video>

Expand All @@ -28,16 +28,87 @@
<input type='hidden' name='redirect' value='{{PREFIX_URL}}/dictionary/gloss/{{gloss.id}}'>
<input type='hidden' name='annotatedsentenceid' value='{{annotated_sentence.id}}'>
<input type='hidden' name='glossid' value='{{gloss.id}}'>
<input type='hidden' id='check_gloss_label' value='{{annotationidgloss}}'>
<input type='hidden' id='check-gloss-label' value='{{annotationidgloss}}'>
<input type='hidden' id='dataset' value='{{gloss.lemma.dataset.acronym}}'>
<br>
<br><br>
<input type="checkbox" id="trim-video-checked" name="trim-video-checked" role="button" value="off"> {% trans 'Shorten the video' %}
<div id="trim_video">
{% trans "Slide to a point in the video and click 'Set' to define it as the new start and/or end point" %}<br>
<table class='table' style="width:70%">
<tr>
<td style="width:50%">
Start: <input type="text" id="start-point" name="start-ms" value="0" readonly>
<button type="button" id="start-button" class="btn btn-primary" data-dismiss="modal">{% trans "Set" %}</button>
</td>
<td style="width:50%">
End: <input type="text" id="end-point" name="end-ms" value="{{ annotated_sentence.annotatedvideo.get_end_ms }}" readonly>
<button type="button" id="end-button" class="btn btn-primary" data-dismiss="modal">{% trans "Set" %}</button>
</td>
</tr>
<tr>
<td colspan="2">
<button type="button" id="reset-trim" class="btn btn-primary" data-dismiss="modal">{% trans "Reset" %}</button>
<span id="trim-feedback"></span>
</td>
</tr>
</table>

</div>

<style>
#trim-video-checked:not(:checked)~#trim_video {
display: none;
}
#start-point, #end-point {
color: #787878;
}
</style>

<script>
var video = document.getElementById('sentence-video');
var startButton = document.getElementById('start-button');
var startPoint = document.getElementById('start-point');
var endButton = document.getElementById('end-button');
var endPoint = document.getElementById('end-point');
var resetTrim = document.getElementById('reset-trim');
var feedback = document.getElementById('trim-feedback');
const end = endPoint.value;

startButton.addEventListener('click', function() {
var currentTime = (video.currentTime * 1000).toFixed(0);
var endValue = parseInt(endPoint.value, 10);
if (!isNaN(endValue) && currentTime > endValue) {
feedback.innerHTML = '<font color="red">Start point must be before end point</font>';
} else {
startPoint.value = currentTime;
feedback.innerHTML = "";
}
});

endButton.addEventListener('click', function() {
var currentTime = (video.currentTime * 1000).toFixed(0);
var startValue = parseInt(startPoint.value, 10);
if (!isNaN(startValue) && currentTime < startValue) {
feedback.innerHTML = '<font color="red">End point must be after start point</font>';
} else {
endPoint.value = currentTime;
feedback.innerHTML = "";
}
});

resetTrim.addEventListener('click', function() {
startPoint.value = 0;
endPoint.value = end;
feedback.innerHTML = "";
});
</script>

<br><br>
{% trans "Download the current .eaf file here:" %}
<a href="{{ annotated_sentence.annotatedvideo.eaffile.url }}" download>{{ annotated_sentence.annotatedvideo.get_eaffile_name }}</a>
<br><br>
{% trans "Choose the updated annotation file (.eaf) here:" %}
<input type="file" id="eaffile" name="eaffile" required>
<input type="file" id="eaffile" name="eaffile">
<br>
<div id="feedback">
{{ annotations_table_html|safe }}
Expand All @@ -56,8 +127,16 @@
{% endfor %}

<br><br>
{% trans "From corpus:" %}
<input style="width:100%" id="corpus_name" name="corpus_name" value="{{ corpus }}" maxlength="100" type="text"/>
{% trans "Source:" %}
<select name="source_id">
{% if annotated_sentence.annotatedvideo.source %}
<option value="{{ annotated_sentence.annotatedvideo.source.id }}">{{ annotated_sentence.annotatedvideo.source.name }}</option>
{% endif %}
<option value="">{% trans "-" %}</option>
{% for source in annotated_sentence_sources %}
<option value="{{ source.id }}">{{ source.name }}</option>
{% endfor %}
</select>

<br><br>
<input class='btn btn-primary' type='submit' value='Save' />
Expand Down
11 changes: 7 additions & 4 deletions signbank/dictionary/templates/dictionary/gloss_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -2405,7 +2405,7 @@ <h2 id='modalTitleDeleteAnnotatedSentence'>{% trans "Delete this annotated sente
<style>.highlight {background-color: rgb(255, 149, 63);}</style>

<video id="myVideo_{{ forloop.counter }}" controls>
<source src="{{ protected_media_url }}/{{ annotated_sentence.annotatedvideo.videofile }}" type="video/mp4">
<source src="{{ protected_media_url }}/{{ annotated_sentence.annotatedvideo.videofile}}?v={% now 'YmdHis' %}" type="video/mp4">
</video>

<br><br><i>Glosses</i><br>
Expand Down Expand Up @@ -2449,9 +2449,12 @@ <h2 id='modalTitleDeleteAnnotatedSentence'>{% trans "Delete this annotated sente
{% endif %}
</p>
<p>
{% if annotated_sentence.annotatedvideo.corpus %}
<i>{% trans "Corpus" %}</i><br>
{{ annotated_sentence.annotatedvideo.corpus }}
{% if annotated_sentence.annotatedvideo.source %}
<i>{% trans "Source" %}</i><br>
{{ annotated_sentence.annotatedvideo.source.source }}
{% if annotated_sentence.annotatedvideo.source.url %}
, <a href="{{ annotated_sentence.annotatedvideo.source.get_absolute_url }}">{{ annotated_sentence.annotatedvideo.source.url }}</a>
{% endif %}
{% endif %}
</p>
</td>
Expand Down
Loading

0 comments on commit da651ab

Please sign in to comment.