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