Improvements to the item page.

This commit is contained in:
Edward Betts 2019-09-25 13:40:15 +01:00
parent 0b10bde447
commit 0a575b7b69
3 changed files with 203 additions and 57 deletions

150
app.py
View file

@ -1,7 +1,8 @@
#!/usr/bin/python3 #!/usr/bin/python3
from flask import Flask, render_template, url_for, redirect, request, g from flask import Flask, render_template, url_for, redirect, request, g, jsonify
from depicts import utils, wdqs, commons, mediawiki, painting from depicts import utils, wdqs, commons, mediawiki, painting, saam, database
from depicts.model import DepictsItem, DepictsItemAltLabel
import json import json
import os import os
import locale import locale
@ -9,9 +10,9 @@ import random
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
thumbwidth = 300
app = Flask(__name__) app = Flask(__name__)
app.config.from_object('config.default')
database.init_db(app.config['DB_URL'])
find_more_props = { find_more_props = {
'P135': 'movement', 'P135': 'movement',
@ -159,13 +160,7 @@ def random_painting():
item_id = wdqs.row_id(row) item_id = wdqs.row_id(row)
return redirect(url_for('item_page', item_id=item_id)) return redirect(url_for('item_page', item_id=item_id))
@app.route("/item/Q<int:item_id>") def image_with_cache(qid, image_filename, width):
def item_page(item_id):
qid = f'Q{item_id}'
item = painting.Painting(qid)
width = 800
image_filename = item.image_filename
filename = f'cache/{qid}_{width}_image.json' filename = f'cache/{qid}_{width}_image.json'
if os.path.exists(filename): if os.path.exists(filename):
detail = json.load(open(filename)) detail = json.load(open(filename))
@ -173,13 +168,46 @@ def item_page(item_id):
detail = commons.image_detail([image_filename], thumbwidth=width) detail = commons.image_detail([image_filename], thumbwidth=width)
json.dump(detail, open(filename, 'w'), indent=2) json.dump(detail, open(filename, 'w'), indent=2)
hits = item.run_query() return detail[image_filename]
def first_datavalue(entity, pid):
return entity['claims'][pid][0]['mainsnak']['datavalue']['value']
@app.route("/item/Q<int:item_id>")
def item_page(item_id):
qid = f'Q{item_id}'
item = painting.Painting(qid)
entity = mediawiki.get_entity_with_cache(qid)
width = 800
image_filename = item.image_filename
image = image_with_cache(qid, image_filename, width)
# hits = item.run_query()
label = get_entity_label(entity)
other = get_other(item.entity)
if 'P4704' in entity['claims']:
saam_id = first_datavalue(entity, 'P4704')
catalog = saam.get_catalog(saam_id)
saam_data = {
'keywords': catalog['keywords'],
'description': catalog['ld']['description']
}
else:
saam_data = None
return render_template('item.html', return render_template('item.html',
qid=qid, qid=qid,
item=item, item=item,
image=detail[image_filename], saam_data=saam_data,
hits=hits, labels=find_more_props,
entity=item.entity,
label=label,
image=image,
other=other,
# hits=hits,
title=item.display_title) title=item.display_title)
def get_entity_label(entity): def get_entity_label(entity):
@ -209,21 +237,7 @@ def get_labels(keys, name=None):
return {entity['id']: get_entity_label(entity) for entity in labels} return {entity['id']: get_entity_label(entity) for entity in labels}
@app.route("/next/Q<int:item_id>") def get_other(entity):
def next_page(item_id):
qid = f'Q{item_id}'
entity = mediawiki.get_entity_with_cache(qid)
width = 800
image_filename = entity['claims']['P18'][0]['mainsnak']['datavalue']['value']
filename = f'cache/{qid}_{width}_image.json'
if os.path.exists(filename):
detail = json.load(open(filename))
else:
detail = commons.image_detail([image_filename], thumbwidth=width)
json.dump(detail, open(filename, 'w'), indent=2)
other_items = set() other_items = set()
for key in find_more_props.keys(): for key in find_more_props.keys():
if key not in entity['claims']: if key not in entity['claims']:
@ -231,21 +245,27 @@ def next_page(item_id):
for claim in entity['claims'][key]: for claim in entity['claims'][key]:
other_items.add(claim['mainsnak']['datavalue']['value']['id']) other_items.add(claim['mainsnak']['datavalue']['value']['id'])
item_labels = get_labels(other_items) return get_labels(other_items)
if 'en' in entity['labels']: @app.route("/next/Q<int:item_id>")
label = entity['labels']['en']['value'] def next_page(item_id):
elif len(entity['labels']) == 1: qid = f'Q{item_id}'
label = list(entity['labels'].values())[0]['value']
else: entity = mediawiki.get_entity_with_cache(qid)
label = 'title missing'
width = 800
image_filename = first_datavalue(entity, 'P18')
image = image_with_cache(qid, image_filename, width)
label = get_entity_label(entity)
other = get_other(entity)
return render_template('next.html', return render_template('next.html',
qid=qid, qid=qid,
label=label, label=label,
image=detail[image_filename], image=image,
labels=find_more_props, labels=find_more_props,
other=item_labels, other=other,
entity=entity) entity=entity)
@app.route('/P<int:property_id>/Q<int:item_id>') @app.route('/P<int:property_id>/Q<int:item_id>')
@ -315,6 +335,8 @@ def browse_page():
filenames = [cur['image_filename'] for cur in items] filenames = [cur['image_filename'] for cur in items]
thumbwidth = app.config['THUMBWIDTH']
filename = f'cache/{flat}_{page_size}_images.json' filename = f'cache/{flat}_{page_size}_images.json'
if os.path.exists(filename): if os.path.exists(filename):
detail = json.load(open(filename)) detail = json.load(open(filename))
@ -337,6 +359,58 @@ def browse_page():
total=len(bindings), total=len(bindings),
items=items) items=items)
@app.route('/lookup')
def depicts_lookup():
terms = request.args.get('terms')
if not terms:
return jsonify(error='terms parameter is required')
terms = terms.strip()
if len(terms) < 3:
return jsonify(
count=0,
hits=[],
notice='terms too short for lookup',
)
item_ids = []
hits = []
q1 = DepictsItem.query.filter(DepictsItem.label.ilike(terms + '%'))
for item in q1:
hit = {
'label': item.label,
'description': item.description,
'qid': item.qid,
'count': item.count,
}
item_ids.append(item.item_id)
hits.append(hit)
cls = DepictsItemAltLabel
q2 = cls.query.filter(cls.alt_label.ilike(terms + '%'),
~cls.item_id.in_(item_ids))
for alt in q2:
item = alt.item
hit = {
'label': item.label,
'description': item.description,
'qid': item.qid,
'count': item.count,
'alt_label': alt.alt_label,
}
hits.append(hit)
hits.sort(key=lambda hit: hit['count'], reverse=True)
ret = {
'count': q1.count() + q2.count(),
'hits': hits,
'terms': terms,
}
return jsonify(ret)
if __name__ == "__main__": if __name__ == "__main__":
app.debug = True app.debug = True

View file

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <link rel="stylesheet" href="{{ url_for('static', filename='javascript/bootstrap4/css/bootstrap.min.css') }}">
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title> <title>
@ -15,9 +15,9 @@
<body> <body>
{% block content %}{% endblock %} {% block content %}{% endblock %}
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="{{ url_for('static', filename='javascript/jquery/jquery.min.js') }}"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> {# <script src="{{ url_for('static', filename='javascript/popper.js/popper.min.js') }}"></script> #}
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> <script src="{{ url_for('static', filename='javascript/bootstrap4/js/bootstrap.min.js') }}"></script>
{% block script %}{% endblock %} {% block script %}{% endblock %}
</body> </body>

View file

@ -2,17 +2,32 @@
{% block title %}{{ label }} ({{qid }}){% endblock %} {% block title %}{{ label }} ({{qid }}){% endblock %}
{% block content %} {% block style %}
<div class="m-3"> <style>
<h1>{{ self.title() }}</h1> .description { margin-left: 2em; color: rgb(96, 96, 96); }
<div class="row"> </style>
<div class="col"> {% endblock %}
<img src="{{ image.thumburl }}">
</div>
<div class="col"> {% block content %}
<p><a href="https://www.wikidata.org/wiki/{{ qid }}">view on Wikidata</a></p> <div>
<p><a href="{{ url_for('random_painting') }}">random painting</a></p> <div class="d-flex">
<div class="flex-shrink-1 vh-100">
<img src="{{ image.thumburl }}" class="h-100" />
</div>
<div class="p-2 flex-fill">
<h1>{{ self.title() }}</h1>
<p>
<a href="https://www.wikidata.org/wiki/{{ qid }}">view this painting on Wikidata</a>
|
<a href="{{ url_for('random_painting') }}">open a random painting</a>
</p>
<div>
{% for hit in hits %} {% for hit in hits %}
<p> <p>
url: {{ hit.url }}<br> url: {{ hit.url }}<br>
@ -22,13 +37,70 @@
</p> </p>
{% endfor %} {% endfor %}
<div>
{% for key, prop_label in labels.items() %}
{% set claims = entity['claims'][key] %}
{% if claims %}
<div>
<strong>{{ prop_label }}</strong>:
{% for claim in claims %}
{% set claim_qid = claim.mainsnak.datavalue.value.id %}
<a href="https://www.wikidata.org/wiki/{{ claim_qid }}">{{ other[claim_qid] or '[ label missing ]' }}</a> ({{ claim_qid }})
{% endfor %}
</div>
{% endif %}
{% endfor %}
</div>
{% if saam_data %}
<pre>{{ saam_data | pprint }}</pre>
{% endif %}
</div>
{% raw %}
<div id="app" class="mt-2">
<h3>what can you see in this painting?</h3>
<div v-for="hit in new_depicts">
<div>
{{ hit.label }}
<span v-if="hit.alt_label">({{ hit.alt_label }})</span>
&mdash; {{ hit.count }} existing paintings
({{ hit.qid }})
<a :href="'https://www.wikidata.org/wiki/' + hit.qid">view on Wikidata</a>
</div>
<div v-if="hit.description">
<div class="description">{{ hit.description }}</div>
</div>
</div>
<input class="form-control-lg mt-2 w-100" autofocus autocomplete="off" v-model.trim="searchTerms" @input="search" />
<div id="item-list">
<div v-for="hit in hits">
<div>
<a href="#" @click="add_depicts(hit)">{{ hit.label }}</a>
<span v-if="hit.alt_label">({{ hit.alt_label }})</span>
&mdash; {{ hit.count }} existing paintings
({{ hit.qid }})
<a :href="'https://www.wikidata.org/wiki/' + hit.qid">view on Wikidata</a>
</div>
<div v-if="hit.description">
<div class="description">{{ hit.description }}</div>
</div>
</div>
</div>
</div>
{% endraw %}
</div> </div>
</div> </div>
<pre>{{ item.query_variables() | pprint }}</pre>
<pre>{{ item.build_query() }}</pre>
</div> </div>
{% endblock %} {% endblock %}
{% block script %}
<script>
var lookup_url = {{ url_for('depicts_lookup') | tojson }};
</script>
<script src="{{ url_for('static', filename='vue/vue.js') }}"></script>
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
{% endblock %}