Spaces:
Paused
Paused
| <html> | |
| <head> | |
| <title>Model Presets</title> | |
| <script type="module"> | |
| import { store } from "/plugins/_model_config/webui/model-config-store.js"; | |
| </script> | |
| </head> | |
| <body> | |
| <div x-data | |
| x-init=" | |
| await $store.modelConfig.ensureLoaded(); | |
| await $store.modelConfig.loadGlobalPresets(); | |
| $store.modelConfig.resetApiKeyDrafts(); | |
| await $store.modelConfig.refreshApiKeyStatus(); | |
| "> | |
| <template x-if="$store.modelConfig._loaded && $store.modelConfig._presetsLoaded"> | |
| <div class="presets-page" x-data="{ presets: JSON.parse(JSON.stringify($store.modelConfig.globalPresets)) }"> | |
| <div class="presets-header"> | |
| <div class="field-title" style="font-size:1rem;">Model Presets</div> | |
| <div class="field-description">Global presets shared across all projects and agents. Used by the model switcher in the chat area.</div> | |
| </div> | |
| <template x-for="(preset, idx) in presets" :key="idx"> | |
| <div class="preset-card" x-data="{ expanded: false }"> | |
| <div class="preset-card-header" @click="expanded = !expanded"> | |
| <span class="material-symbols-outlined preset-expand-icon" | |
| :style="expanded ? 'transform:rotate(90deg)' : ''" | |
| style="font-size:16px; transition:transform 0.15s ease;">chevron_right</span> | |
| <span class="preset-card-name" x-text="preset.name || '(unnamed)'"></span> | |
| <span class="preset-card-summary" x-show="!expanded" | |
| x-text="(preset.chat?.provider ? preset.chat.provider + '/' : '') + (preset.chat?.name || '')"></span> | |
| <button class="text-button preset-delete-btn" | |
| @click.stop="$confirmClick($event, () => { presets.splice(idx, 1); presets = [...presets]; })" | |
| title="Remove preset"> | |
| <span class="material-symbols-outlined" style="font-size:16px;">close</span> | |
| </button> | |
| </div> | |
| <div class="preset-card-body" x-show="expanded" x-transition.opacity> | |
| <div class="field"> | |
| <div class="field-label"> | |
| <div class="field-title">Preset name</div> | |
| <div class="field-description">Display name shown in the model switcher dropdown.</div> | |
| </div> | |
| <div class="field-control"><input type="text" x-model="preset.name" placeholder="e.g. GPT-4o, Claude Sonnet" | |
| @blur="if (!preset.name.trim()) preset.name = 'Preset ' + (idx + 1)" required /></div> | |
| </div> | |
| <div class="preset-subheader">Main Model</div> | |
| <div x-data="{ model: preset.chat, modelType: 'chat', providers: $store.modelConfig.chatProviders, searchType: 'chat', apiKeyMode: 'store' }"> | |
| <x-component path="/plugins/_model_config/webui/model-field.html"></x-component> | |
| </div> | |
| <div class="preset-subheader">Utility Model <span style="opacity:0.5; font-size:0.75rem;">(optional — falls back to the configured Utility Model)</span></div> | |
| <div x-data="{ model: preset.utility, modelType: 'utility', providers: $store.modelConfig.chatProviders, searchType: 'chat', apiKeyMode: 'store', providerFallback: preset.chat.provider, apiBaseFallback: preset.chat.api_base }"> | |
| <x-component path="/plugins/_model_config/webui/model-field.html"></x-component> | |
| </div> | |
| </div> | |
| </div> | |
| </template> | |
| <div class="presets-actions"> | |
| <button class="text-button preset-add-btn" | |
| @click=" | |
| presets = [...presets, { | |
| name: 'Preset ' + (presets.length + 1), | |
| chat: { provider: '', name: '', api_key: '', api_base: '', ctx_length: 128000, ctx_history: 0.7, vision: true, rl_requests: 0, rl_input: 0, rl_output: 0, kwargs: {}, _kwargs_text: '' }, | |
| utility: { provider: '', name: '', api_key: '', api_base: '', ctx_length: 128000, ctx_input: 0.7, rl_requests: 0, rl_input: 0, rl_output: 0, kwargs: {}, _kwargs_text: '' } | |
| }]"> | |
| <span class="material-symbols-outlined">add</span> | |
| <span>Add Preset</span> | |
| </button> | |
| <button class="text-button" @click="(async () => { | |
| await import('/components/plugins/plugin-settings-store.js'); | |
| await $store.pluginSettingsPrototype.openConfig('_model_config'); | |
| })()"> | |
| <span class="material-symbols-outlined">settings</span> | |
| <span>Settings</span> | |
| </button> | |
| <button class="text-button" @click="openModal('/plugins/_model_config/webui/api-keys.html')"> | |
| <span class="material-symbols-outlined">key</span> | |
| <span>API Keys</span> | |
| </button> | |
| </div> | |
| <div class="presets-footer"> | |
| <button class="button" @click="(async () => { await $store.modelConfig.persistAllDirtyApiKeys(); await $store.modelConfig.saveGlobalPresets(presets); })()"> | |
| <span class="icon material-symbols-outlined">save</span> Save Presets | |
| </button> | |
| </div> | |
| </div> | |
| </template> | |
| </div> | |
| <style> | |
| .presets-page { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| } | |
| .presets-header { | |
| margin-bottom: 8px; | |
| } | |
| .presets-footer { | |
| margin-top: 12px; | |
| display: flex; | |
| justify-content: flex-end; | |
| } | |
| .preset-card { | |
| border: 1px solid var(--color-border); | |
| border-radius: 6px; | |
| } | |
| .preset-card-header { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| padding: 8px 10px; | |
| cursor: pointer; | |
| font-size: 0.85rem; | |
| } | |
| .preset-card-header:hover { | |
| background: var(--color-background-hover, rgba(255,255,255,0.04)); | |
| } | |
| .preset-card-name { | |
| font-weight: 500; | |
| } | |
| .preset-card-summary { | |
| flex: 1; | |
| text-align: right; | |
| opacity: 0.5; | |
| font-size: 0.75rem; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| white-space: nowrap; | |
| } | |
| .preset-delete-btn { | |
| margin-left: auto; | |
| opacity: 0.5; | |
| padding: 2px ; | |
| } | |
| .preset-delete-btn:hover { | |
| opacity: 1; | |
| color: var(--color-error, #f44) ; | |
| } | |
| .preset-card-body { | |
| padding: 4px 12px 12px; | |
| border-top: 1px solid var(--color-border); | |
| } | |
| .preset-subheader { | |
| font-size: 0.8rem; | |
| font-weight: 500; | |
| opacity: 0.7; | |
| margin: 10px 0 4px; | |
| padding-top: 8px; | |
| border-top: 1px dashed var(--color-border); | |
| } | |
| .presets-actions { | |
| display: flex; | |
| gap: 12px; | |
| flex-wrap: wrap; | |
| align-items: center; | |
| margin-top: 4px; | |
| } | |
| </style> | |
| </body> | |
| </html> | |