1<?php 2 3use dokuwiki\ErrorHandler; 4use dokuwiki\Extension\ActionPlugin; 5use dokuwiki\Extension\Event; 6use dokuwiki\Extension\EventHandler; 7use dokuwiki\Logger; 8use dokuwiki\plugin\aichat\Chunk; 9 10/** 11 * DokuWiki Plugin aichat (Action Component) 12 * 13 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 14 * @author Andreas Gohr <gohr@cosmocode.de> 15 */ 16class action_plugin_aichat extends ActionPlugin 17{ 18 /** @inheritDoc */ 19 public function register(EventHandler $controller) 20 { 21 $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handleQuestion'); 22 } 23 24 25 /** 26 * Event handler for AJAX_CALL_UNKNOWN event 27 * 28 * @see https://www.dokuwiki.org/devel:events:ajax_call_unknown 29 * @param Event $event Event object 30 * @param mixed $param optional parameter passed when event was registered 31 * @return void 32 */ 33 public function handleQuestion(Event $event, mixed $param) 34 { 35 if ($event->data !== 'aichat') return; 36 $event->preventDefault(); 37 $event->stopPropagation(); 38 global $INPUT; 39 40 /** @var helper_plugin_aichat $helper */ 41 $helper = plugin_load('helper', 'aichat'); 42 43 $question = $INPUT->post->str('question'); 44 $pagecontext = $INPUT->post->str('pagecontext'); 45 $history = json_decode((string)$INPUT->post->str('history'), null, 512, JSON_THROW_ON_ERROR); 46 header('Content-Type: application/json'); 47 48 if (!$helper->userMayAccess()) { 49 echo json_encode([ 50 'question' => $question, 51 'answer' => $this->getLang('restricted'), 52 'sources' => [], 53 ], JSON_THROW_ON_ERROR); 54 return; 55 } 56 57 try { 58 $result = $helper->askChatQuestion($question, $history, $pagecontext); 59 $sources = []; 60 foreach ($result['sources'] as $source) { 61 /** @var Chunk $source */ 62 if (isset($sources[$source->getPage()])) continue; // only show the first occurrence per page 63 $sources[$source->getPage()] = [ 64 'page' => $source->getPage(), 65 'url' => wl($source->getPage()), 66 'title' => p_get_first_heading($source->getPage()) ?: $source->getPage(), 67 'score' => sprintf("%.2f%%", $source->getScore() * 100), 68 ]; 69 } 70 $parseDown = new Parsedown(); 71 $parseDown->setSafeMode(true); 72 73 echo json_encode([ 74 'question' => $result['question'], 75 'answer' => $parseDown->text($result['answer']), 76 'sources' => array_values($sources), 77 ], JSON_THROW_ON_ERROR); 78 79 if ($this->getConf('logging')) { 80 Logger::getInstance('aichat')->log( 81 $question, 82 [ 83 'interpretation' => $result['question'], 84 'answer' => $result['answer'], 85 'sources' => $sources, 86 'ip' => $INPUT->server->str('REMOTE_ADDR'), 87 'user' => $INPUT->server->str('REMOTE_USER'), 88 'stats' => $helper->getChatModel()->getUsageStats() 89 ] 90 ); 91 } 92 } catch (\Exception $e) { 93 ErrorHandler::logException($e); 94 echo json_encode([ 95 'question' => $question, 96 'answer' => 'An error occurred. More info may be available in the error log. ' . $e->getMessage(), 97 'sources' => [], 98 ], JSON_THROW_ON_ERROR); 99 } 100 } 101} 102