xref: /plugin/aichat/_test/AbstractModelTest.php (revision d72a84c5bd8b465526a89378df9883eea1b18eb6)
1773012cfSAndreas Gohr<?php
2773012cfSAndreas Gohr
3773012cfSAndreas Gohrnamespace dokuwiki\plugin\aichat\test;
4773012cfSAndreas Gohr
5332eea25SAndreas Gohruse dokuwiki\plugin\aichat\Model\ChatInterface;
6332eea25SAndreas Gohruse dokuwiki\plugin\aichat\Model\EmbeddingInterface;
7773012cfSAndreas Gohruse DokuWikiTest;
8773012cfSAndreas Gohr
9773012cfSAndreas Gohr/**
10773012cfSAndreas Gohr * Base for Model provider tests
11773012cfSAndreas Gohr *
12773012cfSAndreas Gohr * @group plugin_aichat
13773012cfSAndreas Gohr * @group plugins
14773012cfSAndreas Gohr * @group internet
15773012cfSAndreas Gohr */
16773012cfSAndreas Gohrabstract class AbstractModelTest extends DokuWikiTest
17773012cfSAndreas Gohr{
18773012cfSAndreas Gohr    /** @inheritdoc */
19773012cfSAndreas Gohr    protected $pluginsEnabled = ['aichat'];
20773012cfSAndreas Gohr
21773012cfSAndreas Gohr    /** @var string The provider name, e.g. 'openai', 'reka', etc. */
22773012cfSAndreas Gohr    protected string $provider;
23773012cfSAndreas Gohr
24773012cfSAndreas Gohr    /** @var string The environment variable name for the API key */
25773012cfSAndreas Gohr    protected string $api_key_env;
26773012cfSAndreas Gohr
27773012cfSAndreas Gohr    /** @var string The chat model name, e.g. 'gpt-3.5-turbo', 'gpt-4', etc. */
28773012cfSAndreas Gohr    protected string $chat_model;
29773012cfSAndreas Gohr
30773012cfSAndreas Gohr    /** @var string The embedding model name, e.g. 'text-embedding-3-small', etc. */
31773012cfSAndreas Gohr    protected string $embedding_model;
32773012cfSAndreas Gohr
33773012cfSAndreas Gohr    /** @inheritdoc */
34773012cfSAndreas Gohr    public function setUp(): void
35773012cfSAndreas Gohr    {
36773012cfSAndreas Gohr        parent::setUp();
37773012cfSAndreas Gohr        global $conf;
38773012cfSAndreas Gohr
39*d72a84c5SAndreas Gohr        // get API key from environment
40*d72a84c5SAndreas Gohr        if($this->api_key_env) {
41773012cfSAndreas Gohr            $apikey = getenv($this->api_key_env);
42773012cfSAndreas Gohr            if (!$apikey) {
43773012cfSAndreas Gohr                $this->markTestSkipped('API key environment not set');
44773012cfSAndreas Gohr            }
45*d72a84c5SAndreas Gohr        } else {
46*d72a84c5SAndreas Gohr            // if not env name is set, probably no key is needed. We simply set it to empty
47*d72a84c5SAndreas Gohr            $apikey = '';
48*d72a84c5SAndreas Gohr        }
49773012cfSAndreas Gohr
50*d72a84c5SAndreas Gohr        // set basic configuration for the plugin
51773012cfSAndreas Gohr        $providerName = ucfirst($this->provider);
52773012cfSAndreas Gohr        $providerConf = strtolower($this->provider);
53773012cfSAndreas Gohr        $conf['plugin']['aichat']['chatmodel'] = $providerName . ' ' . $this->chat_model;
54773012cfSAndreas Gohr        $conf['plugin']['aichat']['rephrasemodel'] = $providerName . ' ' . $this->chat_model;
55332eea25SAndreas Gohr        $conf['plugin']['aichat']['embedmodel'] = $providerName . ' ' . $this->embedding_model;
56773012cfSAndreas Gohr        $conf['plugin']['aichat'][$providerConf . '_apikey'] = $apikey;
57773012cfSAndreas Gohr    }
58773012cfSAndreas Gohr
59773012cfSAndreas Gohr    public function testChat()
60773012cfSAndreas Gohr    {
61773012cfSAndreas Gohr        $prompt = 'This is a test. Please reply with "Hello World"';
62773012cfSAndreas Gohr
63773012cfSAndreas Gohr        /** @var \helper_plugin_aichat $helper */
64773012cfSAndreas Gohr        $helper = plugin_load('helper', 'aichat');
65773012cfSAndreas Gohr        $model = $helper->getChatModel();
66332eea25SAndreas Gohr
67332eea25SAndreas Gohr        $this->assertInstanceOf(ChatInterface::class, $model, 'Model should implement ChatInterface');
68332eea25SAndreas Gohr        $this->assertEquals(
69332eea25SAndreas Gohr            'dokuwiki\\plugin\\aichat\\Model\\' . $this->provider . '\\ChatModel',
70332eea25SAndreas Gohr            get_class($model),
71332eea25SAndreas Gohr            'Model seems to be the wrong class'
72332eea25SAndreas Gohr        );
73332eea25SAndreas Gohr
7475a24d82SAndreas Gohr        try {
75773012cfSAndreas Gohr            $reply = $model->getAnswer([
76773012cfSAndreas Gohr                ['role' => 'user', 'content' => $prompt]
77773012cfSAndreas Gohr            ]);
7875a24d82SAndreas Gohr        } catch (\Exception $e) {
7975a24d82SAndreas Gohr            if (preg_match('/(credit|fund|balance)/i', $e->getMessage())) {
8075a24d82SAndreas Gohr                $this->markTestIncomplete($e->getMessage());
8175a24d82SAndreas Gohr            } else {
8275a24d82SAndreas Gohr                throw $e;
8375a24d82SAndreas Gohr            }
8475a24d82SAndreas Gohr        }
85773012cfSAndreas Gohr
86773012cfSAndreas Gohr        $this->assertStringContainsString('hello world', strtolower($reply));
87773012cfSAndreas Gohr    }
88773012cfSAndreas Gohr
89773012cfSAndreas Gohr    public function testEmbedding()
90773012cfSAndreas Gohr    {
91773012cfSAndreas Gohr        $text = 'This is a test for embeddings.';
92773012cfSAndreas Gohr
93773012cfSAndreas Gohr        /** @var \helper_plugin_aichat $helper */
94773012cfSAndreas Gohr        $helper = plugin_load('helper', 'aichat');
95773012cfSAndreas Gohr        $model = $helper->getEmbeddingModel();
96332eea25SAndreas Gohr
97332eea25SAndreas Gohr        $this->assertInstanceOf(EmbeddingInterface::class, $model, 'Model should implement EmbeddingInterface');
98332eea25SAndreas Gohr        $this->assertEquals(
99332eea25SAndreas Gohr            'dokuwiki\\plugin\\aichat\\Model\\' . $this->provider . '\\EmbeddingModel',
100332eea25SAndreas Gohr            get_class($model),
101332eea25SAndreas Gohr            'Model seems to be the wrong class'
102332eea25SAndreas Gohr        );
103332eea25SAndreas Gohr
10475a24d82SAndreas Gohr        try {
105773012cfSAndreas Gohr            $embedding = $model->getEmbedding($text);
10675a24d82SAndreas Gohr        } catch (\Exception $e) {
10775a24d82SAndreas Gohr            if (preg_match('/(credit|fund|balance)/i', $e->getMessage())) {
10875a24d82SAndreas Gohr                $this->markTestIncomplete($e->getMessage());
10975a24d82SAndreas Gohr            } else {
11075a24d82SAndreas Gohr                throw $e;
11175a24d82SAndreas Gohr            }
11275a24d82SAndreas Gohr        }
11375a24d82SAndreas Gohr
114773012cfSAndreas Gohr        $this->assertIsArray($embedding);
115773012cfSAndreas Gohr        $this->assertNotEmpty($embedding, 'Embedding should not be empty');
116773012cfSAndreas Gohr        $this->assertIsFloat($embedding[0], 'Embedding should be an array of floats');
117773012cfSAndreas Gohr    }
118773012cfSAndreas Gohr}
119