Spaces:
XCAPI
/
Sleeping

XCAPI commited on
Commit
aee6f2b
·
verified ·
1 Parent(s): 2f8351b

Update admin.html

Browse files
Files changed (1) hide show
  1. admin.html +289 -249
admin.html CHANGED
@@ -1,249 +1,289 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>代理端点管理</title>
5
- <style>
6
- body {
7
- font-family: Arial, sans-serif;
8
- max-width: 1000px;
9
- margin: 20px auto;
10
- padding: 0 20px;
11
- }
12
- .endpoint-group {
13
- margin: 20px 0;
14
- padding: 15px;
15
- border: 1px solid #ddd;
16
- border-radius: 8px;
17
- }
18
- .endpoint {
19
- display: flex;
20
- align-items: center;
21
- margin: 10px 0;
22
- padding: 10px;
23
- border: 1px solid #eee;
24
- border-radius: 4px;
25
- background-color: #f9f9f9;
26
- }
27
- .endpoint input[type="text"] {
28
- flex: 1;
29
- margin-right: 10px;
30
- padding: 8px;
31
- border: 1px solid #ddd;
32
- border-radius: 4px;
33
- }
34
- .endpoint input[type="number"] {
35
- width: 80px;
36
- margin: 0 10px;
37
- padding: 8px;
38
- border: 1px solid #ddd;
39
- border-radius: 4px;
40
- }
41
- .endpoint input[type="checkbox"] {
42
- margin: 0 10px;
43
- transform: scale(1.2);
44
- }
45
- button {
46
- padding: 8px 15px;
47
- margin: 5px;
48
- cursor: pointer;
49
- border: none;
50
- border-radius: 4px;
51
- background-color: #4CAF50;
52
- color: white;
53
- }
54
- button:hover {
55
- background-color: #45a049;
56
- }
57
- button.delete {
58
- background-color: #f44336;
59
- }
60
- button.delete:hover {
61
- background-color: #da190b;
62
- }
63
- .status {
64
- position: fixed;
65
- top: 20px;
66
- right: 20px;
67
- padding: 15px;
68
- border-radius: 4px;
69
- display: none;
70
- z-index: 1000;
71
- }
72
- .success {
73
- background-color: #4CAF50;
74
- color: white;
75
- }
76
- .error {
77
- background-color: #f44336;
78
- color: white;
79
- }
80
- h2 {
81
- color: #333;
82
- border-bottom: 2px solid #4CAF50;
83
- padding-bottom: 10px;
84
- }
85
- .controls {
86
- margin: 20px 0;
87
- padding: 10px;
88
- background-color: #f5f5f5;
89
- border-radius: 4px;
90
- text-align: right;
91
- }
92
- </style>
93
- </head>
94
- <body>
95
- <h1>代理端点管理</h1>
96
-
97
- <div class="endpoint-group">
98
- <h2>Models 端点</h2>
99
- <div id="modelsEndpoints"></div>
100
- <button onclick="addEndpoint('models')">添加 Models 端点</button>
101
- </div>
102
-
103
- <div class="endpoint-group">
104
- <h2>Chat 端点</h2>
105
- <div id="chatEndpoints"></div>
106
- <button onclick="addEndpoint('chat')">添加 Chat 端点</button>
107
- </div>
108
-
109
- <div class="controls">
110
- <button onclick="saveConfig()">保存所有配置</button>
111
- <button onclick="logout()" style="background-color: #f44336;">退出登录</button>
112
- </div>
113
-
114
- <div id="status" class="status"></div>
115
-
116
- <script>
117
- // 获取存储的密钥
118
- let apiKey = localStorage.getItem('apiKey');
119
-
120
- // 如果没有密钥,提示输入
121
- if (!apiKey) {
122
- apiKey = prompt('请输入访问密钥:');
123
- if (apiKey) {
124
- localStorage.setItem('apiKey', apiKey);
125
- } else {
126
- window.location.href = '/';
127
- }
128
- }
129
-
130
- // 显示状态信息
131
- function showStatus(message, isError = false) {
132
- const status = document.getElementById('status');
133
- status.textContent = message;
134
- status.className = 'status ' + (isError ? 'error' : 'success');
135
- status.style.display = 'block';
136
- setTimeout(() => status.style.display = 'none', 3000);
137
- }
138
-
139
- // 添加端点
140
- function addEndpoint(type, url = '', weight = 1, enabled = true) {
141
- const container = document.getElementById(type + 'Endpoints');
142
- const div = document.createElement('div');
143
- div.className = 'endpoint';
144
- div.innerHTML = `
145
- <input type="text" placeholder="输入端点URL" value="${url}">
146
- <input type="number" placeholder="权重" value="${weight}" min="1">
147
- <label>
148
- <input type="checkbox" ${enabled ? 'checked' : ''}>
149
- 启用
150
- </label>
151
- <button class="delete" onclick="this.parentElement.remove()">删除</button>
152
- `;
153
- container.appendChild(div);
154
- }
155
-
156
- // 获取端点配置
157
- function getEndpointsConfig(type) {
158
- const endpoints = [];
159
- document.querySelectorAll(`#${type}Endpoints .endpoint`).forEach(el => {
160
- endpoints.push({
161
- url: el.querySelector('input[type="text"]').value.trim(),
162
- weight: parseInt(el.querySelector('input[type="number"]').value) || 1,
163
- enabled: el.querySelector('input[type="checkbox"]').checked
164
- });
165
- });
166
- return endpoints;
167
- }
168
-
169
- // 带认证的fetch
170
- async function fetchWithAuth(url, options = {}) {
171
- const headers = {
172
- ...options.headers,
173
- 'Authorization': apiKey
174
- };
175
-
176
- const response = await fetch(url, { ...options, headers });
177
-
178
- if (response.status === 401) {
179
- localStorage.removeItem('apiKey');
180
- window.location.reload();
181
- return null;
182
- }
183
-
184
- return response;
185
- }
186
-
187
- // 保存配置
188
- async function saveConfig() {
189
- const config = {
190
- models: getEndpointsConfig('models'),
191
- chat: getEndpointsConfig('chat')
192
- };
193
-
194
- try {
195
- const response = await fetchWithAuth('/admin/config', {
196
- method: 'POST',
197
- headers: {'Content-Type': 'application/json'},
198
- body: JSON.stringify(config)
199
- });
200
-
201
- if (!response) return;
202
-
203
- if (response.ok) {
204
- showStatus('配置已保存');
205
- } else {
206
- showStatus('保存失败: ' + await response.text(), true);
207
- }
208
- } catch (error) {
209
- showStatus('保存失败: ' + error.message, true);
210
- }
211
- }
212
-
213
- // 加载配置
214
- async function loadConfig() {
215
- try {
216
- const response = await fetchWithAuth('/admin/config');
217
- if (!response) return;
218
-
219
- const config = await response.json();
220
-
221
- // 清空现有配置
222
- document.getElementById('modelsEndpoints').innerHTML = '';
223
- document.getElementById('chatEndpoints').innerHTML = '';
224
-
225
- // 加载Models端点
226
- config.models.forEach(ep => {
227
- addEndpoint('models', ep.url, ep.weight, ep.enabled);
228
- });
229
-
230
- // 加载Chat端点
231
- config.chat.forEach(ep => {
232
- addEndpoint('chat', ep.url, ep.weight, ep.enabled);
233
- });
234
- } catch (error) {
235
- showStatus('加载配置失败: ' + error.message, true);
236
- }
237
- }
238
-
239
- // 退出登录
240
- function logout() {
241
- localStorage.removeItem('apiKey');
242
- window.location.reload();
243
- }
244
-
245
- // 页面加载时获取配置
246
- document.addEventListener('DOMContentLoaded', loadConfig);
247
- </script>
248
- </body>
249
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>代理端点管理</title>
5
+ <style>
6
+ body {
7
+ font-family: Arial, sans-serif;
8
+ max-width: 1200px;
9
+ margin: 20px auto;
10
+ padding: 0 20px;
11
+ }
12
+ .endpoint-group {
13
+ margin: 20px 0;
14
+ padding: 15px;
15
+ border: 1px solid #ddd;
16
+ border-radius: 8px;
17
+ }
18
+ .endpoint {
19
+ display: flex;
20
+ align-items: center;
21
+ margin: 10px 0;
22
+ padding: 10px;
23
+ border: 1px solid #eee;
24
+ border-radius: 4px;
25
+ background-color: #f9f9f9;
26
+ }
27
+ .endpoint input[type="text"] {
28
+ flex: 1;
29
+ margin-right: 10px;
30
+ padding: 8px;
31
+ border: 1px solid #ddd;
32
+ border-radius: 4px;
33
+ }
34
+ .endpoint input[type="number"] {
35
+ width: 80px;
36
+ margin: 0 10px;
37
+ padding: 8px;
38
+ border: 1px solid #ddd;
39
+ border-radius: 4px;
40
+ }
41
+ .endpoint input[type="checkbox"] {
42
+ margin: 0 10px;
43
+ transform: scale(1.2);
44
+ }
45
+ button {
46
+ padding: 8px 15px;
47
+ margin: 5px;
48
+ cursor: pointer;
49
+ border: none;
50
+ border-radius: 4px;
51
+ background-color: #4CAF50;
52
+ color: white;
53
+ }
54
+ button:hover {
55
+ background-color: #45a049;
56
+ }
57
+ button.delete {
58
+ background-color: #f44336;
59
+ }
60
+ button.delete:hover {
61
+ background-color: #da190b;
62
+ }
63
+ .status {
64
+ position: fixed;
65
+ top: 20px;
66
+ right: 20px;
67
+ padding: 15px;
68
+ border-radius: 4px;
69
+ display: none;
70
+ z-index: 1000;
71
+ }
72
+ .success {
73
+ background-color: #4CAF50;
74
+ color: white;
75
+ }
76
+ .error {
77
+ background-color: #f44336;
78
+ color: white;
79
+ }
80
+ h2 {
81
+ color: #333;
82
+ border-bottom: 2px solid #4CAF50;
83
+ padding-bottom: 10px;
84
+ }
85
+ .controls {
86
+ margin: 20px 0;
87
+ padding: 10px;
88
+ background-color: #f5f5f5;
89
+ border-radius: 4px;
90
+ text-align: right;
91
+ }
92
+ .stats-group {
93
+ margin: 20px 0;
94
+ }
95
+ .stat-item {
96
+ margin: 10px 0;
97
+ padding: 10px;
98
+ border: 1px solid #ddd;
99
+ border-radius: 4px;
100
+ background-color: #f9f9f9;
101
+ }
102
+ .stat-item p {
103
+ margin: 5px 0;
104
+ }
105
+ .blocked {
106
+ background-color: #ffebee;
107
+ }
108
+ </style>
109
+ </head>
110
+ <body>
111
+ <h1>代理端点管理</h1>
112
+
113
+ <div class="endpoint-group">
114
+ <h2>Models 端点</h2>
115
+ <div id="modelsEndpoints"></div>
116
+ <button onclick="addEndpoint('models')">添加 Models 端点</button>
117
+ </div>
118
+
119
+ <div class="endpoint-group">
120
+ <h2>Chat 端点</h2>
121
+ <div id="chatEndpoints"></div>
122
+ <button onclick="addEndpoint('chat')">添加 Chat 端点</button>
123
+ </div>
124
+
125
+ <div class="stats-group">
126
+ <h2>请求统计</h2>
127
+ <div id="statsData"></div>
128
+ </div>
129
+
130
+ <div class="controls">
131
+ <button onclick="saveConfig()">保存所有配置</button>
132
+ <button onclick="logout()" style="background-color: #f44336;">退出登录</button>
133
+ </div>
134
+
135
+ <div id="status" class="status"></div>
136
+
137
+ <script>
138
+ // 获取存储的密钥
139
+ let apiKey = localStorage.getItem('apiKey');
140
+
141
+ // 如果没有密钥,提示输入
142
+ if (!apiKey) {
143
+ apiKey = prompt('请输入访问密钥:');
144
+ if (apiKey) {
145
+ localStorage.setItem('apiKey', apiKey);
146
+ } else {
147
+ window.location.href = '/';
148
+ }
149
+ }
150
+
151
+ // 显示状态信息
152
+ function showStatus(message, isError = false) {
153
+ const status = document.getElementById('status');
154
+ status.textContent = message;
155
+ status.className = 'status ' + (isError ? 'error' : 'success');
156
+ status.style.display = 'block';
157
+ setTimeout(() => status.style.display = 'none', 3000);
158
+ }
159
+
160
+ // 添加端点
161
+ function addEndpoint(type, url = '', weight = 1, enabled = true) {
162
+ const container = document.getElementById(type + 'Endpoints');
163
+ const div = document.createElement('div');
164
+ div.className = 'endpoint';
165
+ div.innerHTML = `
166
+ <input type="text" placeholder="输入端点URL" value="${url}">
167
+ <input type="number" placeholder="权重" value="${weight}" min="1">
168
+ <label>
169
+ <input type="checkbox" ${enabled ? 'checked' : ''}>
170
+ 启用
171
+ </label>
172
+ <button class="delete" onclick="this.parentElement.remove()">删除</button>
173
+ `;
174
+ container.appendChild(div);
175
+ }
176
+
177
+ // 获取端点配置
178
+ function getEndpointsConfig(type) {
179
+ const endpoints = [];
180
+ document.querySelectorAll(`#${type}Endpoints .endpoint`).forEach(el => {
181
+ endpoints.push({
182
+ url: el.querySelector('input[type="text"]').value.trim(),
183
+ weight: parseInt(el.querySelector('input[type="number"]').value) || 1,
184
+ enabled: el.querySelector('input[type="checkbox"]').checked
185
+ });
186
+ });
187
+ return endpoints;
188
+ }
189
+
190
+ // 带认证的fetch
191
+ async function fetchWithAuth(url, options = {}) {
192
+ const headers = {
193
+ ...options.headers,
194
+ 'Authorization': apiKey
195
+ };
196
+
197
+ const response = await fetch(url, { ...options, headers });
198
+
199
+ if (response.status === 401) {
200
+ localStorage.removeItem('apiKey');
201
+ window.location.reload();
202
+ return null;
203
+ }
204
+
205
+ return response;
206
+ }
207
+
208
+ // 保存配置
209
+ async function saveConfig() {
210
+ const config = {
211
+ models: getEndpointsConfig('models'),
212
+ chat: getEndpointsConfig('chat')
213
+ };
214
+
215
+ try {
216
+ const response = await fetchWithAuth('/admin/config', {
217
+ method: 'POST',
218
+ headers: {'Content-Type': 'application/json'},
219
+ body: JSON.stringify(config)
220
+ });
221
+
222
+ if (!response) return;
223
+
224
+ if (response.ok) {
225
+ showStatus('配置已保存');
226
+ loadConfig(); // 重新加载配置以更新统计数据
227
+ } else {
228
+ showStatus('保存失败: ' + await response.text(), true);
229
+ }
230
+ } catch (error) {
231
+ showStatus('保存失败: ' + error.message, true);
232
+ }
233
+ }
234
+
235
+ // 加载配置和统计数据
236
+ async function loadConfig() {
237
+ try {
238
+ const response = await fetchWithAuth('/admin/config');
239
+ if (!response) return;
240
+
241
+ const config = await response.json();
242
+
243
+ // 清空现有配置
244
+ document.getElementById('modelsEndpoints').innerHTML = '';
245
+ document.getElementById('chatEndpoints').innerHTML = '';
246
+ document.getElementById('statsData').innerHTML = '';
247
+
248
+ // 加载Models端点
249
+ config.models.forEach(ep => {
250
+ addEndpoint('models', ep.url, ep.weight, ep.enabled);
251
+ });
252
+
253
+ // 加载Chat端点
254
+ config.chat.forEach(ep => {
255
+ addEndpoint('chat', ep.url, ep.weight, ep.enabled);
256
+ });
257
+
258
+ // 显示统计数据
259
+ const statsHtml = Object.entries(config.stats).map(([fingerprint, stat]) => `
260
+ <div class="stat-item ${stat.blocked ? 'blocked' : ''}">
261
+ <p><strong>指纹:</strong> ${fingerprint}</p>
262
+ <p><strong>IP:</strong> ${stat.ip}</p>
263
+ <p><strong>设备:</strong> ${stat.user_agent}</p>
264
+ <p><strong>请求次数:</strong> ${stat.chat_count}</p>
265
+ <p><strong>最后访问:</strong> ${new Date(stat.last_access).toLocaleString()}</p>
266
+ <p><strong>状态:</strong> ${stat.blocked ? '已拉黑' : '正常'}</p>
267
+ </div>
268
+ `).join('');
269
+
270
+ document.getElementById('statsData').innerHTML = statsHtml || '<p>暂无统计数据</p>';
271
+ } catch (error) {
272
+ showStatus('加载配置失败: ' + error.message, true);
273
+ }
274
+ }
275
+
276
+ // 退出登录
277
+ function logout() {
278
+ localStorage.removeItem('apiKey');
279
+ window.location.reload();
280
+ }
281
+
282
+ // 页面加载时获取配置
283
+ document.addEventListener('DOMContentLoaded', loadConfig);
284
+
285
+ // 定期刷新统计数据
286
+ setInterval(loadConfig, 30000); // 每30秒刷新一次
287
+ </script>
288
+ </body>
289
+ </html>