Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added sentence source model and video trimming #1266 #1277 #1289

Merged
merged 6 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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