Jump to content

User:Sophivorus/chatbot.js

From Appropedia

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
const Chatbot = {

	init() {
		const mainPage = mw.config.get( 'wgIsMainPage' );
		if ( !mainPage ) {
			return;
		}
		const action = mw.config.get( 'wgAction' );
		if ( action !== 'view' ) {
			return;
		}
		Chatbot.addIcon();
	},

	addIcon() {
		const $chatbot = $( '<div id="appropedia-chatbot"></div>' );
		const $icon = $( '<svg id="appropedia-chatbot-icon" xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 122.88 119.35" transform="scale(-1,1)"><path d="M57.49,29.2V23.53a14.41,14.41,0,0,1-2-.93A12.18,12.18,0,0,1,50.44,7.5a12.39,12.39,0,0,1,2.64-3.95A12.21,12.21,0,0,1,57,.92,12,12,0,0,1,61.66,0,12.14,12.14,0,0,1,72.88,7.5a12.14,12.14,0,0,1,0,9.27,12.08,12.08,0,0,1-2.64,3.94l-.06.06a12.74,12.74,0,0,1-2.36,1.83,11.26,11.26,0,0,1-2,.93V29.2H94.3a15.47,15.47,0,0,1,15.42,15.43v2.29H115a7.93,7.93,0,0,1,7.9,7.91V73.2A7.93,7.93,0,0,1,115,81.11h-5.25v2.07A15.48,15.48,0,0,1,94.3,98.61H55.23L31.81,118.72a2.58,2.58,0,0,1-3.65-.29,2.63,2.63,0,0,1-.63-1.85l1.25-18h-.21A15.45,15.45,0,0,1,13.16,83.18V81.11H7.91A7.93,7.93,0,0,1,0,73.2V54.83a7.93,7.93,0,0,1,7.9-7.91h5.26v-2.3A15.45,15.45,0,0,1,28.57,29.2H57.49ZM82.74,47.32a9.36,9.36,0,1,1-9.36,9.36,9.36,9.36,0,0,1,9.36-9.36Zm-42.58,0a9.36,9.36,0,1,1-9.36,9.36,9.36,9.36,0,0,1,9.36-9.36Zm6.38,31.36a2.28,2.28,0,0,1-.38-.38,2.18,2.18,0,0,1-.52-1.36,2.21,2.21,0,0,1,.46-1.39,2.4,2.4,0,0,1,.39-.39,3.22,3.22,0,0,1,3.88-.08A22.36,22.36,0,0,0,56,78.32a14.86,14.86,0,0,0,5.47,1A16.18,16.18,0,0,0,67,78.22,25.39,25.39,0,0,0,72.75,75a3.24,3.24,0,0,1,3.89.18,3,3,0,0,1,.37.41,2.22,2.22,0,0,1,.42,1.4,2.33,2.33,0,0,1-.58,1.35,2.29,2.29,0,0,1-.43.38,30.59,30.59,0,0,1-7.33,4,22.28,22.28,0,0,1-7.53,1.43A21.22,21.22,0,0,1,54,82.87a27.78,27.78,0,0,1-7.41-4.16l0,0ZM94.29,34.4H28.57A10.26,10.26,0,0,0,18.35,44.63V83.18A10.26,10.26,0,0,0,28.57,93.41h3.17a2.61,2.61,0,0,1,2.41,2.77l-1,14.58L52.45,94.15a2.56,2.56,0,0,1,1.83-.75h40a10.26,10.26,0,0,0,10.22-10.23V44.62A10.24,10.24,0,0,0,94.29,34.4Z"/></svg>' );
		$icon.on( 'click', Chatbot.openChat );
		$chatbot.append( $icon );
		const chatbot = $chatbot[0];
		document.body.append( chatbot );
	},

	openChat() {
		mw.loader.using( '@wikimedia/codex' ).then( require => {
			const Vue = require( 'vue' );
			const Codex = require( '@wikimedia/codex' );
			const app = Vue.createMwApp( Chatbot.chatComponent );
			app.component( 'cdx-text-input', Codex.CdxTextInput );
			const chatbot = this.parentElement;
			app.mount( chatbot );
		} );
	},

	chatComponent: {

		template: `
			<div id="appropedia-chatbot-chat">
				<div id="appropedia-chatbot-history" v-if="history.length">
					<div v-for="item in history" :class="item.type" v-html="item.text"></div>
				</div>
				<cdx-text-input id="appropedia-chatbot-input" v-model="input.value" :disabled="input.disabled" :placeholder="input.placeholder" @keydown="onKeydown"></cdx-text-input>
				<div id="appropedia-chatbot-footer">
					<a href="/Appropedia:Village_pump">Leave feedback</a>
				</div>
			</div>
		`,

		data() {
			return {
				input: {
					value: '',
					placeholder: 'Ask Appropedia...',
					disabled: false
				},
				history: [],
				session: null,
			};
		},

		methods: {

			onKeydown( event ) {
				if ( event.key === 'Enter' ) {
					this.send();
				}
			},

			async send() {
				const value = this.input.value;

				// Update the interface
				const inputItem = { type: 'input', text: value };
				this.history.push( inputItem );
				this.input.placeholder = 'Thinking...';
				this.input.value = '';
				this.input.disabled = true;

				// Fetch the response
				const body = {
					message: value,
					source_mode: 'none',
					sources: [ 'appropedia' ],
					session_id: this.session
				};
				const response = await fetch( 'https://disaster-clippy.up.railway.app/api/v1/chat', {
					method: 'POST',
					headers: { 'Content-Type': 'application/json' },
					body: JSON.stringify( body )
				} );
				const data = await response.json();
				let text = data.response;
				text = text.replace( /\[(.*?)\]\((.*?)\)/g, '<a href="$2">$1</a>' );
				text = text.replace( /\*\*(.*?)\*\*/g, '<em>$1</em>' );
				text = text.replace( /\n/g, '<br>' );

				// Save the session
				this.session = data.session_id;

				// Update the interface
				const outputItem = { type: 'output', text: text };
				this.history.push( outputItem );
				this.input.disabled = false;
				this.input.placeholder = 'Ask Appropedia...';
			}
		},

		updated() {
			const history = document.getElementById( 'appropedia-chatbot-history' );
			history.scrollTop = history.scrollHeight;

			const input = document.getElementById( 'appropedia-chatbot-input' );
			input.focus();
		}
	}
};

mw.hook( 'wikipage.content' ).add( Chatbot.init );
Cookies help us deliver our services. By using our services, you agree to our use of cookies.