142b2c6e8SAndreas Gohr<?php 242b2c6e8SAndreas Gohr 342b2c6e8SAndreas Gohruse dokuwiki\Extension\RemotePlugin; 4*aa6bbe75SAndreas Gohruse dokuwiki\plugin\aichat\RemoteResponse\Chunk; 542b2c6e8SAndreas Gohruse dokuwiki\plugin\aichat\RemoteResponse\LlmReply; 642b2c6e8SAndreas Gohruse dokuwiki\Remote\AccessDeniedException; 742b2c6e8SAndreas Gohr 842b2c6e8SAndreas Gohr/** 942b2c6e8SAndreas Gohr * DokuWiki Plugin aichat (Action Component) 1042b2c6e8SAndreas Gohr * 1142b2c6e8SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 1242b2c6e8SAndreas Gohr * @author Andreas Gohr <gohr@cosmocode.de> 1342b2c6e8SAndreas Gohr */ 1442b2c6e8SAndreas Gohrclass remote_plugin_aichat extends RemotePlugin 1542b2c6e8SAndreas Gohr{ 16*aa6bbe75SAndreas Gohr 1742b2c6e8SAndreas Gohr /** 18*aa6bbe75SAndreas Gohr * Initialize the helper and check permissions 1942b2c6e8SAndreas Gohr * 20*aa6bbe75SAndreas Gohr * @param string $model 21*aa6bbe75SAndreas Gohr * @param string $lang 22*aa6bbe75SAndreas Gohr * @return helper_plugin_aichat 23*aa6bbe75SAndreas Gohr * @throws AccessDeniedException 2442b2c6e8SAndreas Gohr */ 25*aa6bbe75SAndreas Gohr protected function initHelper($model = '', $lang = '') 2642b2c6e8SAndreas Gohr { 2742b2c6e8SAndreas Gohr /** @var helper_plugin_aichat $helper */ 2842b2c6e8SAndreas Gohr $helper = plugin_load('helper', 'aichat'); 2942b2c6e8SAndreas Gohr if ($model) { 3042b2c6e8SAndreas Gohr $helper->updateConfig( 3142b2c6e8SAndreas Gohr ['chatmodel' => $model, 'rephasemodel' => $model] 3242b2c6e8SAndreas Gohr ); 3342b2c6e8SAndreas Gohr } 3442b2c6e8SAndreas Gohr 3542b2c6e8SAndreas Gohr if (!$helper->userMayAccess()) { 3642b2c6e8SAndreas Gohr throw new AccessDeniedException('You are not allowed to use this plugin', 111); 3742b2c6e8SAndreas Gohr } 3842b2c6e8SAndreas Gohr 3942b2c6e8SAndreas Gohr if ($lang === 'auto') { 4042b2c6e8SAndreas Gohr $helper->updateConfig(['preferUIlanguage' => 0]); 4142b2c6e8SAndreas Gohr } elseif ($lang) { 4242b2c6e8SAndreas Gohr $helper->updateConfig(['preferUIlanguage' => 1]); 4342b2c6e8SAndreas Gohr global $conf; 4442b2c6e8SAndreas Gohr $conf['lang'] = $lang; 4542b2c6e8SAndreas Gohr } 4642b2c6e8SAndreas Gohr 47*aa6bbe75SAndreas Gohr return $helper; 48*aa6bbe75SAndreas Gohr } 49*aa6bbe75SAndreas Gohr 50*aa6bbe75SAndreas Gohr /** 51*aa6bbe75SAndreas Gohr * Ask the LLM a question 52*aa6bbe75SAndreas Gohr * 53*aa6bbe75SAndreas Gohr * Sends the given question to the LLM and returns the answer, including the used sources. 54*aa6bbe75SAndreas Gohr * 55*aa6bbe75SAndreas Gohr * @param string $query The question to ask the LLM 56*aa6bbe75SAndreas Gohr * @param string $model The model to use, if empty the default model is used 57*aa6bbe75SAndreas Gohr * @param string $lang Language code to override preferUIlanguage setting. "auto" to force autodetection. 58*aa6bbe75SAndreas Gohr * @return LlmReply 59*aa6bbe75SAndreas Gohr * @throws AccessDeniedException 60*aa6bbe75SAndreas Gohr * @throws Exception 61*aa6bbe75SAndreas Gohr */ 62*aa6bbe75SAndreas Gohr public function ask($query, $model = '', $lang = '') 63*aa6bbe75SAndreas Gohr { 64*aa6bbe75SAndreas Gohr $helper = $this->initHelper($model, $lang); 6542b2c6e8SAndreas Gohr $result = $helper->askQuestion($query); 6642b2c6e8SAndreas Gohr 6742b2c6e8SAndreas Gohr return new LlmReply($result); 6842b2c6e8SAndreas Gohr } 69*aa6bbe75SAndreas Gohr 70*aa6bbe75SAndreas Gohr /** 71*aa6bbe75SAndreas Gohr * Get page chunks similar to a given query 72*aa6bbe75SAndreas Gohr * 73*aa6bbe75SAndreas Gohr * Uses the given query to find similar pages in the wiki. Returns the most similar chunks. 74*aa6bbe75SAndreas Gohr * 75*aa6bbe75SAndreas Gohr * This call returns chunks, not pages. So a page may returned multiple times when different chunks of it 76*aa6bbe75SAndreas Gohr * are similar to the query. 77*aa6bbe75SAndreas Gohr * 78*aa6bbe75SAndreas Gohr * Note that this call may return less results than requested depending on the used vector store. 79*aa6bbe75SAndreas Gohr * 80*aa6bbe75SAndreas Gohr * @param string $query 81*aa6bbe75SAndreas Gohr * @param int $max Maximum number of results to return. -1 for default set in config 82*aa6bbe75SAndreas Gohr * @param float $threshold Minimum similarity score to return results for. -1 for default set in config 83*aa6bbe75SAndreas Gohr * @param string $lang Language code to override preferUIlanguage setting. "auto" to force autodetection. 84*aa6bbe75SAndreas Gohr * @return Chunk[] A list of similar chunks 85*aa6bbe75SAndreas Gohr * @throws AccessDeniedException 86*aa6bbe75SAndreas Gohr * @throws Exception 87*aa6bbe75SAndreas Gohr */ 88*aa6bbe75SAndreas Gohr public function similar($query, $max = -1, $threshold = -1, $lang = '') 89*aa6bbe75SAndreas Gohr { 90*aa6bbe75SAndreas Gohr $helper = $this->initHelper('', $lang); 91*aa6bbe75SAndreas Gohr $langlimit = $helper->getLanguageLimit(); 92*aa6bbe75SAndreas Gohr 93*aa6bbe75SAndreas Gohr $embeddings = $helper->getEmbeddings(); 94*aa6bbe75SAndreas Gohr if ($max !== -1) { 95*aa6bbe75SAndreas Gohr $embeddings->setConfigContextChunks($max); 96*aa6bbe75SAndreas Gohr } 97*aa6bbe75SAndreas Gohr if ($threshold !== -1) { 98*aa6bbe75SAndreas Gohr $embeddings->setSimilarityThreshold($threshold); 99*aa6bbe75SAndreas Gohr } 100*aa6bbe75SAndreas Gohr 101*aa6bbe75SAndreas Gohr $sources = $embeddings->getSimilarChunks($query, $langlimit, false); 102*aa6bbe75SAndreas Gohr 103*aa6bbe75SAndreas Gohr $results = []; 104*aa6bbe75SAndreas Gohr foreach ($sources as $source) { 105*aa6bbe75SAndreas Gohr $results[] = new Chunk($source); 106*aa6bbe75SAndreas Gohr } 107*aa6bbe75SAndreas Gohr return $results; 108*aa6bbe75SAndreas Gohr } 109*aa6bbe75SAndreas Gohr 11042b2c6e8SAndreas Gohr} 111