feat: consolidate docs, backend/session infra, and settings updates
This commit is contained in:
@@ -18,6 +18,14 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
*/
|
||||
class WP_Agentic_Writer_Cost_Tracker {
|
||||
|
||||
/**
|
||||
* Singleton instance.
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @var WP_Agentic_Writer_Cost_Tracker
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Get singleton instance.
|
||||
*
|
||||
@@ -25,13 +33,11 @@ class WP_Agentic_Writer_Cost_Tracker {
|
||||
* @return WP_Agentic_Writer_Cost_Tracker
|
||||
*/
|
||||
public static function get_instance() {
|
||||
static $instance = null;
|
||||
|
||||
if ( null === $instance ) {
|
||||
$instance = new self();
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return $instance;
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,22 +46,82 @@ class WP_Agentic_Writer_Cost_Tracker {
|
||||
* @since 0.1.0
|
||||
*/
|
||||
private function __construct() {
|
||||
// Hooks for tracking costs.
|
||||
add_action( 'wp_aw_after_api_request', array( $this, 'add_request' ), 10, 6 );
|
||||
// Hooks for tracking costs - accept 9 args (provider, session_id, status added).
|
||||
add_action( 'wp_aw_after_api_request', array( $this, 'add_request' ), 10, 9 );
|
||||
|
||||
// Ensure table has new columns on first access.
|
||||
$this->maybe_upgrade_table();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure table has latest schema with provider/session/status columns.
|
||||
*
|
||||
* @since 0.2.0
|
||||
*/
|
||||
private function maybe_upgrade_table() {
|
||||
global $wpdb;
|
||||
static $checked = false;
|
||||
|
||||
if ( $checked ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$table_name = $wpdb->prefix . 'wpaw_cost_tracking';
|
||||
|
||||
// Check if table exists first.
|
||||
$table_exists = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table_name ) );
|
||||
if ( ! $table_exists ) {
|
||||
// Table missing - trigger recreation.
|
||||
if ( function_exists( 'wp_agentic_writer_create_cost_table' ) ) {
|
||||
wp_agentic_writer_create_cost_table();
|
||||
}
|
||||
$checked = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if new columns exist.
|
||||
$columns = $wpdb->get_col( "DESCRIBE {$table_name}", 0 );
|
||||
|
||||
$needs_provider = ! in_array( 'provider', $columns, true );
|
||||
$needs_session = ! in_array( 'session_id', $columns, true );
|
||||
$needs_status = ! in_array( 'status', $columns, true );
|
||||
|
||||
if ( $needs_provider || $needs_session || $needs_status ) {
|
||||
$alter_parts = array();
|
||||
|
||||
if ( $needs_provider ) {
|
||||
$alter_parts[] = "ADD COLUMN provider varchar(50) DEFAULT 'openrouter' AFTER action";
|
||||
}
|
||||
if ( $needs_session ) {
|
||||
$alter_parts[] = "ADD COLUMN session_id varchar(32) DEFAULT '' AFTER post_id";
|
||||
}
|
||||
if ( $needs_status ) {
|
||||
$alter_parts[] = "ADD COLUMN status varchar(20) DEFAULT 'success' AFTER cost";
|
||||
}
|
||||
|
||||
if ( ! empty( $alter_parts ) ) {
|
||||
$wpdb->query( "ALTER TABLE {$table_name} " . implode( ', ', $alter_parts ) );
|
||||
}
|
||||
}
|
||||
|
||||
$checked = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add API request to cost tracking.
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @since 0.2.0 Parameters changed: added provider, session_id, status.
|
||||
* @param int $post_id Post ID.
|
||||
* @param string $model Model name.
|
||||
* @param string $action Action type (planning, execution, research, image).
|
||||
* @param int $input_tokens Input tokens.
|
||||
* @param int $output_tokens Output tokens.
|
||||
* @param float $cost Cost in USD.
|
||||
* @param string $provider Provider name (optional, defaults to 'unknown').
|
||||
* @param string $session_id Session ID (optional).
|
||||
* @param string $status Request status (optional, defaults to 'success').
|
||||
*/
|
||||
public function add_request( $post_id, $model, $action, $input_tokens, $output_tokens, $cost ) {
|
||||
public function add_request( $post_id, $model, $action, $input_tokens, $output_tokens, $cost, $provider = 'unknown', $session_id = '', $status = 'success' ) {
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . 'wpaw_cost_tracking';
|
||||
@@ -64,14 +130,90 @@ class WP_Agentic_Writer_Cost_Tracker {
|
||||
$table_name,
|
||||
array(
|
||||
'post_id' => $post_id,
|
||||
'session_id' => $session_id,
|
||||
'model' => $model,
|
||||
'provider' => $provider,
|
||||
'action' => $action,
|
||||
'input_tokens' => $input_tokens,
|
||||
'output_tokens' => $output_tokens,
|
||||
'cost' => $cost,
|
||||
'status' => $status,
|
||||
'created_at' => current_time( 'mysql' ),
|
||||
),
|
||||
array( '%d', '%s', '%s', '%d', '%d', '%f', '%s' )
|
||||
array( '%d', '%s', '%s', '%s', '%s', '%d', '%d', '%f', '%s', '%s' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy add_request for backward compatibility (4 params).
|
||||
*
|
||||
* @deprecated 0.2.0 Use add_request with all parameters.
|
||||
* @param int $post_id Post ID.
|
||||
* @param string $model Model name.
|
||||
* @param string $action Action type.
|
||||
* @param int $input_tokens Input tokens.
|
||||
* @param int $output_tokens Output tokens.
|
||||
* @param float $cost Cost in USD.
|
||||
*/
|
||||
public function add_request_legacy( $post_id, $model, $action, $input_tokens, $output_tokens, $cost ) {
|
||||
$this->add_request( $post_id, $model, $action, $input_tokens, $output_tokens, $cost );
|
||||
}
|
||||
|
||||
/**
|
||||
* Record usage from WP AI Client wrapper (legacy contract).
|
||||
*
|
||||
* This method provides backward compatibility for the WP AI Client wrapper
|
||||
* and other callers that use a simpler interface.
|
||||
*
|
||||
* @deprecated 0.1.4 Use record_usage_full() instead for accurate provider attribution.
|
||||
* @since 0.1.3
|
||||
* @param int $post_id Post ID.
|
||||
* @param string $action Action/task type (e.g., 'chat', 'planning', 'writing').
|
||||
* @param string $model Model identifier.
|
||||
* @param float $cost Cost in USD.
|
||||
* @param string $session_id Session ID (optional).
|
||||
*/
|
||||
public function record_usage( $post_id, $action, $model, $cost, $session_id = '' ) {
|
||||
$this->record_usage_full(
|
||||
$post_id,
|
||||
$model,
|
||||
$action,
|
||||
0, // input_tokens - not available in wrapper
|
||||
0, // output_tokens - not available in wrapper
|
||||
$cost,
|
||||
'unknown', // deprecated wrapper - provider unknown
|
||||
$session_id,
|
||||
'success'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record usage with full metadata.
|
||||
*
|
||||
* Use this method when you have complete information about the request.
|
||||
*
|
||||
* @since 0.1.4
|
||||
* @param int $post_id Post ID.
|
||||
* @param string $model Model identifier.
|
||||
* @param string $action Action/task type.
|
||||
* @param int $input_tokens Input token count.
|
||||
* @param int $output_tokens Output token count.
|
||||
* @param float $cost Cost in USD.
|
||||
* @param string $provider Provider name.
|
||||
* @param string $session_id Session ID.
|
||||
* @param string $status Request status.
|
||||
*/
|
||||
public function record_usage_full( $post_id, $model, $action, $input_tokens, $output_tokens, $cost, $provider, $session_id = '', $status = 'success' ) {
|
||||
$this->add_request(
|
||||
$post_id,
|
||||
$model,
|
||||
$action,
|
||||
$input_tokens,
|
||||
$output_tokens,
|
||||
$cost,
|
||||
$provider,
|
||||
$session_id,
|
||||
$status
|
||||
);
|
||||
}
|
||||
|
||||
@@ -94,7 +236,7 @@ class WP_Agentic_Writer_Cost_Tracker {
|
||||
)
|
||||
);
|
||||
|
||||
return floatval( $total );
|
||||
return floatval( $total ) + $this->get_image_variants_total_for_post( $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,15 +249,16 @@ class WP_Agentic_Writer_Cost_Tracker {
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . 'wpaw_cost_tracking';
|
||||
$month_start = date( 'Y-m-01 00:00:00' );
|
||||
|
||||
$total = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT SUM(cost) FROM {$table_name} WHERE created_at >= %s",
|
||||
date( 'Y-m-01 00:00:00' )
|
||||
$month_start
|
||||
)
|
||||
);
|
||||
|
||||
return floatval( $total );
|
||||
return floatval( $total ) + $this->get_image_variants_total_since( $month_start );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,6 +296,15 @@ class WP_Agentic_Writer_Cost_Tracker {
|
||||
$total_tokens += intval( $row['tokens'] );
|
||||
}
|
||||
|
||||
$image_cost = $this->get_image_variants_total_since( date( 'Y-m-d 00:00:00' ) );
|
||||
if ( $image_cost > 0 ) {
|
||||
$usage['image_generation'] = array(
|
||||
'tokens' => 0,
|
||||
'cost' => $image_cost,
|
||||
);
|
||||
$total_cost += $image_cost;
|
||||
}
|
||||
|
||||
$usage['total'] = array(
|
||||
'cost' => $total_cost,
|
||||
'tokens' => $total_tokens,
|
||||
@@ -205,7 +357,129 @@ class WP_Agentic_Writer_Cost_Tracker {
|
||||
ARRAY_A
|
||||
);
|
||||
|
||||
return $results;
|
||||
$history = $results ?: array();
|
||||
$image_history = $this->get_image_variants_history_for_post( $post_id, $limit );
|
||||
$history = array_merge( $history, $image_history );
|
||||
|
||||
usort(
|
||||
$history,
|
||||
function( $a, $b ) {
|
||||
return strcmp( $b['created_at'] ?? '', $a['created_at'] ?? '' );
|
||||
}
|
||||
);
|
||||
|
||||
return array_slice( $history, 0, $limit );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a table exists.
|
||||
*
|
||||
* @since 0.2.1
|
||||
* @param string $table_name Table name.
|
||||
* @return bool
|
||||
*/
|
||||
private function table_exists( $table_name ) {
|
||||
global $wpdb;
|
||||
return (bool) $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get image variant generation total for a post.
|
||||
*
|
||||
* @since 0.2.1
|
||||
* @param int $post_id Post ID.
|
||||
* @return float
|
||||
*/
|
||||
private function get_image_variants_total_for_post( $post_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . 'wpaw_images_variants';
|
||||
if ( $post_id <= 0 || ! $this->table_exists( $table_name ) ) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$total = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT SUM(cost) FROM {$table_name} WHERE post_id = %d",
|
||||
$post_id
|
||||
)
|
||||
);
|
||||
|
||||
return floatval( $total );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get image variant generation total since a timestamp.
|
||||
*
|
||||
* @since 0.2.1
|
||||
* @param string $since MySQL datetime.
|
||||
* @return float
|
||||
*/
|
||||
private function get_image_variants_total_since( $since ) {
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . 'wpaw_images_variants';
|
||||
if ( ! $this->table_exists( $table_name ) ) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$total = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT SUM(cost) FROM {$table_name} WHERE created_at >= %s",
|
||||
$since
|
||||
)
|
||||
);
|
||||
|
||||
return floatval( $total );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get image variant generation history for a post in cost-history shape.
|
||||
*
|
||||
* @since 0.2.1
|
||||
* @param int $post_id Post ID.
|
||||
* @param int $limit Limit.
|
||||
* @return array
|
||||
*/
|
||||
private function get_image_variants_history_for_post( $post_id, $limit = 50 ) {
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . 'wpaw_images_variants';
|
||||
if ( $post_id <= 0 || ! $this->table_exists( $table_name ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$rows = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT id, post_id, image_model_used, cost, generation_time, status, created_at
|
||||
FROM {$table_name}
|
||||
WHERE post_id = %d
|
||||
ORDER BY created_at DESC
|
||||
LIMIT %d",
|
||||
$post_id,
|
||||
$limit
|
||||
),
|
||||
ARRAY_A
|
||||
);
|
||||
|
||||
return array_map(
|
||||
function( $row ) {
|
||||
return array(
|
||||
'id' => 'image_variant_' . ( $row['id'] ?? '' ),
|
||||
'post_id' => (int) ( $row['post_id'] ?? 0 ),
|
||||
'session_id' => '',
|
||||
'model' => $row['image_model_used'] ?? '',
|
||||
'provider' => 'openrouter',
|
||||
'action' => 'image_generation',
|
||||
'input_tokens' => 0,
|
||||
'output_tokens' => 0,
|
||||
'cost' => (float) ( $row['cost'] ?? 0 ),
|
||||
'status' => $row['status'] ?? '',
|
||||
'created_at' => $row['created_at'] ?? '',
|
||||
);
|
||||
},
|
||||
$rows ?: array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user