@appkit/llamacpp-cli 1.12.0 → 1.13.0
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/README.md +294 -168
- package/dist/cli.js +35 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/launch/claude.d.ts +6 -0
- package/dist/commands/launch/claude.d.ts.map +1 -0
- package/dist/commands/launch/claude.js +277 -0
- package/dist/commands/launch/claude.js.map +1 -0
- package/dist/lib/integration-checker.d.ts +26 -0
- package/dist/lib/integration-checker.d.ts.map +1 -0
- package/dist/lib/integration-checker.js +77 -0
- package/dist/lib/integration-checker.js.map +1 -0
- package/dist/lib/router-manager.d.ts +4 -0
- package/dist/lib/router-manager.d.ts.map +1 -1
- package/dist/lib/router-manager.js +10 -0
- package/dist/lib/router-manager.js.map +1 -1
- package/dist/lib/router-server.d.ts +13 -0
- package/dist/lib/router-server.d.ts.map +1 -1
- package/dist/lib/router-server.js +267 -7
- package/dist/lib/router-server.js.map +1 -1
- package/dist/types/integration-config.d.ts +28 -0
- package/dist/types/integration-config.d.ts.map +1 -0
- package/dist/types/integration-config.js +3 -0
- package/dist/types/integration-config.js.map +1 -0
- package/package.json +10 -2
- package/web/dist/assets/index-Bin89Lwr.css +1 -0
- package/web/dist/assets/index-CVmonw3T.js +17 -0
- package/web/{index.html → dist/index.html} +2 -1
- package/.versionrc.json +0 -16
- package/CHANGELOG.md +0 -213
- package/docs/images/.gitkeep +0 -1
- package/docs/images/web-ui-servers.png +0 -0
- package/src/cli.ts +0 -523
- package/src/commands/admin/config.ts +0 -121
- package/src/commands/admin/logs.ts +0 -91
- package/src/commands/admin/restart.ts +0 -26
- package/src/commands/admin/start.ts +0 -27
- package/src/commands/admin/status.ts +0 -84
- package/src/commands/admin/stop.ts +0 -16
- package/src/commands/config-global.ts +0 -38
- package/src/commands/config.ts +0 -323
- package/src/commands/create.ts +0 -183
- package/src/commands/delete.ts +0 -74
- package/src/commands/list.ts +0 -37
- package/src/commands/logs-all.ts +0 -251
- package/src/commands/logs.ts +0 -345
- package/src/commands/monitor.ts +0 -110
- package/src/commands/ps.ts +0 -84
- package/src/commands/pull.ts +0 -44
- package/src/commands/rm.ts +0 -107
- package/src/commands/router/config.ts +0 -116
- package/src/commands/router/logs.ts +0 -256
- package/src/commands/router/restart.ts +0 -36
- package/src/commands/router/start.ts +0 -60
- package/src/commands/router/status.ts +0 -119
- package/src/commands/router/stop.ts +0 -33
- package/src/commands/run.ts +0 -233
- package/src/commands/search.ts +0 -107
- package/src/commands/server-show.ts +0 -161
- package/src/commands/show.ts +0 -207
- package/src/commands/start.ts +0 -101
- package/src/commands/stop.ts +0 -39
- package/src/commands/tui.ts +0 -25
- package/src/lib/admin-manager.ts +0 -435
- package/src/lib/admin-server.ts +0 -1243
- package/src/lib/config-generator.ts +0 -130
- package/src/lib/download-job-manager.ts +0 -213
- package/src/lib/history-manager.ts +0 -172
- package/src/lib/launchctl-manager.ts +0 -225
- package/src/lib/metrics-aggregator.ts +0 -257
- package/src/lib/model-downloader.ts +0 -328
- package/src/lib/model-scanner.ts +0 -157
- package/src/lib/model-search.ts +0 -114
- package/src/lib/models-dir-setup.ts +0 -46
- package/src/lib/port-manager.ts +0 -80
- package/src/lib/router-logger.ts +0 -201
- package/src/lib/router-manager.ts +0 -414
- package/src/lib/router-server.ts +0 -538
- package/src/lib/state-manager.ts +0 -206
- package/src/lib/status-checker.ts +0 -113
- package/src/lib/system-collector.ts +0 -315
- package/src/tui/ConfigApp.ts +0 -1085
- package/src/tui/HistoricalMonitorApp.ts +0 -587
- package/src/tui/ModelsApp.ts +0 -368
- package/src/tui/MonitorApp.ts +0 -386
- package/src/tui/MultiServerMonitorApp.ts +0 -1833
- package/src/tui/RootNavigator.ts +0 -74
- package/src/tui/SearchApp.ts +0 -511
- package/src/tui/SplashScreen.ts +0 -149
- package/src/types/admin-config.ts +0 -25
- package/src/types/global-config.ts +0 -26
- package/src/types/history-types.ts +0 -39
- package/src/types/model-info.ts +0 -8
- package/src/types/monitor-types.ts +0 -162
- package/src/types/router-config.ts +0 -25
- package/src/types/server-config.ts +0 -46
- package/src/utils/downsample-utils.ts +0 -128
- package/src/utils/file-utils.ts +0 -146
- package/src/utils/format-utils.ts +0 -98
- package/src/utils/log-parser.ts +0 -284
- package/src/utils/log-utils.ts +0 -178
- package/src/utils/process-utils.ts +0 -316
- package/src/utils/prompt-utils.ts +0 -47
- package/test-load.sh +0 -100
- package/tsconfig.json +0 -20
- package/web/eslint.config.js +0 -23
- package/web/llamacpp-web-dist.tar.gz +0 -0
- package/web/package-lock.json +0 -4017
- package/web/package.json +0 -38
- package/web/postcss.config.js +0 -6
- package/web/src/App.css +0 -42
- package/web/src/App.tsx +0 -86
- package/web/src/assets/react.svg +0 -1
- package/web/src/components/ApiKeyPrompt.tsx +0 -71
- package/web/src/components/CreateServerModal.tsx +0 -372
- package/web/src/components/DownloadProgress.tsx +0 -123
- package/web/src/components/Nav.tsx +0 -89
- package/web/src/components/RouterConfigModal.tsx +0 -240
- package/web/src/components/SearchModal.tsx +0 -306
- package/web/src/components/ServerConfigModal.tsx +0 -291
- package/web/src/hooks/useApi.ts +0 -259
- package/web/src/index.css +0 -42
- package/web/src/lib/api.ts +0 -226
- package/web/src/main.tsx +0 -10
- package/web/src/pages/Dashboard.tsx +0 -103
- package/web/src/pages/Models.tsx +0 -258
- package/web/src/pages/Router.tsx +0 -270
- package/web/src/pages/RouterLogs.tsx +0 -201
- package/web/src/pages/ServerLogs.tsx +0 -553
- package/web/src/pages/Servers.tsx +0 -358
- package/web/src/types/api.ts +0 -140
- package/web/tailwind.config.js +0 -31
- package/web/tsconfig.app.json +0 -28
- package/web/tsconfig.json +0 -7
- package/web/tsconfig.node.json +0 -26
- package/web/vite.config.ts +0 -25
- /package/web/{public → dist}/vite.svg +0 -0
package/web/src/hooks/useApi.ts
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import { useQuery, useMutation, useQueryClient, keepPreviousData } from '@tanstack/react-query';
|
|
2
|
-
import { api } from '../lib/api';
|
|
3
|
-
import type { CreateServerRequest, UpdateServerRequest, UpdateRouterRequest } from '../types/api';
|
|
4
|
-
|
|
5
|
-
// System
|
|
6
|
-
export function useSystemStatus() {
|
|
7
|
-
return useQuery({
|
|
8
|
-
queryKey: ['system', 'status'],
|
|
9
|
-
queryFn: () => api.getSystemStatus(),
|
|
10
|
-
refetchInterval: 5000, // Auto-refresh every 5s
|
|
11
|
-
});
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// Servers
|
|
15
|
-
export function useServers() {
|
|
16
|
-
return useQuery({
|
|
17
|
-
queryKey: ['servers'],
|
|
18
|
-
queryFn: () => api.listServers(),
|
|
19
|
-
refetchInterval: 5000, // Auto-refresh every 5s
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function useServer(id: string) {
|
|
24
|
-
return useQuery({
|
|
25
|
-
queryKey: ['servers', id],
|
|
26
|
-
queryFn: () => api.getServer(id),
|
|
27
|
-
enabled: !!id,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function useCreateServer() {
|
|
32
|
-
const queryClient = useQueryClient();
|
|
33
|
-
|
|
34
|
-
return useMutation({
|
|
35
|
-
mutationFn: (data: CreateServerRequest) => api.createServer(data),
|
|
36
|
-
onSuccess: () => {
|
|
37
|
-
queryClient.invalidateQueries({ queryKey: ['servers'] });
|
|
38
|
-
queryClient.invalidateQueries({ queryKey: ['system'] });
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function useUpdateServer() {
|
|
44
|
-
const queryClient = useQueryClient();
|
|
45
|
-
|
|
46
|
-
return useMutation({
|
|
47
|
-
mutationFn: ({ id, data }: { id: string; data: UpdateServerRequest }) =>
|
|
48
|
-
api.updateServer(id, data),
|
|
49
|
-
onSuccess: (_, variables) => {
|
|
50
|
-
queryClient.invalidateQueries({ queryKey: ['servers'] });
|
|
51
|
-
queryClient.invalidateQueries({ queryKey: ['servers', variables.id] });
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function useDeleteServer() {
|
|
57
|
-
const queryClient = useQueryClient();
|
|
58
|
-
|
|
59
|
-
return useMutation({
|
|
60
|
-
mutationFn: (id: string) => api.deleteServer(id),
|
|
61
|
-
onSuccess: () => {
|
|
62
|
-
queryClient.invalidateQueries({ queryKey: ['servers'] });
|
|
63
|
-
queryClient.invalidateQueries({ queryKey: ['system'] });
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function useStartServer() {
|
|
69
|
-
const queryClient = useQueryClient();
|
|
70
|
-
|
|
71
|
-
return useMutation({
|
|
72
|
-
mutationFn: (id: string) => api.startServer(id),
|
|
73
|
-
onSuccess: (_, id) => {
|
|
74
|
-
queryClient.invalidateQueries({ queryKey: ['servers'] });
|
|
75
|
-
queryClient.invalidateQueries({ queryKey: ['servers', id] });
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function useStopServer() {
|
|
81
|
-
const queryClient = useQueryClient();
|
|
82
|
-
|
|
83
|
-
return useMutation({
|
|
84
|
-
mutationFn: (id: string) => api.stopServer(id),
|
|
85
|
-
onSuccess: (_, id) => {
|
|
86
|
-
queryClient.invalidateQueries({ queryKey: ['servers'] });
|
|
87
|
-
queryClient.invalidateQueries({ queryKey: ['servers', id] });
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export function useRestartServer() {
|
|
93
|
-
const queryClient = useQueryClient();
|
|
94
|
-
|
|
95
|
-
return useMutation({
|
|
96
|
-
mutationFn: (id: string) => api.restartServer(id),
|
|
97
|
-
onSuccess: (_, id) => {
|
|
98
|
-
queryClient.invalidateQueries({ queryKey: ['servers'] });
|
|
99
|
-
queryClient.invalidateQueries({ queryKey: ['servers', id] });
|
|
100
|
-
},
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function useServerLogs(serverId: string | null, lines = 500) {
|
|
105
|
-
return useQuery({
|
|
106
|
-
queryKey: ['serverLogs', serverId, lines],
|
|
107
|
-
queryFn: () => api.getServerLogs(serverId!, 'both', lines),
|
|
108
|
-
enabled: !!serverId,
|
|
109
|
-
refetchInterval: 2000, // Auto-refresh every 2s
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Models
|
|
114
|
-
export function useModels() {
|
|
115
|
-
return useQuery({
|
|
116
|
-
queryKey: ['models'],
|
|
117
|
-
queryFn: () => api.listModels(),
|
|
118
|
-
refetchInterval: 10000, // Auto-refresh every 10s
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function useModel(name: string) {
|
|
123
|
-
return useQuery({
|
|
124
|
-
queryKey: ['models', name],
|
|
125
|
-
queryFn: () => api.getModel(name),
|
|
126
|
-
enabled: !!name,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export function useDeleteModel() {
|
|
131
|
-
const queryClient = useQueryClient();
|
|
132
|
-
|
|
133
|
-
return useMutation({
|
|
134
|
-
mutationFn: ({ name, cascade }: { name: string; cascade: boolean }) =>
|
|
135
|
-
api.deleteModel(name, cascade),
|
|
136
|
-
onSuccess: () => {
|
|
137
|
-
queryClient.invalidateQueries({ queryKey: ['models'] });
|
|
138
|
-
queryClient.invalidateQueries({ queryKey: ['servers'] });
|
|
139
|
-
queryClient.invalidateQueries({ queryKey: ['system'] });
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export function useDownloadModel() {
|
|
145
|
-
return useMutation({
|
|
146
|
-
mutationFn: ({ repo, filename }: { repo: string; filename: string }) =>
|
|
147
|
-
api.downloadModel(repo, filename),
|
|
148
|
-
// Don't invalidate immediately - download is background job
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Search
|
|
153
|
-
export function useSearchModels() {
|
|
154
|
-
return useMutation({
|
|
155
|
-
mutationFn: ({ query, limit = 20 }: { query: string; limit?: number }) =>
|
|
156
|
-
api.searchModels(query, limit),
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export function useModelFiles(repoId: string | null) {
|
|
161
|
-
return useQuery({
|
|
162
|
-
queryKey: ['modelFiles', repoId],
|
|
163
|
-
queryFn: () => api.getModelFiles(repoId!),
|
|
164
|
-
enabled: !!repoId,
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Download Jobs
|
|
169
|
-
export function useDownloadJobs(enabled = true) {
|
|
170
|
-
return useQuery({
|
|
171
|
-
queryKey: ['downloadJobs'],
|
|
172
|
-
queryFn: () => api.listDownloadJobs(),
|
|
173
|
-
refetchInterval: enabled ? 1000 : false, // Poll every 1s when enabled
|
|
174
|
-
enabled,
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
export function useDownloadJob(jobId: string | null) {
|
|
179
|
-
return useQuery({
|
|
180
|
-
queryKey: ['downloadJobs', jobId],
|
|
181
|
-
queryFn: () => api.getDownloadJob(jobId!),
|
|
182
|
-
enabled: !!jobId,
|
|
183
|
-
refetchInterval: 500, // Fast polling for active job
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export function useCancelDownload() {
|
|
188
|
-
const queryClient = useQueryClient();
|
|
189
|
-
|
|
190
|
-
return useMutation({
|
|
191
|
-
mutationFn: (jobId: string) => api.cancelDownloadJob(jobId),
|
|
192
|
-
onSuccess: () => {
|
|
193
|
-
queryClient.invalidateQueries({ queryKey: ['downloadJobs'] });
|
|
194
|
-
},
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Router
|
|
199
|
-
export function useRouter() {
|
|
200
|
-
return useQuery({
|
|
201
|
-
queryKey: ['router'],
|
|
202
|
-
queryFn: () => api.getRouter(),
|
|
203
|
-
refetchInterval: 5000, // Auto-refresh every 5s
|
|
204
|
-
placeholderData: keepPreviousData, // Keep previous data during refetch to prevent flash
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
export function useStartRouter() {
|
|
209
|
-
const queryClient = useQueryClient();
|
|
210
|
-
|
|
211
|
-
return useMutation({
|
|
212
|
-
mutationFn: () => api.startRouter(),
|
|
213
|
-
onSuccess: () => {
|
|
214
|
-
queryClient.invalidateQueries({ queryKey: ['router'] });
|
|
215
|
-
},
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
export function useStopRouter() {
|
|
220
|
-
const queryClient = useQueryClient();
|
|
221
|
-
|
|
222
|
-
return useMutation({
|
|
223
|
-
mutationFn: () => api.stopRouter(),
|
|
224
|
-
onSuccess: () => {
|
|
225
|
-
queryClient.invalidateQueries({ queryKey: ['router'] });
|
|
226
|
-
},
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
export function useRestartRouter() {
|
|
231
|
-
const queryClient = useQueryClient();
|
|
232
|
-
|
|
233
|
-
return useMutation({
|
|
234
|
-
mutationFn: () => api.restartRouter(),
|
|
235
|
-
onSuccess: () => {
|
|
236
|
-
queryClient.invalidateQueries({ queryKey: ['router'] });
|
|
237
|
-
},
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
export function useRouterLogs(lines = 500) {
|
|
242
|
-
return useQuery({
|
|
243
|
-
queryKey: ['routerLogs', lines],
|
|
244
|
-
queryFn: () => api.getRouterLogs('both', lines),
|
|
245
|
-
refetchInterval: 2000, // Auto-refresh every 2s
|
|
246
|
-
placeholderData: keepPreviousData, // Keep previous data during refetch to prevent flash
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
export function useUpdateRouter() {
|
|
251
|
-
const queryClient = useQueryClient();
|
|
252
|
-
|
|
253
|
-
return useMutation({
|
|
254
|
-
mutationFn: (data: UpdateRouterRequest) => api.updateRouter(data),
|
|
255
|
-
onSuccess: () => {
|
|
256
|
-
queryClient.invalidateQueries({ queryKey: ['router'] });
|
|
257
|
-
},
|
|
258
|
-
});
|
|
259
|
-
}
|
package/web/src/index.css
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
@import "tailwindcss";
|
|
2
|
-
|
|
3
|
-
:root {
|
|
4
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
5
|
-
line-height: 1.5;
|
|
6
|
-
font-weight: 400;
|
|
7
|
-
font-synthesis: none;
|
|
8
|
-
text-rendering: optimizeLegibility;
|
|
9
|
-
-webkit-font-smoothing: antialiased;
|
|
10
|
-
-moz-osx-font-smoothing: grayscale;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
body {
|
|
14
|
-
margin: 0;
|
|
15
|
-
min-width: 320px;
|
|
16
|
-
min-height: 100vh;
|
|
17
|
-
background-color: #fafafa;
|
|
18
|
-
color: #171717;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
#root {
|
|
22
|
-
min-height: 100vh;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/* Custom scrollbar for Ollama aesthetic */
|
|
26
|
-
::-webkit-scrollbar {
|
|
27
|
-
width: 8px;
|
|
28
|
-
height: 8px;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
::-webkit-scrollbar-track {
|
|
32
|
-
background: transparent;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
::-webkit-scrollbar-thumb {
|
|
36
|
-
background: #d4d4d4;
|
|
37
|
-
border-radius: 4px;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
::-webkit-scrollbar-thumb:hover {
|
|
41
|
-
background: #a3a3a3;
|
|
42
|
-
}
|
package/web/src/lib/api.ts
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Server,
|
|
3
|
-
Model,
|
|
4
|
-
SystemStatus,
|
|
5
|
-
CreateServerRequest,
|
|
6
|
-
UpdateServerRequest,
|
|
7
|
-
ApiError,
|
|
8
|
-
HFModelResult,
|
|
9
|
-
DownloadJob,
|
|
10
|
-
RouterInfo,
|
|
11
|
-
UpdateRouterRequest,
|
|
12
|
-
} from '../types/api';
|
|
13
|
-
|
|
14
|
-
const API_BASE = ''; // Proxy handles routing
|
|
15
|
-
|
|
16
|
-
class ApiClient {
|
|
17
|
-
private apiKey: string | null = null;
|
|
18
|
-
|
|
19
|
-
setApiKey(key: string) {
|
|
20
|
-
this.apiKey = key;
|
|
21
|
-
localStorage.setItem('llamacpp_api_key', key);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
getApiKey(): string | null {
|
|
25
|
-
if (!this.apiKey) {
|
|
26
|
-
this.apiKey = localStorage.getItem('llamacpp_api_key');
|
|
27
|
-
}
|
|
28
|
-
return this.apiKey;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
clearApiKey() {
|
|
32
|
-
this.apiKey = null;
|
|
33
|
-
localStorage.removeItem('llamacpp_api_key');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
private async request<T>(
|
|
37
|
-
endpoint: string,
|
|
38
|
-
options: RequestInit = {}
|
|
39
|
-
): Promise<T> {
|
|
40
|
-
const apiKey = this.getApiKey();
|
|
41
|
-
|
|
42
|
-
const headers: Record<string, string> = {
|
|
43
|
-
'Content-Type': 'application/json',
|
|
44
|
-
...(options.headers as Record<string, string>),
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
if (apiKey && endpoint !== '/health') {
|
|
48
|
-
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const response = await fetch(`${API_BASE}${endpoint}`, {
|
|
52
|
-
...options,
|
|
53
|
-
headers,
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
if (!response.ok) {
|
|
57
|
-
const error: ApiError = await response.json();
|
|
58
|
-
throw new Error(error.details || error.error);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return response.json();
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Health
|
|
65
|
-
async getHealth() {
|
|
66
|
-
return this.request<{ status: string; uptime: number; timestamp: string }>('/health');
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// System
|
|
70
|
-
async getSystemStatus() {
|
|
71
|
-
return this.request<SystemStatus>('/api/status');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Servers
|
|
75
|
-
async listServers() {
|
|
76
|
-
return this.request<{ servers: Server[] }>('/api/servers');
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async getServer(id: string) {
|
|
80
|
-
return this.request<{ server: Server }>(`/api/servers/${id}`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async createServer(data: CreateServerRequest) {
|
|
84
|
-
return this.request<{ server: Server }>('/api/servers', {
|
|
85
|
-
method: 'POST',
|
|
86
|
-
body: JSON.stringify(data),
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async updateServer(id: string, data: UpdateServerRequest) {
|
|
91
|
-
return this.request<{ server: Server }>(`/api/servers/${id}`, {
|
|
92
|
-
method: 'PATCH',
|
|
93
|
-
body: JSON.stringify(data),
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
async deleteServer(id: string) {
|
|
98
|
-
return this.request<{ success: boolean }>(`/api/servers/${id}`, {
|
|
99
|
-
method: 'DELETE',
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async startServer(id: string) {
|
|
104
|
-
return this.request<{ server: Server }>(`/api/servers/${id}/start`, {
|
|
105
|
-
method: 'POST',
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async stopServer(id: string) {
|
|
110
|
-
return this.request<{ server: Server }>(`/api/servers/${id}/stop`, {
|
|
111
|
-
method: 'POST',
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
async restartServer(id: string) {
|
|
116
|
-
return this.request<{ server: Server }>(`/api/servers/${id}/restart`, {
|
|
117
|
-
method: 'POST',
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
async getServerLogs(id: string, type: 'stdout' | 'stderr' | 'both' = 'both', lines = 100) {
|
|
122
|
-
return this.request<{ stdout: string; stderr: string }>(
|
|
123
|
-
`/api/servers/${id}/logs?type=${type}&lines=${lines}`
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Models
|
|
128
|
-
async listModels() {
|
|
129
|
-
return this.request<{ models: Model[] }>('/api/models');
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async getModel(name: string) {
|
|
133
|
-
return this.request<{ model: Model }>(`/api/models/${encodeURIComponent(name)}`);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async searchModels(query: string, limit = 20) {
|
|
137
|
-
return this.request<{ results: HFModelResult[] }>(
|
|
138
|
-
`/api/models/search?q=${encodeURIComponent(query)}&limit=${limit}`
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async getModelFiles(repoId: string) {
|
|
143
|
-
return this.request<{ repoId: string; files: string[] }>(
|
|
144
|
-
`/api/models/${encodeURIComponent(repoId)}/files`
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async downloadModel(repo: string, filename: string) {
|
|
149
|
-
return this.request<{ jobId: string; status: string }>(
|
|
150
|
-
'/api/models/download',
|
|
151
|
-
{
|
|
152
|
-
method: 'POST',
|
|
153
|
-
body: JSON.stringify({ repo, filename }),
|
|
154
|
-
}
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
async deleteModel(name: string, cascade = false) {
|
|
159
|
-
return this.request<{ success: boolean; deletedServers?: string[] }>(
|
|
160
|
-
`/api/models/${encodeURIComponent(name)}?cascade=${cascade}`,
|
|
161
|
-
{
|
|
162
|
-
method: 'DELETE',
|
|
163
|
-
}
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Download Jobs
|
|
168
|
-
async listDownloadJobs() {
|
|
169
|
-
return this.request<{ jobs: DownloadJob[] }>('/api/jobs');
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
async getDownloadJob(jobId: string) {
|
|
173
|
-
return this.request<{ job: DownloadJob }>(`/api/jobs/${jobId}`);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async cancelDownloadJob(jobId: string) {
|
|
177
|
-
return this.request<{ success: boolean; message: string }>(
|
|
178
|
-
`/api/jobs/${jobId}`,
|
|
179
|
-
{ method: 'DELETE' }
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Router
|
|
184
|
-
async getRouter() {
|
|
185
|
-
return this.request<RouterInfo>('/api/router');
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
async startRouter() {
|
|
189
|
-
return this.request<{ success: boolean; status: string; pid: number | null }>(
|
|
190
|
-
'/api/router/start',
|
|
191
|
-
{ method: 'POST' }
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
async stopRouter() {
|
|
196
|
-
return this.request<{ success: boolean; status: string }>(
|
|
197
|
-
'/api/router/stop',
|
|
198
|
-
{ method: 'POST' }
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
async restartRouter() {
|
|
203
|
-
return this.request<{ success: boolean; status: string; pid: number | null }>(
|
|
204
|
-
'/api/router/restart',
|
|
205
|
-
{ method: 'POST' }
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
async getRouterLogs(type: 'stdout' | 'stderr' | 'both' = 'both', lines = 100) {
|
|
210
|
-
return this.request<{ stdout: string; stderr: string }>(
|
|
211
|
-
`/api/router/logs?type=${type}&lines=${lines}`
|
|
212
|
-
);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
async updateRouter(data: UpdateRouterRequest) {
|
|
216
|
-
return this.request<{ success: boolean; needsRestart: boolean; config: any }>(
|
|
217
|
-
'/api/router',
|
|
218
|
-
{
|
|
219
|
-
method: 'PATCH',
|
|
220
|
-
body: JSON.stringify(data),
|
|
221
|
-
}
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
export const api = new ApiClient();
|
package/web/src/main.tsx
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { useSystemStatus, useServers } from '../hooks/useApi';
|
|
2
|
-
import { Server, Box, Activity, Clock } from 'lucide-react';
|
|
3
|
-
|
|
4
|
-
export function Dashboard() {
|
|
5
|
-
const { data: status } = useSystemStatus();
|
|
6
|
-
const { data: serversData } = useServers();
|
|
7
|
-
|
|
8
|
-
const runningServers = serversData?.servers.filter(s => s.status === 'running') || [];
|
|
9
|
-
|
|
10
|
-
return (
|
|
11
|
-
<div className="max-w-7xl mx-auto px-6 py-8">
|
|
12
|
-
<div className="mb-8">
|
|
13
|
-
<h1 className="text-3xl font-semibold text-gray-900 dark:text-white mb-2">
|
|
14
|
-
Dashboard
|
|
15
|
-
</h1>
|
|
16
|
-
<p className="text-gray-600 dark:text-gray-400">
|
|
17
|
-
Manage your local llama.cpp servers
|
|
18
|
-
</p>
|
|
19
|
-
</div>
|
|
20
|
-
|
|
21
|
-
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
|
|
22
|
-
<div className="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-lg p-6">
|
|
23
|
-
<div className="flex items-center justify-between mb-2">
|
|
24
|
-
<span className="text-sm text-gray-600 dark:text-gray-400">Total Servers</span>
|
|
25
|
-
<Server className="w-4 h-4 text-gray-400" />
|
|
26
|
-
</div>
|
|
27
|
-
<div className="text-3xl font-semibold text-gray-900 dark:text-white">
|
|
28
|
-
{status?.servers.total || 0}
|
|
29
|
-
</div>
|
|
30
|
-
</div>
|
|
31
|
-
|
|
32
|
-
<div className="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-lg p-6">
|
|
33
|
-
<div className="flex items-center justify-between mb-2">
|
|
34
|
-
<span className="text-sm text-gray-600 dark:text-gray-400">Running</span>
|
|
35
|
-
<Activity className="w-4 h-4 text-green-500" />
|
|
36
|
-
</div>
|
|
37
|
-
<div className="text-3xl font-semibold text-green-600 dark:text-green-500">
|
|
38
|
-
{status?.servers.running || 0}
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
|
|
42
|
-
<div className="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-lg p-6">
|
|
43
|
-
<div className="flex items-center justify-between mb-2">
|
|
44
|
-
<span className="text-sm text-gray-600 dark:text-gray-400">Stopped</span>
|
|
45
|
-
<Clock className="w-4 h-4 text-gray-400" />
|
|
46
|
-
</div>
|
|
47
|
-
<div className="text-3xl font-semibold text-gray-900 dark:text-white">
|
|
48
|
-
{status?.servers.stopped || 0}
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
<div className="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-lg p-6">
|
|
53
|
-
<div className="flex items-center justify-between mb-2">
|
|
54
|
-
<span className="text-sm text-gray-600 dark:text-gray-400">Models</span>
|
|
55
|
-
<Box className="w-4 h-4 text-gray-400" />
|
|
56
|
-
</div>
|
|
57
|
-
<div className="text-3xl font-semibold text-gray-900 dark:text-white">
|
|
58
|
-
{status?.models.total || 0}
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
|
|
63
|
-
<div className="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-lg">
|
|
64
|
-
<div className="p-6 border-b border-gray-200 dark:border-gray-800">
|
|
65
|
-
<h2 className="text-lg font-semibold text-gray-900 dark:text-white">
|
|
66
|
-
Running Servers
|
|
67
|
-
</h2>
|
|
68
|
-
</div>
|
|
69
|
-
<div className="divide-y divide-gray-200 dark:divide-gray-800">
|
|
70
|
-
{runningServers.length === 0 ? (
|
|
71
|
-
<div className="p-8 text-center">
|
|
72
|
-
<p className="text-gray-500 dark:text-gray-400">No servers running</p>
|
|
73
|
-
</div>
|
|
74
|
-
) : (
|
|
75
|
-
runningServers.map((server) => (
|
|
76
|
-
<div key={server.id} className="p-6 hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors">
|
|
77
|
-
<div className="flex items-center justify-between">
|
|
78
|
-
<div>
|
|
79
|
-
<h3 className="text-sm font-medium text-gray-900 dark:text-white mb-1">
|
|
80
|
-
{server.modelName}
|
|
81
|
-
</h3>
|
|
82
|
-
<div className="flex items-center space-x-4 text-sm text-gray-600 dark:text-gray-400">
|
|
83
|
-
<span>Port {server.port}</span>
|
|
84
|
-
<span>•</span>
|
|
85
|
-
<span>{server.threads} threads</span>
|
|
86
|
-
<span>•</span>
|
|
87
|
-
<span>Context {server.ctxSize}</span>
|
|
88
|
-
</div>
|
|
89
|
-
</div>
|
|
90
|
-
<div className="flex items-center space-x-2">
|
|
91
|
-
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400">
|
|
92
|
-
Running
|
|
93
|
-
</span>
|
|
94
|
-
</div>
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
))
|
|
98
|
-
)}
|
|
99
|
-
</div>
|
|
100
|
-
</div>
|
|
101
|
-
</div>
|
|
102
|
-
);
|
|
103
|
-
}
|