@hina114514/chaite 1.9.4 → 1.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { d as init_adapters, f as createClient, g as AbstractClient, h as OpenAIClient, m as ClaudeClient, p as GeminiClient } from "./src-DGgOl4PZ.mjs";
1
+ import { d as init_adapters, f as createClient, g as AbstractClient, h as OpenAIClient, m as ClaudeClient, p as GeminiClient } from "./src-Biu4SIt6.mjs";
2
2
  import "./chunks/lop/index.mjs-BWbOMJZv.mjs";
3
3
  import "./chunks/bluebird/index.mjs-D4zFjek8.mjs";
4
4
  import "./chunks/mammoth/index.mjs-C9xwBIgf.mjs";
@@ -12,7 +12,7 @@ import "./chunks/@xmldom/xmldom/index.mjs-BARr5-gb.mjs";
12
12
  import "./chunks/dingbat-to-unicode/index.mjs-DjR5pQCM.mjs";
13
13
  import "./chunks/@karinjs/node-schedule/index.mjs-UoPXNUgp.mjs";
14
14
  import "./chunks/chokidar/index.mjs-BvSuth5p.mjs";
15
- import "./chunks/openai/index.mjs-M-HPLtaS.mjs";
15
+ import "./chunks/openai/index.mjs-CE7SAzV0.mjs";
16
16
  import "./chunks/@anthropic-ai/sdk/index.mjs-BBdoshoG.mjs";
17
17
  import "./chunks/accepts/index.mjs-BpfWQu4-.mjs";
18
18
  import "./chunks/express/index.mjs-CHnhA_pr.mjs";
@@ -6673,8 +6673,6 @@ var init_client = __esm({ "node_modules/.pnpm/openai@5.23.2_ws@8.18.3/node_modul
6673
6673
  //#endregion
6674
6674
  //#region node_modules/.pnpm/openai@5.23.2_ws@8.18.3/node_modules/openai/azure.mjs
6675
6675
  var init_azure = __esm({ "node_modules/.pnpm/openai@5.23.2_ws@8.18.3/node_modules/openai/azure.mjs": (() => {
6676
- init_error();
6677
- init_utils();
6678
6676
  init_client();
6679
6677
  }) });
6680
6678
 
package/dist/index.d.ts CHANGED
@@ -1567,7 +1567,7 @@ declare const PROCESSOR_TYPE_MAP: {
1567
1567
  };
1568
1568
  //#endregion
1569
1569
  //#region src/version.d.ts
1570
- declare const VERSION = "1.9.4";
1570
+ declare const VERSION = "1.9.6";
1571
1571
  //#endregion
1572
1572
  //#region src/controllers/index.d.ts
1573
1573
  declare function createApp(configure?: (app: Application) => void): Application;
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as ChaiteStorage, A as FrontEndAuthHandler, B as VectorizerImpl, C as Channel, D as ExecutableShareableManager, E as ToolManager, F as PureTextFileParser, G as KVHistoryManager, H as RAGManager, I as DocxBufferParser, J as getKey, K as asyncLocalStorage, L as DocxFileParser, M as DEFAULT_PORT, N as GlobalConfig, O as NonExecutableShareableManager, P as PureTextBufferParser, Q as ChaiteResponse, R as PdfBufferParser, S as ChatPreset, T as DefaultCloudService, U as TextProcessor, V as AbstractVectorDatabase, W as InMemoryHistoryManager, X as useEvent, Y as saveAndLoadModule, Z as AbstractUserModeSelector, _ as TriggerManager, _t as AbstractShareable, a as EventTrigger, at as AbstractHistoryManager, b as ProcessorsManager, c as createApp, ct as DocumentFileParser, dt as ToolDTO, et as PostProcessor, f as createClient, ft as ToolsGroupDTO, g as AbstractClient, gt as MultipleKeyStrategyChoice, h as OpenAIClient, ht as DefaultLogger, i as CronTrigger, it as PROCESSOR_TYPE_MAP, j as DEFAULT_HOST, k as getLogger, l as runServer, lt as DocumentPathParser, m as ClaudeClient, mt as ChaiteContext, nt as ProcessorDTO, o as TriggerDTO, ot as SendMessageOption, p as GeminiClient, pt as BaseClientOptions, q as extractClassName, r as BaseTrigger, rt as CHANNEL_STATUS_MAP, s as Chaite, st as ChannelStatistics, t as init_src, tt as PreProcessor, u as VERSION, ut as CustomTool, v as ToolsGroupManager, w as DefaultChannelLoadBalancer, x as ChannelsManager, y as ChatPresetManager, z as PdfFileParser } from "./src-DGgOl4PZ.mjs";
1
+ import { $ as ChaiteStorage, A as FrontEndAuthHandler, B as VectorizerImpl, C as Channel, D as ExecutableShareableManager, E as ToolManager, F as PureTextFileParser, G as KVHistoryManager, H as RAGManager, I as DocxBufferParser, J as getKey, K as asyncLocalStorage, L as DocxFileParser, M as DEFAULT_PORT, N as GlobalConfig, O as NonExecutableShareableManager, P as PureTextBufferParser, Q as ChaiteResponse, R as PdfBufferParser, S as ChatPreset, T as DefaultCloudService, U as TextProcessor, V as AbstractVectorDatabase, W as InMemoryHistoryManager, X as useEvent, Y as saveAndLoadModule, Z as AbstractUserModeSelector, _ as TriggerManager, _t as AbstractShareable, a as EventTrigger, at as AbstractHistoryManager, b as ProcessorsManager, c as createApp, ct as DocumentFileParser, dt as ToolDTO, et as PostProcessor, f as createClient, ft as ToolsGroupDTO, g as AbstractClient, gt as MultipleKeyStrategyChoice, h as OpenAIClient, ht as DefaultLogger, i as CronTrigger, it as PROCESSOR_TYPE_MAP, j as DEFAULT_HOST, k as getLogger, l as runServer, lt as DocumentPathParser, m as ClaudeClient, mt as ChaiteContext, nt as ProcessorDTO, o as TriggerDTO, ot as SendMessageOption, p as GeminiClient, pt as BaseClientOptions, q as extractClassName, r as BaseTrigger, rt as CHANNEL_STATUS_MAP, s as Chaite, st as ChannelStatistics, t as init_src, tt as PreProcessor, u as VERSION, ut as CustomTool, v as ToolsGroupManager, w as DefaultChannelLoadBalancer, x as ChannelsManager, y as ChatPresetManager, z as PdfFileParser } from "./src-Biu4SIt6.mjs";
2
2
  import "./chunks/lop/index.mjs-BWbOMJZv.mjs";
3
3
  import "./chunks/bluebird/index.mjs-D4zFjek8.mjs";
4
4
  import "./chunks/mammoth/index.mjs-C9xwBIgf.mjs";
@@ -12,7 +12,7 @@ import "./chunks/@xmldom/xmldom/index.mjs-BARr5-gb.mjs";
12
12
  import "./chunks/dingbat-to-unicode/index.mjs-DjR5pQCM.mjs";
13
13
  import "./chunks/@karinjs/node-schedule/index.mjs-UoPXNUgp.mjs";
14
14
  import "./chunks/chokidar/index.mjs-BvSuth5p.mjs";
15
- import "./chunks/openai/index.mjs-M-HPLtaS.mjs";
15
+ import "./chunks/openai/index.mjs-CE7SAzV0.mjs";
16
16
  import "./chunks/@anthropic-ai/sdk/index.mjs-BBdoshoG.mjs";
17
17
  import "./chunks/accepts/index.mjs-BpfWQu4-.mjs";
18
18
  import "./chunks/express/index.mjs-CHnhA_pr.mjs";
@@ -3,7 +3,7 @@ import { t as require_lib } from "./chunks/mammoth/index.mjs-C9xwBIgf.mjs";
3
3
  import { i as init_node, n as GoogleGenAI, r as Type, t as FunctionCallingConfigMode } from "./chunks/@google/genai/index.mjs-CJMm4uh0.mjs";
4
4
  import { n as src_default, t as init_dist } from "./chunks/@karinjs/node-schedule/index.mjs-UoPXNUgp.mjs";
5
5
  import { n as init_esm, t as esm_default } from "./chunks/chokidar/index.mjs-BvSuth5p.mjs";
6
- import { n as OpenAI, t as init_openai$1 } from "./chunks/openai/index.mjs-M-HPLtaS.mjs";
6
+ import { n as OpenAI, t as init_openai$1 } from "./chunks/openai/index.mjs-CE7SAzV0.mjs";
7
7
  import { n as sdk_default, t as init_sdk } from "./chunks/@anthropic-ai/sdk/index.mjs-BBdoshoG.mjs";
8
8
  import { t as require_express } from "./chunks/express/index.mjs-CHnhA_pr.mjs";
9
9
  import { t as require_lib$1 } from "./chunks/cors/index.mjs-DGt6p49t.mjs";
@@ -4441,7 +4441,7 @@ var init_trigger$1 = __esm({ "src/controllers/trigger.ts": (() => {
4441
4441
  //#region src/version.ts
4442
4442
  var VERSION;
4443
4443
  var init_version = __esm({ "src/version.ts": (() => {
4444
- VERSION = "1.9.4";
4444
+ VERSION = "1.9.6";
4445
4445
  }) });
4446
4446
 
4447
4447
  //#endregion
@@ -4567,8 +4567,8 @@ var init_basic = __esm({ "src/controllers/basic.ts": (() => {
4567
4567
  res.status(404).json(ChaiteResponse.fail(null, "Channel not found"));
4568
4568
  return;
4569
4569
  }
4570
- const { createClient: createClient$1 } = await import("./adapters-DLb1sL9p.mjs");
4571
- const { ChaiteContext: ChaiteContext$1 } = await import("./types-BN6lBxWd.mjs");
4570
+ const { createClient: createClient$1 } = await import("./adapters-CIf_e4TX.mjs");
4571
+ const { ChaiteContext: ChaiteContext$1 } = await import("./types-Cd68vIOz.mjs");
4572
4572
  const ctx = new ChaiteContext$1(chaite.getLogger());
4573
4573
  ctx.setChaite(chaite);
4574
4574
  const client = createClient$1(channel.adapterType, channel.options, ctx);
@@ -1,4 +1,4 @@
1
- import { $ as ChaiteStorage, Q as ChaiteResponse, Z as AbstractUserModeSelector, _t as AbstractShareable, a as EventTrigger, at as AbstractHistoryManager, ct as DocumentFileParser, dt as ToolDTO, et as PostProcessor, ft as ToolsGroupDTO, gt as MultipleKeyStrategyChoice, ht as DefaultLogger, i as CronTrigger, lt as DocumentPathParser, mt as ChaiteContext, n as init_types, nt as ProcessorDTO, o as TriggerDTO, ot as SendMessageOption, pt as BaseClientOptions, r as BaseTrigger, st as ChannelStatistics, tt as PreProcessor, ut as CustomTool } from "./src-DGgOl4PZ.mjs";
1
+ import { $ as ChaiteStorage, Q as ChaiteResponse, Z as AbstractUserModeSelector, _t as AbstractShareable, a as EventTrigger, at as AbstractHistoryManager, ct as DocumentFileParser, dt as ToolDTO, et as PostProcessor, ft as ToolsGroupDTO, gt as MultipleKeyStrategyChoice, ht as DefaultLogger, i as CronTrigger, lt as DocumentPathParser, mt as ChaiteContext, n as init_types, nt as ProcessorDTO, o as TriggerDTO, ot as SendMessageOption, pt as BaseClientOptions, r as BaseTrigger, st as ChannelStatistics, tt as PreProcessor, ut as CustomTool } from "./src-Biu4SIt6.mjs";
2
2
  import "./chunks/lop/index.mjs-BWbOMJZv.mjs";
3
3
  import "./chunks/bluebird/index.mjs-D4zFjek8.mjs";
4
4
  import "./chunks/mammoth/index.mjs-C9xwBIgf.mjs";
@@ -12,7 +12,7 @@ import "./chunks/@xmldom/xmldom/index.mjs-BARr5-gb.mjs";
12
12
  import "./chunks/dingbat-to-unicode/index.mjs-DjR5pQCM.mjs";
13
13
  import "./chunks/@karinjs/node-schedule/index.mjs-UoPXNUgp.mjs";
14
14
  import "./chunks/chokidar/index.mjs-BvSuth5p.mjs";
15
- import "./chunks/openai/index.mjs-M-HPLtaS.mjs";
15
+ import "./chunks/openai/index.mjs-CE7SAzV0.mjs";
16
16
  import "./chunks/@anthropic-ai/sdk/index.mjs-BBdoshoG.mjs";
17
17
  import "./chunks/accepts/index.mjs-BpfWQu4-.mjs";
18
18
  import "./chunks/express/index.mjs-CHnhA_pr.mjs";
@@ -1,18 +1,534 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en">
3
-
2
+ <html lang="zh-CN">
4
3
  <head>
5
- <meta charset="UTF-8" />
6
- <link rel="icon" href="/favicon.svg" />
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
- <title>Chaite Dashboard</title>
9
- <script type="module" crossorigin src="/assets/index-DzBQLoNi.js"></script>
10
- <link rel="stylesheet" crossorigin href="/assets/index-Dn5ZzrRm.css">
11
- </head>
4
+ <meta charset="UTF-8"/>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1"/>
6
+ <title>Chaite Dashboard</title>
7
+ <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
8
+ <style>
9
+ *{margin:0;padding:0;box-sizing:border-box}
10
+ :root{
11
+ --bg:#0c0e14;--surface:#141720;--surface2:#1a1e2a;--surface3:#222738;
12
+ --border:#2a2f42;--text:#e0e4ef;--text2:#8b92a8;--accent:#6c8cff;--accent2:#4a6aef;
13
+ --green:#4ade80;--red:#f87171;--yellow:#facc15;--purple:#a78bfa;
14
+ --radius:10px;--shadow:0 2px 12px rgba(0,0,0,.4);
15
+ }
16
+ body{background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;line-height:1.6;min-height:100vh}
17
+ a{color:var(--accent);text-decoration:none}
18
+ a:hover{text-decoration:underline}
19
+ .app{max-width:1280px;margin:0 auto;padding:20px}
20
+
21
+ /* Login */
22
+ .login-wrap{display:flex;align-items:center;justify-content:center;min-height:100vh}
23
+ .login-box{background:var(--surface);border:1px solid var(--border);border-radius:16px;padding:48px 40px;width:380px;text-align:center;box-shadow:var(--shadow)}
24
+ .login-box h1{font-size:24px;margin-bottom:8px}
25
+ .login-box p{color:var(--text2);font-size:14px;margin-bottom:32px}
26
+ .login-box .spinner{display:inline-block;width:18px;height:18px;border:2px solid var(--text2);border-top-color:var(--accent);border-radius:50%;animation:spin .6s linear infinite}
27
+ .login-box .err{color:var(--red);font-size:13px;margin-bottom:12px;min-height:20px}
28
+ @keyframes spin{to{transform:rotate(360deg)}}
29
+
30
+ /* Header */
31
+ .header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;margin-bottom:24px}
32
+ .header h1{font-size:20px;display:flex;align-items:center;gap:8px}
33
+ .header h1 span{color:var(--accent)}
34
+ .header .meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
35
+ .badge{background:var(--surface2);border:1px solid var(--border);border-radius:20px;padding:3px 12px;font-size:12px;color:var(--text2)}
36
+ .badge.ok{border-color:var(--green);color:var(--green)}
37
+ .badge.err{border-color:var(--red);color:var(--red)}
38
+
39
+ /* Buttons */
40
+ .btn{background:var(--surface2);border:1px solid var(--border);border-radius:8px;color:var(--text);padding:6px 14px;font-size:13px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;transition:all .15s}
41
+ .btn:hover{background:var(--surface3);border-color:var(--accent)}
42
+ .btn:disabled{opacity:.5;cursor:not-allowed}
43
+ .btn.primary{background:var(--accent2);border-color:var(--accent);color:#fff}
44
+ .btn.primary:hover{background:var(--accent)}
45
+ .btn.danger{border-color:var(--red);color:var(--red)}
46
+ .btn.danger:hover{background:rgba(248,113,113,.15)}
47
+ .btn.sm{padding:3px 10px;font-size:12px}
48
+
49
+ /* Cards */
50
+ .card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:20px;margin-bottom:16px;box-shadow:var(--shadow)}
51
+ .card h3{font-size:15px;margin-bottom:14px;display:flex;align-items:center;gap:8px}
52
+ .card h3 .dot{width:8px;height:8px;border-radius:50%}
12
53
 
54
+ /* Stat cards */
55
+ .stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;margin-bottom:20px}
56
+ .stat{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:16px;text-align:center}
57
+ .stat .val{font-size:28px;font-weight:700;color:var(--accent)}
58
+ .stat .label{font-size:12px;color:var(--text2);margin-top:4px}
59
+
60
+ /* Table */
61
+ .tbl{width:100%;border-collapse:collapse;font-size:13px}
62
+ .tbl th{text-align:left;padding:10px 12px;color:var(--text2);font-weight:600;border-bottom:1px solid var(--border);font-size:12px;text-transform:uppercase;letter-spacing:.5px}
63
+ .tbl td{padding:10px 12px;border-bottom:1px solid var(--border)}
64
+ .tbl tr:hover td{background:var(--surface2)}
65
+ .pill{display:inline-block;padding:2px 10px;border-radius:12px;font-size:11px;font-weight:600}
66
+ .pill.on{background:rgba(74,222,128,.15);color:var(--green)}
67
+ .pill.off{background:rgba(248,113,113,.12);color:var(--red)}
68
+ .pill.model{background:rgba(108,140,255,.12);color:var(--accent);margin:2px 3px 2px 0}
69
+
70
+ /* Tabs */
71
+ .tabs{display:flex;gap:0;margin-bottom:20px;border-bottom:1px solid var(--border)}
72
+ .tab{padding:10px 20px;font-size:13px;cursor:pointer;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}
73
+ .tab:hover{color:var(--text)}
74
+ .tab.active{color:var(--accent);border-bottom-color:var(--accent)}
75
+
76
+ /* Modal */
77
+ .modal-mask{position:fixed;inset:0;background:rgba(0,0,0,.6);display:flex;align-items:center;justify-content:center;z-index:100}
78
+ .modal{background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:28px;width:520px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 32px rgba(0,0,0,.5)}
79
+ .modal h3{margin-bottom:20px;font-size:17px}
80
+ .form-row{margin-bottom:14px}
81
+ .form-row label{display:block;font-size:12px;color:var(--text2);margin-bottom:5px}
82
+ .form-row input,.form-row select,.form-row textarea{width:100%;padding:8px 12px;background:var(--surface2);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px;font-family:inherit}
83
+ .form-row textarea{min-height:80px;resize:vertical}
84
+ .form-row input:focus,.form-row select:focus,.form-row textarea:focus{outline:none;border-color:var(--accent)}
85
+ .modal-btns{display:flex;justify-content:flex-end;gap:8px;margin-top:20px}
86
+
87
+ /* Toast */
88
+ .toast{position:fixed;top:20px;right:20px;padding:10px 20px;border-radius:8px;font-size:13px;z-index:200;animation:slideIn .3s}
89
+ .toast.ok{background:var(--green);color:#000}
90
+ .toast.err{background:var(--red);color:#fff}
91
+ @keyframes slideIn{from{opacity:0;transform:translateX(40px)}to{opacity:1;transform:none}}
92
+
93
+ /* Responsive */
94
+ @media(max-width:768px){
95
+ .stats{grid-template-columns:repeat(2,1fr)}
96
+ .modal{width:95%;margin:10px}
97
+ .header{flex-direction:column;align-items:flex-start}
98
+ }
99
+ </style>
100
+ </head>
13
101
  <body>
14
- <div id="appLoading"></div>
15
- <div id="app"></div>
16
- </body>
102
+ <div id="app"></div>
103
+ <script>
104
+ const{createApp,ref,reactive,computed,onMounted,onUnmounted,watch}=Vue
105
+
106
+ const API=(path,opt={})=>{
107
+ const t=localStorage.getItem('chaite_jwt')
108
+ return fetch(path,{...opt,headers:{'Content-Type':'application/json','Authorization':t?'Bearer '+t:'',...(opt.headers||{})}}).then(async r=>{
109
+ if(r.status===401){localStorage.removeItem('chaite_jwt');location.reload()}
110
+ return r.json()
111
+ })
112
+ }
113
+
114
+ createApp({
115
+ setup(){
116
+ // Auth
117
+ const jwt=ref(localStorage.getItem('chaite_jwt')||'')
118
+ const loggedIn=ref(!!jwt.value)
119
+ const loginLoading=ref(false)
120
+ const loginError=ref('')
121
+
122
+ // State
123
+ const tab=ref('overview')
124
+ const health=ref(null)
125
+ const stats=ref(null)
126
+ const channels=ref([])
127
+ const tools=ref([])
128
+ const presets=ref([])
129
+ const processors=ref([])
130
+ const triggers=ref([])
131
+ const toolGroups=ref([])
132
+ const loading=ref(true)
133
+ const refreshTime=ref('')
134
+ let timer=null
135
+
136
+ // Modal
137
+ const modal=ref(null) // 'channel'|'preset'|'tool'|'processor'|'trigger'|'toolGroup'|null
138
+ const editing=ref(null) // object being edited
139
+ const form=ref({})
140
+
141
+ // Toast
142
+ const toastMsg=ref('')
143
+ const toastType=ref('ok')
144
+ let toastTimer=null
145
+ function toast(msg,type='ok'){toastMsg.value=msg;toastType.value=type;clearTimeout(toastTimer);toastTimer=setTimeout(()=>toastMsg.value='',3000)}
146
+
147
+ // Login
148
+ async function doLogin(){
149
+ loginError.value='';loginLoading.value=true
150
+ try{
151
+ const url=new URL(location.href)
152
+ const urlToken=url.searchParams.get('token')
153
+ const token=urlToken||prompt('Enter access token:')
154
+ if(!token){loginLoading.value=false;return}
155
+ const d=await fetch('/api/auth/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({token})}).then(r=>r.json())
156
+ if(d.data?.token){
157
+ jwt.value=d.data.token;localStorage.setItem('chaite_jwt',d.data.token);loggedIn.value=true
158
+ url.searchParams.delete('token');history.replaceState(null,'',url.pathname+url.search)
159
+ refreshAll()
160
+ }else{loginError.value=d.message||'Login failed'}
161
+ }catch(e){loginError.value='Network error'}
162
+ finally{loginLoading.value=false}
163
+ }
164
+
165
+ function logout(){jwt.value='';localStorage.removeItem('chaite_jwt');loggedIn.value=false;clearInterval(timer)}
166
+
167
+ // Data fetching
168
+ async function refreshAll(){
169
+ loading.value=true
170
+ try{
171
+ const[h,s,c,t,p,pr,tr,tg]=await Promise.all([
172
+ API('/api/system/health').catch(()=>({})),
173
+ API('/api/system/stats').catch(()=>({})),
174
+ API('/api/channels/list').catch(()=>({})),
175
+ API('/api/tools/list').catch(()=>({})),
176
+ API('/api/preset/list').catch(()=>({})),
177
+ API('/api/processors/list').catch(()=>({})),
178
+ API('/api/triggers/list').catch(()=>({})),
179
+ API('/api/toolGroups/list').catch(()=>({})),
180
+ ])
181
+ health.value=h.data||null
182
+ stats.value=s.data||null
183
+ channels.value=c.data||[]
184
+ tools.value=t.data||[]
185
+ presets.value=p.data||[]
186
+ processors.value=pr.data||[]
187
+ triggers.value=tr.data||[]
188
+ toolGroups.value=tg.data||[]
189
+ refreshTime.value=new Date().toLocaleTimeString()
190
+ }catch(e){console.error(e)}
191
+ finally{loading.value=false}
192
+ }
193
+
194
+ // CRUD helpers
195
+ async function testChannel(id){
196
+ const d=await API('/api/system/test-channel',{method:'POST',body:JSON.stringify({channelId:id})})
197
+ if(d.data?.status==='ok')toast(`✅ ${d.data.channelName} — ${d.data.latency}ms`)
198
+ else toast(`❌ ${d.data?.error||d.message}`,'err')
199
+ }
200
+
201
+ function openModal(type,item=null){
202
+ modal.value=type
203
+ editing.value=item
204
+ if(item)form.value=JSON.parse(JSON.stringify(item))
205
+ else{
206
+ const defaults={
207
+ channel:{name:'',adapterType:'openai',type:'openai',models:[''],options:{baseUrl:'',apiKey:''},status:'enabled',weight:1,priority:0},
208
+ preset:{name:'',prefix:'',sendMessageOption:{model:'',temperature:0.8,maxToken:4096,systemOverride:''}},
209
+ tool:{name:'',description:'',code:''},
210
+ processor:{name:'',type:'pre',description:'',code:''},
211
+ trigger:{name:'',description:'',code:''},
212
+ toolGroup:{name:'',description:'',toolIds:[],status:'enabled',isDefault:false},
213
+ }
214
+ form.value=defaults[type]||{}
215
+ }
216
+ }
217
+ function closeModal(){modal.value=null;editing.value=null;form.value={}}
218
+
219
+ async function saveItem(){
220
+ const type=modal.value
221
+ const apiMap={channel:'/api/channels',preset:'/api/preset',tool:'/api/tools',processor:'/api/processors',trigger:'/api/triggers',toolGroup:'/api/toolGroups'}
222
+ try{
223
+ const id=editing.value?.id
224
+ const url=apiMap[type]+(id?'/'+id:'')
225
+ const method=id?'PUT':'POST'
226
+ const d=await API(url,{method,body:JSON.stringify(form.value)})
227
+ if(d.data!==undefined){toast('Saved');closeModal();refreshAll()}
228
+ else toast(d.message||'Error','err')
229
+ }catch(e){toast(e.message,'err')}
230
+ }
17
231
 
232
+ async function deleteItem(type,id){
233
+ if(!confirm('Delete this item?'))return
234
+ const apiMap={channel:'/api/channels',preset:'/api/preset',tool:'/api/tools',processor:'/api/processors',trigger:'/api/triggers',toolGroup:'/api/toolGroups'}
235
+ try{
236
+ await API(apiMap[type]+'/'+id,{method:'DELETE'})
237
+ toast('Deleted');refreshAll()
238
+ }catch(e){toast(e.message,'err')}
239
+ }
240
+
241
+ function uptimeStr(s){
242
+ if(!s)return '-'
243
+ const h=Math.floor(s/3600),m=Math.floor(s%3600/60),sec=s%60
244
+ return h>0?`${h}h ${m}m ${sec}s`:`${m}m ${sec}s`
245
+ }
246
+ function fmtNum(n){if(n>=1e6)return(n/1e6).toFixed(1)+'M';if(n>=1e3)return(n/1e3).toFixed(1)+'K';return String(n||0)}
247
+
248
+ onMounted(()=>{
249
+ if(loggedIn.value)refreshAll()
250
+ timer=setInterval(()=>{if(logged.value)refreshAll()},30000)
251
+ })
252
+ onUnmounted(()=>clearInterval(timer))
253
+
254
+ const loggedIn=computed(()=>!!jwt.value)
255
+
256
+ return{
257
+ jwt,loggedIn,loginLoading,loginError,doLogin,logout,
258
+ tab,health,stats,channels,tools,presets,processors,triggers,toolGroups,loading,refreshTime,
259
+ modal,editing,form,openModal,closeModal,saveItem,deleteItem,testChannel,
260
+ toastMsg,toastType,uptimeStr,fmtNum,refreshAll,
261
+ }
262
+ },
263
+ template:`
264
+ <!-- Toast -->
265
+ <div v-if="toastMsg" :class="['toast',toastType]">{{toastMsg}}</div>
266
+
267
+ <!-- Login -->
268
+ <div v-if="!loggedIn" class="login-wrap">
269
+ <div class="login-box">
270
+ <h1>⚡ <span style="color:var(--accent)">Chaite</span></h1>
271
+ <p>Management Dashboard</p>
272
+ <div v-if="!loginLoading">
273
+ <div style="margin-bottom:16px">
274
+ <input v-model="loginInput" type="password" placeholder="Paste access token here..."
275
+ @keyup.enter="doLogin" autofocus
276
+ style="width:100%;padding:10px 14px;border-radius:8px;border:1px solid var(--border);background:var(--surface2);color:var(--text);font-size:14px;outline:none"/>
277
+ </div>
278
+ <div class="err">{{loginError}}</div>
279
+ <button class="btn primary" @click="doLogin" style="width:100%;padding:10px">Login</button>
280
+ <p style="margin-top:16px;font-size:12px;color:var(--text2)">Or append <code>?token=xxx</code> to URL</p>
281
+ </div>
282
+ <div v-else><div class="spinner"></div></div>
283
+ </div>
284
+ </div>
285
+
286
+ <!-- Dashboard -->
287
+ <div v-else class="app">
288
+ <!-- Header -->
289
+ <div class="header">
290
+ <h1>⚡ <span>Chaite</span> Dashboard</h1>
291
+ <div class="meta">
292
+ <span class="badge" v-if="refreshTime">↻ {{refreshTime}}</span>
293
+ <span class="badge ok" v-if="health?.status==='ok'">Healthy</span>
294
+ <span class="badge err" v-else-if="health">Error</span>
295
+ <button class="btn" @click="refreshAll" :disabled="loading">
296
+ <span v-if="loading" style="display:inline-block;width:14px;height:14px;border:2px solid var(--text2);border-top-color:var(--accent);border-radius:50%;animation:spin .6s linear infinite"></span>
297
+ <span v-else>↻ Refresh</span>
298
+ </button>
299
+ <button class="btn" @click="logout">Logout</button>
300
+ </div>
301
+ </div>
302
+
303
+ <!-- Stats -->
304
+ <div class="stats" v-if="health">
305
+ <div class="stat"><div class="val">{{uptimeStr(health.uptime)}}</div><div class="label">Uptime</div></div>
306
+ <div class="stat"><div class="val">{{health.channels?.total||0}}</div><div class="label">Channels</div></div>
307
+ <div class="stat"><div class="val">{{health.models?.count||0}}</div><div class="label">Models</div></div>
308
+ <div class="stat"><div class="val">{{health.tools?.count||0}}</div><div class="label">Tools</div></div>
309
+ <div class="stat"><div class="val">{{health.system?.processMemory||0}}MB</div><div class="label">Memory</div></div>
310
+ <div class="stat"><div class="val">{{fmtNum(stats?.summary?.totalCalls)}}</div><div class="label">Total Calls</div></div>
311
+ </div>
312
+
313
+ <!-- Tabs -->
314
+ <div class="tabs">
315
+ <div :class="['tab',tab==='overview'&&'active']" @click="tab='overview'">Overview</div>
316
+ <div :class="['tab',tab==='channels'&&'active']" @click="tab='channels'">Channels</div>
317
+ <div :class="['tab',tab==='tools'&&'active']" @click="tab='tools'">Tools</div>
318
+ <div :class="['tab',tab==='presets'&&'active']" @click="tab='presets'">Presets</div>
319
+ <div :class="['tab',tab==='processors'&&'active']" @click="tab='processors'">Processors</div>
320
+ <div :class="['tab',tab==='triggers'&&'active']" @click="tab='triggers'">Triggers</div>
321
+ <div :class="['tab',tab==='groups'&&'active']" @click="tab='groups'">Groups</div>
322
+ </div>
323
+
324
+ <!-- Overview -->
325
+ <div v-if="tab==='overview'">
326
+ <div class="card" v-if="health">
327
+ <h3><span class="dot" style="background:var(--green)"></span> System</h3>
328
+ <div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;font-size:13px">
329
+ <div><span style="color:var(--text2)">Version:</span> {{health.version}}</div>
330
+ <div><span style="color:var(--text2)">Node:</span> {{health.system?.nodeVersion}}</div>
331
+ <div><span style="color:var(--text2)">Platform:</span> {{health.system?.platform}} {{health.system?.arch}}</div>
332
+ <div><span style="color:var(--text2)">CPUs:</span> {{health.system?.cpus}}</div>
333
+ <div><span style="color:var(--text2)">Heap:</span> {{health.system?.heapUsed}}MB / {{health.system?.processMemory}}MB</div>
334
+ <div><span style="color:var(--text2)">System Mem:</span> {{health.system?.freeMemory}}MB free / {{health.system?.totalMemory}}MB</div>
335
+ </div>
336
+ </div>
337
+
338
+ <div class="card" v-if="health?.models?.list?.length">
339
+ <h3>Available Models</h3>
340
+ <div><span v-for="m in health.models.list" class="pill model">{{m}}</span></div>
341
+ </div>
342
+
343
+ <div class="card" v-if="stats">
344
+ <h3>Usage by Model</h3>
345
+ <table class="tbl">
346
+ <tr><th>Model</th><th>Calls</th><th>Tokens</th></tr>
347
+ <tr v-for="(v,k) in stats.perModel" :key="k">
348
+ <td><span class="pill model">{{k}}</span></td>
349
+ <td>{{fmtNum(v.calls)}}</td>
350
+ <td>{{fmtNum(v.tokens)}}</td>
351
+ </tr>
352
+ <tr v-if="!Object.keys(stats.perModel||{}).length"><td colspan="3" style="color:var(--text2)">No usage data</td></tr>
353
+ </table>
354
+ </div>
355
+ </div>
356
+
357
+ <!-- Channels -->
358
+ <div v-if="tab==='channels'">
359
+ <div class="card">
360
+ <h3 style="justify-content:space-between">Channels <button class="btn primary sm" @click="openModal('channel')">+ New</button></h3>
361
+ <table class="tbl">
362
+ <tr><th>Status</th><th>Name</th><th>Adapter</th><th>Models</th><th>Priority</th><th>Calls</th><th>Actions</th></tr>
363
+ <tr v-for="ch in channels" :key="ch.id">
364
+ <td><span :class="['pill',ch.status==='enabled'?'on':'off']">{{ch.status}}</span></td>
365
+ <td>{{ch.name}}</td>
366
+ <td>{{ch.adapterType}}</td>
367
+ <td><span v-for="m in (ch.models||[])" class="pill model">{{m}}</span></td>
368
+ <td>{{ch.priority}}</td>
369
+ <td>{{fmtNum(ch.statistics?.callTimes)}}</td>
370
+ <td>
371
+ <button class="btn sm" @click="testChannel(ch.id)">Test</button>
372
+ <button class="btn sm" @click="openModal('channel',ch)">Edit</button>
373
+ <button class="btn sm danger" @click="deleteItem('channel',ch.id)">Del</button>
374
+ </td>
375
+ </tr>
376
+ <tr v-if="!channels.length"><td colspan="7" style="color:var(--text2)">No channels</td></tr>
377
+ </table>
378
+ </div>
379
+ </div>
380
+
381
+ <!-- Tools -->
382
+ <div v-if="tab==='tools'">
383
+ <div class="card">
384
+ <h3 style="justify-content:space-between">Tools <button class="btn primary sm" @click="openModal('tool')">+ New</button></h3>
385
+ <table class="tbl">
386
+ <tr><th>Name</th><th>Description</th><th>Actions</th></tr>
387
+ <tr v-for="t in tools" :key="t.id">
388
+ <td>{{t.name||t.id}}</td>
389
+ <td style="max-width:400px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{{t.description}}</td>
390
+ <td>
391
+ <button class="btn sm" @click="openModal('tool',t)">Edit</button>
392
+ <button class="btn sm danger" @click="deleteItem('tool',t.id)">Del</button>
393
+ </td>
394
+ </tr>
395
+ <tr v-if="!tools.length"><td colspan="3" style="color:var(--text2)">No tools</td></tr>
396
+ </table>
397
+ </div>
398
+ </div>
399
+
400
+ <!-- Presets -->
401
+ <div v-if="tab==='presets'">
402
+ <div class="card">
403
+ <h3 style="justify-content:space-between">Presets <button class="btn primary sm" @click="openModal('preset')">+ New</button></h3>
404
+ <table class="tbl">
405
+ <tr><th>Name</th><th>Prefix</th><th>Model</th><th>Temp</th><th>Actions</th></tr>
406
+ <tr v-for="p in presets" :key="p.id">
407
+ <td>{{p.name}}</td>
408
+ <td><code>{{p.prefix}}</code></td>
409
+ <td><span class="pill model">{{p.sendMessageOption?.model||'-'}}</span></td>
410
+ <td>{{p.sendMessageOption?.temperature}}</td>
411
+ <td>
412
+ <button class="btn sm" @click="openModal('preset',p)">Edit</button>
413
+ <button class="btn sm danger" @click="deleteItem('preset',p.id)">Del</button>
414
+ </td>
415
+ </tr>
416
+ <tr v-if="!presets.length"><td colspan="5" style="color:var(--text2)">No presets</td></tr>
417
+ </table>
418
+ </div>
419
+ </div>
420
+
421
+ <!-- Processors -->
422
+ <div v-if="tab==='processors'">
423
+ <div class="card">
424
+ <h3 style="justify-content:space-between">Processors <button class="btn primary sm" @click="openModal('processor')">+ New</button></h3>
425
+ <table class="tbl">
426
+ <tr><th>Name</th><th>Type</th><th>Description</th><th>Actions</th></tr>
427
+ <tr v-for="p in processors" :key="p.id">
428
+ <td>{{p.name}}</td>
429
+ <td><span class="pill" :style="{background:p.type==='pre'?'rgba(167,139,250,.15)':'rgba(250,204,21,.15)',color:p.type==='pre'?'var(--purple)':'var(--yellow)'}">{{p.type}}</span></td>
430
+ <td>{{p.description}}</td>
431
+ <td>
432
+ <button class="btn sm" @click="openModal('processor',p)">Edit</button>
433
+ <button class="btn sm danger" @click="deleteItem('processor',p.id)">Del</button>
434
+ </td>
435
+ </tr>
436
+ <tr v-if="!processors.length"><td colspan="4" style="color:var(--text2)">No processors</td></tr>
437
+ </table>
438
+ </div>
439
+ </div>
440
+
441
+ <!-- Triggers -->
442
+ <div v-if="tab==='triggers'">
443
+ <div class="card">
444
+ <h3 style="justify-content:space-between">Triggers <button class="btn primary sm" @click="openModal('trigger')">+ New</button></h3>
445
+ <table class="tbl">
446
+ <tr><th>Name</th><th>Description</th><th>Actions</th></tr>
447
+ <tr v-for="t in triggers" :key="t.id">
448
+ <td>{{t.name||t.id}}</td>
449
+ <td>{{t.description}}</td>
450
+ <td>
451
+ <button class="btn sm" @click="openModal('trigger',t)">Edit</button>
452
+ <button class="btn sm danger" @click="deleteItem('trigger',t.id)">Del</button>
453
+ </td>
454
+ </tr>
455
+ <tr v-if="!triggers.length"><td colspan="3" style="color:var(--text2)">No triggers</td></tr>
456
+ </table>
457
+ </div>
458
+ </div>
459
+
460
+ <!-- Tool Groups -->
461
+ <div v-if="tab==='groups'">
462
+ <div class="card">
463
+ <h3 style="justify-content:space-between">Tool Groups <button class="btn primary sm" @click="openModal('toolGroup')">+ New</button></h3>
464
+ <table class="tbl">
465
+ <tr><th>Name</th><th>Description</th><th>Default</th><th>Actions</th></tr>
466
+ <tr v-for="g in toolGroups" :key="g.id">
467
+ <td>{{g.name}}</td>
468
+ <td>{{g.description}}</td>
469
+ <td><span v-if="g.isDefault" class="pill on">Default</span></td>
470
+ <td>
471
+ <button class="btn sm" @click="openModal('toolGroup',g)">Edit</button>
472
+ <button class="btn sm danger" @click="deleteItem('toolGroup',g.id)">Del</button>
473
+ </td>
474
+ </tr>
475
+ <tr v-if="!toolGroups.length"><td colspan="4" style="color:var(--text2)">No groups</td></tr>
476
+ </table>
477
+ </div>
478
+ </div>
479
+
480
+ <!-- Modal -->
481
+ <div v-if="modal" class="modal-mask" @click.self="closeModal">
482
+ <div class="modal">
483
+ <h3>{{editing?'Edit':'New'}} {{modal}}</h3>
484
+
485
+ <!-- Channel form -->
486
+ <template v-if="modal==='channel'">
487
+ <div class="form-row"><label>Name</label><input v-model="form.name"/></div>
488
+ <div class="form-row"><label>Adapter Type</label><select v-model="form.adapterType"><option>openai</option><option>gemini</option><option>claude</option></select></div>
489
+ <div class="form-row"><label>Models (comma separated)</label><input v-model="form._models" :placeholder="(form.models||[]).join(', ')"/></div>
490
+ <div class="form-row"><label>Base URL</label><input v-model="form.options.baseUrl"/></div>
491
+ <div class="form-row"><label>API Key</label><input v-model="form.options.apiKey" type="password"/></div>
492
+ <div class="form-row"><label>Priority</label><input v-model.number="form.priority" type="number"/></div>
493
+ <div class="form-row"><label>Weight</label><input v-model.number="form.weight" type="number"/></div>
494
+ <div class="form-row"><label>Status</label><select v-model="form.status"><option>enabled</option><option>disabled</option></select></div>
495
+ </template>
496
+
497
+ <!-- Preset form -->
498
+ <template v-if="modal==='preset'">
499
+ <div class="form-row"><label>Name</label><input v-model="form.name"/></div>
500
+ <div class="form-row"><label>Prefix</label><input v-model="form.prefix"/></div>
501
+ <div class="form-row"><label>Model</label><input v-model="form.sendMessageOption.model"/></div>
502
+ <div class="form-row"><label>Temperature</label><input v-model.number="form.sendMessageOption.temperature" type="number" step="0.1"/></div>
503
+ <div class="form-row"><label>Max Token</label><input v-model.number="form.sendMessageOption.maxToken" type="number"/></div>
504
+ <div class="form-row"><label>System Prompt</label><textarea v-model="form.sendMessageOption.systemOverride"></textarea></div>
505
+ </template>
506
+
507
+ <!-- Tool / Processor / Trigger form -->
508
+ <template v-if="modal==='tool'||modal==='processor'||modal==='trigger'">
509
+ <div class="form-row"><label>Name</label><input v-model="form.name"/></div>
510
+ <div class="form-row" v-if="modal==='processor'"><label>Type</label><select v-model="form.type"><option>pre</option><option>post</option></select></div>
511
+ <div class="form-row"><label>Description</label><input v-model="form.description"/></div>
512
+ <div class="form-row"><label>Code</label><textarea v-model="form.code" style="min-height:200px;font-family:monospace;font-size:12px"></textarea></div>
513
+ </template>
514
+
515
+ <!-- Tool Group form -->
516
+ <template v-if="modal==='toolGroup'">
517
+ <div class="form-row"><label>Name</label><input v-model="form.name"/></div>
518
+ <div class="form-row"><label>Description</label><input v-model="form.description"/></div>
519
+ <div class="form-row"><label>Tool IDs (comma separated)</label><input v-model="form._toolIds" :placeholder="(form.toolIds||[]).join(', ')"/></div>
520
+ <div class="form-row"><label>Status</label><select v-model="form.status"><option>enabled</option><option>disabled</option></select></div>
521
+ </template>
522
+
523
+ <div class="modal-btns">
524
+ <button class="btn" @click="closeModal">Cancel</button>
525
+ <button class="btn primary" @click="saveItem">Save</button>
526
+ </div>
527
+ </div>
528
+ </div>
529
+ </div>
530
+ `
531
+ }).mount('#app')
532
+ </script>
533
+ </body>
18
534
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hina114514/chaite",
3
- "version": "1.9.4",
3
+ "version": "1.9.6",
4
4
  "description": "core for chatgpt-plugin and karin-plugin-chatgpt",
5
5
  "keywords": [
6
6
  "yunzai",