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:
17
public/class-peptide-news-public.php
Normal file → Executable file
17
public/class-peptide-news-public.php
Normal file → Executable file
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
declare( strict_types=1 );
|
||||
/**
|
||||
* Public-facing functionality.
|
||||
*
|
||||
@@ -16,7 +17,7 @@ class Peptide_News_Public {
|
||||
/** @var string */
|
||||
private $version;
|
||||
|
||||
public function __construct( $plugin_name, $version ) {
|
||||
public function __construct( string $plugin_name, string $version ) {
|
||||
$this->plugin_name = $plugin_name;
|
||||
$this->version = $version;
|
||||
}
|
||||
@@ -24,7 +25,7 @@ class Peptide_News_Public {
|
||||
/**
|
||||
* Register front-end CSS (enqueued on demand by the shortcode/widget).
|
||||
*/
|
||||
public function enqueue_styles() {
|
||||
public function enqueue_styles(): void {
|
||||
wp_register_style(
|
||||
$this->plugin_name,
|
||||
PEPTIDE_NEWS_PLUGIN_URL . 'public/css/public-style.css',
|
||||
@@ -40,7 +41,7 @@ class Peptide_News_Public {
|
||||
* Loads React (from WordPress core), the feed component, and
|
||||
* passes configuration via wp_localize_script.
|
||||
*/
|
||||
public function enqueue_scripts() {
|
||||
public function enqueue_scripts(): void {
|
||||
// React feed component (depends on WP-bundled React).
|
||||
wp_register_script(
|
||||
$this->plugin_name . '-feed',
|
||||
@@ -54,14 +55,14 @@ class Peptide_News_Public {
|
||||
/**
|
||||
* Register the shortcode.
|
||||
*/
|
||||
public function register_shortcode() {
|
||||
public function register_shortcode(): void {
|
||||
add_shortcode( 'peptide_news', array( $this, 'render_shortcode' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the widget.
|
||||
*/
|
||||
public function register_widget() {
|
||||
public function register_widget(): void {
|
||||
register_widget( 'Peptide_News_Widget' );
|
||||
}
|
||||
|
||||
@@ -75,7 +76,7 @@ class Peptide_News_Public {
|
||||
* @param array $atts Shortcode attributes.
|
||||
* @return string HTML output.
|
||||
*/
|
||||
public function render_shortcode( $atts ) {
|
||||
public function render_shortcode( $atts ): string {
|
||||
$atts = shortcode_atts( array(
|
||||
'count' => get_option( 'peptide_news_articles_count', 10 ),
|
||||
), $atts, 'peptide_news' );
|
||||
@@ -102,7 +103,7 @@ class Peptide_News_Public {
|
||||
/**
|
||||
* Handle AJAX click tracking with basic rate limiting.
|
||||
*/
|
||||
public function handle_click_tracking() {
|
||||
public function handle_click_tracking(): void {
|
||||
check_ajax_referer( 'peptide_news_track', 'nonce' );
|
||||
|
||||
$article_id = isset( $_POST['article_id'] ) ? absint( $_POST['article_id'] ) : 0;
|
||||
@@ -142,7 +143,7 @@ class Peptide_News_Public {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_or_create_session_id() {
|
||||
private function get_or_create_session_id(): string {
|
||||
if ( isset( $_COOKIE['pn_session_id'] ) ) {
|
||||
return sanitize_text_field( wp_unslash( $_COOKIE['pn_session_id'] ) );
|
||||
}
|
||||
|
||||
0
public/css/public-style.css
Normal file → Executable file
0
public/css/public-style.css
Normal file → Executable file
0
public/images/default-thumb.png
Normal file → Executable file
0
public/images/default-thumb.png
Normal file → Executable file
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
0
public/js/peptide-news-feed.js
Normal file → Executable file
0
public/js/peptide-news-feed.js
Normal file → Executable file
0
public/js/public-script.js
Normal file → Executable file
0
public/js/public-script.js
Normal file → Executable file
0
public/react-app/PeptideNewsFeed.jsx
Normal file → Executable file
0
public/react-app/PeptideNewsFeed.jsx
Normal file → Executable file
Reference in New Issue
Block a user