@hina114514/chaite 1.9.3 → 1.9.4
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.
- package/dist/{adapters-BeZFg37c.mjs → adapters-DLb1sL9p.mjs} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-BjDIhdKO.mjs → src-DGgOl4PZ.mjs} +3 -3
- package/dist/{types-6jzst6Q4.mjs → types-BN6lBxWd.mjs} +1 -1
- package/frontend/build/index.html +18 -537
- package/package.json +70 -70
|
@@ -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-
|
|
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";
|
|
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";
|
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.
|
|
1570
|
+
declare const VERSION = "1.9.4";
|
|
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-
|
|
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";
|
|
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";
|
|
@@ -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.
|
|
4444
|
+
VERSION = "1.9.4";
|
|
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-
|
|
4571
|
-
const { ChaiteContext: ChaiteContext$1 } = await import("./types-
|
|
4570
|
+
const { createClient: createClient$1 } = await import("./adapters-DLb1sL9p.mjs");
|
|
4571
|
+
const { ChaiteContext: ChaiteContext$1 } = await import("./types-BN6lBxWd.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-
|
|
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";
|
|
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";
|
|
@@ -1,537 +1,18 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<meta
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
--red: #ef4444;
|
|
20
|
-
--orange: #f59e0b;
|
|
21
|
-
--radius: 10px;
|
|
22
|
-
}
|
|
23
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
24
|
-
body {
|
|
25
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
|
|
26
|
-
background: var(--bg);
|
|
27
|
-
color: var(--text);
|
|
28
|
-
min-height: 100vh;
|
|
29
|
-
}
|
|
30
|
-
.app { max-width: 1200px; margin: 0 auto; padding: 24px; }
|
|
31
|
-
|
|
32
|
-
/* Header */
|
|
33
|
-
.header {
|
|
34
|
-
display: flex; justify-content: space-between; align-items: center;
|
|
35
|
-
padding: 16px 0; margin-bottom: 24px;
|
|
36
|
-
border-bottom: 1px solid var(--border);
|
|
37
|
-
}
|
|
38
|
-
.header h1 { font-size: 22px; font-weight: 600; }
|
|
39
|
-
.header h1 span { color: var(--accent2); }
|
|
40
|
-
.header .meta { display: flex; gap: 12px; align-items: center; }
|
|
41
|
-
.badge {
|
|
42
|
-
padding: 4px 10px; border-radius: 20px;
|
|
43
|
-
font-size: 12px; font-weight: 500;
|
|
44
|
-
background: var(--surface2); border: 1px solid var(--border);
|
|
45
|
-
}
|
|
46
|
-
.badge.ok { border-color: var(--green); color: var(--green); }
|
|
47
|
-
.badge.err { border-color: var(--red); color: var(--red); }
|
|
48
|
-
|
|
49
|
-
/* Cards grid */
|
|
50
|
-
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; margin-bottom: 24px; }
|
|
51
|
-
.card {
|
|
52
|
-
background: var(--surface);
|
|
53
|
-
border: 1px solid var(--border);
|
|
54
|
-
border-radius: var(--radius);
|
|
55
|
-
padding: 20px;
|
|
56
|
-
transition: border-color .15s;
|
|
57
|
-
}
|
|
58
|
-
.card:hover { border-color: var(--accent); }
|
|
59
|
-
.card .label { font-size: 12px; color: var(--text2); text-transform: uppercase; letter-spacing: .5px; margin-bottom: 8px; }
|
|
60
|
-
.card .value { font-size: 28px; font-weight: 700; color: var(--text); }
|
|
61
|
-
.card .sub { font-size: 13px; color: var(--text2); margin-top: 4px; }
|
|
62
|
-
|
|
63
|
-
/* Section */
|
|
64
|
-
.section { margin-bottom: 32px; }
|
|
65
|
-
.section h2 {
|
|
66
|
-
font-size: 16px; font-weight: 600; margin-bottom: 16px;
|
|
67
|
-
display: flex; align-items: center; gap: 8px;
|
|
68
|
-
}
|
|
69
|
-
.section h2 .dot {
|
|
70
|
-
width: 8px; height: 8px; border-radius: 50%; background: var(--accent);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/* Table */
|
|
74
|
-
.table-wrap {
|
|
75
|
-
background: var(--surface);
|
|
76
|
-
border: 1px solid var(--border);
|
|
77
|
-
border-radius: var(--radius);
|
|
78
|
-
overflow: hidden;
|
|
79
|
-
}
|
|
80
|
-
table { width: 100%; border-collapse: collapse; }
|
|
81
|
-
th {
|
|
82
|
-
text-align: left; padding: 12px 16px;
|
|
83
|
-
font-size: 11px; text-transform: uppercase; letter-spacing: .5px;
|
|
84
|
-
color: var(--text2); border-bottom: 1px solid var(--border);
|
|
85
|
-
background: var(--surface2);
|
|
86
|
-
}
|
|
87
|
-
td {
|
|
88
|
-
padding: 12px 16px; font-size: 14px;
|
|
89
|
-
border-bottom: 1px solid var(--border);
|
|
90
|
-
}
|
|
91
|
-
tr:last-child td { border-bottom: none; }
|
|
92
|
-
tr:hover td { background: rgba(99,102,241,.04); }
|
|
93
|
-
|
|
94
|
-
.status-dot {
|
|
95
|
-
display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 6px;
|
|
96
|
-
}
|
|
97
|
-
.status-dot.on { background: var(--green); }
|
|
98
|
-
.status-dot.off { background: var(--red); }
|
|
99
|
-
|
|
100
|
-
.model-tag {
|
|
101
|
-
display: inline-block; padding: 2px 8px; border-radius: 4px;
|
|
102
|
-
font-size: 11px; background: var(--surface2); color: var(--text2);
|
|
103
|
-
margin: 2px 2px;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/* Button */
|
|
107
|
-
.btn {
|
|
108
|
-
padding: 8px 16px; border-radius: 6px; font-size: 13px; font-weight: 500;
|
|
109
|
-
border: 1px solid var(--border); background: var(--surface2); color: var(--text);
|
|
110
|
-
cursor: pointer; transition: all .15s;
|
|
111
|
-
}
|
|
112
|
-
.btn:hover { border-color: var(--accent); color: var(--accent2); }
|
|
113
|
-
.btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
|
|
114
|
-
.btn.primary:hover { background: var(--accent2); }
|
|
115
|
-
.btn:disabled { opacity: .5; cursor: not-allowed; }
|
|
116
|
-
|
|
117
|
-
/* Login */
|
|
118
|
-
.login-overlay {
|
|
119
|
-
position: fixed; inset: 0; background: var(--bg);
|
|
120
|
-
display: flex; align-items: center; justify-content: center;
|
|
121
|
-
z-index: 1000;
|
|
122
|
-
}
|
|
123
|
-
.login-box {
|
|
124
|
-
background: var(--surface); border: 1px solid var(--border);
|
|
125
|
-
border-radius: var(--radius); padding: 40px; width: 360px; text-align: center;
|
|
126
|
-
}
|
|
127
|
-
.login-box h2 { margin-bottom: 24px; font-size: 20px; }
|
|
128
|
-
.login-box input {
|
|
129
|
-
width: 100%; padding: 10px 14px; border-radius: 6px;
|
|
130
|
-
border: 1px solid var(--border); background: var(--surface2);
|
|
131
|
-
color: var(--text); font-size: 14px; margin-bottom: 16px; outline: none;
|
|
132
|
-
}
|
|
133
|
-
.login-box input:focus { border-color: var(--accent); }
|
|
134
|
-
.login-box .error { color: var(--red); font-size: 13px; margin-bottom: 12px; min-height: 20px; }
|
|
135
|
-
.login-box .btn { width: 100%; }
|
|
136
|
-
.login-box .hint { font-size: 12px; color: var(--text2); margin-top: 12px; line-height: 1.5; }
|
|
137
|
-
|
|
138
|
-
/* Refresh bar */
|
|
139
|
-
.toolbar {
|
|
140
|
-
display: flex; justify-content: space-between; align-items: center;
|
|
141
|
-
margin-bottom: 16px;
|
|
142
|
-
}
|
|
143
|
-
.toolbar .info { font-size: 13px; color: var(--text2); }
|
|
144
|
-
|
|
145
|
-
/* Spinner */
|
|
146
|
-
.spinner {
|
|
147
|
-
display: inline-block; width: 14px; height: 14px;
|
|
148
|
-
border: 2px solid var(--border); border-top-color: var(--accent);
|
|
149
|
-
border-radius: 50%; animation: spin .6s linear infinite;
|
|
150
|
-
}
|
|
151
|
-
@keyframes spin { to { transform: rotate(360deg); } }
|
|
152
|
-
|
|
153
|
-
/* Test result */
|
|
154
|
-
.test-result {
|
|
155
|
-
margin-top: 16px; padding: 12px 16px;
|
|
156
|
-
border-radius: var(--radius); font-size: 13px;
|
|
157
|
-
}
|
|
158
|
-
.test-result.ok { background: rgba(34,197,94,.1); border: 1px solid rgba(34,197,94,.3); }
|
|
159
|
-
.test-result.err { background: rgba(239,68,68,.1); border: 1px solid rgba(239,68,68,.3); }
|
|
160
|
-
|
|
161
|
-
/* Conversations */
|
|
162
|
-
.conv-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; }
|
|
163
|
-
.conv-card {
|
|
164
|
-
background: var(--surface); border: 1px solid var(--border);
|
|
165
|
-
border-radius: var(--radius); padding: 16px;
|
|
166
|
-
}
|
|
167
|
-
.conv-card .uid { font-size: 14px; font-weight: 600; }
|
|
168
|
-
.conv-card .cid { font-size: 12px; color: var(--text2); margin-top: 4px; word-break: break-all; }
|
|
169
|
-
.conv-card .model { font-size: 12px; color: var(--accent2); margin-top: 4px; }
|
|
170
|
-
|
|
171
|
-
@media (max-width: 640px) {
|
|
172
|
-
.app { padding: 16px; }
|
|
173
|
-
.grid { grid-template-columns: 1fr 1fr; }
|
|
174
|
-
.conv-list { grid-template-columns: 1fr; }
|
|
175
|
-
}
|
|
176
|
-
</style>
|
|
177
|
-
</head>
|
|
178
|
-
<body>
|
|
179
|
-
<div id="app"></div>
|
|
180
|
-
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
|
|
181
|
-
<script>
|
|
182
|
-
const { createApp, ref, reactive, onMounted, onUnmounted } = Vue
|
|
183
|
-
|
|
184
|
-
createApp({
|
|
185
|
-
setup() {
|
|
186
|
-
const jwt = ref(localStorage.getItem('chaite_jwt') || '')
|
|
187
|
-
const loggedIn = ref(!!jwt.value)
|
|
188
|
-
const loginError = ref('')
|
|
189
|
-
const loginLoading = ref(false)
|
|
190
|
-
|
|
191
|
-
const health = ref(null)
|
|
192
|
-
const stats = ref(null)
|
|
193
|
-
const channels = ref([])
|
|
194
|
-
const conversations = ref([])
|
|
195
|
-
const testResult = ref(null)
|
|
196
|
-
const testLoading = ref(false)
|
|
197
|
-
const loading = ref(true)
|
|
198
|
-
const refreshTime = ref('')
|
|
199
|
-
let timer = null
|
|
200
|
-
let tokenExpiresAt = parseInt(localStorage.getItem('chaite_jwt_exp') || '0')
|
|
201
|
-
|
|
202
|
-
const headers = () => ({
|
|
203
|
-
'Content-Type': 'application/json',
|
|
204
|
-
'Authorization': `Bearer ${jwt.value}`
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
// Extract ?token=xxx from URL
|
|
208
|
-
function getUrlToken() {
|
|
209
|
-
const params = new URLSearchParams(window.location.search)
|
|
210
|
-
return params.get('token') || ''
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function isTokenExpired() {
|
|
214
|
-
if (!tokenExpiresAt) return false
|
|
215
|
-
return Date.now() / 1000 > tokenExpiresAt - 300
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// Auto-login: if ?token= is in URL, use it to get a JWT
|
|
219
|
-
async function autoLogin() {
|
|
220
|
-
const urlToken = getUrlToken()
|
|
221
|
-
if (!urlToken) {
|
|
222
|
-
// No URL token — check if we have a stored JWT
|
|
223
|
-
if (jwt.value && !isTokenExpired()) {
|
|
224
|
-
loggedIn.value = true
|
|
225
|
-
refreshAll()
|
|
226
|
-
} else if (jwt.value && isTokenExpired()) {
|
|
227
|
-
// Try refresh
|
|
228
|
-
tryRefresh()
|
|
229
|
-
}
|
|
230
|
-
return
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Exchange access token for JWT
|
|
234
|
-
loginLoading.value = true
|
|
235
|
-
loginError.value = ''
|
|
236
|
-
try {
|
|
237
|
-
const r = await fetch('/api/auth/login', {
|
|
238
|
-
method: 'POST',
|
|
239
|
-
headers: { 'Content-Type': 'application/json' },
|
|
240
|
-
body: JSON.stringify({ token: urlToken })
|
|
241
|
-
})
|
|
242
|
-
const d = await r.json()
|
|
243
|
-
if (d.data?.token) {
|
|
244
|
-
jwt.value = d.data.token
|
|
245
|
-
tokenExpiresAt = Math.floor(Date.now() / 1000) + (d.data.expiresIn || 604800)
|
|
246
|
-
localStorage.setItem('chaite_jwt', d.data.token)
|
|
247
|
-
localStorage.setItem('chaite_jwt_exp', String(tokenExpiresAt))
|
|
248
|
-
loggedIn.value = true
|
|
249
|
-
// Clean URL (remove ?token= from address bar)
|
|
250
|
-
window.history.replaceState({}, '', window.location.pathname)
|
|
251
|
-
refreshAll()
|
|
252
|
-
} else {
|
|
253
|
-
loginError.value = 'Invalid or expired access token'
|
|
254
|
-
}
|
|
255
|
-
} catch (e) {
|
|
256
|
-
loginError.value = 'Network error'
|
|
257
|
-
} finally {
|
|
258
|
-
loginLoading.value = false
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
async function tryRefresh() {
|
|
263
|
-
try {
|
|
264
|
-
const r = await fetch('/api/auth/refresh', { method: 'POST', headers: headers() })
|
|
265
|
-
const d = await r.json()
|
|
266
|
-
if (d.data?.token) {
|
|
267
|
-
jwt.value = d.data.token
|
|
268
|
-
tokenExpiresAt = Math.floor(Date.now() / 1000) + (d.data.expiresIn || 604800)
|
|
269
|
-
localStorage.setItem('chaite_jwt', d.data.token)
|
|
270
|
-
localStorage.setItem('chaite_jwt_exp', String(tokenExpiresAt))
|
|
271
|
-
loggedIn.value = true
|
|
272
|
-
refreshAll()
|
|
273
|
-
} else {
|
|
274
|
-
logout()
|
|
275
|
-
}
|
|
276
|
-
} catch {
|
|
277
|
-
logout()
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
function logout() {
|
|
282
|
-
jwt.value = ''
|
|
283
|
-
tokenExpiresAt = 0
|
|
284
|
-
localStorage.removeItem('chaite_jwt')
|
|
285
|
-
localStorage.removeItem('chaite_jwt_exp')
|
|
286
|
-
loggedIn.value = false
|
|
287
|
-
health.value = null
|
|
288
|
-
stats.value = null
|
|
289
|
-
channels.value = []
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
async function api(path) {
|
|
293
|
-
if (isTokenExpired()) {
|
|
294
|
-
await tryRefresh()
|
|
295
|
-
if (!loggedIn.value) return null
|
|
296
|
-
}
|
|
297
|
-
const r = await fetch(path, { headers: headers() })
|
|
298
|
-
if (r.status === 401) { logout(); return null }
|
|
299
|
-
const d = await r.json()
|
|
300
|
-
return d.data
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
async function refreshAll() {
|
|
304
|
-
loading.value = true
|
|
305
|
-
try {
|
|
306
|
-
const [h, s, ch, cv] = await Promise.all([
|
|
307
|
-
api('/api/system/health'),
|
|
308
|
-
api('/api/system/stats'),
|
|
309
|
-
api('/api/channels/list'),
|
|
310
|
-
api('/api/state/conversations/list'),
|
|
311
|
-
])
|
|
312
|
-
health.value = h
|
|
313
|
-
stats.value = s
|
|
314
|
-
channels.value = ch || []
|
|
315
|
-
conversations.value = cv || []
|
|
316
|
-
refreshTime.value = new Date().toLocaleTimeString()
|
|
317
|
-
} catch (e) {
|
|
318
|
-
console.error('refresh error', e)
|
|
319
|
-
} finally {
|
|
320
|
-
loading.value = false
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
async function testChannel(channelId) {
|
|
325
|
-
testLoading.value = true
|
|
326
|
-
testResult.value = null
|
|
327
|
-
try {
|
|
328
|
-
const r = await fetch('/api/system/test-channel', {
|
|
329
|
-
method: 'POST',
|
|
330
|
-
headers: headers(),
|
|
331
|
-
body: JSON.stringify({ channelId })
|
|
332
|
-
})
|
|
333
|
-
testResult.value = await r.json()
|
|
334
|
-
} catch (e) {
|
|
335
|
-
testResult.value = { data: { status: 'error', error: e.message } }
|
|
336
|
-
} finally {
|
|
337
|
-
testLoading.value = false
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
function uptimeStr(s) {
|
|
342
|
-
if (!s && s !== 0) return '-'
|
|
343
|
-
const h = Math.floor(s / 3600)
|
|
344
|
-
const m = Math.floor((s % 3600) / 60)
|
|
345
|
-
const sec = s % 60
|
|
346
|
-
return h ? `${h}h ${m}m` : m ? `${m}m ${sec}s` : `${sec}s`
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
function fmtNum(n) {
|
|
350
|
-
if (!n && n !== 0) return '0'
|
|
351
|
-
if (n >= 1e6) return (n / 1e6).toFixed(1) + 'M'
|
|
352
|
-
if (n >= 1e3) return (n / 1e3).toFixed(1) + 'K'
|
|
353
|
-
return String(n)
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
onMounted(() => {
|
|
357
|
-
autoLogin()
|
|
358
|
-
timer = setInterval(() => { if (loggedIn.value) refreshAll() }, 30000)
|
|
359
|
-
})
|
|
360
|
-
onUnmounted(() => clearInterval(timer))
|
|
361
|
-
|
|
362
|
-
return {
|
|
363
|
-
jwt, loggedIn, loginError, loginLoading,
|
|
364
|
-
health, stats, channels, conversations,
|
|
365
|
-
testResult, testLoading, loading, refreshTime,
|
|
366
|
-
logout, refreshAll, testChannel,
|
|
367
|
-
uptimeStr, fmtNum,
|
|
368
|
-
}
|
|
369
|
-
},
|
|
370
|
-
template: `
|
|
371
|
-
<!-- No token in URL and no stored JWT -->
|
|
372
|
-
<div v-if="!loggedIn && !loginLoading" class="login-overlay">
|
|
373
|
-
<div class="login-box">
|
|
374
|
-
<h2>⚡ Chaite Dashboard</h2>
|
|
375
|
-
<div class="error">{{ loginError }}</div>
|
|
376
|
-
<div class="hint">
|
|
377
|
-
No access token found.<br><br>
|
|
378
|
-
Open the dashboard with your access token in the URL:<br>
|
|
379
|
-
<code style="word-break:break-all;color:var(--accent2);">http://host:port?token=YOUR_TOKEN</code><br><br>
|
|
380
|
-
The token is printed in the server console at startup.
|
|
381
|
-
</div>
|
|
382
|
-
</div>
|
|
383
|
-
</div>
|
|
384
|
-
|
|
385
|
-
<!-- Loading state (auto-login in progress) -->
|
|
386
|
-
<div v-else-if="loginLoading" class="login-overlay">
|
|
387
|
-
<div class="login-box">
|
|
388
|
-
<h2>⚡ Chaite Dashboard</h2>
|
|
389
|
-
<div class="spinner" style="margin:16px auto;"></div>
|
|
390
|
-
<div style="color:var(--text2);font-size:13px;">Authenticating...</div>
|
|
391
|
-
</div>
|
|
392
|
-
</div>
|
|
393
|
-
|
|
394
|
-
<div v-else class="app">
|
|
395
|
-
<!-- Header -->
|
|
396
|
-
<div class="header">
|
|
397
|
-
<h1>⚡ <span>Chaite</span> Dashboard</h1>
|
|
398
|
-
<div class="meta">
|
|
399
|
-
<span class="badge" v-if="refreshTime">Updated {{ refreshTime }}</span>
|
|
400
|
-
<span class="badge ok" v-if="health?.status === 'ok'">Healthy</span>
|
|
401
|
-
<span class="badge err" v-else-if="health">Unhealthy</span>
|
|
402
|
-
<button class="btn" @click="refreshAll" :disabled="loading">
|
|
403
|
-
<span v-if="loading" class="spinner"></span>
|
|
404
|
-
<span v-else>↻ Refresh</span>
|
|
405
|
-
</button>
|
|
406
|
-
<button class="btn" @click="logout">Logout</button>
|
|
407
|
-
</div>
|
|
408
|
-
</div>
|
|
409
|
-
|
|
410
|
-
<!-- Stats cards -->
|
|
411
|
-
<div class="grid" v-if="health">
|
|
412
|
-
<div class="card">
|
|
413
|
-
<div class="label">Uptime</div>
|
|
414
|
-
<div class="value">{{ uptimeStr(health.uptime) }}</div>
|
|
415
|
-
<div class="sub">v{{ health.version }} · Node {{ health.system?.nodeVersion }}</div>
|
|
416
|
-
</div>
|
|
417
|
-
<div class="card">
|
|
418
|
-
<div class="label">Channels</div>
|
|
419
|
-
<div class="value">{{ health.channels?.total }}</div>
|
|
420
|
-
<div class="sub">{{ health.channels?.enabled }} enabled · {{ health.channels?.disabled }} disabled</div>
|
|
421
|
-
</div>
|
|
422
|
-
<div class="card">
|
|
423
|
-
<div class="label">Models</div>
|
|
424
|
-
<div class="value">{{ health.models?.count }}</div>
|
|
425
|
-
<div class="sub">{{ health.tools?.count ?? 0 }} tools registered</div>
|
|
426
|
-
</div>
|
|
427
|
-
<div class="card">
|
|
428
|
-
<div class="label">Memory</div>
|
|
429
|
-
<div class="value">{{ health.system?.processMemory ?? '-' }} MB</div>
|
|
430
|
-
<div class="sub">Heap {{ health.system?.heapUsed ?? '-' }} MB · Free {{ health.system?.freeMemory ?? '-' }} MB</div>
|
|
431
|
-
</div>
|
|
432
|
-
<div class="card" v-if="stats?.summary">
|
|
433
|
-
<div class="label">Total Calls</div>
|
|
434
|
-
<div class="value">{{ fmtNum(stats.summary.totalCalls) }}</div>
|
|
435
|
-
<div class="sub">{{ fmtNum(stats.summary.totalTokens) }} tokens used</div>
|
|
436
|
-
</div>
|
|
437
|
-
</div>
|
|
438
|
-
|
|
439
|
-
<!-- Channels -->
|
|
440
|
-
<div class="section">
|
|
441
|
-
<h2><span class="dot"></span> Channels</h2>
|
|
442
|
-
<div class="table-wrap">
|
|
443
|
-
<table>
|
|
444
|
-
<thead>
|
|
445
|
-
<tr>
|
|
446
|
-
<th>Status</th>
|
|
447
|
-
<th>Name</th>
|
|
448
|
-
<th>Adapter</th>
|
|
449
|
-
<th>Models</th>
|
|
450
|
-
<th>Priority</th>
|
|
451
|
-
<th>Calls</th>
|
|
452
|
-
<th>Actions</th>
|
|
453
|
-
</tr>
|
|
454
|
-
</thead>
|
|
455
|
-
<tbody>
|
|
456
|
-
<tr v-for="ch in channels" :key="ch.id">
|
|
457
|
-
<td>
|
|
458
|
-
<span class="status-dot" :class="ch.status === 'enabled' ? 'on' : 'off'"></span>
|
|
459
|
-
{{ ch.status }}
|
|
460
|
-
</td>
|
|
461
|
-
<td>{{ ch.name || ch.id?.slice(0, 8) }}</td>
|
|
462
|
-
<td>{{ ch.adapterType }}</td>
|
|
463
|
-
<td>
|
|
464
|
-
<span class="model-tag" v-for="m in (ch.models || []).slice(0, 3)" :key="m">{{ m }}</span>
|
|
465
|
-
<span v-if="(ch.models || []).length > 3" class="model-tag">+{{ ch.models.length - 3 }}</span>
|
|
466
|
-
</td>
|
|
467
|
-
<td>{{ ch.priority }}</td>
|
|
468
|
-
<td>{{ ch.statistics?.callTimes ?? 0 }}</td>
|
|
469
|
-
<td>
|
|
470
|
-
<button class="btn" @click="testChannel(ch.id)" :disabled="testLoading"
|
|
471
|
-
style="font-size:12px;padding:4px 10px;">
|
|
472
|
-
<span v-if="testLoading" class="spinner"></span>
|
|
473
|
-
<span v-else>Test</span>
|
|
474
|
-
</button>
|
|
475
|
-
</td>
|
|
476
|
-
</tr>
|
|
477
|
-
<tr v-if="!channels.length">
|
|
478
|
-
<td colspan="7" style="text-align:center;color:var(--text2);padding:24px;">No channels configured</td>
|
|
479
|
-
</tr>
|
|
480
|
-
</tbody>
|
|
481
|
-
</table>
|
|
482
|
-
</div>
|
|
483
|
-
<div v-if="testResult" class="test-result" :class="testResult.data?.status === 'ok' ? 'ok' : 'err'">
|
|
484
|
-
<template v-if="testResult.data?.status === 'ok'">
|
|
485
|
-
✅ Channel test passed · Model: {{ testResult.data.model }} · Latency: {{ testResult.data.latency }}ms
|
|
486
|
-
</template>
|
|
487
|
-
<template v-else>
|
|
488
|
-
❌ Test failed: {{ testResult.data?.error || testResult.message }}
|
|
489
|
-
</template>
|
|
490
|
-
</div>
|
|
491
|
-
</div>
|
|
492
|
-
|
|
493
|
-
<!-- Models -->
|
|
494
|
-
<div class="section" v-if="health?.models?.list?.length">
|
|
495
|
-
<h2><span class="dot"></span> Available Models</h2>
|
|
496
|
-
<div style="display:flex;flex-wrap:wrap;gap:6px;">
|
|
497
|
-
<span class="model-tag" v-for="m in health.models.list" :key="m"
|
|
498
|
-
style="font-size:13px;padding:5px 12px;">{{ m }}</span>
|
|
499
|
-
</div>
|
|
500
|
-
</div>
|
|
501
|
-
|
|
502
|
-
<!-- Conversations -->
|
|
503
|
-
<div class="section" v-if="conversations.length">
|
|
504
|
-
<h2><span class="dot"></span> Active Conversations</h2>
|
|
505
|
-
<div class="conv-list">
|
|
506
|
-
<div class="conv-card" v-for="c in conversations" :key="c.userId">
|
|
507
|
-
<div class="uid">User {{ c.userId }}</div>
|
|
508
|
-
<div class="cid" v-if="c.conversationId">Conv: {{ c.conversationId }}</div>
|
|
509
|
-
<div class="model" v-if="c.currentModel">Model: {{ c.currentModel }}</div>
|
|
510
|
-
</div>
|
|
511
|
-
</div>
|
|
512
|
-
</div>
|
|
513
|
-
|
|
514
|
-
<!-- Per-model stats -->
|
|
515
|
-
<div class="section" v-if="stats?.perModel && Object.keys(stats.perModel).length">
|
|
516
|
-
<h2><span class="dot"></span> Per-Model Stats</h2>
|
|
517
|
-
<div class="table-wrap">
|
|
518
|
-
<table>
|
|
519
|
-
<thead>
|
|
520
|
-
<tr><th>Model</th><th>Calls</th><th>Tokens</th></tr>
|
|
521
|
-
</thead>
|
|
522
|
-
<tbody>
|
|
523
|
-
<tr v-for="(s, model) in stats.perModel" :key="model">
|
|
524
|
-
<td>{{ model }}</td>
|
|
525
|
-
<td>{{ fmtNum(s.calls) }}</td>
|
|
526
|
-
<td>{{ fmtNum(s.tokens) }}</td>
|
|
527
|
-
</tr>
|
|
528
|
-
</tbody>
|
|
529
|
-
</table>
|
|
530
|
-
</div>
|
|
531
|
-
</div>
|
|
532
|
-
</div>
|
|
533
|
-
`
|
|
534
|
-
}).mount('#app')
|
|
535
|
-
</script>
|
|
536
|
-
</body>
|
|
537
|
-
</html>
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<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>
|
|
12
|
+
|
|
13
|
+
<body>
|
|
14
|
+
<div id="appLoading"></div>
|
|
15
|
+
<div id="app"></div>
|
|
16
|
+
</body>
|
|
17
|
+
|
|
18
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@hina114514/chaite",
|
|
3
|
-
"version": "1.9.
|
|
4
|
-
"description": "core for chatgpt-plugin and karin-plugin-chatgpt",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"yunzai",
|
|
7
|
-
"karin",
|
|
8
|
-
"chatgpt"
|
|
9
|
-
],
|
|
10
|
-
"license": "ISC",
|
|
11
|
-
"author": "ikechan8370",
|
|
12
|
-
"sideEffects": true,
|
|
13
|
-
"type": "module",
|
|
14
|
-
"main": "dist/index.mjs",
|
|
15
|
-
"types": "dist/index.d.ts",
|
|
16
|
-
"files": [
|
|
17
|
-
"dist",
|
|
18
|
-
"frontend",
|
|
19
|
-
"LICENSE",
|
|
20
|
-
"README.md",
|
|
21
|
-
"package.json"
|
|
22
|
-
],
|
|
23
|
-
"scripts": {
|
|
24
|
-
"build": "tsc --noEmit && tsdown",
|
|
25
|
-
"dev": "nodemon --exec ts-node src/index.ts",
|
|
26
|
-
"lint": "eslint . --ext .ts",
|
|
27
|
-
"lint:fix": "eslint . --ext .ts --fix",
|
|
28
|
-
"prebuild": "node scripts/generate-version.js",
|
|
29
|
-
"prepublishOnly": "npm run build",
|
|
30
|
-
"pub": "npm publish --access public",
|
|
31
|
-
"test": "jest"
|
|
32
|
-
},
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"@anthropic-ai/sdk": "^0.39.0",
|
|
35
|
-
"@eslint/js": "^9.21.0",
|
|
36
|
-
"@google/genai": "^1.8.0",
|
|
37
|
-
"@karinjs/node-schedule": "^1.1.2",
|
|
38
|
-
"@types/cors": "^2.8.17",
|
|
39
|
-
"@types/express": "^5.0.0",
|
|
40
|
-
"@types/jest": "^29.5.14",
|
|
41
|
-
"@types/node": "^20.17.24",
|
|
42
|
-
"@typescript-eslint/eslint-plugin": "^8.25.0",
|
|
43
|
-
"@typescript-eslint/parser": "^8.25.0",
|
|
44
|
-
"axios": "^1.8.1",
|
|
45
|
-
"chokidar": "^4.0.3",
|
|
46
|
-
"copyfiles": "^2.4.1",
|
|
47
|
-
"cors": "^2.8.5",
|
|
48
|
-
"eslint": "^9.21.0",
|
|
49
|
-
"eslint-config-prettier": "^10.0.2",
|
|
50
|
-
"eslint-plugin-prettier": "^5.2.3",
|
|
51
|
-
"express": "^4.21.2",
|
|
52
|
-
"jest": "^29.7.0",
|
|
53
|
-
"mammoth": "^1.9.0",
|
|
54
|
-
"openai": "^5.20.1",
|
|
55
|
-
"pdf-parse": "^2.4.5",
|
|
56
|
-
"prettier": "^3.5.2",
|
|
57
|
-
"reflect-metadata": "^0.2.2",
|
|
58
|
-
"ts-jest": "^29.2.6",
|
|
59
|
-
"tsdown": "^0.16.0",
|
|
60
|
-
"typescript": "^5.7.3",
|
|
61
|
-
"typescript-eslint": "^8.25.0"
|
|
62
|
-
},
|
|
63
|
-
"peerDependencies": {
|
|
64
|
-
"pdf-parse": "^2.4.5"
|
|
65
|
-
},
|
|
66
|
-
"peerDependenciesMeta": {
|
|
67
|
-
"pdf-parse": {
|
|
68
|
-
"optional": true
|
|
69
|
-
}
|
|
70
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@hina114514/chaite",
|
|
3
|
+
"version": "1.9.4",
|
|
4
|
+
"description": "core for chatgpt-plugin and karin-plugin-chatgpt",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"yunzai",
|
|
7
|
+
"karin",
|
|
8
|
+
"chatgpt"
|
|
9
|
+
],
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"author": "ikechan8370",
|
|
12
|
+
"sideEffects": true,
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "dist/index.mjs",
|
|
15
|
+
"types": "dist/index.d.ts",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"frontend",
|
|
19
|
+
"LICENSE",
|
|
20
|
+
"README.md",
|
|
21
|
+
"package.json"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc --noEmit && tsdown",
|
|
25
|
+
"dev": "nodemon --exec ts-node src/index.ts",
|
|
26
|
+
"lint": "eslint . --ext .ts",
|
|
27
|
+
"lint:fix": "eslint . --ext .ts --fix",
|
|
28
|
+
"prebuild": "node scripts/generate-version.js",
|
|
29
|
+
"prepublishOnly": "npm run build",
|
|
30
|
+
"pub": "npm publish --access public",
|
|
31
|
+
"test": "jest"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@anthropic-ai/sdk": "^0.39.0",
|
|
35
|
+
"@eslint/js": "^9.21.0",
|
|
36
|
+
"@google/genai": "^1.8.0",
|
|
37
|
+
"@karinjs/node-schedule": "^1.1.2",
|
|
38
|
+
"@types/cors": "^2.8.17",
|
|
39
|
+
"@types/express": "^5.0.0",
|
|
40
|
+
"@types/jest": "^29.5.14",
|
|
41
|
+
"@types/node": "^20.17.24",
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "^8.25.0",
|
|
43
|
+
"@typescript-eslint/parser": "^8.25.0",
|
|
44
|
+
"axios": "^1.8.1",
|
|
45
|
+
"chokidar": "^4.0.3",
|
|
46
|
+
"copyfiles": "^2.4.1",
|
|
47
|
+
"cors": "^2.8.5",
|
|
48
|
+
"eslint": "^9.21.0",
|
|
49
|
+
"eslint-config-prettier": "^10.0.2",
|
|
50
|
+
"eslint-plugin-prettier": "^5.2.3",
|
|
51
|
+
"express": "^4.21.2",
|
|
52
|
+
"jest": "^29.7.0",
|
|
53
|
+
"mammoth": "^1.9.0",
|
|
54
|
+
"openai": "^5.20.1",
|
|
55
|
+
"pdf-parse": "^2.4.5",
|
|
56
|
+
"prettier": "^3.5.2",
|
|
57
|
+
"reflect-metadata": "^0.2.2",
|
|
58
|
+
"ts-jest": "^29.2.6",
|
|
59
|
+
"tsdown": "^0.16.0",
|
|
60
|
+
"typescript": "^5.7.3",
|
|
61
|
+
"typescript-eslint": "^8.25.0"
|
|
62
|
+
},
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"pdf-parse": "^2.4.5"
|
|
65
|
+
},
|
|
66
|
+
"peerDependenciesMeta": {
|
|
67
|
+
"pdf-parse": {
|
|
68
|
+
"optional": true
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
71
|
}
|