:- module(yaz_cgarden, [ ]). :- use_module(library(http/http_dispatch)). :- use_module(library(http/http_parameters)). :- use_module(library(http/http_path)). :- use_module(library(http/html_write)). :- use_module(library(http/html_head)). :- use_module(library(http/http_json)). :- use_module(library(http/js_write)). :- use_module(library(http/json)). :- use_module(library(http/json_convert)). :- use_module(library(http/http_session)). :- use_module(user(user_db)). :- use_module(library(semweb/rdf_db)). :- use_module(library(semweb/rdfs)). :- use_module(library(semweb/rdf_label)). :- use_module(library(yaz_util)). :- use_module(library(yui3)). :- use_module(library(user_process)). :- use_module(library(video_annotation)). :- use_module(library(rdf_history)). :- use_module(library(tag_match)). :- use_module(components(label)). :- use_module(components(yaz_page)). :- use_module(api(reconcile)). :- http_handler(yaz(cgarden), http_yaz_cgarden, []). :- http_handler(yaz('data/confirmconcept'), http_yaz_api_confirm_concept, []). :- http_handler(yaz('data/cgarden'), http_yaz_api_cgarden_data, []). :- setting(request_interval, integer, 2000, 'Interval between requests to the server (in miliseconds)'). %% http_yaz_cgarden(+Request) % % Emit the a video player with a tag carousel running along side % of it. http_yaz_cgarden(Request) :- ensure_logged_on(User0), user_property(User0, url(CurrentUser)), http_parameters(Request, [ video(Video, [optional(true), description('Current video')]), process(Process, [optional(true), desription('When set only annotations within this process are shown')]), user(User, [optional(true),%default(CurrentUser), description('When set only annotations created by this user are shown')]), interval(Interval, [default(10000), description('Use only confirmed tags when set to true')]) ]), ( var(Video), var(Process) -> fail % proper error ; var(Video) -> rdf(Process,opmv:used,Video) ; true ), Options = [process(Process), user(User), interval(Interval) ], create_user_process(CurrentUser, [rdf:type=pprime:'cgarden', opmv:used=Video ], _GardenProcess), video_annotations(Video, As0, Options), sort_by_arg(As0, 2, As), rdf_equal(skos:'Concept', SKOSConcept), link_tags_to_concepts(As, SKOSConcept, Annotations), html_video_page(Process, Video, CurrentUser, Annotations, 0, Options). %% link_tags_to_concepts(+Annotations, -Annotations1) % % Add candidate concepts. link_tags_to_concepts([], _, []). link_tags_to_concepts([A0|As], Type, [A|Rest]) :- A0 = annotation(Tag,Start,End,Entries,Score), A = annotation(Tag,Start,End,Entries,Score,Concepts), tag_value(Tag, Value), ( reconcile(Value, 3, Type, [], Hits) -> maplist(hit_concept, Hits, Concepts) ; Concepts = [] ), link_tags_to_concepts(As, Type, Rest). tag_value(literal(L), L). tag_value(uri(_,L), L). hit_concept(hit(_,URI,_,Label), concept(URI,Label,Alt,Desc)) :- ( rdf_has(URI, rdfs:label, Lit), literal_text(Lit, Alt), \+ Alt == Label -> true ; Alt = '' ), ( rdf_has(URI,skos:scopeNote,Txt) -> literal_text(Txt,Desc) ; rdf_has(URI, skos:definition,Txt) -> literal_text(Txt,Desc) ; Desc = '' ). %% html_video_page(+Game, +Video, +User, +Annotations, +StartTime, %% +Options) % % Emit an HTML page with a video player and a tag carousel. html_video_page(Game, Video, User, Annotations, StartTime, Options) :- reply_html_page(yaz, [ title(['YAZ - ', Video]) ], [\html_requires(css('player.css')), \html_requires('http://freebaselibs.com/static/suggest/1.2.1/suggest.min.css'), div(class('video-results'), \html_video_page_containers(Video, Options)), script(type('text/javascript'), \html_video_page_yui(Game, Video, User, Annotations, StartTime, Options)) ]). html_video_page_containers(Video, _Options) --> { display_label(Video, Title) }, html([ h2(Title), div(id(video), [ div(id(tagplayer), []), div(id(videoplayer), []) ]) ]). html_video_page_yui(Game, Video, User, Annotations, StartTime, _Options) --> { video_source(Video, Src), http_absolute_location(js('videoplayer/'), FilePath, []), http_absolute_location(js('videoplayer/videoplayer.js'), VideoPlayer, []), http_absolute_location(js('tagcarousel/tagcarousel.js'), TagCarousel, []), %setting(request_interval, RequestInterval), %http_location_by_id(http_reconcile, ReconcileServer), annotation_to_json(Annotations, JSONTags) }, html_requires(js('videoplayer/swfobject.js')), js_yui3([{modules:{'video-player':{fullpath:VideoPlayer}, 'tag-carousel':{fullpath:TagCarousel} }} ], [node,event,widget,anim, 'querystring-stringify-simple',io,json,jsonp,'jsonp-url', overlay,'widget-position-align', 'video-player','tag-carousel' ], [ \js_new(videoPlayer, 'Y.mazzle.VideoPlayer'({filepath:FilePath, src:Src, width:640, height:480, autoplay:symbol(false), controls:symbol(true), start:StartTime })), \js_new(tagCarousel, 'Y.mazzle.TagCarousel'({tags:JSONTags, height:480, width:200, concept:symbol(true), topIndent:symbol(false) %info:true })), 'var oldTime;\n', \js_call('videoPlayer.render'('#videoplayer')), \js_call('tagCarousel.render'('#tagplayer')), %\js_yui3_on(tagCarousel, itemSelect, \js_tag_select), \js_yui3_on(tagCarousel, itemConfirm, \js_confirm(User)), \js_support_functions(Game, User) %\js_call('tagCarousel.reconcile'('http://standard-reconcile.freebaseapps.com/reconcile')) %\js_call('tagCarousel.reconcile'(ReconcileServer)) /*\js_call('Y.later'(RequestInterval, symbol('Y'), symbol(fetchData), symbol({}), symbol(true)))*/ ]). js_support_functions(_Game, User) --> { http_location_by_id(http_yaz_api_cgarden_data, DataServer) }, js_function_decl(fetchData, [e], \[ ' var data = {user:"',User,'"};', %game:"',Game,'"}; ' Y.io("',DataServer,'", {data: data, on: {success:handleResponse} });\n' ]), js_function_decl(handleResponse, [id, o], \[ ' var r = Y.JSON.parse(o.responseText); tagCarousel.updateMatch(r);\n' ]). js_tag_select --> js_function([e], \[ ' if(e.tag.startTime) { var time = (e.tag.startTime/1000)-2; videoPlayer.setTime(time, false); }\n' ]). js_confirm(User) --> { http_location_by_id(http_yaz_api_confirm_concept, ConfirmServer) }, js_function([e], [ ' var i = e.index, source = e.annotation.annotations[0].uri, target = e.annotation.match.uri, match = e.annotation.match.type;\n', \js_call('Y.io'(ConfirmServer, { data:{user:User, source:symbol(source), target:symbol(target), match:symbol(match)}, on:{success:symbol('function(id, o) {var r = Y.JSON.parse(o.responseText); tagCarousel.scoreIndex(i,r.score,"confirm",r.confirm) }')}, context:symbol(tagCarousel) })) ]). %% http_Yaz_Api_Confirm_Match(+Request) % % Handler for GET submission of a tag modification. http_yaz_api_confirm_concept(Request) :- http_parameters(Request, [ user(User, [description('URL of the user')]), source(Source, [description('URL of source')]), target(Target, [description('URL of the target')]), match(Match, [description('type of the match')]) ]), debug(yaz(update), 'confirm ~w match between ~w and ~w', [Match, Source, Target]), ( confirmed(Match, Source, Target, User, Confirm) -> match_score(Match, Score) ; Score = 0, rdf_bnode(Confirm), rdfh_transaction((rdfh_assert(Confirm, pprime:match, literal(Match)), rdfh_assert(Confirm, pprime:creator, User), rdfh_assert(Confirm, pprime:matchSource, Source), rdfh_assert(Confirm, pprime:matchTarget, Target))) ), reply_json(json([confirm=Confirm, score=Score ])). confirmed(specific, Source, Target, User, Confirm) :- rdf(Confirm, pprime:match, literal(Match)), \+ rdf(Confirm, pprime:creator, User), ( Match = specific -> confirmed_(Confirm, Source, Target) ; Match = generic -> confirmed_(Confirm, Target, Source) ). confirmed(generic, Source, Target, User, Confirm) :- rdf(Confirm, pprime:match, literal(Match)), \+ rdf(Confirm, pprime:creator, User), ( Match = generic -> confirmed_(Confirm, Source, Target) ; Match = specific -> confirmed_(Confirm, Target, Source) ). confirmed(Match, Source, Target, User, Confirm) :- rdf(Confirm, pprime:match, literal(Match)), \+ rdf(Confirm, pprime:creator, User), ( confirmed_(Confirm, Source, Target) ; confirmed_(Confirm, Target, Source) ). confirmed_(Confirm, Source, Target) :- rdf(Confirm, pprime:matchSource, Source), rdf(Confirm, pprime:matchTarget, Target). match_score(stem, 75). match_score(synonym, 100). match_score(specific, 150). match_score(generic, 125). %% http_yaz_api_mgarden_data(+Request) % % Handler for request of match data. http_yaz_api_cgarden_data(Request) :- http_parameters(Request, [ user(User, [description('URL of the user')]) ]), current_user_process(Process), Obj = json([confirm=Confirm, score=Score]), findall(Obj, user_confirmed(User, Process, Confirm, Score), Confirmed), reply_json(Confirmed). user_confirmed(User, Process, Confirm, Score) :- rdf(Confirm, pprime:creator, User, Process), rdf(Confirm, pprime:match, literal(Match)), rdf(Confirm, pprime:matchSource, Source), rdf(Confirm, pprime:matchTarget, Target), ( confirmed(Match, Source, Target, User, _) -> match_score(Match, Score) ; Score = 0 ).