OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

CostEstimatorTest.php

3 KB
<?php

declare(strict_types=1);

use OpenNIT\AI\CostEstimator;

return static function (): void {

    test('estimate: exakter Treffer', function () {
        // gpt-4o-mini: 0.15 in / 0.60 out je 1M; 1M in + 1M out
        $eur = CostEstimator::estimate('gpt-4o-mini', ['prompt_tokens' => 1_000_000, 'completion_tokens' => 1_000_000]);
        // (0.15 + 0.60) * 0.92 = 0.69
        assertTrue($eur !== null && abs($eur - 0.69) < 1e-6, 'erwartet ~0,69 €, erhalten ' . var_export($eur, true));
    });

    test('estimate: Prefix-Fallback für Varianten', function () {
        $eur = CostEstimator::estimate('claude-3-5-sonnet-20241022', ['prompt_tokens' => 1_000_000, 'completion_tokens' => 0]);
        // 3.00 * 0.92 = 2.76
        assertTrue($eur !== null && abs($eur - 2.76) < 1e-6, 'Prefix-Match claude-3-5-sonnet');
    });

    test('estimate: unbekanntes Modell = null', function () {
        assertSame(null, CostEstimator::estimate('llama3-local', ['prompt_tokens' => 100]));
    });

    test('estimate: der Kurs laesst sich vorgeben', function () {
        // Die Preislisten stehen in USD; gerechnet wird in die Waehrung der Instanz.
        $kosten = CostEstimator::estimate('gpt-4o-mini', ['prompt_tokens' => 1_000_000], 1.0);
        assertTrue($kosten !== null && abs($kosten - 0.15) < 1e-6, 'Kurs 1,0 erwartet 0,15, erhalten ' . var_export($kosten, true));

        // Ein unbrauchbarer Kurs faellt auf den ueblichen zurueck.
        foreach ([0.0, -1.0, null] as $kurs) {
            $k = CostEstimator::estimate('gpt-4o-mini', ['prompt_tokens' => 1_000_000], $kurs);
            assertTrue($k !== null && abs($k - 0.15 * CostEstimator::STANDARD_KURS) < 1e-6,
                'Kurs ' . var_export($kurs, true) . ' erhielt ' . var_export($k, true));
        }
    });

    test('estimate: ohne hinterlegten Kurs gilt der uebliche', function () {
        assertSame(0.92, CostEstimator::STANDARD_KURS);
        assertSame(CostEstimator::STANDARD_KURS, CostEstimator::kurs(null));
    });

    test('contextWindow: modellabhängig + Override', function () {
        assertSame(200000, CostEstimator::contextWindow(['model' => 'claude-haiku-4-5']));
        assertSame(128000, CostEstimator::contextWindow(['model' => 'gpt-4o-mini']));
        assertSame(8000,   CostEstimator::contextWindow(['provider' => 'openai_compatible', 'model' => 'llama3']));
        assertSame(32000,  CostEstimator::contextWindow(['model' => 'mystery']));
        assertSame(4096,   CostEstimator::contextWindow(['model' => 'llama3', 'context_window' => 4096]), 'Override greift');
    });
};