18817535bSAndreas Gohr<?php 28817535bSAndreas Gohr 3c4584168SAndreas Gohruse splitbrain\phpcli\Colors; 48817535bSAndreas Gohruse splitbrain\phpcli\Options; 58817535bSAndreas Gohr 68817535bSAndreas Gohr 78817535bSAndreas Gohr/** 88817535bSAndreas Gohr * DokuWiki Plugin aichat (CLI Component) 98817535bSAndreas Gohr * 108817535bSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 118817535bSAndreas Gohr * @author Andreas Gohr <gohr@cosmocode.de> 128817535bSAndreas Gohr */ 138817535bSAndreas Gohrclass cli_plugin_aichat extends \dokuwiki\Extension\CLIPlugin 148817535bSAndreas Gohr{ 15*0337f47fSAndreas Gohr /** @var helper_plugin_aichat */ 16*0337f47fSAndreas Gohr protected $helper; 17*0337f47fSAndreas Gohr 18*0337f47fSAndreas Gohr public function __construct($autocatch = true) 19*0337f47fSAndreas Gohr { 20*0337f47fSAndreas Gohr parent::__construct($autocatch); 21*0337f47fSAndreas Gohr $this->helper = plugin_load('helper', 'aichat'); 22*0337f47fSAndreas Gohr } 23*0337f47fSAndreas Gohr 248817535bSAndreas Gohr 258817535bSAndreas Gohr /** @inheritDoc */ 268817535bSAndreas Gohr protected function setup(Options $options) 278817535bSAndreas Gohr { 288817535bSAndreas Gohr $options->setHelp('Manage the AI chatbot data'); 298817535bSAndreas Gohr 308817535bSAndreas Gohr $options->registerCommand('embed', 'Create embeddings for all pages'); 318817535bSAndreas Gohr 328817535bSAndreas Gohr $options->registerCommand('similar', 'Search for similar pages'); 338817535bSAndreas Gohr $options->registerArgument('query', 'Look up chunks similar to this query', true, 'similar'); 348817535bSAndreas Gohr 358817535bSAndreas Gohr $options->registerCommand('ask', 'Ask a question'); 368817535bSAndreas Gohr $options->registerArgument('question', 'The question to ask', true, 'ask'); 37c4584168SAndreas Gohr 38c4584168SAndreas Gohr $options->registerCommand('chat', 'Start an interactive chat session'); 398817535bSAndreas Gohr } 408817535bSAndreas Gohr 418817535bSAndreas Gohr /** @inheritDoc */ 428817535bSAndreas Gohr protected function main(Options $options) 438817535bSAndreas Gohr { 448817535bSAndreas Gohr switch ($options->getCmd()) { 458817535bSAndreas Gohr 468817535bSAndreas Gohr case 'embed': 478817535bSAndreas Gohr $this->createEmbeddings(); 488817535bSAndreas Gohr break; 498817535bSAndreas Gohr case 'similar': 508817535bSAndreas Gohr $this->similar($options->getArgs()[0]); 518817535bSAndreas Gohr break; 527552f1aaSAndreas Gohr case 'ask': 537552f1aaSAndreas Gohr $this->ask($options->getArgs()[0]); 547552f1aaSAndreas Gohr break; 55c4584168SAndreas Gohr case 'chat': 56c4584168SAndreas Gohr $this->chat(); 57c4584168SAndreas Gohr break; 588817535bSAndreas Gohr default: 598817535bSAndreas Gohr echo $options->help(); 608817535bSAndreas Gohr } 618817535bSAndreas Gohr } 628817535bSAndreas Gohr 63c4584168SAndreas Gohr /** 64c4584168SAndreas Gohr * Interactive Chat Session 65c4584168SAndreas Gohr * 66c4584168SAndreas Gohr * @return void 67c4584168SAndreas Gohr * @throws Exception 68c4584168SAndreas Gohr */ 69c4584168SAndreas Gohr protected function chat() 70c4584168SAndreas Gohr { 71c4584168SAndreas Gohr $history = []; 72c4584168SAndreas Gohr while ($q = $this->readLine('Your Question')) { 73c4584168SAndreas Gohr if ($history) { 74*0337f47fSAndreas Gohr $question = $this->helper->rephraseChatQuestion($q, $history); 75c4584168SAndreas Gohr $this->colors->ptln("Interpretation: $question", Colors::C_LIGHTPURPLE); 76c4584168SAndreas Gohr } else { 77c4584168SAndreas Gohr $question = $q; 78c4584168SAndreas Gohr } 79*0337f47fSAndreas Gohr $result = $this->helper->askQuestion($question); 80c4584168SAndreas Gohr $history[] = [$q, $result['answer']]; 81c4584168SAndreas Gohr $this->printAnswer($result); 82c4584168SAndreas Gohr } 83c4584168SAndreas Gohr } 84c4584168SAndreas Gohr 85c4584168SAndreas Gohr /** 86c4584168SAndreas Gohr * Print the given detailed answer in a nice way 87c4584168SAndreas Gohr * 88c4584168SAndreas Gohr * @param array $answer 89c4584168SAndreas Gohr * @return void 90c4584168SAndreas Gohr */ 91c4584168SAndreas Gohr protected function printAnswer($answer) 92c4584168SAndreas Gohr { 93c4584168SAndreas Gohr $this->colors->ptln($answer['answer'], Colors::C_LIGHTCYAN); 94c4584168SAndreas Gohr echo "\n"; 95c4584168SAndreas Gohr foreach ($answer['sources'] as $source) { 96c4584168SAndreas Gohr $this->colors->ptln("\t" . $source['meta']['pageid'], Colors::C_LIGHTBLUE); 97c4584168SAndreas Gohr } 98c4584168SAndreas Gohr echo "\n"; 99c4584168SAndreas Gohr } 100c4584168SAndreas Gohr 101c4584168SAndreas Gohr /** 102c4584168SAndreas Gohr * Handle a single, standalone question 103c4584168SAndreas Gohr * 104c4584168SAndreas Gohr * @param string $query 105c4584168SAndreas Gohr * @return void 106c4584168SAndreas Gohr * @throws Exception 107c4584168SAndreas Gohr */ 108c4584168SAndreas Gohr protected function ask($query) 109c4584168SAndreas Gohr { 110*0337f47fSAndreas Gohr $result = $this->helper->askQuestion($query); 111c4584168SAndreas Gohr $this->printAnswer($result); 1127552f1aaSAndreas Gohr } 1137552f1aaSAndreas Gohr 114c4584168SAndreas Gohr /** 115c4584168SAndreas Gohr * Get the pages that are similar to the query 116c4584168SAndreas Gohr * 117c4584168SAndreas Gohr * @param string $query 118c4584168SAndreas Gohr * @return void 119c4584168SAndreas Gohr */ 1208817535bSAndreas Gohr protected function similar($query) 1218817535bSAndreas Gohr { 122*0337f47fSAndreas Gohr $sources = $this->helper->getEmbeddings()->getSimilarChunks($query); 123c4584168SAndreas Gohr foreach ($sources as $source) { 124c4584168SAndreas Gohr $this->colors->ptln($source['meta']['pageid'], Colors::C_LIGHTBLUE); 125c4584168SAndreas Gohr } 1268817535bSAndreas Gohr } 1278817535bSAndreas Gohr 128c4584168SAndreas Gohr /** 129c4584168SAndreas Gohr * Recreate chunks and embeddings for all pages 130c4584168SAndreas Gohr * 131c4584168SAndreas Gohr * @return void 132c4584168SAndreas Gohr */ 1338817535bSAndreas Gohr protected function createEmbeddings() 1348817535bSAndreas Gohr { 135*0337f47fSAndreas Gohr $this->helper->getEmbeddings()->createNewIndex(); 1368817535bSAndreas Gohr } 1378817535bSAndreas Gohr 138c4584168SAndreas Gohr /** 139c4584168SAndreas Gohr * Interactively ask for a value from the user 140c4584168SAndreas Gohr * 141c4584168SAndreas Gohr * @param string $prompt 142c4584168SAndreas Gohr * @return string 143c4584168SAndreas Gohr */ 144c4584168SAndreas Gohr protected function readLine($prompt) 145c4584168SAndreas Gohr { 146c4584168SAndreas Gohr $value = ''; 1478817535bSAndreas Gohr 148c4584168SAndreas Gohr while ($value === '') { 149c4584168SAndreas Gohr echo $prompt; 150c4584168SAndreas Gohr echo ': '; 151c4584168SAndreas Gohr 152c4584168SAndreas Gohr $fh = fopen('php://stdin', 'r'); 153c4584168SAndreas Gohr $value = trim(fgets($fh)); 154c4584168SAndreas Gohr fclose($fh); 155c4584168SAndreas Gohr } 156c4584168SAndreas Gohr 157c4584168SAndreas Gohr return $value; 158c4584168SAndreas Gohr } 1598817535bSAndreas Gohr} 1608817535bSAndreas Gohr 161