1<?php
2
3use dokuwiki\Extension\RemotePlugin;
4use dokuwiki\plugin\aichat\RemoteResponse\Chunk;
5use dokuwiki\plugin\aichat\RemoteResponse\LlmReply;
6use dokuwiki\Remote\AccessDeniedException;
7
8/**
9 * DokuWiki Plugin aichat (Action Component)
10 *
11 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
12 * @author Andreas Gohr <gohr@cosmocode.de>
13 */
14class remote_plugin_aichat extends RemotePlugin
15{
16
17    /**
18     * Initialize the helper and check permissions
19     *
20     * @param string $model
21     * @param string $lang
22     * @return helper_plugin_aichat
23     * @throws AccessDeniedException
24     */
25    protected function initHelper($model = '', $lang = '')
26    {
27        /** @var helper_plugin_aichat $helper */
28        $helper = plugin_load('helper', 'aichat');
29        if ($model) {
30            $helper->updateConfig(
31                ['chatmodel' => $model, 'rephasemodel' => $model]
32            );
33        }
34
35        if (!$helper->userMayAccess()) {
36            throw new AccessDeniedException('You are not allowed to use this plugin', 111);
37        }
38
39        if ($lang === 'auto') {
40            $helper->updateConfig(['preferUIlanguage' => 0]);
41        } elseif ($lang) {
42            $helper->updateConfig(['preferUIlanguage' => 1]);
43            global $conf;
44            $conf['lang'] = $lang;
45        }
46
47        return $helper;
48    }
49
50    /**
51     * Ask the LLM a question
52     *
53     * Sends the given question to the LLM and returns the answer, including the used sources.
54     *
55     * @param string $query The question to ask the LLM
56     * @param string $model The model to use, if empty the default model is used
57     * @param string $lang Language code to override preferUIlanguage setting. "auto" to force autodetection.
58     * @return LlmReply
59     * @throws AccessDeniedException
60     * @throws Exception
61     */
62    public function ask($query, $model = '', $lang = '')
63    {
64        $helper = $this->initHelper($model, $lang);
65        $result = $helper->askQuestion($query);
66
67        return new LlmReply($result);
68    }
69
70    /**
71     * Get page chunks similar to a given query
72     *
73     * Uses the given query to find similar pages in the wiki. Returns the most similar chunks.
74     *
75     * This call returns chunks, not pages. So a page may returned multiple times when different chunks of it
76     * are similar to the query.
77     *
78     * Note that this call may return less results than requested depending on the used vector store.
79     *
80     * @param string $query
81     * @param int $max Maximum number of results to return. -1 for default set in config
82     * @param float $threshold Minimum similarity score to return results for. -1 for default set in config
83     * @param string $lang Language code to override preferUIlanguage setting. "auto" to force autodetection.
84     * @return Chunk[] A list of similar chunks
85     * @throws AccessDeniedException
86     * @throws Exception
87     */
88    public function similar($query, $max = -1, $threshold = -1, $lang = '')
89    {
90        $helper = $this->initHelper('', $lang);
91        $langlimit = $helper->getLanguageLimit();
92
93        $embeddings = $helper->getEmbeddings();
94        if ($max !== -1) {
95            $embeddings->setConfigContextChunks($max);
96        }
97        if ($threshold !== -1) {
98            $embeddings->setSimilarityThreshold($threshold);
99        }
100
101        $sources = $embeddings->getSimilarChunks($query, $langlimit, false);
102
103        $results = [];
104        foreach ($sources as $source) {
105            $results[] = new Chunk($source);
106        }
107        return $results;
108    }
109
110}
111