1<?php 2/** 3 * DokuWiki Plugin keywords (Action Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Gerry Weißbach <tools@inetsoftware.de> 7 */ 8use dokuwiki\HTTP\DokuHTTPClient; 9use \dokuwiki\Logger; 10 11class action_plugin_keywords_keywords extends \dokuwiki\Extension\ActionPlugin 12{ 13 private $CHATGPT_API_URL = "https://api.openai.com/v1/chat/completions"; 14 15 /** @inheritDoc */ 16 public function register(Doku_Event_Handler $controller) 17 { 18 $controller->register_hook('FORM_EDIT_OUTPUT', 'BEFORE', $this, 'handleFormEditOutput'); 19 $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'BEFORE', $this, 'handleCommonWikipageSave'); 20 $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handleMetaheaderOutput'); 21 } 22 23 /** 24 * Event handler for TPL_METAHEADER_OUTPUT 25 * 26 * @see https://www.dokuwiki.org/devel:event:TPL_METAHEADER_OUTPUT 27 * @param Doku_Event $event Event object 28 * @param mixed $param optional parameter passed when event was registered 29 * @return void 30 */ 31 public function handleFormEditOutput(Doku_Event $event, $param) { 32 global $lang; 33 34 // if no API key is set, do not show the option 35 if ( empty( $this->getConf('APIKey') ) ) { 36 return; 37 } 38 39 /** @var Doku_Form||\dokuwiki\Form\Form $form */ 40 $form =& $event->data; 41 42 if (is_a($form, \dokuwiki\Form\Form::class) ) { 43 $form->addHTML(' '); 44 $form->addCheckbox('updateKeywords', $this->getLang('updateKeywords'))->id('edit__updateKeywords')->addClass('nowrap')->val('1'); 45 } 46 47 if (is_a($form, Doku_Form::class) ) { 48 $form->addElement( form_makeCheckboxField( 'updateKeywords', '1', $this->getLang('updateKeywords'), 'edit__updateKeywords', 'nowrap' ) ); 49 } 50 } 51 52 /** 53 * Event handler for COMMON_WIKIPAGE_SAVE 54 * 55 * @see https://www.dokuwiki.org/devel:event:COMMON_WIKIPAGE_SAVE 56 * @param Doku_Event $event Event object 57 * @param mixed $param optional parameter passed when event was registered 58 * @return void 59 */ 60 public function handleCommonWikipageSave(Doku_Event $event, $param) { 61 global $INPUT; 62 63 $hasUpdateKeywords = $INPUT->bool( 'updateKeywords', false ); 64 if ( !$hasUpdateKeywords ) { 65 return; 66 } 67 68 $requestContent = $event->data['newContent']; 69 $requestContent = trim( preg_replace( '/\{\{keywords>.*?\}\}/is' , '', $requestContent ) ); 70 if ( empty( $requestContent ) ) { 71 $event->data['contentChanged'] = 1; 72 $event->data['newContent'] = ''; 73 return; 74 } 75 76//* // Remove one slash to have a sample of keywords saved instead of checking with chatGPT 77 $httpClient = new DokuHTTPClient(); 78 // $httpClient->debug = true; 79 $httpClient->headers = [ 80 'Authorization' => 'Bearer ' . $this->getConf('APIKey'), 81 'Content-Type' => 'application/json', 82 ]; 83 $status = $httpClient->sendRequest($this->CHATGPT_API_URL, json_encode( [ 84 'model' => $this->getConf('APIModel'), 85 'messages' => [ 86 [ "role" => "system", "content" => $this->getConf('APIRole') ], 87 [ "role" => "user", "content" => $requestContent ] 88 ], 89 "functions" => [[ 90 "name" => "keywords_for_text", 91 "description" => "Use this function to sent the list of keywords back to the dokuwiki. The Input is the array of keywords", 92 "parameters" => [ 93 "type" => "object", 94 "properties" => [ 95 "keywords" => [ 96 "type" => "array", 97 "items" => [ 98 "type" => "string" 99 ], 100 "description" => "This is the list of keywords generated from the input. Each keyword is given as string." 101 ] 102 ] 103 ] 104 ],[ 105 "name" => "no_content", 106 "description" => "Use this function to indicate that no kexwords could be generated.", 107 "parameters" => [ 108 "type" => "object", 109 "properties" => [ 110 "empty" => [ 111 "type" => "string", 112 "description" => "This parameter must always be NULL." 113 ] 114 ] 115 ] 116 ]] 117 ] ), 'POST'); 118 119 $data = json_decode( $httpClient->resp_body ); 120 121 if ( $status === false ) { 122 Logger::error( "An error occurred during the Chat GPT call", $httpClient->error, __FILE__, __LINE__ ); 123 return; 124 } else if ( $data->error ) { 125 Logger::error( "An error occurred during the Chat GPT call", $data->error->message, __FILE__, __LINE__ ); 126 return; 127 } 128 129 if ( $data->choices[0]->message->function_call->name == "keywords_for_text" ) { 130 $arguments = json_decode( $data->choices[0]->message->function_call->arguments ); 131 $keywords = $arguments->keywords; 132 Logger::debug( "Chat GPT response", $keywords, __FILE__, __LINE__ ); 133 } else { 134 Logger::debug( "INVALID Chat GPT response", $data->choices[0]->message, __FILE__, __LINE__ ); 135 } 136 137 if ( empty( $keywords ) || !is_array( $keywords ) ) { 138 // there is no content herre. 139 if ( $requestContent == $event->data['newContent'] ) { 140 // Nothing has changed, return 141 return; 142 } 143 144 // The keywords are empty now. 145 $event->data['contentChanged'] = 1; 146 $event->data['newContent'] = $requestContent; 147 return; 148 } 149/*/ 150 $keywords = [ "word1", "word2", "word3", "word4" ]; 151//*/ 152 153 $event->data['contentChanged'] = 1; 154 $event->data['newContent'] = '{{keywords>' . implode( ", ", $keywords ) . '}}' . "\n\n" . $requestContent; 155 } 156 157 /** 158 * Prints keywords to the meta header 159 * Event handler for TPL_METAHEADER_OUTPUT 160 * 161 * @see https://www.dokuwiki.org/devel:event:TPL_METAHEADER_OUTPUT 162 * @param Doku_Event $event Event object 163 * @param mixed $param optional parameter passed when event was registered 164 * @return void 165 * @author Ilya Lebedev <ilya@lebedev.net> 166 */ 167 public function handleMetaheaderOutput(Doku_Event $event, $param) { 168 global $ID; 169 global $conf; 170 171 if (empty($event->data) || empty($event->data['meta'])) return; // nothing to do for us 172 173 //Check if keywords are exists 174 $kw = p_get_metadata($ID,'keywords'); 175 if (empty($kw)) return; 176 177 for ($i=0;$i<sizeof($event->data['meta']);$i++) { 178 $h = &$event->data['meta'][$i]; 179 if ('keywords' == $h['name']) { 180 $h['content'] .= $kw; 181 break; 182 } 183 } 184 } 185} 186 187