08ec021b5f
Erste Stufe der V3.3-Spezifikation: Token- und Kosten-Tracking-Fundament. Schema und Persistenz: - Neue Flyway-Migration V2__token_tracking.sql mit sechs Token-/Preis-Snapshot- Spalten in processing_attempt, neuer model_price-Tabelle (Composite-Key provider+model_name) und Default-Preisen fuer beide Provider-Familien. - SqliteModelPriceRepositoryAdapter mit UPSERT, transaktionalem Batch und invalidUpdatedAt-Mapping. - Zentrale SqliteConnectionFactory; alle direkten DriverManager.getConnection- Stellen in den Repository-Adaptern (Document, Attempt, History, UnitOfWork) auf die Factory umgezogen, damit WAL und busy_timeout pro Connection greifen. Application und Domain: - Neue DTOs AiUsageMetadata, ModelPriceEntry/View/Key/ChangeSet, CostResult. - AiInvocationSuccess um usageMetadata erweitert; AiAttemptContext um vier nullable Token-Felder. - ProcessingAttempt um sechs Token-/Preis-Snapshot-Felder erweitert (Convenience-Konstruktor und withoutAiFields-Factory unveraendert). - ModelPriceRepository-Port mit Schreib-/Lese-Trennung. - DefaultManageModelPricesUseCase mit ChangeSet-Konfliktvalidierung, Provider-Whitelist und Clock-Stempel. - CostCalculator (formatRow + calculateAttempt; formatTotal als Stub fuer AP-B). KI-Adapter: - AnthropicClaudeHttpAdapter und OpenAiHttpAdapter extrahieren Token-Daten aus den Response-Bodies inklusive Validierung (negativ, > 10 Mio., nicht numerisch -> NULL + WARN-Log). BatchRunProcessingUseCase-Hook: - DocumentProcessingCoordinator erhaelt optional ModelPriceRepository und ein Headless-Flag. Beim Bau eines KI-Versuchs wird der Snapshot-Preis fuer (Provider, Modell) geladen und mit den Token-Daten am ProcessingAttempt persistiert. Lookup-Fehler verlieren keinen Attempt. GUI: - Neuer Tab "Modell-Preise" (TableView mit Editierfeldern, Add-Dialog, Loesch-Bestaetigung, Konvertierung Nano-USD <-> $/1M Tokens). - History-Tab um drei Spalten erweitert: Input-Tokens, Output-Tokens, Kosten. - Summary-Banner um Token-, Kosten- und Cache-only-Zeile erweitert (Default-Werte; AP-B liefert spaeter die echten Aggregate). - Konfigurations-Tab warnt beim Speichern, wenn das aktive Modell keinen Preis-Eintrag hat. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
65 lines
3.7 KiB
SQL
65 lines
3.7 KiB
SQL
-- V2: Token-Erfassung mit Preis-Snapshot in processing_attempt;
|
|
-- neue model_price-Tabelle mit Composite Primary Key.
|
|
-- Verifizierter Stand: V1__initial_schema.sql ist die einzige bisherige
|
|
-- Migration im Projekt.
|
|
|
|
ALTER TABLE processing_attempt
|
|
ADD COLUMN input_tokens INTEGER
|
|
CHECK (input_tokens IS NULL OR (input_tokens >= 0 AND input_tokens <= 10000000));
|
|
|
|
ALTER TABLE processing_attempt
|
|
ADD COLUMN output_tokens INTEGER
|
|
CHECK (output_tokens IS NULL OR (output_tokens >= 0 AND output_tokens <= 10000000));
|
|
|
|
ALTER TABLE processing_attempt
|
|
ADD COLUMN cache_creation_input_tokens INTEGER
|
|
CHECK (cache_creation_input_tokens IS NULL OR (cache_creation_input_tokens >= 0 AND cache_creation_input_tokens <= 10000000));
|
|
|
|
ALTER TABLE processing_attempt
|
|
ADD COLUMN cache_read_input_tokens INTEGER
|
|
CHECK (cache_read_input_tokens IS NULL OR (cache_read_input_tokens >= 0 AND cache_read_input_tokens <= 10000000));
|
|
|
|
ALTER TABLE processing_attempt
|
|
ADD COLUMN price_input_per_token_nano_usd INTEGER
|
|
CHECK (price_input_per_token_nano_usd IS NULL OR (price_input_per_token_nano_usd >= 0 AND price_input_per_token_nano_usd <= 100000000));
|
|
|
|
ALTER TABLE processing_attempt
|
|
ADD COLUMN price_output_per_token_nano_usd INTEGER
|
|
CHECK (price_output_per_token_nano_usd IS NULL OR (price_output_per_token_nano_usd >= 0 AND price_output_per_token_nano_usd <= 100000000));
|
|
|
|
CREATE TABLE model_price (
|
|
provider TEXT NOT NULL,
|
|
model_name TEXT NOT NULL,
|
|
price_input_per_token_nano_usd INTEGER NOT NULL CHECK (price_input_per_token_nano_usd >= 0 AND price_input_per_token_nano_usd <= 100000000),
|
|
price_output_per_token_nano_usd INTEGER NOT NULL CHECK (price_output_per_token_nano_usd >= 0 AND price_output_per_token_nano_usd <= 100000000),
|
|
currency TEXT NOT NULL DEFAULT 'USD' CHECK (currency = 'USD'),
|
|
updated_at TEXT NOT NULL,
|
|
PRIMARY KEY (provider, model_name)
|
|
);
|
|
|
|
CREATE INDEX idx_processing_attempt_started_at_provider_fp_model
|
|
ON processing_attempt (started_at, ai_provider, fingerprint, model_name);
|
|
|
|
CREATE INDEX idx_processing_attempt_run_id_provider_model
|
|
ON processing_attempt (run_id, ai_provider, model_name);
|
|
|
|
-- Default-Preise (Stand 2026-05-08, in Nano-USD pro Token)
|
|
-- Quellen (abgerufen 2026-05-08):
|
|
-- OpenAI: https://openai.com/api/pricing/
|
|
-- Anthropic: https://www.anthropic.com/pricing
|
|
-- ON CONFLICT DO NOTHING: schuetzt vor manuell vorhandenen Default-Zeilen.
|
|
INSERT INTO model_price
|
|
(provider, model_name, price_input_per_token_nano_usd, price_output_per_token_nano_usd, currency, updated_at)
|
|
VALUES
|
|
('openai-compatible', 'gpt-4o-mini', 150, 600, 'USD', '2026-05-08T00:00:00Z'),
|
|
('openai-compatible', 'gpt-4o', 2500, 10000, 'USD', '2026-05-08T00:00:00Z'),
|
|
('openai-compatible', 'gpt-4.1', 2000, 8000, 'USD', '2026-05-08T00:00:00Z'),
|
|
('openai-compatible', 'gpt-4.1-mini', 400, 1600, 'USD', '2026-05-08T00:00:00Z'),
|
|
('openai-compatible', 'gpt-4.1-nano', 100, 400, 'USD', '2026-05-08T00:00:00Z'),
|
|
('openai-compatible', 'gpt-5', 1250, 10000, 'USD', '2026-05-08T00:00:00Z'),
|
|
('openai-compatible', 'gpt-5-mini', 250, 2000, 'USD', '2026-05-08T00:00:00Z'),
|
|
('claude', 'claude-haiku-4-5-20251001', 1000, 5000, 'USD', '2026-05-08T00:00:00Z'),
|
|
('claude', 'claude-sonnet-4-6', 3000, 15000, 'USD', '2026-05-08T00:00:00Z'),
|
|
('claude', 'claude-opus-4-7', 5000, 25000, 'USD', '2026-05-08T00:00:00Z')
|
|
ON CONFLICT (provider, model_name) DO NOTHING;
|