Skip to content

Commit

Permalink
#12 Update advanced entity extraction
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastiano-G committed Apr 19, 2024
1 parent 5cc2f98 commit 705f8a4
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 15 deletions.
2 changes: 2 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ def GET(self, name):
the record ID (a timestamp)
"""

web.header("X-Forwarded-For", session['ip_address'])
web.header("Cache-Control", "no-cache, max-age=0, must-revalidate, no-store")
web.header("Content-Type","text/html; charset=utf-8")
web.header('Access-Control-Allow-Origin', '*')
Expand Down Expand Up @@ -574,6 +575,7 @@ def POST(self, name):
the record ID (a timestamp)
"""

web.header("X-Forwarded-For", session['ip_address'])
web.header("Content-Type","text/html; charset=utf-8")
web.header('Access-Control-Allow-Origin', '*')
web.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
Expand Down
29 changes: 29 additions & 0 deletions static/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -2204,7 +2204,36 @@ input[subtemplate]+.fa-plus-circle {
}


/* tips */
.bold {
font-weight: bold;
}

.tips-div {
padding: 10px 15px;
overflow:auto;
}

.tips-div .fa-caret-right {
position: absolute;
top: 15px;
font-size: 40px;
right: 45px;
color: rgb(100, 23, 180);
cursor: pointer;
}

.tips-div .fa-caret-left {
position: absolute;
top: 15px;
font-size: 40px;
right: 70px;
color: rgb(100, 23, 180);
cursor: pointer;
}

/* extra */
.fa-globe, .fa-plus-circle, .fa-eye, .fa-trash{color: rgba(100,23,180,1); cursor: pointer;}
.link_btn, .btn {white-space: nowrap;}
.add_fields .link_btn {display: inline-block; margin-bottom: 8px}

160 changes: 150 additions & 10 deletions static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,9 @@ $(document).ready(function() {

// autoresize textarea
$('textarea').each(function () {
this.setAttribute('style', 'height:' + (this.scrollHeight)/2 + 'px;overflow-y:hidden;');
var styleAttr= 'height:' + (this.scrollHeight)/2 + 'px;overflow-y:hidden;';
if (this.classList.contains('hiddenInput')) { styleAttr += 'display:none;'}
this.setAttribute('style', styleAttr);
}).on('input', function () {
this.style.height = 'auto';
this.style.height = (this.scrollHeight) + 'px';
Expand Down Expand Up @@ -522,6 +524,31 @@ $(document).ready(function() {
});
});

$(window).on('resize', function() {

$('.tips-div').each(function() {
var target = $(this).attr('data-target');
var yasqeObj = $('#'+target+'>.yasqe');
var offset = yasqeObj.offset();
var left = offset.left;
var top = offset.top;
var width = yasqeObj.width()+1;
var height = yasqeObj.height();

$(this).css({
left: left+"px",
top: top+"px",
width: width+"px",
height: height+"px",
position: "absolute",
"z-index": "5",
"background-color": "white",
border: "1px solid #D1D1D1",
})
})
});


/////////////////////////
// MULTIPLE LANGUAGES ///
/////////////////////////
Expand Down Expand Up @@ -970,7 +997,9 @@ function callViafAPI(querySubstring, doneCallback){
// Ancillary function: make a SPARQL query (Wikidata/catalogue, for advanced search only)
function makeSPARQLQuery( endpointUrl, sparqlQuery, doneCallback ) {
var settings = {
headers: { Accept: 'application/sparql-results+json' },
headers: {
Accept: 'application/sparql-results+json',
Forwarded: "for="+ip},
data: { query: sparqlQuery }
};
return $.ajax( endpointUrl, settings ).then( doneCallback );
Expand Down Expand Up @@ -3087,7 +3116,7 @@ function disable_other_cb(ckType) {


// generate an instance of the YASQE editor to introduce a new SPARQL query constraint
function SPARQL_constraint_editor(field,el,temp_id) {
function SPARQL_constraint_editor(field,el,temp_id,reset=false) {
var select_input = $(el);
let endpoint = "";
let value_to_set = "";
Expand All @@ -3106,7 +3135,10 @@ function SPARQL_constraint_editor(field,el,temp_id) {
if (selected_option === 'WD') {
endpoint = wikidataEndpoint;
var id = $(field).attr('id').split('__')[0] + '__wikidataConstraint__' + temp_id;
value_to_set = `SELECT ?item ?itemLabel ?itemDescription WHERE {
if ($('[name="'+id+'"]').length>0 && reset==false) {
value_to_set = $('[name="'+id+'"]').val().replaceAll('&lt;','<').replaceAll('&gt;','>').replaceAll(/&quot;/g, '"');;
} else {
value_to_set = `SELECT ?item ?itemLabel ?itemDescription WHERE {
?item wdt:P31 wd:Q5 .
?item wdt:P106 wd:Q2526255 .
SERVICE wikibase:mwapi {
Expand All @@ -3118,18 +3150,23 @@ function SPARQL_constraint_editor(field,el,temp_id) {
}
SERVICE wikibase:label {bd:serviceParam wikibase:language "en".}
}`
}
}
// catalogue
if (selected_option === 'catalogue') {
endpoint = myPublicEndpoint
var id = $(field).attr('id').split('__')[0] + '__catalogueConstraint__' + temp_id;
value_to_set = `PREFIX bds: <http://www.bigdata.com/rdf/search#>
if ($('[name="'+id+'"]').length>0 && reset==false) {
value_to_set = $('[name="'+id+'"]').val().replaceAll('&lt;','<').replaceAll('&gt;','>').replaceAll(/&quot;/g, '"');;
} else {
value_to_set = `PREFIX bds: <http://www.bigdata.com/rdf/search#>
SELECT DISTINCT * WHERE {
?item rdfs:label ?itemLabel .
?item rdf:type ?itemClass .
?itemLabel bds:search "insertQueryTerm*" .
OPTIONAL { ?item rdfs:comment ?desc } .
}`
}
};

var cls = selected_option + "_" + id;
Expand All @@ -3141,6 +3178,7 @@ SELECT DISTINCT * WHERE {
var field_constraints = $("<div class='col-md-12 "+cls+"' id='yasqe_"+cls+"'></div>");
var button_save = $("<span class='comment'>Save constraint: <i class='fas fa-save'></i></span>");
var button_delete = $("<span class='comment'>Remove constraint: <i class='far fa-trash-alt'></i></span>");
var button_reset = $("<span class='comment'>Reset constraint: <i class='fas fa-redo'></i></span>");
var button_help = $("<span class='comment'>Help: <i class='far fa-lightbulb'></i></span>");

// save the SPARQL constraint on click
Expand All @@ -3165,7 +3203,109 @@ SELECT DISTINCT * WHERE {
button_delete.find('i').on('click', function() {
$(this).parent().parent().parent().remove();
$('[name="'+id+'"]').remove();
})
});

// refresh the SPARQL constraint and get back to the default value
button_reset.find('i').on('click', function() {
$(this).parent().parent().parent().remove();
$('[name="'+id+'"]').remove();
SPARQL_constraint_editor(field,el,temp_id,reset=true);
});

// get some tips
button_help.find('i').on('click', function() {
var buttonsDiv = $(this).parent().parent();
var goBackButton = $("<span class='comment'>Go back to editor: <i class='fas fa-undo'></i></span>");
goBackButton.find('i').on('click', function() {
$('.tips-div').remove();
buttonsDiv.find('span').show();
$(this).parent().remove();
})
buttonsDiv.find('span').hide();
buttonsDiv.append(goBackButton);


// create a new div to show the tips and anchor it to the .yasqe div
const yasqeObj = $(this).parent().parent().prev();
var offset = yasqeObj.offset();
var left = offset.left;
var top = offset.top;
var width = yasqeObj.width()+1;
var height = yasqeObj.height();

const newDiv = $('<div class="tips-div" data-target="yasqe_'+cls+'"></div>');
newDiv.css({
left: left+"px",
top: top+"px",
width: width+"px",
height: height+"px",
position: "absolute",
"z-index": "5",
"background-color": "white",
border: "1px solid #D1D1D1",
})

// retrieve the tips
$.getJSON("./static/json/help.json", function(data) {
const wikidataTipsObj = data.wikidataConstraint;
$.each(wikidataTipsObj, function(pageNumber, pageContent) {

// create a clone of the model div and populate it with HTML content
let cloneDiv = newDiv.clone();
cloneDiv.html(pageContent);

// set the clone div attributes and css properties
$(cloneDiv).attr('data-number', pageNumber.replace('page',''));
if (pageNumber !== 'page1') {
$(cloneDiv).hide();
} else {
$(cloneDiv).addClass('active-page');
}
$('body').append(cloneDiv);
});

$('.tips-div[data-target="yasqe_'+cls+'"]').each(function() {
var prevButton = $('<i class="fas fa-caret-left"></i>');
var nextButton = $('<i class="fas fa-caret-right"></i>');

// previous page
prevButton.on('click', function() {
var currentPage = $('.tips-div.active-page[data-target="yasqe_'+cls+'"]').attr('data-number');
var newPageNumber = parseInt(currentPage)-1;
var targetPage = $('.tips-div[data-target="yasqe_'+cls+'"][data-number="'+newPageNumber+'"]');
$('.tips-div.active-page[data-target="yasqe_'+cls+'"]').hide();
$('.tips-div.active-page[data-target="yasqe_'+cls+'"]').removeClass('active-page');
targetPage.show();
targetPage.addClass('active-page');
});

// next page
nextButton.on('click', function() {
console.log('c')
var currentPage = $('.tips-div.active-page[data-target="yasqe_'+cls+'"]').attr('data-number');
console.log(currentPage)

var newPageNumber = parseInt(currentPage)+1;
var targetPage = $('.tips-div[data-target="yasqe_'+cls+'"][data-number="'+newPageNumber+'"]');
$('.tips-div.active-page[data-target="yasqe_'+cls+'"]').hide();
$('.tips-div.active-page[data-target="yasqe_'+cls+'"]').removeClass('active-page');
targetPage.show();
targetPage.addClass('active-page');
});

if ($(this).prev('div').length>0) {
$(this).append(prevButton)
};
if ($(this).next('div').length>0) {
$(this).append(nextButton)
};
})

});

});
// end of tips section

select_input.after(field_constraints);

// complete the creation of the YASQE editor
Expand All @@ -3176,8 +3316,8 @@ SELECT DISTINCT * WHERE {
}
});
yasqe.setValue(value_to_set);
$('.'+cls).append('<div class="yasqe-buttons"></div>')
$('.'+cls+' .yasqe-buttons').append(button_save, button_delete, button_help);
$('.'+cls).append('<div class="yasqe-buttons"></div>');
$('.'+cls+' .yasqe-buttons').append(button_save, button_delete, button_reset, button_help);
}
}

Expand Down Expand Up @@ -3359,7 +3499,7 @@ function check_input_form(input_array) {
function yasqe_to_hidden_field(el,keep=false) {
let value = '';
var yasqe_div = $(el).parent().parent().parent();
var yasqe_lines = yasqe_div.find('.CodeMirror-code div');
var yasqe_lines = yasqe_div.find('.CodeMirror-code>div');
yasqe_lines.each(function() {
var tokens = $(this).find('pre span span');
tokens.each(function() {
Expand All @@ -3369,7 +3509,7 @@ function yasqe_to_hidden_field(el,keep=false) {
value+=' ';
}
});
value += ' ';
value += '\n';
});
if (keep===false){ yasqe_div.remove(); } else { yasqe_div.hide(); }
return value
Expand Down
11 changes: 11 additions & 0 deletions static/json/help.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"wikidataConstraint": {
"page1": "<p class='caption'>Tips</p><div><p>The query will allow contributors to automaticatically extract <span class='bold'>entities</span> and related <span class='bold'>data</span>, based on an input string, from Wikidata. Specify the information you would like to retrieve about entities after the <code>SELECT</code> clause (e.g.: <code>SELECT ?itemURI ?itemLabel</code>). You can optionally replace those labels with an asterysc to retrieve <span class='bold'>all</span> the variables expressed within the <code>WHERE</code> clause, which provides the basic graph pattern to match against the data graph.</p><p>Be careful: since a URI (<code>?item</code>) and a label (<code>?itemLabel</code>) are always required, you must always include them in your query.<br></p></div>",
"page2": "<p class='caption'>Tips</p><div><p>The default query is structured as follows:</p><ul><li><p><span class='bold'>SELECT clause:</span> the query currently retrieves the URI (<code>?item</code>), the label (<code>?itemLabel</code>), and the description (<code>?itemDescription</code>) of each entity.</p></li><li><p><span class='bold'>WHERE clause:</span> The first two lines introduces two triple patterns. The first one looks for entities which are instances (<code>wdt:P31</code>) of human (<code>wd:Q5</code>), while the second one looks for entities whose occupation (<code>wdt:106</code>) is film director (<code>wd:Q2526255</code>).</p></li><li><p><span class='bold'>SERVICE clause:</span> thanks to the <code>SERVICE</code> clauses it is possible to activate the autosuggestion machanism based on a input string. You can set your preferred language for retrieved values by modifying the object of the language properties (\"en\" by default), while any other modification is strongly discouraged</p></li></ul></div>",
"page3": "<p class='caption'>Tips</p><div><p>In the end, the best way to filter results from Wikidata is to modify the graph patterns right after the <code>WHERE</code> clause."
},
"catalogueConstraint":{
"page1": "<p class='caption'>Tips</p><div><p>The query will allow contributors to automaticatically extract <span class='bold'>entities</span> and related <span class='bold'>data</span>, based on an input string, from Wikidata. Specify the information you would like to retrieve about entities after the <code>SELECT</code> clause (e.g.: <code>SELECT ?itemURI ?itemLabel</code>). You can optionally replace those labels with an asterysc to retrieve <span class='bold'>all</span> the variables expressed within the <code>WHERE</code> clause, which provides the basic graph pattern to match against the data graph.</p><p>Be careful: since a URI (<code>?item</code>) and a label (<code>?itemLabel</code>) are always required, you must always include them in your query.<br></p></div>",
"page2": "<p class='caption'>Tips</p><div><p>The default query is structured as follows:</p><ul><li><p><span class='bold'>SELECT clause:</span> the query currently retrieves the URI (<code>?item</code>), the label (<code>?itemLabel</code>), and the description (<code>?itemDescription</code>) of each entity.</p></li><li><p><span class='bold'>WHERE clause:</span> The first two lines introduces two triple patterns. The first one looks for entities which are instances (<code>wdt:P31</code>) of human (<code>wd:Q5</code>), while the second one looks for entities whose occupation (<code>wdt:106</code>) is film director (<code>wd:Q2526255</code>).</p></li></ul></div>"
}
}
2 changes: 2 additions & 0 deletions templates/record.html
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,5 @@ <h2>What did you find?</h2>
<header class="row needDoc">
<h3>You already proposed $limit new resources today! Please come back tomorrow</h3>
</header>

<script type="text/javascript">var ip ='$session["ip_address"]'</script>
24 changes: 22 additions & 2 deletions templates/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,26 @@ <h3 class="col-md-12 col-sm-12">$res_name</h3>
$$("#value__$id option[value$$=$field['value']]").attr("selected","selected");
</script>
</section>

<!-- SPARQL CONSTRAINT -->
$if field['value'] == 'URI':
<section class='row'>
<label class='col-md-3'>SPARQL CONSTRAINTS <br><span class='comment'>select a service to show, modify, or add a constraint</span></label>
<select class='custom-select col-md-8' name='service__$id' onchange='SPARQL_constraint_editor($$(this).parent().prev().find("select"),this,$id)'>
<option value='None'>Select a service</option>
<option value='WD'>Wikidata</option>
<option value='catalogue'>This catalogue SPARQL endpoint</option>
</select>
</section>
$if 'wikidataConstraint' in field:
<textarea class='hiddenInput' style='display: none;' name='wikidataConstraint__$id'></textarea>
<script type="text/javascript">
$$('[name*="wikidataConstraint__$id"]').val(`$field['wikidataConstraint']`)
</script>
$if 'catalogueConstraint' in field:
<textarea class='hiddenInput' style='display: none;' name='catalogueConstraint__$id' value='$field["catalogueConstraint"]'></textarea>
<script type="text/javascript">
$$('[name*="catalogueConstraint__$id"]').val(`$field['catalogueConstraint']`)
</script>
<!-- PLACEHOLDER -->
<section class="row">
<label class='col-md-3'>PLACEHOLDER <br><span class="comment">an example value to be shown to the user (optional)</span></label>
Expand Down Expand Up @@ -331,4 +350,5 @@ <h5>Knowledge Extraction</h5>
<script src='static/js/yasr.bundled.min.js'></script>
<script src='static/js/yasqe.bundled.min.js'></script>
<script src="static/js/sparql.js"></script>
<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script type="text/javascript">var ip ='$session["ip_address"]'</script>
6 changes: 3 additions & 3 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,9 +542,9 @@ def get_query_templates(res_tpl):
if 'searchWikidata' in field and field['searchWikidata'] == 'True':
field_id = field['id']
if 'wikidataConstraint' in field and 'catalogueConstraint' in field:
query_dict[field_id] = {'wikidata':field['wikidataConstraint'], 'catalogue':field['catalogueConstraint']}
query_dict[field_id] = {'wikidata':field['wikidataConstraint'].replace('\r','').replace('\n',''), 'catalogue':field['catalogueConstraint'].replace('\r','').replace('\n','')}
elif 'wikidataConstraint' in field:
query_dict[field_id] = field['wikidataConstraint']
query_dict[field_id] = field['wikidataConstraint'].replace('\r','').replace('\n','')
elif 'catalogueConstraint' in field:
query_dict[field_id] = field['catalogueConstraint']
query_dict[field_id] = field['catalogueConstraint'].replace('\r','').replace('\n','')
return query_dict

0 comments on commit 705f8a4

Please sign in to comment.