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 $history = json_decode((string)$INPUT->post->str('history'), null, 512, JSON_THROW_ON_ERROR); 45 header('Content-Type: application/json'); 46 47 if (!$helper->userMayAccess()) { 48 echo json_encode([ 49 'question' => $question, 50 'answer' => $this->getLang('restricted'), 51 'sources' => [], 52 ], JSON_THROW_ON_ERROR); 53 return; 54 } 55 56 try { 57 $result = $helper->askChatQuestion($question, $history); 58 $sources = []; 59 foreach ($result['sources'] as $source) { 60 /** @var Chunk $source */ 61 if (isset($sources[$source->getPage()])) continue; // only show the first occurrence per page 62 $sources[$source->getPage()] = [ 63 'page' => $source->getPage(), 64 'url' => wl($source->getPage()), 65 'title' => p_get_first_heading($source->getPage()) ?: $source->getPage(), 66 'score' => sprintf("%.2f%%", $source->getScore() * 100), 67 ]; 68 } 69 $parseDown = new Parsedown(); 70 $parseDown->setSafeMode(true); 71 72 echo json_encode([ 73 'question' => $result['question'], 74 'answer' => $parseDown->text($result['answer']), 75 'sources' => array_values($sources), 76 ], JSON_THROW_ON_ERROR); 77 78 if ($this->getConf('logging')) { 79 Logger::getInstance('aichat')->log( 80 $question, 81 [ 82 'interpretation' => $result['question'], 83 'answer' => $result['answer'], 84 'sources' => $sources, 85 'ip' => $INPUT->server->str('REMOTE_ADDR'), 86 'user' => $INPUT->server->str('REMOTE_USER'), 87 'stats' => $helper->getChatModel()->getUsageStats() 88 ] 89 ); 90 } 91 } catch (\Exception $e) { 92 ErrorHandler::logException($e); 93 echo json_encode([ 94 'question' => $question, 95 'answer' => 'An error occurred. More info may be available in the error log. ' . $e->getMessage(), 96 'sources' => [], 97 ], JSON_THROW_ON_ERROR); 98 } 99 } 100} 101