// get css
importStylesheet("User:Anpang01/Wikipe-tan_Chatbox.css");
// add box
const wptcGreeting = "👋 Hello! What would you like me to help with?";
$("body").append(`
<div class="wptc-box" id="wptc-box">
<div>
<img src="https://upload.wikimedia.org/wikipedia/commons/a/ac/Wikipe-tan_head.png" class="wptc-image" />
<span class="wptc-name">Wikipe-tan</span>
<a href="#" class="wptc-close" id="wptc-close">×</a>
</div>
<div class="wptc-inner-box">
<div>
<div id="wptc-bubbles">
<div class="wptc-bubble-left">
<span>${wptcGreeting}</span>
</div>
</div>
<input type="text" class="wptc-input" id="wptc-input" />
</div>
</div>
<span class="wptc-bottom-links">
 
<a href="https://en.wikipedia.org/wiki/User:Anpang01/Wikipe-tan_Chatbox">JS script</a>
 
<a href="https://en.wikipedia.org/wiki/Wikipedia:Wikipe-tan">Based on Wikipe-tan</a>
 
</span>
</div>
`);
// close box handler
$("#wptc-close").on("click", function() {
$("#wptc-box").hide();
});
// conversation data
const wptcConvers = [
[
"Hello!",
"Hello {username}! What would you like me to help with?",
"Nothing, actually.",
"Okay, I'll just stay here in case you need my help."
],
[
"What skin does Wikipedia use?",
"Wikipedia uses the Vector skin, and this page uses the {skin} skin."
],
[
"What skin am I using?",
"You are using the {skin} skin."
],
[
"What is the name of this website?",
"This is the English {sitename}."
]
];
const wptcDontKnow = [
"Sorry, I couldn't understand you.",
"Sorry, what do you mean by that?",
"Sorry {username}, I couldn't understand that."
];
const wptcVariables = {
"username": mw.config.get("wgUserName"),
"skin": `${mw.config.get("skin")[0].toUpperCase()}${mw.config.get("skin").slice(1)}`.replace("-", " "),
"sitename": mw.config.get("wgSiteName")
}
// helper functions
function wptcRandomElement(array) {
return array[Math.floor(Math.random() * array.length)];
}
// from https://github.com/saniales/gestalt-pattern-matcher/blob/master/index.ts
function wptcGestaltSimilarity(first, second) {
let stack = [first, second];
let score = 0;
while(stack.length != 0) {
const first_sub_string = stack.pop();
const second_sub_string = stack.pop();
let longest_sequence_length = 0;
let longest_sequence_index_1 = -1;
let longest_sequence_index_2 = -1;
for(let i = 0; i < first_sub_string.length; i++) {
for(let j = 0; j < second_sub_string.length; j++) {
let k = 0;
while(i+k < first_sub_string.length && j+k < second_sub_string.length && first_sub_string.charAt(i+k) === second_sub_string.charAt(j+k)) {
k++;
}
if(k > longest_sequence_length) {
longest_sequence_length = k;
longest_sequence_index_1 = i;
longest_sequence_index_2 = j;
}
}
}
if(longest_sequence_length > 0) {
score += longest_sequence_length * 2;
if(longest_sequence_index_1 !== 0 && longest_sequence_index_2 !== 0) {
stack.push(first_sub_string.substring(0, longest_sequence_index_1));
stack.push(second_sub_string.substring(0, longest_sequence_index_2));
}
if(longest_sequence_index_1 + longest_sequence_length !== first_sub_string.length &&
longest_sequence_index_2 + longest_sequence_length !== second_sub_string.length) {
stack.push(first_sub_string.substring(longest_sequence_index_1 + longest_sequence_length, first_sub_string.length));
stack.push(second_sub_string.substring(longest_sequence_index_2 + longest_sequence_length, second_sub_string.length));
}
}
}
return score / (first.length + second.length);
}
// get response
function wptcGetResponse(input) {
contenders = [];
highestScore = 0;
for(const conver of wptcConvers) {
for(const [index, message] of conver.entries()) {
score = wptcGestaltSimilarity(message, input);
if(conver.length == (index + 1)) {
continue;
}
nextMessage = conver[index + 1];
if(score > highestScore) {
contenders = [nextMessage];
highestScore = score;
} else if(score == highestScore) {
contenders.push(nextMessage);
}
}
}
let response = wptcRandomElement(highestScore < 0.3? wptcDontKnow: contenders);
for(const [name, value] of Object.entries(wptcVariables)) {
response = response.replace(`{${name}}`, value);
}
return response;
}
// submit handler
$("#wptc-input").keypress(function(key) {
if(key.which === 13) { // is enter key
// get and clear input
let input = $("#wptc-input").val();
$("#wptc-input").val("");
// do stuff
$("#wptc-bubbles").append(`
<div class="wptc-bubble-right">
<span>${input}</span>
</div>
<div class="wptc-bubble-left">
<span>${wptcGetResponse(input)}</span>
</div>
`);
}
});