main
html 135 lines 4.09 KB
Raw
1 <html>
2 <head>
3 <title>Manage API Keys</title>
4 </head>
5
6 <body>
7 <script type="module">
8 import { store } from "/plugins/_model_config/webui/model-config-store.js";
9 </script>
10
11 <div x-data>
12 <template x-if="$store.modelConfig">
13 <div x-data="{
14 loading: true,
15 saving: false,
16 error: '',
17 get hasChanges() {
18 const dirty = $store.modelConfig.apiKeyDirty;
19 return Object.keys(dirty).some((p) => dirty[p]);
20 },
21 async init() {
22 await $store.modelConfig.ensureLoaded();
23 $store.modelConfig.resetApiKeyDrafts();
24 await $store.modelConfig.refreshApiKeyStatus();
25 this.loading = false;
26 },
27 async reveal(provider) {
28 try {
29 await $store.modelConfig.revealApiKey(provider);
30 } catch (e) {
31 this.error = e?.message || 'Failed to reveal API key.';
32 }
33 },
34 async saveAndClose() {
35 this.saving = true;
36 this.error = '';
37 try {
38 await $store.modelConfig.persistAllDirtyApiKeys();
39 await $store.modelConfig.refreshApiKeyStatus();
40 window.closeModal?.();
41 } catch (e) {
42 this.error = e?.message || 'Failed to save API keys.';
43 } finally {
44 this.saving = false;
45 }
46 }
47 }"
48 x-init="init()">
49
50 <div class="api-keys-section">
51 <div class="section-title">API Keys</div>
52 <div class="section-description">
53 API keys for model providers and services used by Agent Zero. You can set multiple API keys separated by a comma (,). They will be used in round-robin fashion.<br>
54 For more information about Agent Zero Venice provider, see <a href="http://agent-zero.ai/?community/api-dashboard/about" target="_blank">Agent Zero Venice</a>.
55 </div>
56
57 <div x-show="error" class="plugin-settings-error" style="margin-top: 1rem;">
58 <x-icon name="error"></x-icon>
59 <span x-text="error"></span>
60 </div>
61
62 <div x-show="loading" style="text-align:center; padding: 20px;">
63 <x-icon class="spinning" name="progress_activity"></x-icon>
64 </div>
65
66 <div x-show="!loading">
67 <template x-for="provider in $store.modelConfig.allProviders" :key="provider.value">
68 <div class="field">
69 <div class="field-label">
70 <div class="field-title" x-text="provider.label"></div>
71 </div>
72 <div class="field-control" style="position:relative;" x-data="{ showKey: false }">
73 <input type="text"
74 :class="{ 'masked-text-input': !showKey }"
75 :value="$store.modelConfig.apiKeyValues[provider.value]"
76 :placeholder="provider.has_key ? '••••••••••••' : ''"
77 autocomplete="off"
78 @input="$store.modelConfig.setApiKeyValue(provider.value, $el.value)"
79 style="padding-right:32px;" />
80 <x-icon class="eye-toggle"
81 @click="
82 showKey = !showKey;
83 if (showKey && !$store.modelConfig.apiKeyValues[provider.value] && provider.has_key) {
84 reveal(provider.value);
85 }
86 "
87 :name="showKey ? 'visibility' : 'visibility_off'"></x-icon>
88 </div>
89 </div>
90 </template>
91 </div>
92 </div>
93
94 <div class="modal-footer" data-modal-footer>
95 <button class="btn btn-ok"
96 @click="saveAndClose()"
97 :disabled="loading || saving || !hasChanges">
98 Save
99 </button>
100 <button class="btn btn-cancel"
101 @click="window.closeModal?.()"
102 :disabled="saving">
103 Close
104 </button>
105 </div>
106 </div>
107 </template>
108 </div>
109
110 <style>
111 .api-keys-section {
112 border: 1px solid var(--color-border);
113 border-radius: 8px;
114 padding: 16px;
115 }
116 .api-keys-section .section-title {
117 margin-top: 0;
118 }
119 .eye-toggle {
120 position: absolute;
121 right: 8px;
122 top: 50%;
123 transform: translateY(-50%);
124 font-size: 18px;
125 cursor: pointer;
126 user-select: none;
127 opacity: 0.6;
128 z-index: 1;
129 }
130 .eye-toggle:hover {
131 opacity: 1;
132 }
133 </style>
134 </body>
135 </html>