1*ae09ced4SAndreas Gohr<?php 2*ae09ced4SAndreas Gohr 3*ae09ced4SAndreas Gohruse dokuwiki\plugin\aichat\AbstractCLI; 4*ae09ced4SAndreas Gohruse splitbrain\phpcli\Options; 5*ae09ced4SAndreas Gohr 6*ae09ced4SAndreas Gohr/** 7*ae09ced4SAndreas Gohr * DokuWiki Plugin aichat (CLI Component) 8*ae09ced4SAndreas Gohr * 9*ae09ced4SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 10*ae09ced4SAndreas Gohr * @author Andreas Gohr <gohr@cosmocode.de> 11*ae09ced4SAndreas Gohr */ 12*ae09ced4SAndreas Gohrclass cli_plugin_aichat_dev extends AbstractCLI 13*ae09ced4SAndreas Gohr{ 14*ae09ced4SAndreas Gohr /** @inheritDoc */ 15*ae09ced4SAndreas Gohr protected function setup(Options $options) 16*ae09ced4SAndreas Gohr { 17*ae09ced4SAndreas Gohr $options->setHelp('Helps with development of this plugin'); 18*ae09ced4SAndreas Gohr 19*ae09ced4SAndreas Gohr $options->registerCommand('update', 'Update the model data'); 20*ae09ced4SAndreas Gohr } 21*ae09ced4SAndreas Gohr 22*ae09ced4SAndreas Gohr /** @inheritDoc */ 23*ae09ced4SAndreas Gohr protected function main(Options $options) 24*ae09ced4SAndreas Gohr { 25*ae09ced4SAndreas Gohr parent::main($options); 26*ae09ced4SAndreas Gohr 27*ae09ced4SAndreas Gohr switch ($options->getCmd()) { 28*ae09ced4SAndreas Gohr 29*ae09ced4SAndreas Gohr case 'update': 30*ae09ced4SAndreas Gohr $this->updateModelData(); 31*ae09ced4SAndreas Gohr break; 32*ae09ced4SAndreas Gohr default: 33*ae09ced4SAndreas Gohr echo $options->help(); 34*ae09ced4SAndreas Gohr } 35*ae09ced4SAndreas Gohr } 36*ae09ced4SAndreas Gohr 37*ae09ced4SAndreas Gohr protected function updateModelData() 38*ae09ced4SAndreas Gohr { 39*ae09ced4SAndreas Gohr 40*ae09ced4SAndreas Gohr $http = new \dokuwiki\HTTP\DokuHTTPClient(); 41*ae09ced4SAndreas Gohr $url = 'https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json'; 42*ae09ced4SAndreas Gohr $response = $http->get($url); 43*ae09ced4SAndreas Gohr if ($response === false) { 44*ae09ced4SAndreas Gohr $this->error('Failed to fetch model data'); 45*ae09ced4SAndreas Gohr return 1; 46*ae09ced4SAndreas Gohr } 47*ae09ced4SAndreas Gohr $models = json_decode($response, true, 512, JSON_THROW_ON_ERROR); 48*ae09ced4SAndreas Gohr 49*ae09ced4SAndreas Gohr $ourProviders = [ 50*ae09ced4SAndreas Gohr 'anthropic' => [ 51*ae09ced4SAndreas Gohr 'name' => 'Anthropic', 52*ae09ced4SAndreas Gohr ], 53*ae09ced4SAndreas Gohr 'groq' => [ 54*ae09ced4SAndreas Gohr 'name' => 'Groq', 55*ae09ced4SAndreas Gohr 'skip' => '/-preview$/' 56*ae09ced4SAndreas Gohr ], 57*ae09ced4SAndreas Gohr 'mistral' => [ 58*ae09ced4SAndreas Gohr 'name' => 'Mistral', 59*ae09ced4SAndreas Gohr 'skip' => '/-\d\d\d\d$/', 60*ae09ced4SAndreas Gohr ], 61*ae09ced4SAndreas Gohr 'openai' => [ 62*ae09ced4SAndreas Gohr 'name' => 'OpenAI', 63*ae09ced4SAndreas Gohr 'skip' => '/(-\d\d\d\d-\d\d-\d\d|-preview|-\d\d\d\d)$|^ft:/' 64*ae09ced4SAndreas Gohr ], 65*ae09ced4SAndreas Gohr 'reka' => [ 66*ae09ced4SAndreas Gohr 'name' => 'Reka', 67*ae09ced4SAndreas Gohr ], 68*ae09ced4SAndreas Gohr 'voyage' => [ 69*ae09ced4SAndreas Gohr 'name' => 'VoyageAI', 70*ae09ced4SAndreas Gohr 'skip' => '/-(01|02)(-|$)/', // outdated models 71*ae09ced4SAndreas Gohr ], 72*ae09ced4SAndreas Gohr ]; 73*ae09ced4SAndreas Gohr 74*ae09ced4SAndreas Gohr // load existing models 75*ae09ced4SAndreas Gohr foreach ($ourProviders as $provider => $data) { 76*ae09ced4SAndreas Gohr $ourProviders[$provider]['models'] = json_decode( 77*ae09ced4SAndreas Gohr file_get_contents(__DIR__ . '/../Model/' . $data['name'] . '/' . 'models.json'), 78*ae09ced4SAndreas Gohr true 79*ae09ced4SAndreas Gohr ); 80*ae09ced4SAndreas Gohr } 81*ae09ced4SAndreas Gohr 82*ae09ced4SAndreas Gohr // update models 83*ae09ced4SAndreas Gohr foreach ($models as $model => $data) { 84*ae09ced4SAndreas Gohr if (!isset($ourProviders[$data['litellm_provider']])) continue; 85*ae09ced4SAndreas Gohr if (!in_array($data['mode'], ['chat', 'embedding'])) continue; 86*ae09ced4SAndreas Gohr $provider = $data['litellm_provider']; 87*ae09ced4SAndreas Gohr $model = explode('/', $model); 88*ae09ced4SAndreas Gohr $model = array_pop($model); 89*ae09ced4SAndreas Gohr 90*ae09ced4SAndreas Gohr if (isset($ourProviders[$provider]['skip']) && preg_match($ourProviders[$provider]['skip'], $model)) { 91*ae09ced4SAndreas Gohr $this->info('Skipping ' . $provider . ' ' . $model); 92*ae09ced4SAndreas Gohr continue; 93*ae09ced4SAndreas Gohr } 94*ae09ced4SAndreas Gohr $this->success("$provider $model"); 95*ae09ced4SAndreas Gohr 96*ae09ced4SAndreas Gohr $oldmodel = $ourProviders[$provider]['models'][$data['mode']][$model] ?? []; 97*ae09ced4SAndreas Gohr $newmodel = [ 98*ae09ced4SAndreas Gohr "description" => $oldmodel['description'] ?? $data['source'] ?? '', 99*ae09ced4SAndreas Gohr "inputTokens" => $data['max_input_tokens'] ?? $data['max_tokens'], 100*ae09ced4SAndreas Gohr "inputTokenPrice" => round($data['input_cost_per_token'] * 1_000_000, 2), 101*ae09ced4SAndreas Gohr ]; 102*ae09ced4SAndreas Gohr 103*ae09ced4SAndreas Gohr if ($data['mode'] === 'chat') { 104*ae09ced4SAndreas Gohr $newmodel['outputTokens'] = $data['max_output_tokens']; 105*ae09ced4SAndreas Gohr $newmodel['outputTokenPrice'] = round($data['output_cost_per_token'] * 1_000_000, 2); 106*ae09ced4SAndreas Gohr } else { 107*ae09ced4SAndreas Gohr if (isset($oldmodel['dimensions'])) { 108*ae09ced4SAndreas Gohr $newmodel['dimensions'] = $oldmodel['dimensions']; 109*ae09ced4SAndreas Gohr } else { 110*ae09ced4SAndreas Gohr $this->warning('No dimensions for ' . $provider . ' ' . $model . '. Check manually!'); 111*ae09ced4SAndreas Gohr $newmodel['dimensions'] = 1536; 112*ae09ced4SAndreas Gohr } 113*ae09ced4SAndreas Gohr } 114*ae09ced4SAndreas Gohr $ourProviders[$provider]['models'][$data['mode']][$model] = $newmodel; 115*ae09ced4SAndreas Gohr } 116*ae09ced4SAndreas Gohr 117*ae09ced4SAndreas Gohr // save models 118*ae09ced4SAndreas Gohr foreach ($ourProviders as $data) { 119*ae09ced4SAndreas Gohr file_put_contents( 120*ae09ced4SAndreas Gohr __DIR__ . '/../Model/' . $data['name'] . '/' . 'models.json', 121*ae09ced4SAndreas Gohr json_encode($data['models'], JSON_PRETTY_PRINT) 122*ae09ced4SAndreas Gohr ); 123*ae09ced4SAndreas Gohr } 124*ae09ced4SAndreas Gohr 125*ae09ced4SAndreas Gohr return 0; 126*ae09ced4SAndreas Gohr } 127*ae09ced4SAndreas Gohr} 128