From 1831f9a500429d01a431b83ac7a5366653712fd8 Mon Sep 17 00:00:00 2001 From: Edward Chernenko Date: Sat, 7 Dec 2024 05:17:24 +0300 Subject: [PATCH] Add JavaScript that submits the form to Special:AI and shows the result --- extension.json | 3 +++ i18n/en.json | 2 ++ i18n/qqq.json | 4 +++- includes/Service/OpenAI.php | 2 +- includes/SpecialAI.php | 23 ++++++++++++----------- modules/ext.askai.js | 29 +++++++++++++++++++++++++++++ 6 files changed, 50 insertions(+), 13 deletions(-) create mode 100644 modules/ext.askai.js diff --git a/extension.json b/extension.json index c3503df..da21ef5 100644 --- a/extension.json +++ b/extension.json @@ -54,6 +54,9 @@ "targets": [ "desktop", "mobile" + ], + "messages": [ + "askai-submit-failed" ] } }, diff --git a/i18n/en.json b/i18n/en.json index b90091c..68f0dd9 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -14,7 +14,9 @@ "askai-field-pages": "List of wiki pages (and paragraphs in them) to be analyzed by the AI:", "askai-field-prompt": "Question to ask:", "askai-field-response": "Response from the AI:", + "askai-openai-failed": "Failed to contact OpenAI: $1", "askai-openai-not-configured": "Error: OpenAI not configured: apiKey, apiUrl or model are not set.", + "askai-submit-failed": "HTTP error when submitting the form: $1", "askai-unknown-service": "Not configured: incorrect value of $wgAskAIServiceClass.", "right-askai": "Send queries to Special:AI." } diff --git a/i18n/qqq.json b/i18n/qqq.json index ecdfe15..deda493 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -14,7 +14,9 @@ "askai-field-pages": "Label of field for the list of pages/paragraphs.", "askai-field-prompt": "Label of field for a question to the AI.:", "askai-field-response": "Label of readonly field that will show the response from the AI.", + "askai-openai-failed": "Error message if HTTP request to OpenAI resulted in an error.", "askai-openai-not-configured": "Error message if OpenAI API key, etc. are not configured.", + "askai-submit-failed": "Error message if HTTP POST request to Special:AI resulted in an error.", "askai-unknown-service": "Error message if failed to create an AI service.", - "right-askai": "{{doc-right|askai}}\nAllows to use Special:AI.", + "right-askai": "{{doc-right|askai}}\nAllows to use Special:AI." } diff --git a/includes/Service/OpenAI.php b/includes/Service/OpenAI.php index 2a9e65d..3c5a4d1 100644 --- a/includes/Service/OpenAI.php +++ b/includes/Service/OpenAI.php @@ -96,7 +96,7 @@ public function query( $prompt, $instructions = '' ) { $status = $req->execute(); if ( !$status->isOK() ) { - return "HTTP request failed: " . $status->getMessage()->plain(); + return wfMessage( 'askai-openai-failed', $status->getMessage()->plain() ); } $ret = FormatJson::decode( $req->getContent(), true ); diff --git a/includes/SpecialAI.php b/includes/SpecialAI.php index bbd060c..1189d48 100644 --- a/includes/SpecialAI.php +++ b/includes/SpecialAI.php @@ -44,19 +44,19 @@ public function requiresWrite() { /** @inheritDoc */ protected function getFormFields() { return [ - 'pagesAndParagraphs' => [ + 'Pages' => [ 'type' => 'textarea', - 'rows' => 5, + 'rows' => 3, 'label-message' => 'askai-field-pages', 'required' => true ], - 'response' => [ + 'Response' => [ 'type' => 'textarea', - 'rows' => 10, + 'rows' => 15, 'label-message' => 'askai-field-response', 'readonly' => true ], - 'prompt' => [ + 'Prompt' => [ 'type' => 'text', 'label-message' => 'askai-field-prompt', 'required' => true @@ -66,6 +66,8 @@ protected function getFormFields() { /** @inheritDoc */ protected function alterForm( HTMLForm $form ) { + $form->setId( 'mw-askai' ); + $this->getOutput()->addModules( 'ext.askai' ); } /** @inheritDoc */ @@ -75,18 +77,17 @@ public function onSubmit( array $data ) { return Status::newFatal( 'askai-unknown-service' ); } - $response = $ai->query( $data['prompt'], $data['pagesAndParagraphs'] ); + $response = $ai->query( $data['Prompt'], $data['Pages'] ); - $this->getOutput()->addHTML( Xml::element( 'div', [ + $this->getOutput()->disable(); + echo Xml::element( 'div', [ + 'id' => 'mw-askai-response', 'style' => 'white-space: pre-wrap' - ], $response ) ); + ], $response ); return Status::newGood(); } - public function onSuccess() { - } - /** @inheritDoc */ protected function getDisplayFormat() { return 'ooui'; diff --git a/modules/ext.askai.js b/modules/ext.askai.js new file mode 100644 index 0000000..d6b6fea --- /dev/null +++ b/modules/ext.askai.js @@ -0,0 +1,29 @@ +/* Submits the form [[Special:AI]] and displays results without reloading the page. */ + +$( function () { + var $form = $( '#mw-askai' ), + $response = $form.find( '[name="wpResponse"]' ), + $pages = $form.find( '[name="wpPages"]' ), + $prompt = $form.find( '[name="wpPrompt"]' ), + token = $( '#wpEditToken' ).val(), + url = $form[ 0 ].action; + + function onsubmit( ev ) { + ev.preventDefault(); + + $.post( url, { + wpPages: $pages.val(), + wpPrompt: $prompt.val(), + wpEditToken: token + } ).fail( function ( xhr ) { + $response.val( mw.msg( 'askai-submit-failed', + xhr.statusText + ' (' + url + ')' + ) ); + } ).done( function ( ret ) { + var responseText = $( '
' ).append( ret ).find( '#mw-askai-response' ).text(); + $response.val( responseText ); + } ); + } + + $form.on( 'submit', onsubmit ); +}() );