1<?php 2 3namespace dokuwiki\plugin\aichat\test; 4 5use dokuwiki\plugin\aichat\Model\ChatInterface; 6use dokuwiki\plugin\aichat\Model\EmbeddingInterface; 7use DokuWikiTest; 8 9/** 10 * Base for Model provider tests 11 * 12 * @group plugin_aichat 13 * @group plugins 14 * @group internet 15 */ 16abstract class AbstractModelTest extends DokuWikiTest 17{ 18 /** @inheritdoc */ 19 protected $pluginsEnabled = ['aichat']; 20 21 /** @var string The provider name, e.g. 'openai', 'reka', etc. */ 22 protected string $provider; 23 24 /** @var string The environment variable name for the API key */ 25 protected string $api_key_env; 26 27 /** @var string The chat model name, e.g. 'gpt-3.5-turbo', 'gpt-4', etc. */ 28 protected string $chat_model; 29 30 /** @var string The embedding model name, e.g. 'text-embedding-3-small', etc. */ 31 protected string $embedding_model; 32 33 /** @inheritdoc */ 34 public function setUp(): void 35 { 36 parent::setUp(); 37 global $conf; 38 39 // get API key from environment 40 if($this->api_key_env) { 41 $apikey = getenv($this->api_key_env); 42 if (!$apikey) { 43 $this->markTestSkipped('API key environment not set'); 44 } 45 } else { 46 // if not env name is set, probably no key is needed. We simply set it to empty 47 $apikey = ''; 48 } 49 50 // set basic configuration for the plugin 51 $providerName = ucfirst($this->provider); 52 $providerConf = strtolower($this->provider); 53 $conf['plugin']['aichat']['chatmodel'] = $providerName . ' ' . $this->chat_model; 54 $conf['plugin']['aichat']['rephrasemodel'] = $providerName . ' ' . $this->chat_model; 55 $conf['plugin']['aichat']['embedmodel'] = $providerName . ' ' . $this->embedding_model; 56 $conf['plugin']['aichat'][$providerConf . '_apikey'] = $apikey; 57 } 58 59 public function testChat() 60 { 61 $prompt = 'This is a test. Please reply with "Hello World"'; 62 63 /** @var \helper_plugin_aichat $helper */ 64 $helper = plugin_load('helper', 'aichat'); 65 $model = $helper->getChatModel(); 66 67 $this->assertInstanceOf(ChatInterface::class, $model, 'Model should implement ChatInterface'); 68 $this->assertEquals( 69 'dokuwiki\\plugin\\aichat\\Model\\' . $this->provider . '\\ChatModel', 70 get_class($model), 71 'Model seems to be the wrong class' 72 ); 73 74 try { 75 $reply = $model->getAnswer([ 76 ['role' => 'user', 'content' => $prompt] 77 ]); 78 } catch (\Exception $e) { 79 if (preg_match('/(credit|fund|balance)/i', $e->getMessage())) { 80 $this->markTestIncomplete($e->getMessage()); 81 } else { 82 throw $e; 83 } 84 } 85 86 $this->assertStringContainsString('hello world', strtolower($reply)); 87 } 88 89 public function testEmbedding() 90 { 91 $text = 'This is a test for embeddings.'; 92 93 /** @var \helper_plugin_aichat $helper */ 94 $helper = plugin_load('helper', 'aichat'); 95 $model = $helper->getEmbeddingModel(); 96 97 $this->assertInstanceOf(EmbeddingInterface::class, $model, 'Model should implement EmbeddingInterface'); 98 $this->assertEquals( 99 'dokuwiki\\plugin\\aichat\\Model\\' . $this->provider . '\\EmbeddingModel', 100 get_class($model), 101 'Model seems to be the wrong class' 102 ); 103 104 try { 105 $embedding = $model->getEmbedding($text); 106 } catch (\Exception $e) { 107 if (preg_match('/(credit|fund|balance)/i', $e->getMessage())) { 108 $this->markTestIncomplete($e->getMessage()); 109 } else { 110 throw $e; 111 } 112 } 113 114 $this->assertIsArray($embedding); 115 $this->assertNotEmpty($embedding, 'Embedding should not be empty'); 116 $this->assertIsFloat($embedding[0], 'Embedding should be an array of floats'); 117 } 118} 119