xref: /plugin/aichat/cli.php (revision 9da5f0df9b3bbdaf1de18d37258b054d79f1eaa7)
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