1<?php 2 3use splitbrain\phpcli\Colors; 4use splitbrain\phpcli\Options; 5 6 7/** 8 * DokuWiki Plugin aichat (CLI Component) 9 * 10 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 11 * @author Andreas Gohr <gohr@cosmocode.de> 12 */ 13class cli_plugin_aichat extends \dokuwiki\Extension\CLIPlugin 14{ 15 /** @var helper_plugin_aichat */ 16 protected $helper; 17 18 public function __construct($autocatch = true) 19 { 20 parent::__construct($autocatch); 21 $this->helper = plugin_load('helper', 'aichat'); 22 } 23 24 25 /** @inheritDoc */ 26 protected function setup(Options $options) 27 { 28 $options->setHelp('Manage and query the AI chatbot data'); 29 30 $options->registerCommand('embed', 'Create embeddings for all pages'); 31 32 $options->registerCommand('similar', 'Search for similar pages'); 33 $options->registerArgument('query', 'Look up chunks similar to this query', true, 'similar'); 34 35 $options->registerCommand('ask', 'Ask a question'); 36 $options->registerArgument('question', 'The question to ask', true, 'ask'); 37 38 $options->registerCommand('chat', 'Start an interactive chat session'); 39 } 40 41 /** @inheritDoc */ 42 protected function main(Options $options) 43 { 44 switch ($options->getCmd()) { 45 46 case 'embed': 47 $this->createEmbeddings(); 48 break; 49 case 'similar': 50 $this->similar($options->getArgs()[0]); 51 break; 52 case 'ask': 53 $this->ask($options->getArgs()[0]); 54 break; 55 case 'chat': 56 $this->chat(); 57 break; 58 default: 59 echo $options->help(); 60 } 61 } 62 63 /** 64 * Interactive Chat Session 65 * 66 * @return void 67 * @throws Exception 68 */ 69 protected function chat() 70 { 71 $history = []; 72 while ($q = $this->readLine('Your Question')) { 73 if ($history) { 74 $question = $this->helper->rephraseChatQuestion($q, $history); 75 $this->colors->ptln("Interpretation: $question", Colors::C_LIGHTPURPLE); 76 } else { 77 $question = $q; 78 } 79 $result = $this->helper->askQuestion($question); 80 $history[] = [$q, $result['answer']]; 81 $this->printAnswer($result); 82 } 83 } 84 85 /** 86 * Print the given detailed answer in a nice way 87 * 88 * @param array $answer 89 * @return void 90 */ 91 protected function printAnswer($answer) 92 { 93 $this->colors->ptln($answer['answer'], Colors::C_LIGHTCYAN); 94 echo "\n"; 95 foreach ($answer['sources'] as $source) { 96 $this->colors->ptln("\t" . $source['meta']['pageid'], Colors::C_LIGHTBLUE); 97 } 98 echo "\n"; 99 } 100 101 /** 102 * Handle a single, standalone question 103 * 104 * @param string $query 105 * @return void 106 * @throws Exception 107 */ 108 protected function ask($query) 109 { 110 $result = $this->helper->askQuestion($query); 111 $this->printAnswer($result); 112 } 113 114 /** 115 * Get the pages that are similar to the query 116 * 117 * @param string $query 118 * @return void 119 */ 120 protected function similar($query) 121 { 122 $sources = $this->helper->getEmbeddings()->getSimilarChunks($query); 123 foreach ($sources as $source) { 124 $this->colors->ptln($source['meta']['pageid'], Colors::C_LIGHTBLUE); 125 } 126 } 127 128 /** 129 * Recreate chunks and embeddings for all pages 130 * 131 * @return void 132 */ 133 protected function createEmbeddings() 134 { 135 $this->helper->getEmbeddings()->createNewIndex(); 136 } 137 138 /** 139 * Interactively ask for a value from the user 140 * 141 * @param string $prompt 142 * @return string 143 */ 144 protected function readLine($prompt) 145 { 146 $value = ''; 147 148 while ($value === '') { 149 echo $prompt; 150 echo ': '; 151 152 $fh = fopen('php://stdin', 'r'); 153 $value = trim(fgets($fh)); 154 fclose($fh); 155 } 156 157 return $value; 158 } 159} 160 161