feat: add LLM cost tracking with budget enforcement and admin dashboard
- New Cost_Tracker class: logs every API call (model, tokens, cost), enforces monthly budgets with hard-stop mode, provides aggregated reporting - New llm_costs database table with indexes on created_at, model, operation - Modified LLM class: call_openrouter_with_usage() extracts token usage from OpenRouter responses; budget gate checks before each API call - Admin settings: monthly budget (USD), enforcement mode (disabled/warn/hard-stop), cost log retention period - Admin cost dashboard: budget progress bar, daily cost chart (Chart.js), per-model and per-operation breakdowns, recent API call log - PHPUnit tests: 16 tests covering cost calculation, pricing lookups, budget enforcement logic, and model validation - Updated ARCHITECTURE.md with new table schema, data flow, and key decisions - Updated CONVENTIONS.md with "how to add cost tracking for a new operation" - Version bump to 2.4.0 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
19
includes/class-peptide-news-activator.php
Normal file → Executable file
19
includes/class-peptide-news-activator.php
Normal file → Executable file
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare( strict_types=1 );
|
||||
/**
|
||||
* Fired during plugin activation.
|
||||
*
|
||||
@@ -11,7 +12,7 @@ class Peptide_News_Activator {
|
||||
/**
|
||||
* Create custom tables and schedule cron.
|
||||
*/
|
||||
public static function activate() {
|
||||
public static function activate(): void {
|
||||
self::create_tables();
|
||||
self::set_default_options();
|
||||
self::schedule_cron();
|
||||
@@ -20,12 +21,17 @@ class Peptide_News_Activator {
|
||||
if ( class_exists( 'Peptide_News_Logger' ) ) {
|
||||
Peptide_News_Logger::create_table();
|
||||
}
|
||||
|
||||
// Create the LLM cost tracking table (idempotent via dbDelta).
|
||||
if ( class_exists( 'Peptide_News_Cost_Tracker' ) ) {
|
||||
Peptide_News_Cost_Tracker::create_table();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the articles and analytics database tables.
|
||||
*/
|
||||
private static function create_tables() {
|
||||
private static function create_tables(): void {
|
||||
global $wpdb;
|
||||
|
||||
$charset_collate = $wpdb->get_charset_collate();
|
||||
@@ -107,7 +113,7 @@ class Peptide_News_Activator {
|
||||
/**
|
||||
* Set sensible default option values.
|
||||
*/
|
||||
private static function set_default_options() {
|
||||
private static function set_default_options(): void {
|
||||
$defaults = array(
|
||||
'fetch_interval' => 'twicedaily',
|
||||
'articles_count' => 10,
|
||||
@@ -128,6 +134,9 @@ class Peptide_News_Activator {
|
||||
'llm_keywords_model' => 'google/gemini-2.0-flash-001',
|
||||
'llm_summary_model' => 'google/gemini-2.0-flash-001',
|
||||
'llm_max_articles' => 10,
|
||||
'monthly_budget' => 0,
|
||||
'budget_mode' => 'disabled',
|
||||
'cost_retention' => 365,
|
||||
);
|
||||
|
||||
foreach ( $defaults as $key => $value ) {
|
||||
@@ -140,7 +149,7 @@ class Peptide_News_Activator {
|
||||
/**
|
||||
* Schedule the cron event based on the configured interval.
|
||||
*/
|
||||
private static function schedule_cron() {
|
||||
private static function schedule_cron(): void {
|
||||
$interval = get_option( 'peptide_news_fetch_interval', 'twicedaily' );
|
||||
|
||||
if ( ! wp_next_scheduled( 'peptide_news_cron_fetch' ) ) {
|
||||
@@ -151,7 +160,7 @@ class Peptide_News_Activator {
|
||||
/**
|
||||
* Add foreign key constraints to tables.
|
||||
*/
|
||||
private static function add_foreign_key_constraints( $articles_table, $clicks_table, $daily_table ) {
|
||||
private static function add_foreign_key_constraints( string $articles_table, string $clicks_table, string $daily_table ): void {
|
||||
global $wpdb;
|
||||
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
||||
|
||||
Reference in New Issue
Block a user