User:Anpang/Wikipe-tan Chatbox.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
This user script seems to have a documentation page at User:Anpang/Wikipe-tan Chatbox and an accompanying .css page at User:Anpang/Wikipe-tan Chatbox.css. |
// 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>
`);
}
});