wpmind/modules/cost-control/CostControlModule.php
LinuxJoy 74db7a20af refactor: 方法名 camelCase → snake_case (39文件, WordPress 编码规范)
将项目自有代码的方法名从 camelCase 统一为 snake_case,
符合 WordPress PHP 编码规范。涉及 Routing、Failover、Budget、
Analytics、Usage、ErrorHandler 等模块。外部库接口方法和
Image Provider 子系统保持不变。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-07 03:21:31 +08:00

305 lines
No EOL
8.2 KiB
PHP

<?php
/**
* Cost Control Module
*
* AI service cost control module for WPMind.
*
* @package WPMind\Modules\CostControl
* @since 1.0.0
*/
declare(strict_types=1);
namespace WPMind\Modules\CostControl;
use WPMind\Core\ModuleInterface;
// Load module classes.
require_once __DIR__ . '/includes/UsageTracker.php';
require_once __DIR__ . '/includes/BudgetManager.php';
require_once __DIR__ . '/includes/BudgetChecker.php';
require_once __DIR__ . '/includes/BudgetAlert.php';
/**
* Class CostControlModule
*
* Main entry point for the cost control module.
*/
class CostControlModule implements ModuleInterface {
/**
* Module components.
*
* @var array
*/
private array $components = [];
/**
* Get module ID.
*
* @return string
*/
public function get_id(): string {
return 'cost-control';
}
/**
* Get module name.
*
* @return string
*/
public function get_name(): string {
return __( 'Cost Control', 'wpmind' );
}
/**
* Get module description.
*
* @return string
*/
public function get_description(): string {
return __( 'AI 服务费用控制 - 用量追踪、预算限额、告警通知', 'wpmind' );
}
/**
* Get module version.
*
* @return string
*/
public function get_version(): string {
return '1.0.0';
}
/**
* Check dependencies.
*
* @return bool
*/
public function check_dependencies(): bool {
// Cost control module has no external dependencies.
return true;
}
/**
* Get settings tab slug.
*
* @return string|null
*/
public function get_settings_tab(): ?string {
return 'cost-control';
}
/**
* Initialize the module.
*/
public function init(): void {
// Initialize components.
$this->init_components();
// Register settings tab.
add_filter( 'wpmind_settings_tabs', array( $this, 'register_settings_tab' ) );
// Register AJAX handlers.
add_action( 'wp_ajax_wpmind_save_cost_control_settings', array( $this, 'ajax_save_settings' ) );
add_action( 'wp_ajax_wpmind_get_cost_control_status', array( $this, 'ajax_get_status' ) );
add_action( 'wp_ajax_wpmind_clear_usage_stats', array( $this, 'ajax_clear_stats' ) );
// Register usage recording hook (event-driven architecture).
add_action( 'wpmind_usage_record', array( $this, 'record_usage' ), 10, 5 );
/**
* Fires when Cost Control module is initialized.
*
* @param CostControlModule $this Module instance.
*/
do_action( 'wpmind_cost_control_init', $this );
}
/**
* Initialize module components.
*/
private function init_components(): void {
// Usage Tracker (always active).
$this->components['usage_tracker'] = UsageTracker::class;
// Budget Manager.
$this->components['budget_manager'] = BudgetManager::instance();
// Budget Checker.
$this->components['budget_checker'] = BudgetChecker::instance();
// Budget Alert (initialize to register hooks).
BudgetAlert::init();
$this->components['budget_alert'] = BudgetAlert::instance();
}
/**
* Register settings tab.
*
* @param array $tabs Existing tabs.
* @return array Modified tabs.
*/
public function register_settings_tab( array $tabs ): array {
$tabs['cost-control'] = array(
'title' => __( 'Cost Control', 'wpmind' ),
'icon' => 'ri-money-cny-circle-line',
'template' => WPMIND_PATH . 'modules/cost-control/templates/settings.php',
'priority' => 25,
);
return $tabs;
}
/**
* Record usage via event-driven hook.
*
* @param string $provider Provider ID.
* @param string $model Model name.
* @param int $input_tokens Input tokens.
* @param int $output_tokens Output tokens.
* @param int $latency_ms Latency in milliseconds.
*/
public function record_usage( string $provider, string $model, int $input_tokens, int $output_tokens, int $latency_ms = 0 ): void {
UsageTracker::record( $provider, $model, $input_tokens, $output_tokens, $latency_ms );
// Check budget and send alerts.
BudgetAlert::instance()->check_and_alert();
/**
* Fires after usage has been recorded by the Cost Control module.
*
* This action is used to signal that usage recording has been handled,
* preventing duplicate recording by backward compatibility code.
*
* @since 1.0.0
*
* @param string $provider Provider ID.
* @param string $model Model name.
* @param int $input_tokens Input tokens.
* @param int $output_tokens Output tokens.
* @param int $latency_ms Latency in milliseconds.
*/
do_action( 'wpmind_usage_recorded', $provider, $model, $input_tokens, $output_tokens, $latency_ms );
}
/**
* AJAX handler for saving settings.
*/
public function ajax_save_settings(): void {
check_ajax_referer( 'wpmind_ajax', 'nonce' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( array( 'message' => __( '权限不足', 'wpmind' ) ) );
}
// Parse JSON data.
$json_input = isset( $_POST['settings'] ) ? wp_unslash( $_POST['settings'] ) : '';
$input = json_decode( $json_input, true );
if ( ! is_array( $input ) ) {
wp_send_json_error( array( 'message' => __( '无效的数据格式', 'wpmind' ) ) );
}
// Build settings array.
$settings = array();
$settings['enabled'] = ! empty( $input['enabled'] );
$settings['global'] = array(
'daily_limit_usd' => (float) ( $input['global']['daily_limit_usd'] ?? 0 ),
'daily_limit_cny' => (float) ( $input['global']['daily_limit_cny'] ?? 0 ),
'monthly_limit_usd' => (float) ( $input['global']['monthly_limit_usd'] ?? 0 ),
'monthly_limit_cny' => (float) ( $input['global']['monthly_limit_cny'] ?? 0 ),
'alert_threshold' => (int) ( $input['global']['alert_threshold'] ?? 80 ),
);
$settings['enforcement_mode'] = sanitize_text_field( $input['enforcement_mode'] ?? 'alert' );
$settings['notifications'] = array(
'admin_notice' => ! empty( $input['notifications']['admin_notice'] ),
'email_alert' => ! empty( $input['notifications']['email_alert'] ),
'email_address' => sanitize_email( $input['notifications']['email_address'] ?? '' ),
);
// Provider-specific settings.
$settings['providers'] = array();
if ( ! empty( $input['providers'] ) && is_array( $input['providers'] ) ) {
foreach ( $input['providers'] as $provider => $limits ) {
$provider = sanitize_key( $provider );
$settings['providers'][ $provider ] = array(
'daily_limit' => (float) ( $limits['daily_limit'] ?? 0 ),
'monthly_limit' => (float) ( $limits['monthly_limit'] ?? 0 ),
);
}
}
$manager = BudgetManager::instance();
$result = $manager->save_settings( $settings );
if ( $result ) {
wp_send_json_success( array( 'message' => __( '设置已保存', 'wpmind' ) ) );
} else {
wp_send_json_error( array( 'message' => __( '保存失败', 'wpmind' ) ) );
}
}
/**
* AJAX handler for getting status.
*/
public function ajax_get_status(): void {
check_ajax_referer( 'wpmind_ajax', 'nonce' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( array( 'message' => __( '权限不足', 'wpmind' ) ) );
}
$checker = BudgetChecker::instance();
$summary = $checker->get_summary();
$stats = UsageTracker::get_stats();
$today = UsageTracker::get_today_stats();
$month = UsageTracker::get_month_stats();
wp_send_json_success( array(
'budget' => $summary,
'stats' => $stats,
'today' => $today,
'month' => $month,
) );
}
/**
* AJAX handler for clearing stats.
*/
public function ajax_clear_stats(): void {
check_ajax_referer( 'wpmind_ajax', 'nonce' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( array( 'message' => __( '权限不足', 'wpmind' ) ) );
}
UsageTracker::clear_all();
wp_send_json_success( array( 'message' => __( '用量统计已清除', 'wpmind' ) ) );
}
/**
* Get a component instance.
*
* @param string $name Component name.
* @return object|null Component instance or null.
*/
public function get_component( string $name ): ?object {
$component = $this->components[ $name ] ?? null;
if ( is_string( $component ) && class_exists( $component ) ) {
return null; // Static class, no instance.
}
return $component;
}
/**
* Get all components.
*
* @return array Components array.
*/
public function get_components(): array {
return $this->components;
}
}