PHP Classes

File: templates/admin/ai_settings.twig

Recommend this page to a friend!
  Packages of Matthew Asham   Binkterm PHP   templates/admin/ai_settings.twig   Download  
File: templates/admin/ai_settings.twig
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Binkterm PHP
Bulletin board system based on the Web
Author: By
Last change:
Date: 5 days ago
Size: 12,004 bytes
 

Contents

Class file image Download
{% extends "base.twig" %} {% block title %}{{ t('ui.admin.bbs_settings.ai.page_title', {}, 'common') }}{% endblock %} {% block content %} <div class="container-fluid"> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> <h1 class="h2">{{ t('ui.admin.bbs_settings.ai.heading', {}, 'common') }}</h1> </div> <div class="row g-4"> <div class="col-lg-6"> <div class="card shadow h-100"> <div class="card-header"> <h6 class="mb-0">{{ t('ui.admin.bbs_settings.ai.status_title', {}, 'common') }}</h6> </div> <div class="card-body"> {% for provider in provider_status %} <div class="{% if not loop.last %}mb-3 pb-3 border-bottom{% endif %}"> <div class="d-flex align-items-center mb-2"> <strong class="me-2">{{ provider.display_name }}</strong> {% if provider.configured and provider.name == system_default_provider %} <span class="badge bg-primary me-1">{{ t('ui.admin.bbs_settings.ai.system_default', {}, 'common') }}</span> {% endif %} {% if provider.configured %} <span class="badge bg-success">{{ t('ui.admin.bbs_settings.ai.status_enabled', {}, 'common') }}</span> {% else %} <span class="badge bg-secondary">{{ t('ui.admin.bbs_settings.ai.status_disabled', {}, 'common') }}</span> {% endif %} </div> {% if provider.configured %} <table class="table table-sm table-borderless mb-2"> <tbody> <tr> <td class="text-muted ps-0 py-1" style="width:40%">{{ t('ui.admin.bbs_settings.ai.status_default_model', {}, 'common') }}</td> <td class="py-1"><code>{{ provider.default_model }}</code></td> </tr> <tr> <td class="text-muted ps-0 py-1">{{ t('ui.admin.bbs_settings.ai.status_tools', {}, 'common') }}</td> <td class="py-1"> {% if provider.supports_tools %} <span class="text-success"><i class="fas fa-check me-1"></i>{{ t('ui.admin.bbs_settings.ai.status_tools_yes', {}, 'common') }}</span> {% else %} <span class="text-muted">{{ t('ui.admin.bbs_settings.ai.status_tools_no', {}, 'common') }}</span> {% endif %} </td> </tr> </tbody> </table> {% if provider.power_cost is not null %} <div> <small class="text-muted fw-semibold">{{ t('ui.admin.bbs_settings.ai.power_cost_title', {}, 'common') }}</small><br> {% if provider.power_cost.gpu_watts > 0 and provider.power_cost.per_kwh > 0 %} <small>{{ t('ui.admin.bbs_settings.ai.power_cost_configured', {watts: provider.power_cost.gpu_watts, per_kwh: provider.power_cost.per_kwh, per_hour: provider.power_cost.cost_per_hour}, 'common') }}</small> {% else %} <small class="text-muted">{{ t('ui.admin.bbs_settings.ai.power_cost_not_configured', {}, 'common') }}</small> {% endif %} </div> {% else %} <div> <small class="text-muted fw-semibold">{{ t('ui.admin.bbs_settings.ai.pricing_title', {}, 'common') }}</small><br> {% if provider.pricing.has_pricing %} <table class="table table-sm table-borderless mb-0"> <tbody> <tr> <td class="text-muted ps-0 py-0" style="width:50%"><small>{{ t('ui.admin.bbs_settings.ai.pricing_input', {}, 'common') }}</small></td> <td class="py-0"><small>${{ provider.pricing.input }}</small></td> </tr> <tr> <td class="text-muted ps-0 py-0"><small>{{ t('ui.admin.bbs_settings.ai.pricing_output', {}, 'common') }}</small></td> <td class="py-0"><small>${{ provider.pricing.output }}</small></td> </tr> {% if provider.pricing.cached_input > 0 %} <tr> <td class="text-muted ps-0 py-0"><small>{{ t('ui.admin.bbs_settings.ai.pricing_cached', {}, 'common') }}</small></td> <td class="py-0"><small>${{ provider.pricing.cached_input }}</small></td> </tr> {% endif %} {% if provider.pricing.cache_write > 0 %} <tr> <td class="text-muted ps-0 py-0"><small>{{ t('ui.admin.bbs_settings.ai.pricing_cache_write', {}, 'common') }}</small></td> <td class="py-0"><small>${{ provider.pricing.cache_write }}</small></td> </tr> {% endif %} </tbody> </table> {% else %} <small class="text-muted">{{ t('ui.admin.bbs_settings.ai.pricing_not_configured', {}, 'common') }}</small> {% endif %} </div> {% endif %} {% else %} <small class="text-muted">{{ t('ui.admin.bbs_settings.ai.status_configure_hint', {env_var: provider.env_var_hint}, 'common') }}</small> {% endif %} </div> {% endfor %} </div> </div> </div> <div class="col-lg-6"> <div class="card shadow h-100"> <div class="card-header"> <h6 class="mb-0">{{ t('ui.admin.bbs_settings.ai.features_title', {}, 'common') }}</h6> </div> <div class="card-body"> {% if not ai_available %} <div class="alert alert-warning"> <i class="fas fa-exclamation-triangle me-2"></i>{{ t('ui.admin.bbs_settings.ai.no_provider_warning', {}, 'common') }} </div> {% endif %} <div id="aiSettingsAlert"></div> <form id="aiSettingsForm"> <div class="form-check mb-3"> <input class="form-check-input" type="checkbox" id="aiAssistantEnabled"> <label class="form-check-label" for="aiAssistantEnabled">{{ t('ui.admin.bbs_settings.features.enable_ai_assistant', {}, 'common') }}</label> <div><small class="text-muted">{{ t('ui.admin.bbs_settings.features.ai_assistant_help', {}, 'common') }}</small></div> </div> <div class="form-check mb-3"> <input class="form-check-input" type="checkbox" id="aiShareSummaryEnabled"> <label class="form-check-label" for="aiShareSummaryEnabled">{{ t('ui.admin.bbs_settings.ai.enable_share_summary', {}, 'common') }}</label> <div><small class="text-muted">{{ t('ui.admin.bbs_settings.ai.share_summary_help', {}, 'common') }}</small></div> </div> <div class="mb-3"> <label for="aiShareSummaryPrompt" class="form-label">{{ t('ui.admin.bbs_settings.ai.share_summary_prompt_label', {}, 'common') }}</label> <textarea class="form-control" id="aiShareSummaryPrompt" rows="5" placeholder="{{ share_summary_default_prompt }}"></textarea> <small class="text-muted">{{ t('ui.admin.bbs_settings.ai.share_summary_prompt_help', {}, 'common') }}</small> </div> <button type="button" class="btn btn-primary" onclick="saveAiSettings()">{{ t('ui.admin.bbs_settings.ai.save', {}, 'common') }}</button> </form> </div> </div> </div> </div> </div> {% endblock %} {% block scripts %} <script> function uiT(key, fallback, params = {}) { if (window.t) { return window.t(key, params, fallback); } return fallback; } function apiError(payload, fallback) { if (window.getApiErrorMessage) { return window.getApiErrorMessage(payload, fallback); } return payload && payload.error ? payload.error : fallback; } function showAiSettingsAlert(message, type) { const container = document.getElementById('aiSettingsAlert'); container.innerHTML = ` <div class="alert alert-${type} alert-dismissible fade show" role="alert"> ${message} <button type="button" class="btn-close" data-bs-dismiss="alert"></button> </div> `; } function loadAiSettings() { fetch('/admin/api/bbs-settings') .then(r => r.json()) .then(data => { if (!data.success) throw new Error(apiError(data, uiT('ui.admin.bbs_settings.load_failed', 'Failed to load settings'))); const ai = data.config?.ai_assistant || {}; document.getElementById('aiAssistantEnabled').checked = ai.enabled === true; document.getElementById('aiShareSummaryEnabled').checked = ai.share_summary_enabled === true; document.getElementById('aiShareSummaryPrompt').value = ai.share_summary_prompt || ''; }) .catch(err => showAiSettingsAlert(err.message || uiT('ui.admin.bbs_settings.load_failed', 'Failed to load settings'), 'danger')); } function saveAiSettings() { const payload = { ai_assistant: { enabled: document.getElementById('aiAssistantEnabled').checked, share_summary_enabled: document.getElementById('aiShareSummaryEnabled').checked, share_summary_prompt: document.getElementById('aiShareSummaryPrompt').value, } }; fetch('/admin/api/ai-settings', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }) .then(r => r.json()) .then(data => { if (!data.success) throw new Error(apiError(data, uiT('ui.admin.bbs_settings.ai.save_failed', 'Failed to save AI settings'))); const msg = window.getApiMessage ? window.getApiMessage(data, uiT('ui.admin.bbs_settings.ai.saved_success', 'AI settings saved.')) : uiT('ui.admin.bbs_settings.ai.saved_success', 'AI settings saved.'); showAiSettingsAlert(msg, 'success'); }) .catch(err => showAiSettingsAlert(err.message || uiT('ui.admin.bbs_settings.ai.save_failed', 'Failed to save AI settings'), 'danger')); } document.addEventListener('DOMContentLoaded', function() { loadI18nNamespaces(['common', 'errors']).then(function() { loadAiSettings(); }); }); </script> {% endblock %}