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