array( __CLASS__, 'sanitize_settings' ), ) ); // OpenRouter Section. add_settings_section( 'psa_ai_section', __( 'OpenRouter API Settings', 'peptide-search-ai' ), array( __CLASS__, 'render_section_description' ), 'peptide-search-ai' ); add_settings_field( 'api_key', __( 'API Key', 'peptide-search-ai' ), array( __CLASS__, 'render_api_key_field' ), 'peptide-search-ai', 'psa_ai_section' ); add_settings_field( 'ai_model', __( 'Generation Model', 'peptide-search-ai' ), array( __CLASS__, 'render_model_field' ), 'peptide-search-ai', 'psa_ai_section' ); add_settings_field( 'validation_model', __( 'Validation Model', 'peptide-search-ai' ), array( __CLASS__, 'render_validation_model_field' ), 'peptide-search-ai', 'psa_ai_section' ); // Behavior Section. add_settings_section( 'psa_behavior_section', __( 'Behavior Settings', 'peptide-search-ai' ), null, 'peptide-search-ai' ); add_settings_field( 'auto_publish', __( 'Auto-Publish', 'peptide-search-ai' ), array( __CLASS__, 'render_publish_field' ), 'peptide-search-ai', 'psa_behavior_section' ); add_settings_field( 'use_pubchem', __( 'PubChem Enrichment', 'peptide-search-ai' ), array( __CLASS__, 'render_pubchem_field' ), 'peptide-search-ai', 'psa_behavior_section' ); add_settings_field( 'monthly_budget', __( 'Monthly API Budget (USD)', 'peptide-search-ai' ), array( __CLASS__, 'render_budget_field' ), 'peptide-search-ai', 'psa_behavior_section' ); } /** * Sanitize settings input. * * @param array $input Raw input from the form. * @return array Sanitized settings. */ public static function sanitize_settings( $input ) { // Handle API key: encrypt new values, preserve existing on empty/mask. $api_key_input = $input['api_key'] ?? ''; $api_key_value = ''; if ( ! empty( $api_key_input ) && '••••••••' !== $api_key_input ) { // New key provided: encrypt it. $sanitized = sanitize_text_field( $api_key_input ); $encrypted = PSA_Encryption::encrypt( $sanitized ); $api_key_value = ( false !== $encrypted ) ? $encrypted : ''; } else { // Empty or mask string: preserve existing value. $existing = self::get_setting( 'api_key', '' ); $api_key_value = $existing; } return array( 'api_key' => $api_key_value, 'ai_model' => sanitize_text_field( $input['ai_model'] ?? '' ), 'validation_model' => sanitize_text_field( $input['validation_model'] ?? '' ), 'auto_publish' => sanitize_text_field( $input['auto_publish'] ?? 'draft' ), // Checkbox: if key is absent in POST, it was unchecked → '0'. 'use_pubchem' => ! empty( $input['use_pubchem'] ) ? '1' : '0', 'monthly_budget' => max( 0, floatval( $input['monthly_budget'] ?? PSA_Config::DEFAULT_MONTHLY_BUDGET ) ), ); } // ------------------------------------------------------------------------- // Field renderers // ------------------------------------------------------------------------- public static function render_section_description() { ?>

OpenRouter to access AI models. OpenRouter provides a unified API for hundreds of models including open-source options like Gemini Flash, Llama, Mistral, Qwen, and DeepSeek, as well as commercial models.', 'peptide-search-ai' ), esc_url( 'https://openrouter.ai/' ) ); ?>

openrouter.ai/settings/keys.
define( 'PSA_OPENROUTER_KEY', 'your-key-here' );

google/gemini-2.5-flash.
openrouter.ai/models. meta-llama/llama-4-maverick, deepseek/deepseek-chat-v3-0324, qwen/qwen-2.5-72b-instruct.

google/gemini-2.0-flash-001.
meta-llama/llama-4-scout, mistralai/mistral-small-3.1-24b-instruct.




[peptide_search]

[peptide_search placeholder="Search peptides..."]


GET /wp-json/peptides/v1/search?q=BPC-157

$

created_at ); ?> model ); ?> total_tokens ) ); ?> $estimated_cost_usd, 4 ) ); ?> request_type ); ?> peptide_name ); ?> success ) ? '✓' : '✗'; ?>