ব্যবহারকারী:খাত্তাব হাসান/উইকিচ্যাটবট.js

লক্ষ্য করুন: প্রকাশ করার পর, পরিবর্তনগুলো দেখতে আপনাকে আপনার ব্রাউজারের ক্যাশে পরিষ্কার করার প্রয়োজন হতে পারে।

  • ফায়ারফক্স / সাফারি: পুনরায় লোড-এ ক্লিক করার সময় শিফট টিপে ধরে রাখুন, অথবা হয় Ctrl-F5 বা Ctrl-R টিপুন (ম্যাকে ⌘-R টিপুন)
  • গুগল ক্রোম: Ctrl-Shift-R (ম্যাকে ⌘-Shift-R) টিপুন
  • এজ: Ctrl ধরে রাখা অবস্থায় Refresh-এ ক্লিক করুন, অথবা Ctrl-F5 টিপুন।
  • অপেরা: Ctrl-F5 টিপুন।
// মূল স্ক্রিপ্টটি [[en:Special:diff/1235505388]] হতে আহরিত। লেখক: Phlsph7

(function(){
	// Value for the advanced model checkbox
	if(localStorage.getItem('WikiChatbotAdvancedModel') === null){
		// Set it to true for new users.
		if(localStorage.getItem('WikiChatbotAPIKey') === null){
			localStorage.setItem('WikiChatbotAdvancedModel', true);
		}
		// Set it to false for current users. They have to activate it manually
		else {
			localStorage.setItem('WikiChatbotAdvancedModel', false);
		}
	}
	
	// define values
	let tokenLimit;
	let model;
	if(localStorage.getItem('WikiChatbotAdvancedModel')){
		tokenLimit = 128000;
		model = 'gpt-4o';
	}
	else {
		tokenLimit = 4096;
		model = 'gpt-3.5-turbo';
	}
	
	const temperature = 0.5;
	const charLimit = function(){ return tokenLimit * 5; }; // rough estimate
	const articleContextLimit = function(){ return charLimit() * 0.1;};
	const historyLimit = function(){ return charLimit() * 0.2;};
	const selectionLimit = function(){ return charLimit() * 0.25;};
	const promptLimit = function(){ return charLimit() * 0.25;};
	const backgroundColor = '#def';
	const backgroundColorUser = '#ddd';
	const backgroundColorBot = '#dfd';
	const backgroundColorError = '#faa';
	const messages = getInitialMessages();

	// declare for later references
	const bodyContent = document.getElementById('bodyContent');
	let controlContainer;
	let reRotateControl;
	let chatContainer;
	let chatLog;
	let chatSend;
	let displayWarningMessage = false;
	
	// restrict script to mainspace, userspace, wikipedia, help, and draftspace
	const namespaceNumber = mw.config.get('wgNamespaceNumber');
	const allowedNamespaces = [0, 2, 4, 12, 118];
	
	if (allowedNamespaces.indexOf(namespaceNumber) != -1) {
		// add a link to the toolbox
		$.when(mw.loader.using('mediawiki.util'), $.ready).then(addPortletAndActivate);
	}

	function getInitialMessages(){
		return [
		{"role":"system", "content": `তুমি একটি উইকি চ্যাটবট। একটি এআই সহায়ক, যে উইকিপিডিয়া সম্পাদকদেরকে উইকিপিডিয়া নিবন্ধ উন্নয়নে সহায়তা করবে। সম্পাদকরা হয়তো সাধারণ একটি প্রশ্ন করবেন অথবা নিবন্ধ থেকে কোনো লেখা নির্বাচিত/সিলেক্ট করে সেটাকে নির্দিষ্ট করে সেখান থেকে কাজ করবে। তোমার প্রতিক্রিয়াগুলিতে প্রসঙ্গ হিসাবে নিবন্ধের শুরু থেকে নিম্নলিখিত অংশগুলি ব্যবহার করো। \n\nContext:"""${getContext()}"""	
		`}];
	}

	function createControlUI(){
		controlContainer = document.createElement('div');
		if(localStorage.getItem('WikiChatbotActivated') === 'true'){
			controlContainer.style.display = 'flex';
		}
		else {
			controlContainer.style.display = 'none';
		}
		bodyContent.appendChild(controlContainer);
		controlContainer.style.position = 'fixed';
		controlContainer.style.right = '10px';
		controlContainer.style.bottom = '10px';
		controlContainer.style.backgroundColor = backgroundColor;
		controlContainer.style.overflowY = 'auto';
		controlContainer.style.padding = '10px';
		controlContainer.style.borderRadius = '10px';
		controlContainer.style.whiteSpace = 'nowrap';
		controlContainer.style.alignItems = 'center';
		controlContainer.style.zIndex = '999';
		controlContainer.style.resize = 'vertical';
		controlContainer.style.maxHeight = '80%';
		controlContainer.style.transform = 'rotateZ(180deg)';
		
		reRotateControl = document.createElement('div');
		controlContainer.appendChild(reRotateControl);
		reRotateControl.style.width = '100%';
		reRotateControl.style.height = '100%';
		reRotateControl.style.overflowY = 'auto';
		reRotateControl.style.transform = 'rotateZ(180deg)';
		reRotateControl.style.display = 'flex';
		reRotateControl.style.flexDirection = 'column';
		
		addButtons();
		
		let currentHeight = controlContainer.clientHeight;
		if(currentHeight > 400){
			controlContainer.style.height = currentHeight + 'px';
		}
		
		function addButtons(){
			addControlButton('অনুলিপি সম্পাদনা', 'নির্বাচিত পাঠ্য কপি সম্পাদনা করুন।', getQueryFunction(charLimit() * 0.5, function(){
				return `নির্বাচিত পাঠ্য অনুলিপি সম্পাদনা করুন:\n\nনির্বাচিত লেখা: """${getSelectedText()}"""`;
			}));

			addControlButton('বানান বা ব্যাকরণ মূল্যায়ন', 'নির্বাচিত পাঠ্যের বানান এবং ব্যাকরণ মূল্যায়ন করুন।', getQueryFunction(charLimit() * 0.5, function(){
				return `নির্বাচিত পাঠ্যের বানান বা ব্যাকরণের সাথে সমস্যা আছে?\n\nনির্বাচিত লেখা:"""${getSelectedText()}"""`;
			}));

			addControlButton('সংস্কার', 'নির্বাচিত লেখাটি ', getQueryFunction(charLimit() * 0.5, function(){
				return `Reformulate the selected text:\n\nনির্বাচিত লেখা: """${getSelectedText()}"""`;
			}));

			addControlButton('সরলীকরণ', 'এটিকে আরও অ্যাক্সেসযোগ্য করতে নির্বাচিত পাঠ্যটিকে সরল করুন।', getQueryFunction(charLimit() * 0.5, function(){
				return `নির্বাচিত পাঠ্যটিকে আরও অ্যাক্সেসযোগ্য করতে সরলীকরণ করো:\n\n লেখা: """${getSelectedText()}"""`;
			}));

			addControlButton('সারসংক্ষেপ', 'নির্বাচিত লেখার সংক্ষেপ করুন', getQueryFunction(charLimit() * 0.5, function(){
				return `নির্বাচিত পাঠ্যের একটি সংক্ষিপ্ত সারাংশ প্রদান করো:\n\nনির্বাচিত লেখা: """${getSelectedText()}"""`;
			}));
			
			addControlButton('ব্যাখ্যা', 'নির্বাচিত পাঠ্যটি সহজ ভাষায় ব্যাখ্যা করুন', getQueryFunction(charLimit() * 0.5, function(){
				return `অনুগ্রহ করে নির্বাচিত পাঠ্যটি সহজ ভাষায় ব্যাখ্যা করো:\n\nনির্বাচিত লেখা: """${getSelectedText()}"""`;
			}));

			addControlButton('উদাহরণ', 'নির্বাচিত পাঠ্যের মূল পয়েন্টটি ব্যাখ্যা করার জন্য একটি উদাহরণ প্রদান করুন।', getQueryFunction(charLimit() * 0.5, function(){
				return `Provide an example to illustrate the main point of the selected text:\n\nনির্বাচিত লেখা: """${getSelectedText()}"""`;
			}));

			addControlButton('সম্প্রসারণের পরামর্শ', 'Suggest ideas how the selected text could be expanded.', getQueryFunction(charLimit() * 0.5, function(){
				displayWarningMessage = true;
				return `Suggest ideas how the selected text could be expanded:\n\nনির্বাচিত লেখা: """${getSelectedText()}"""`;
			}));

			addControlButton('চিত্র পরামর্শ', 'Describe images that could be used to illustrate the selected text.', getQueryFunction(charLimit() * 0.5, function(){
				return `Describe some images that could be used to illustrate the selected text:\n\nনির্বাচিত লেখা: """${getSelectedText()}"""`;
			}));

			addControlButton('উইকিসংযোগ পরামর্শ', 'Suggest terms in the selected text that could get a wikilink to another article.', getQueryFunction(charLimit() * 0.5, function(){
				return `Which terms in the selected text should have a wikilink to another Wikipedia article?\n\nনির্বাচিত লেখা: """${getSelectedText()}"""`;
			}));

			addControlButton('আজাকি প্রশ্ন পরামর্শ', 'Suggest questions for the "Did you know" section on the Wikipedia main page based on the selected text.', getQueryFunction(charLimit() * 0.5, function(){
				return `Suggest Did-you-know questions for the selected text. They should present short facts that are unusual or intriguing to make the reader interested in learning more.\n\nনির্বাচিত লেখা: """${getSelectedText()}"""`;
			}));

			addControlLine();

			addControlButton('বিকল্প নিবন্ধ রূপরেখা', 'Writes a general outline of the topic of this article. Ignores the content of the article and the selected text.', async function(){ // jshint ignore:line
				let userMessageText = `Write a detailed outline for a Wikipedia article on the topic "${getTitle()}".`;
				let customMessages = [{"role":"user","content":userMessageText}];
				logUserMessage(userMessageText);
				await getResponse(customMessages).then(function(){
					setTimeout(function(){
						if(customMessages.length > 1){
							messages.push(customMessages[0]);
							messages.push(customMessages[1]);
						}
					}, 100);
				});
			});		

			addControlLine();
			
			addAdvancedModelCheckbox();

			addControlButton('এপিআই কী সেটিংস', 'Enter the OpenAI API key required for usage', function(){
				let currentAPIKey = localStorage.getItem('WikiChatbotAPIKey');
				if(currentAPIKey === 'null' || currentAPIKey === null){
					currentAPIKey = '';
				}
				
				let input = prompt('অনুগ্রহ করে আপনার OpenAI API কীটি লিখুন। এটি "sk-..." দিয়ে শুরু হয়। এটি আপনার ডিভাইসে স্থানীয়ভাবে সংরক্ষণ করা হবে। এটি কারো সাথে শেয়ার করা হবে না এবং শুধুমাত্র OpenAI-তে আপনার প্রশ্নের জন্য ব্যবহার করা হবে। আপনার API কী মুছে ফেলতে, এই ক্ষেত্রটি খালি রেখে [ঠিক আছে/ওকে] টিপুন।', currentAPIKey);
				
				// check that the cancel-button was not pressed
				if(input !== null){
					localStorage.setItem('WikiChatbotAPIKey', input);
				}
			});
		}
		
		function addControlButton(heading, tooltip, clickFunction){
			let button = document.createElement('button');
			reRotateControl.appendChild(button);
			button.style.width = '100%';
			button.style.marginTop = '5px';
			button.style.marginBottom = '5px';
			button.style.borderRadius = '5px';
			button.style.border = '1px solid black';
			button.style.textAlign = 'left';
			button.innerHTML = heading;
			button.title = tooltip;
			button.onclick = clickFunction;
		}

		function addControlLine(){
			const borderLine = document.createElement('div');
			reRotateControl.appendChild(borderLine);
			borderLine.style.width = '100%';
			borderLine.style.marginTop = '5px';
			borderLine.style.marginBottom = '5px';
			borderLine.style.borderBottom = '1px solid grey';
		}
		
		function getQueryFunction(selectedTextLimit, promptFunction){
			return function(){
				let selectedText = getSelectedText();
				if(selectedText.length < 1){
					logErrorMessage("কোন পাঠ্য নির্বাচন করা হয়নি। প্রথমে একটি পাঠ্য নির্বাচন করতে মাউস ব্যবহার করুন।");
				}
				else if(selectedText.length > selectedTextLimit){
					logErrorMessage(`নির্বাচিত পাঠ্য খুবই বড়: ${selectedText.length} characters were selected but the limit is ${selectedTextLimit} characters.`);
				}
				else{
					const promptText = promptFunction();
					clearHistory(messages);
					messages.push(createUserMessage(promptText));
					logUserMessage(promptText);
					getResponse(messages);
				}
			};
		}
		
		function addAdvancedModelCheckbox(){
			const div = document.createElement('div');
			reRotateControl.appendChild(div);
			div.style.width = '100%';
			
			const checkbox = document.createElement('input');
			div.appendChild(checkbox);
			checkbox.type = 'checkbox';
			checkbox.id = 'advancedModelCheckbox';
			checkbox.style.margin = '5px';
			checkbox.checked = localStorage.getItem('WikiChatbotAdvancedModel') === 'true';
			checkbox.onchange = function(){
				if(checkbox.checked){
					localStorage.setItem('WikiChatbotAdvancedModel', true);
					tokenLimit = 128000;
					model = 'gpt-4o';
				}
				else{
					localStorage.setItem('WikiChatbotAdvancedModel', false);
					tokenLimit = 4096;
					model = 'gpt-3.5-turbo';
				}
			};
			
			const label = document.createElement('label');
			div.appendChild(label);
			label.for = 'advancedModelCheckbox';
			label.innerHTML = 'উন্নত এআই মডেল ব্যবহার করুন';
			label.title = 'জিপিটি-৩.৫ টার্বোর পরিবর্তে জিপিটি-৪ও ব্যবহার করে। ভাল প্রতিক্রিয়া দেয় কিন্তু আরো ব্যয়বহুল।';
			label.style.fontSize = 'small';
		}
	}

	function createChatUI(){
		chatContainer = document.createElement('div');
		if(localStorage.getItem('WikiChatbotActivated') === 'true'){
			chatContainer.style.display = '';
		}
		else {
			chatContainer.style.display = 'none';
		}
		bodyContent.appendChild(chatContainer);
		chatContainer.style.position = 'fixed';
		chatContainer.style.bottom = '10px';
		chatContainer.style.left = '10px';
		chatContainer.style.width = '50%';
		chatContainer.style.height = '40%';
		chatContainer.style.backgroundColor = backgroundColor;
		chatContainer.style.resize = 'both';
		chatContainer.style.overflow = 'auto';
		chatContainer.style.transform = 'rotateX(180deg)';
		chatContainer.style.padding = '5px';
		chatContainer.style.borderRadius = '10px';
		chatContainer.style.zIndex = '999';

		const reRotateChat = document.createElement('div');
		chatContainer.appendChild(reRotateChat);
		reRotateChat.style.width = '100%';
		reRotateChat.style.height = '100%';
		reRotateChat.style.overflow = 'auto';
		reRotateChat.style.transform = 'rotateX(180deg)';
		reRotateChat.style.display = 'flex';
		reRotateChat.style.flexDirection = 'column';

		chatLog = document.createElement('div');
		reRotateChat.appendChild(chatLog);
		chatLog.style.width = '100%';
		chatLog.style.overflow = 'auto';
		chatLog.style.flex = 1;
		chatLog.style.marginBottom = '5px';

		const chatResponse = document.createElement('div');
		reRotateChat.appendChild(chatResponse);
		chatResponse.style.width = '100%';
		chatResponse.style.height = '45px';
		chatResponse.style.display = 'flex';

		const chatTextarea = document.createElement('textarea');
		chatResponse.appendChild(chatTextarea);
		chatTextarea.style.flexGrow = '1';
		chatTextarea.style.backgroundColor = backgroundColorUser;
		chatTextarea.style.resize = 'none';
		chatTextarea.style.marginRight = '10px';
		chatTextarea.style.borderRadius = '5px';
		chatTextarea.style.padding = '5px';
		chatTextarea.placeholder = 'এখানে আপনার প্রশ্ন বা কমান্ড দিন...';
		chatTextarea.title = 'যদি পাঠ্য নির্বাচন করা হয়, আপনি আপনার প্রশ্ন/কমান্ডে এটিকে "নির্বাচিত পাঠ্য" হিসাবে উল্লেখ করতে পারেন';
		chatTextarea.onkeydown = function(event){
			if (event.key === 'Enter' && !event.shiftKey){
				event.preventDefault();
				chatSend.click();
			}
		};
		
		// store selected text before focus is lost.
		let storedSelection = '';
		chatTextarea.onmousedown = function(){
			storedSelection = getSelectedText();
		};

		chatSend = document.createElement('button');
		chatResponse.appendChild(chatSend);
		chatSend.innerHTML = 'পাঠান';
		chatSend.style.height = '100%';
		chatSend.style.borderRadius = '5px';
		chatSend.style.border = '1px solid black';
		chatSend.title = 'আপনার কমান্ড/প্রশ্ন প্রেরণ করুন';

		chatSend.onclick = function(){
			let promptText = chatTextarea.value;
			let promptLength = promptText.length;
			
			let selectedText = storedSelection;
			storedSelection = '';
			let selectedLength = storedSelection.length;
			if(promptLength > promptLimit()){
				logErrorMessage(`The prompt text was too long: ${promptLength} characters were entered but the limit is ${promptLimit()} characters.`);
			}
			else if(selectedLength > selectionLimit()){
				logErrorMessage(`The selected text was too long: ${selectedText.length} characters were selected but the limit is ${selectionLimit()} characters.`);
			}
			else {
				chatTextarea.value = '';
				if(selectedText.length > 0){
					promptText += '\n\n(The user selected the following text. Please consider it in your response if it is relevant.)\n\nনির্বাচিত লেখা:"""' + selectedText + '"""';
				}
				imposeHistoryLimit(messages);
				messages.push(createUserMessage(promptText));
				logUserMessage(promptText);
				getResponse(messages);
			}
		};
	}

	async function getResponse(messages){ // jshint ignore:line
		disableButtons();
		
		const url = "https://api.openai.com/v1/chat/completions";
		const body = JSON.stringify({
			"messages": messages,
			"model": model,
			"temperature": temperature,
		});
		const headers = {
			"content-type": "application/json",
			Authorization: "Bearer " + localStorage.getItem('WikiChatbotAPIKey'),
		};
		const init = {
			method: "POST",
			body: body,
			headers: headers
		};
		
		await fetch(url, init).then(function(response){
			enableButtons();
			if(response.ok){
				response.json().then(function(json){
					const message = json.choices[0].message;
					messages.push(message);
					let logText = message.content;
					if(displayWarningMessage){
						displayWarningMessage = false;
						logText = "(Please consult reliable sources to verify the following information)\n" +  logText;
					}
					
					logBotMessage(logText);
				});
			}
			else {
				if(response.status == 400){
					logErrorMessage(composeErrorMessage(400, 'Selecting too much text or writing a very long request can cause this error.'));
				}
				else if(response.status == 401){
					logErrorMessage(composeErrorMessage(401, 'This indicates that no API key was entered or that the entered API key is incorrect.'));
				}
				else if(response.status == 429){
					logErrorMessage(composeErrorMessage(429, 'This indicates that you have sent requests too quickly or that you have reached your monthly limit.'));
				}
				else {
					logErrorMessage(response.status, `You can try to use google and search for "OpenAI API error ${response.status}" to learn more about this error.`);
				}
			}
		});
		
		function composeErrorMessage(errorCode, additionalMessage){
			return `The error code is ${errorCode}. ${additionalMessage}`;
		}
	}
	
	function disableButtons(){
		chatSend.disabled = true;
		let controlButtons = reRotateControl.getElementsByTagName('button');
		for(let controlButton of controlButtons){
			controlButton.disabled = true;
		}
	}
	
	function enableButtons(){
		chatSend.disabled = false;
		let controlButtons = reRotateControl.getElementsByTagName('button');
		for(let controlButton of controlButtons){
			controlButton.disabled = false;
		}
	}
	
	// transform the article text into an object sorted into section titles and section contents
	function articleToObject(){
		const articleObject = {sectionTitles: ['Lead'], sectionContents: ['']};
		const articleContentClone = document.getElementById('mw-content-text').children[0].cloneNode(true);
		
		// avoid images, tables, various templates, and the like
		const allowedElements = 'p, h2, h3, h4, h5, h6, h7, h8, ul, ol'.split(', ');
		
		// remove disallowed elements
		const originalChildArray = Array.from(articleContentClone.children);
		for(let child of originalChildArray){
			if (!allowedElements.includes(child.tagName.toLowerCase())){
				if(!child.classList.contains('mw-heading')){ // fix for changed headings
					articleContentClone.removeChild(child);
				}
			}
		}
		
		removeReferencesAndInlineTemplates(articleContentClone);
		replaceMathFormulas(articleContentClone);
		
		// go through the article element by element & sort them into section title and section contents
		let index = 0;
		const modifiedChildArray = Array.from(articleContentClone.children);
		for(let child of modifiedChildArray){
			if(child.classList.contains('mw-heading2')){
				let innerText = child.innerText;
				let title = innerText.substring(0, innerText.length-6);
				articleObject.sectionTitles.push(title);
				index++;
				articleObject.sectionContents[index] = '';
			}
			else{
				articleObject.sectionContents[index] += child.innerText + '\n\n';
			}
		}
		
		console.log(articleObject);
		return articleObject;
		
		function removeReferencesAndInlineTemplates(element){
			let refs = element.querySelectorAll('.reference, .Inline-Template');
			
			for(let ref of refs){
				ref.outerHTML = '';
			}
		}
		
		function replaceMathFormulas(element){
			let formulas = element.querySelectorAll('.mwe-math-element');
			for(let formula of formulas){
				formula.outerHTML = '<span>[MATHEMATICAL FORMULA]</span>';
			}
		}
	}

	// get context from the article so that the chatbot is aware of the text (mainly lead) of the article
	function getContext(){
		const articleObject = articleToObject();
		
		// add lead to context
		let context = articleObject.sectionContents[0];
		
		// if the lead is too short, add the next section as well
		if(context.length < 1500 && articleObject.sectionContents.length > 1){
			context += '\n\n' + articleObject.sectionTitles[1] + '\n\n' + articleObject.sectionContents[1];
		}
		
		// shorten if the context gets too long
		context = context.substring(0, articleContextLimit());
		return context;
	}

	function getSelectedText(){
		hideRefs();
		let selectedText = window.getSelection().toString();
		showRefs();
		return selectedText;
	}

	function hideRefs(){
		let refs = document.body.querySelectorAll('.reference, .Inline-Template');
		for(let ref of refs){
			ref.style.display = 'none';
		}
	}

	function showRefs(){
		let refs = document.body.querySelectorAll('.reference, .Inline-Template');
		for(let ref of refs){
			ref.style.display = '';
		}
	}

	function createUserMessage(promptText){
		return {"role":"user","content": promptText};
	}

	function imposeHistoryLimit(messages){
		while(getMessagesLength(messages) > historyLimit()){
			if(messages.length <= 1){
				break;
			}
			messages.splice(1, 1);
		}
	}

	function clearHistory(messages){
		while(messages.length > 1){
			messages.pop();
		}
	}

	function getMessagesLength(messages){
		let totalLength = 0;
		for(let message of messages){
			totalLength += message.content.length;
		}
		return totalLength;
	}

	function logBotMessage(text){
		logMessage("চ্যাটজিপিটি: " + text, backgroundColorBot, '0.1em', '1em');
	}

	function logUserMessage(text){
		logMessage("User: " + text, backgroundColorUser, '1em', '0.1em');
	}

	function logErrorMessage(text){
		logMessage("Error: " + text, backgroundColorError, '0.1em', '0.1em');
	}
		
	function logMessage(text, backgroundColor, marginLeft, marginRight){
		let pre = document.createElement('pre');
		pre.innerHTML = text;
		pre.style.backgroundColor = backgroundColor;
		pre.style.margin = '0.2em';
		pre.style.padding = '0.2em';
		pre.style.marginRight = marginRight;
		pre.style.marginLeft = marginLeft;
		pre.style.borderRadius = '5px';
		pre.style.fontFamily = 'sans-serif';
		chatLog.appendChild(pre);
		pre.scrollIntoView();
	}

	function getTitle(){
		let innerText = document.getElementById('firstHeading').innerText;
		if(innerText.substring(0, 8) === 'Editing '){
			innerText = innerText.substring(8);
		}
		if(innerText.substring(0, 6) === 'Draft:'){
			innerText = innerText.substring(6);
		}
		if(innerText.includes('User:')){
			let parts = innerText.split('/');
			parts.shift();
			innerText = parts.join('/');
		}
		return innerText;
	}

	function addPortletAndActivate(){
		// portlet link to activate
		const portletlinkActivate = mw.util.addPortletLink('p-tb', '#', 'উইকিচ্যাটবট চালু', 'portletlinkActivateId');
		portletlinkActivate.onclick = function(e) {
			e.preventDefault();
			activate();
		};
		
		// portlet link to deactivate
		const portletlinkDeactivate = mw.util.addPortletLink('p-tb', '#', 'উইকিচ্যাটবট বন্ধ', 'portletlinkDeactivateId');
		portletlinkDeactivate.onclick = function(e) {
			e.preventDefault();
			deactivate();
		};
		
		if(localStorage.getItem('WikiChatbotActivated') === null){
			localStorage.setItem('WikiChatbotActivated', 'false');
		}
		
		if(localStorage.getItem('WikiChatbotActivated') === 'true'){
			activate();
		}
		
		else{
			deactivate();
		}

		function activate(){
			localStorage.setItem('WikiChatbotActivated', 'true');
			mw.util.hidePortlet('portletlinkActivateId');
			mw.util.showPortlet('portletlinkDeactivateId');
			if(typeof controlContainer === 'undefined'){
				createControlUI();
				createChatUI();
				logBotMessage('অনুগ্রহ করে আপনি যে বাক্যটিতে কাজ করতে চান সেটি নির্বাচন করুন এবং ডানদিকের বাটনগুলি ব্যবহার করুন বা নীচে আপনার প্রশ্ন বা কমান্ড লিখুন৷ (নিবন্ধে পরিবর্তন করার আগে আমার সমস্ত প্রতিক্রিয়া যাচাই করে দেখে নিন। আরও তথ্যের জন্য <a href="https://bn.wiki.x.io/wiki/Wikipedia:Large_language_models">WP:LLM</a> দেখুন।)');
			}
			
			controlContainer.style.display = '';
			chatContainer.style.display = '';
			
		}

		function deactivate(){
			localStorage.setItem('WikiChatbotActivated', 'false');
			mw.util.hidePortlet('portletlinkDeactivateId');
			mw.util.showPortlet('portletlinkActivateId');
			controlContainer.style.display = 'none';
			chatContainer.style.display = 'none';
		}
	}
})();