Gosse Minnema
Add sociofillmore code, load dataset via private dataset repo
b11ac48
raw
history blame
No virus
16.1 kB
/* CONSTANTS */
const maxSelectedFrames = 3;
/* VUE APP */
const SocioFillmoreDemo = {
data() {
return {
interactiveModeEnabled: false,
showIntroductionBox: true,
showExplanationText: true,
// examples
selectedExampleId: -1,
// event types
eventTypeName: "",
eventTypeDescr: "",
eventTypeTextExample: "",
// frames
primaryFrames: Array(maxSelectedFrames).fill(null),
perspectivizingFrames: Array(maxSelectedFrames).fill(Array(2).fill(null)),
frameToAdd: "",
showInvalidFrameWarning: false,
// keywords (for frame selection)
keywordAreaShown: false,
showInvalidKeywordWarning: false,
keywordToAdd: "",
selectedKeywords: [],
keywordSuggestedFrames: [],
// text analysis
textToAnalyze: "",
analyzedSentences: [],
analyzingTextBusy: false,
analysisLanguage: "it"
}
},
mounted() {
},
// methods listed in order as shown in UI
methods: {
// mode 1: interactive mode
startInteractiveMode() {
this.interactiveModeEnabled = true;
console.log(this.$refs);
setTimeout(() => {
this.$refs.interactiveModeHeading.scrollIntoView({ behavior: "smooth" });
}, 100)
},
// 1A: define event type
showEventExample() {
let numExamples = 1;
let randNum = Math.floor(Math.random() * numExamples);
const names = [
"Traffic crash",
];
const descriptions = [
"An accident happens in which a driver hits a pedestrian with their car. Typically, this kind of event is framed with a strong focus on the victim and their actions, and less focus on the driver"
]
const textExamples = [
"Typical newspaper headline (from https://www.irishexaminer.com/news/arid-40791657.html): Cyclist, 70s, seriously injured following collision in Dublin.\nAlternative way of framing: Driver hits pedestrian with his car, sending the 70-year old man to hospital with heavy injuries."
];
this.selectedExampleId = randNum;
this.eventTypeName = names[randNum];
this.eventTypeDescr = descriptions[randNum];
this.eventTypeTextExample = textExamples[randNum];
},
// 1B: defining frames
showFrameExample() {
let selectedExample = this.selectedExampleId;
if (selectedExample === -1) {
selectedExample = Math.floor(Math.random() * 3);
this.selectedExample = selectedExample;
}
this.primaryFrames = this.primaryFrames.map(_ => null);
switch (selectedExample) {
case 0: // measles
this.switchFrame(0, "Impact");
setTimeout(() => {this.switchFrame(1, "Experience_bodily_harm")}, 50);
setTimeout(() => {this.switchFrame(2, "Catastrophe")}, 100);
break;
// case 1:
// this.switchFrame(0, "Win_prize");
// this.switchFrame(1, "Self_motion");
// this.switchFrame(2, "Motion_directional");
// break;
// case 2:
// this.switchFrame(0, "Win_prize");
// this.switchFrame(1, "Self_motion");
// this.switchFrame(2, "Motion_directional");
// break;
}
},
addFrame(frmName) {
this.frameToAdd = "";
let numSelectedFrames = this.primaryFrames.filter((fr) => fr !== null).length;
if (numSelectedFrames >= maxSelectedFrames) {
return;
}
let newFrameIdx = numSelectedFrames;
this.switchFrame(newFrameIdx, frmName);
},
switchFrame(targetIdx, frmName) {
getFrameInfo(frmName,
// success
(data) => {
this.showInvalidFrameWarning = false;
console.log(data);
this.primaryFrames[targetIdx] = {
"name": frmName,
"description": data["description"],
"altPerspectives": [],
"typicalExemplar": data["typicalExemplar"]
};
data["altPerspectives"].forEach((persp) => {
getFrameInfo(persp["frame"],
// success
(perspData) => {
this.primaryFrames[targetIdx].altPerspectives.push({
"name": persp["frame"],
"type": persp["type"][0].toUpperCase() + persp["type"].substring(1),
"description": perspData["description"],
"typicalExemplar": perspData["typicalExemplar"]
});
// this.analyzeText(this.textToAnalyze);
});
});
},
// failure
() => {
this.showInvalidFrameWarning = true;
});
},
removeFrame(frmName) {
this.primaryFrames = this.primaryFrames.filter((frm) => frm === null || frm.name !== frmName);
for (let i = this.primaryFrames.length; i < maxSelectedFrames; i++) {
this.primaryFrames.push(null);
}
},
// 1C: keyword-assisted frame selection
showKeywords() {
this.keywordAreaShown = true;
setTimeout(() => {
this.$refs.keywordHeading.scrollIntoView({ behavior: "smooth" });
}, 100)
},
addKeyword() {
this.selectedKeywords.push({ "text": this.keywordToAdd });
this.keywordToAdd = "";
this.updateKeywordSuggestedFrames();
},
updateKeywordSuggestedFrames() {
this.keywordSuggestedFrames = [];
$.get(
"similar_frames",
{ "words_in": this.selectedKeywords.map((kwd) => kwd.text).join("+") }
).done((data) => {
if (data.result === "FAIL") {
this.showInvalidKeywordWarning = true;
} else {
this.showInvalidKeywordWarning = false;
data["frames"].slice(0, 5).forEach((frm) => {
getFrameInfo(frm, (frameInfo) => {
console.log(frameInfo);
this.keywordSuggestedFrames.push({
text: frm,
description: frameInfo["description"],
exemplars: frameInfo["exemplars"],
altPerspectives: frameInfo["altPerspectives"],
})
});
});
}
});
},
removeKeyword(event) {
this.selectedKeywords = this.selectedKeywords.filter((kwd) => kwd.text !== event.target.attributes["title"].value);
this.updateKeywordSuggestedFrames();
},
// 1D: on-the-fly text analysis
analyzeText(text, language) {
this.analyzedSentences = [];
this.analyzingTextBusy = true;
$.get("sociofillmore", { "text": text, "language": language },
// success
(data) => {
data.forEach((sentenceData) => {
console.log(sentenceData);
let textParts = [];
sentenceData["sentence"].forEach((token, tokenIdx) => {
let targets = sentenceData["fn_structures"].filter(struct => struct["target"]["tokens_idx"].includes(tokenIdx));
if (targets.length === 0) {
textParts.push({ "text": token, "type": "nonTarget" });
} else {
// frame & perspective
let target = targets[0];
let perspectiveType = "Main";
let perspectiveOn = target["frame"];
let subType = "otherTarget";
if (this.primaryFrames.filter(pf => pf !== null).map(pf => pf.name).includes(target["frame"])) {
subType = "primaryTarget";
} else if (this.primaryFrames.filter(pf => pf !== null).flatMap(pf => pf.altPerspectives.map(ap => ap.name)).includes(target["frame"])) {
let primary = this.primaryFrames.filter(pf => pf !== null && pf.altPerspectives.map(ap => ap.name).includes(target["frame"]))[0];
let alternate = primary.altPerspectives.filter(ap => ap.name === target["frame"])[0];
subType = "altTarget";
perspectiveType = alternate.type;
perspectiveOn = primary.name;
}
// grammar info
let syntax = sentenceData["syntax"][tokenIdx][0];
let grammarInfo = getGrammarInfo(syntax);
// FEs
let roles = [];
target["roles"].forEach(role => {
let roleName = role[0];
let roleSpanIdx = role[1]["tokens_idx"];
let roleSpanTxt = role[1]["tokens_str"].join(" ");
roles.push({
"name": roleName,
"spanIdx": roleSpanIdx,
"spanTxt": roleSpanTxt,
"spanTxtClipped": roleSpanTxt.length > 50 ? roleSpanTxt.substring(0, 50) + "...": roleSpanTxt
})
});
console.log(roles);
textParts.push({
"text": token,
"type": "target",
"subType": subType,
"frame": target["frame"],
"perspectiveType": perspectiveType,
"perspectiveOn": perspectiveOn,
"grammarInfo": grammarInfo,
"roles": roles
});
}
});
this.analyzedSentences.push({
"text": sentenceData["sentence"].join(" "),
"textParts": textParts,
"relevantTargets": textParts.filter(tp => (tp.type === "target" && tp.subType !== "otherTarget"))
});
console.log(this.analyzedSentences);
this.analyzingTextBusy = false;
});
});
},
showTextExample() {
this.analysisLanguage = "en";
this.textToAnalyze = this.eventTypeTextExample;
}
},
delimiters: ['@{', '}']
}
/* HELPER FUNCTIONS */
function getFrameInfo(frm, successCallback, failureCallback) {
$.get("frame_info", { "frame": frm }).done((data) => {
if (data["result"] !== "OK") {
failureCallback();
return;
}
let descriptionClipped = clipFrameDescription(data["frameDefinition"]);
let url = "https://framenet2.icsi.berkeley.edu/fnReports/data/frameIndex.xml?frame=" + frm;
descriptionClipped += ' <a href="' + url + '">(read more)</a>';
let sampledExemplars = sampleExemplars(data["exemplars"]);
let exemplarsClipped = clipExemplars(sampledExemplars);
let frameInfo = {
"description": descriptionClipped,
"exemplars": exemplarsClipped,
"altPerspectives": data["altPerspectives"],
"typicalExemplar": data["typicalExemplar"]
};
successCallback(frameInfo);
})
}
function clipFrameDescription(descriptionParts) {
console.log(descriptionParts);
let descriptionClipped = "";
for (let i = 0; i < descriptionParts.length; i++) {
let remainingLength = 300 - descriptionClipped.length;
if (remainingLength >= 0) {
let newPart = descriptionParts[i];
if (newPart.length > remainingLength) {
descriptionClipped += newPart.substring(0, remainingLength) + "...";
} else {
descriptionClipped += newPart;
}
}
}
return descriptionClipped;
}
function sampleExemplars(exemplars) {
let sampledExemplars = [];
let sampleSize = Math.min(10, exemplars.length);
for (let i = 0; i < sampleSize; i++) {
let filteredExemplars = exemplars.filter(((ex) => !sampledExemplars.includes(ex)));
let randIdx = Math.floor(Math.random() * filteredExemplars.length);
sampledExemplars.push(filteredExemplars[randIdx]);
}
return sampledExemplars;
}
function clipExemplars(exemplars) {
// clip exemplars to show the target + some context before and after
return exemplars.map((ex) => {
// target +/- N characters
const maxContextChars = 35;
let tgtStartIdx = ex["target_idx"][0];
let fragmentStartIdx = Math.max(0, tgtStartIdx - maxContextChars);
let tgtEndIdx = ex["target_idx"][1];
let fragmentEndIdx = Math.min(ex["text"].length, tgtEndIdx + maxContextChars);
// adjust for word boundaries
let textWithCapitalizedTarget =
ex["text"].substring(0, tgtStartIdx) +
ex["text"].substring(tgtStartIdx, tgtEndIdx).toUpperCase() +
ex["text"].substring(tgtEndIdx, ex["text"].length);
;
let clippedText = textWithCapitalizedTarget.split(" ").filter((_, idx, arr) => {
let prevChars = arr.slice(0, idx).join(" ").length;
if (prevChars >= fragmentStartIdx && prevChars <= fragmentEndIdx) {
return true;
} else {
return false;
}
}).join(" ");
return { "text": clippedText };
})
}
function getGrammarInfo(syntax) {
let grammarInfo = "other";
if (syntax["syn_category"].startsWith("v:")) {
switch (syntax["syn_construction"]) {
case "verbal:active":
grammarInfo = "active";
break;
case "verbal:passive":
grammarInfo = "passive";
break;
case "verbal:unaccusative":
grammarInfo = "intransitive";
break;
case "verbal:impersonal":
grammarInfo = "impersonal";
break;
case "verbal:reflexive":
grammarInfo = "reflexive";
break;
}
} else if (syntax["syn_category"] == "n") {
grammarInfo = "noun";
} else if (syntax["syn_category"] == "adj") {
grammarInfo = "adjective";
}
return grammarInfo;
}
/* MAIN LOOP */
Vue.createApp(SocioFillmoreDemo).mount("#sociofillmore-demo");