@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
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect, useRef } from 'react';
|
|
2
|
-
import { useNavigate } from 'react-router-dom';
|
|
3
|
-
import { useQueryClient } from '@tanstack/react-query';
|
|
4
|
-
import { useServers, useStartServer, useStopServer } from '../hooks/useApi';
|
|
5
|
-
import { Play, Square, Cpu, Database, Loader2, Settings, Plus, FileText } from 'lucide-react';
|
|
6
|
-
import { ServerConfigModal } from '../components/ServerConfigModal';
|
|
7
|
-
import { CreateServerModal } from '../components/CreateServerModal';
|
|
8
|
-
import type { Server } from '../types/api';
|
|
9
|
-
|
|
10
|
-
type ServerFilter = 'all' | 'running' | 'stopped';
|
|
11
|
-
|
|
12
|
-
export function Servers() {
|
|
13
|
-
const navigate = useNavigate();
|
|
14
|
-
const queryClient = useQueryClient();
|
|
15
|
-
const { data: serversData, isLoading } = useServers();
|
|
16
|
-
const startServer = useStartServer();
|
|
17
|
-
const stopServer = useStopServer();
|
|
18
|
-
|
|
19
|
-
const [actionLoading, setActionLoading] = useState<{ id: string; action: 'start' | 'stop' } | null>(null);
|
|
20
|
-
const [configServer, setConfigServer] = useState<Server | null>(null);
|
|
21
|
-
const [showCreateModal, setShowCreateModal] = useState(false);
|
|
22
|
-
const [filter, setFilter] = useState<ServerFilter>('all');
|
|
23
|
-
|
|
24
|
-
const pendingAction = useRef<{ id: string; expectedStatus: 'running' | 'stopped' } | null>(null);
|
|
25
|
-
|
|
26
|
-
const servers = serversData?.servers || [];
|
|
27
|
-
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
if (pendingAction.current && actionLoading) {
|
|
30
|
-
const { id, expectedStatus } = pendingAction.current;
|
|
31
|
-
const server = servers.find(s => s.id === id);
|
|
32
|
-
if (server && server.status === expectedStatus) {
|
|
33
|
-
pendingAction.current = null;
|
|
34
|
-
setActionLoading(null);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}, [servers, actionLoading]);
|
|
38
|
-
|
|
39
|
-
const handleStart = async (id: string) => {
|
|
40
|
-
setActionLoading({ id, action: 'start' });
|
|
41
|
-
pendingAction.current = { id, expectedStatus: 'running' };
|
|
42
|
-
try {
|
|
43
|
-
await startServer.mutateAsync(id);
|
|
44
|
-
await queryClient.refetchQueries({ queryKey: ['servers'] });
|
|
45
|
-
} catch {
|
|
46
|
-
pendingAction.current = null;
|
|
47
|
-
setActionLoading(null);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const handleStop = async (id: string) => {
|
|
52
|
-
setActionLoading({ id, action: 'stop' });
|
|
53
|
-
pendingAction.current = { id, expectedStatus: 'stopped' };
|
|
54
|
-
try {
|
|
55
|
-
await stopServer.mutateAsync(id);
|
|
56
|
-
await queryClient.refetchQueries({ queryKey: ['servers'] });
|
|
57
|
-
} catch {
|
|
58
|
-
pendingAction.current = null;
|
|
59
|
-
setActionLoading(null);
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const renderStatusBadge = (server: Server) => {
|
|
64
|
-
const serverId = server.id;
|
|
65
|
-
|
|
66
|
-
if (actionLoading?.id === serverId) {
|
|
67
|
-
if (actionLoading.action === 'stop') {
|
|
68
|
-
return (
|
|
69
|
-
<span className="inline-flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-medium bg-neutral-100 text-neutral-700">
|
|
70
|
-
<Loader2 className="w-3 h-3 animate-spin" />
|
|
71
|
-
Stopping
|
|
72
|
-
</span>
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
if (actionLoading.action === 'start') {
|
|
76
|
-
return (
|
|
77
|
-
<span className="inline-flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-medium bg-neutral-100 text-neutral-700">
|
|
78
|
-
<Loader2 className="w-3 h-3 animate-spin" />
|
|
79
|
-
Starting
|
|
80
|
-
</span>
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (server.status === 'running') {
|
|
86
|
-
return (
|
|
87
|
-
<span className="inline-flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-medium bg-green-50 text-green-700 border border-green-200/50">
|
|
88
|
-
<span className="w-1.5 h-1.5 rounded-full bg-green-500"></span>
|
|
89
|
-
Running
|
|
90
|
-
</span>
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (server.status === 'crashed') {
|
|
95
|
-
return (
|
|
96
|
-
<span className="inline-flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-medium bg-red-50 text-red-700 border border-red-200/50">
|
|
97
|
-
<span className="w-1.5 h-1.5 rounded-full bg-red-500"></span>
|
|
98
|
-
Crashed
|
|
99
|
-
</span>
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return (
|
|
104
|
-
<span className="inline-flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-medium bg-neutral-100 text-neutral-600">
|
|
105
|
-
<span className="w-1.5 h-1.5 rounded-full bg-neutral-400"></span>
|
|
106
|
-
Stopped
|
|
107
|
-
</span>
|
|
108
|
-
);
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
const formatContextSize = (size: number) => {
|
|
112
|
-
if (size >= 1024) return `${(size / 1024).toFixed(0)}K`;
|
|
113
|
-
return size.toString();
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
if (isLoading) {
|
|
117
|
-
return (
|
|
118
|
-
<div className="max-w-7xl mx-auto px-6 py-12">
|
|
119
|
-
<p className="text-neutral-500 text-center">Loading...</p>
|
|
120
|
-
</div>
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const runningServers = servers.filter(s => s.status === 'running');
|
|
125
|
-
|
|
126
|
-
// Apply filter
|
|
127
|
-
const filteredServers = servers.filter(server => {
|
|
128
|
-
if (filter === 'all') return true;
|
|
129
|
-
if (filter === 'running') return server.status === 'running';
|
|
130
|
-
if (filter === 'stopped') return server.status !== 'running';
|
|
131
|
-
return true;
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
const displayRunning = filteredServers.filter(s => s.status === 'running');
|
|
135
|
-
const displayStopped = filteredServers.filter(s => s.status !== 'running');
|
|
136
|
-
|
|
137
|
-
return (
|
|
138
|
-
<div className="max-w-7xl mx-auto px-6 py-8">
|
|
139
|
-
{/* Header */}
|
|
140
|
-
<div className="flex items-center justify-between mb-6">
|
|
141
|
-
<div>
|
|
142
|
-
<h1 className="text-2xl font-semibold text-neutral-900 tracking-tight">Servers</h1>
|
|
143
|
-
<p className="text-sm text-neutral-600 mt-1">
|
|
144
|
-
{servers.length} server{servers.length !== 1 ? 's' : ''}
|
|
145
|
-
{runningServers.length > 0 && ` • ${runningServers.length} running`}
|
|
146
|
-
</p>
|
|
147
|
-
</div>
|
|
148
|
-
<button
|
|
149
|
-
onClick={() => setShowCreateModal(true)}
|
|
150
|
-
className="inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-white bg-neutral-900 hover:bg-neutral-800 rounded-md transition-colors cursor-pointer"
|
|
151
|
-
>
|
|
152
|
-
<Plus className="w-4 h-4" />
|
|
153
|
-
Create Server
|
|
154
|
-
</button>
|
|
155
|
-
</div>
|
|
156
|
-
|
|
157
|
-
{/* Filter Buttons */}
|
|
158
|
-
<div className="flex items-center gap-2 mb-6">
|
|
159
|
-
<button
|
|
160
|
-
onClick={() => setFilter('all')}
|
|
161
|
-
className={`px-3 py-1.5 text-sm font-medium rounded-full border transition-all cursor-pointer ${
|
|
162
|
-
filter === 'all'
|
|
163
|
-
? 'bg-neutral-900 text-white border-neutral-900'
|
|
164
|
-
: 'bg-white text-neutral-600 border-neutral-200 hover:border-neutral-300'
|
|
165
|
-
}`}
|
|
166
|
-
>
|
|
167
|
-
All
|
|
168
|
-
</button>
|
|
169
|
-
<button
|
|
170
|
-
onClick={() => setFilter('running')}
|
|
171
|
-
className={`px-3 py-1.5 text-sm font-medium rounded-full border transition-all cursor-pointer ${
|
|
172
|
-
filter === 'running'
|
|
173
|
-
? 'bg-neutral-900 text-white border-neutral-900'
|
|
174
|
-
: 'bg-white text-neutral-600 border-neutral-200 hover:border-neutral-300'
|
|
175
|
-
}`}
|
|
176
|
-
>
|
|
177
|
-
Running
|
|
178
|
-
</button>
|
|
179
|
-
<button
|
|
180
|
-
onClick={() => setFilter('stopped')}
|
|
181
|
-
className={`px-3 py-1.5 text-sm font-medium rounded-full border transition-all cursor-pointer ${
|
|
182
|
-
filter === 'stopped'
|
|
183
|
-
? 'bg-neutral-900 text-white border-neutral-900'
|
|
184
|
-
: 'bg-white text-neutral-600 border-neutral-200 hover:border-neutral-300'
|
|
185
|
-
}`}
|
|
186
|
-
>
|
|
187
|
-
Stopped
|
|
188
|
-
</button>
|
|
189
|
-
</div>
|
|
190
|
-
|
|
191
|
-
{/* Grid Layout */}
|
|
192
|
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
193
|
-
{/* Running Servers */}
|
|
194
|
-
{displayRunning.map((server) => (
|
|
195
|
-
<div
|
|
196
|
-
key={server.id}
|
|
197
|
-
className="group bg-white border border-neutral-200 rounded-lg p-5 hover:border-neutral-300 hover:shadow-sm transition-all"
|
|
198
|
-
>
|
|
199
|
-
<div className="flex items-start justify-between mb-4">
|
|
200
|
-
<div className="flex-1 min-w-0">
|
|
201
|
-
<h3 className="text-base font-semibold text-neutral-900 truncate mb-1">
|
|
202
|
-
{server.modelName.replace('.gguf', '')}
|
|
203
|
-
</h3>
|
|
204
|
-
<p className="text-sm text-neutral-500">
|
|
205
|
-
localhost:{server.port}
|
|
206
|
-
</p>
|
|
207
|
-
</div>
|
|
208
|
-
{renderStatusBadge(server)}
|
|
209
|
-
</div>
|
|
210
|
-
|
|
211
|
-
<div className="space-y-2 mb-4">
|
|
212
|
-
<div className="flex items-center gap-2 text-xs text-neutral-600">
|
|
213
|
-
<Cpu className="w-3.5 h-3.5 text-neutral-400" />
|
|
214
|
-
<span>{server.threads} threads</span>
|
|
215
|
-
</div>
|
|
216
|
-
<div className="flex items-center gap-2 text-xs text-neutral-600">
|
|
217
|
-
<Database className="w-3.5 h-3.5 text-neutral-400" />
|
|
218
|
-
<span>{formatContextSize(server.ctxSize)} context • {server.gpuLayers} GPU layers</span>
|
|
219
|
-
</div>
|
|
220
|
-
</div>
|
|
221
|
-
|
|
222
|
-
{/* Actions */}
|
|
223
|
-
<div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
|
|
224
|
-
<button
|
|
225
|
-
onClick={() => navigate(`/servers/${server.id}/logs`)}
|
|
226
|
-
disabled={actionLoading?.id === server.id}
|
|
227
|
-
className="flex-1 flex items-center justify-center gap-1.5 px-3 py-1.5 text-xs font-medium text-neutral-600 hover:text-neutral-900 hover:bg-neutral-50 rounded-md transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-wait"
|
|
228
|
-
title="Logs"
|
|
229
|
-
>
|
|
230
|
-
<FileText className="w-3.5 h-3.5" />
|
|
231
|
-
Logs
|
|
232
|
-
</button>
|
|
233
|
-
<button
|
|
234
|
-
onClick={() => setConfigServer(server)}
|
|
235
|
-
disabled={actionLoading?.id === server.id}
|
|
236
|
-
className="flex-1 flex items-center justify-center gap-1.5 px-3 py-1.5 text-xs font-medium text-neutral-600 hover:text-neutral-900 hover:bg-neutral-50 rounded-md transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-wait"
|
|
237
|
-
title="Config"
|
|
238
|
-
>
|
|
239
|
-
<Settings className="w-3.5 h-3.5" />
|
|
240
|
-
Config
|
|
241
|
-
</button>
|
|
242
|
-
<button
|
|
243
|
-
onClick={() => handleStop(server.id)}
|
|
244
|
-
disabled={actionLoading?.id === server.id}
|
|
245
|
-
className="flex-1 flex items-center justify-center gap-1.5 px-3 py-1.5 text-xs font-medium text-neutral-600 hover:text-red-600 hover:bg-red-50 rounded-md transition-colors disabled:opacity-50 cursor-pointer disabled:cursor-wait"
|
|
246
|
-
title="Stop"
|
|
247
|
-
>
|
|
248
|
-
<Square className="w-3.5 h-3.5" />
|
|
249
|
-
Stop
|
|
250
|
-
</button>
|
|
251
|
-
</div>
|
|
252
|
-
</div>
|
|
253
|
-
))}
|
|
254
|
-
|
|
255
|
-
{/* Stopped Servers */}
|
|
256
|
-
{displayStopped.map((server) => (
|
|
257
|
-
<div
|
|
258
|
-
key={server.id}
|
|
259
|
-
className="group bg-white border border-neutral-200 rounded-lg p-5 hover:border-neutral-300 hover:shadow-sm transition-all opacity-60 hover:opacity-100"
|
|
260
|
-
>
|
|
261
|
-
<div className="flex items-start justify-between mb-4">
|
|
262
|
-
<div className="flex-1 min-w-0">
|
|
263
|
-
<h3 className="text-base font-semibold text-neutral-900 truncate mb-1">
|
|
264
|
-
{server.modelName.replace('.gguf', '')}
|
|
265
|
-
</h3>
|
|
266
|
-
<p className="text-sm text-neutral-500">
|
|
267
|
-
localhost:{server.port}
|
|
268
|
-
</p>
|
|
269
|
-
</div>
|
|
270
|
-
{renderStatusBadge(server)}
|
|
271
|
-
</div>
|
|
272
|
-
|
|
273
|
-
<div className="space-y-2 mb-4">
|
|
274
|
-
<div className="flex items-center gap-2 text-xs text-neutral-600">
|
|
275
|
-
<Cpu className="w-3.5 h-3.5 text-neutral-400" />
|
|
276
|
-
<span>{server.threads} threads</span>
|
|
277
|
-
</div>
|
|
278
|
-
<div className="flex items-center gap-2 text-xs text-neutral-600">
|
|
279
|
-
<Database className="w-3.5 h-3.5 text-neutral-400" />
|
|
280
|
-
<span>{formatContextSize(server.ctxSize)} context</span>
|
|
281
|
-
</div>
|
|
282
|
-
</div>
|
|
283
|
-
|
|
284
|
-
{/* Actions */}
|
|
285
|
-
<div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
|
|
286
|
-
<button
|
|
287
|
-
onClick={() => navigate(`/servers/${server.id}/logs`)}
|
|
288
|
-
disabled={actionLoading?.id === server.id}
|
|
289
|
-
className="flex-1 flex items-center justify-center gap-1.5 px-3 py-1.5 text-xs font-medium text-neutral-600 hover:text-neutral-900 hover:bg-neutral-50 rounded-md transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-wait"
|
|
290
|
-
title="Logs"
|
|
291
|
-
>
|
|
292
|
-
<FileText className="w-3.5 h-3.5" />
|
|
293
|
-
Logs
|
|
294
|
-
</button>
|
|
295
|
-
<button
|
|
296
|
-
onClick={() => setConfigServer(server)}
|
|
297
|
-
disabled={actionLoading?.id === server.id}
|
|
298
|
-
className="flex-1 flex items-center justify-center gap-1.5 px-3 py-1.5 text-xs font-medium text-neutral-600 hover:text-neutral-900 hover:bg-neutral-50 rounded-md transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-wait"
|
|
299
|
-
title="Config"
|
|
300
|
-
>
|
|
301
|
-
<Settings className="w-3.5 h-3.5" />
|
|
302
|
-
Config
|
|
303
|
-
</button>
|
|
304
|
-
<button
|
|
305
|
-
onClick={() => handleStart(server.id)}
|
|
306
|
-
disabled={actionLoading?.id === server.id}
|
|
307
|
-
className="flex-1 flex items-center justify-center gap-1.5 px-3 py-1.5 text-xs font-medium text-neutral-600 hover:text-green-600 hover:bg-green-50 rounded-md transition-colors disabled:opacity-50 cursor-pointer disabled:cursor-wait"
|
|
308
|
-
title="Start"
|
|
309
|
-
>
|
|
310
|
-
<Play className="w-3.5 h-3.5" />
|
|
311
|
-
Start
|
|
312
|
-
</button>
|
|
313
|
-
</div>
|
|
314
|
-
</div>
|
|
315
|
-
))}
|
|
316
|
-
</div>
|
|
317
|
-
|
|
318
|
-
{/* Empty State */}
|
|
319
|
-
{filteredServers.length === 0 && servers.length > 0 && (
|
|
320
|
-
<div className="text-center py-16 bg-white border border-neutral-200 rounded-lg">
|
|
321
|
-
<p className="text-neutral-600 text-base mb-2">No {filter} servers</p>
|
|
322
|
-
<p className="text-sm text-neutral-500">
|
|
323
|
-
Try a different filter or create a new server
|
|
324
|
-
</p>
|
|
325
|
-
</div>
|
|
326
|
-
)}
|
|
327
|
-
|
|
328
|
-
{servers.length === 0 && (
|
|
329
|
-
<div className="text-center py-16 bg-white border border-neutral-200 rounded-lg">
|
|
330
|
-
<p className="text-neutral-600 text-base mb-2">No servers configured</p>
|
|
331
|
-
<p className="text-sm text-neutral-500 mb-6">
|
|
332
|
-
Create your first server to get started
|
|
333
|
-
</p>
|
|
334
|
-
<button
|
|
335
|
-
onClick={() => setShowCreateModal(true)}
|
|
336
|
-
className="inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-white bg-neutral-900 hover:bg-neutral-800 rounded-md transition-colors cursor-pointer"
|
|
337
|
-
>
|
|
338
|
-
<Plus className="w-4 h-4" />
|
|
339
|
-
Create Server
|
|
340
|
-
</button>
|
|
341
|
-
</div>
|
|
342
|
-
)}
|
|
343
|
-
|
|
344
|
-
{/* Config Modal */}
|
|
345
|
-
<ServerConfigModal
|
|
346
|
-
server={configServer}
|
|
347
|
-
isOpen={configServer !== null}
|
|
348
|
-
onClose={() => setConfigServer(null)}
|
|
349
|
-
/>
|
|
350
|
-
|
|
351
|
-
{/* Create Modal */}
|
|
352
|
-
<CreateServerModal
|
|
353
|
-
isOpen={showCreateModal}
|
|
354
|
-
onClose={() => setShowCreateModal(false)}
|
|
355
|
-
/>
|
|
356
|
-
</div>
|
|
357
|
-
);
|
|
358
|
-
}
|
package/web/src/types/api.ts
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
export type ServerStatus = 'running' | 'stopped' | 'crashed';
|
|
2
|
-
|
|
3
|
-
export interface Server {
|
|
4
|
-
id: string;
|
|
5
|
-
modelPath: string;
|
|
6
|
-
modelName: string;
|
|
7
|
-
port: number;
|
|
8
|
-
host: string;
|
|
9
|
-
threads: number;
|
|
10
|
-
ctxSize: number;
|
|
11
|
-
gpuLayers: number;
|
|
12
|
-
embeddings: boolean;
|
|
13
|
-
jinja: boolean;
|
|
14
|
-
verbose: boolean;
|
|
15
|
-
customFlags?: string[];
|
|
16
|
-
status: ServerStatus;
|
|
17
|
-
pid?: number;
|
|
18
|
-
createdAt: string;
|
|
19
|
-
lastStarted?: string;
|
|
20
|
-
lastStopped?: string;
|
|
21
|
-
plistPath: string;
|
|
22
|
-
label: string;
|
|
23
|
-
stdoutPath: string;
|
|
24
|
-
stderrPath: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface Model {
|
|
28
|
-
filename: string;
|
|
29
|
-
path: string;
|
|
30
|
-
size: number;
|
|
31
|
-
sizeFormatted: string;
|
|
32
|
-
modified: Date;
|
|
33
|
-
exists: boolean;
|
|
34
|
-
serversUsing: number;
|
|
35
|
-
serverIds: string[];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface SystemStatus {
|
|
39
|
-
servers: {
|
|
40
|
-
total: number;
|
|
41
|
-
running: number;
|
|
42
|
-
stopped: number;
|
|
43
|
-
crashed: number;
|
|
44
|
-
};
|
|
45
|
-
models: {
|
|
46
|
-
total: number;
|
|
47
|
-
totalSize: number;
|
|
48
|
-
};
|
|
49
|
-
system: {
|
|
50
|
-
uptime: number;
|
|
51
|
-
timestamp: string;
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface CreateServerRequest {
|
|
56
|
-
model: string;
|
|
57
|
-
port?: number;
|
|
58
|
-
host?: string;
|
|
59
|
-
threads?: number;
|
|
60
|
-
ctxSize?: number;
|
|
61
|
-
gpuLayers?: number;
|
|
62
|
-
verbose?: boolean;
|
|
63
|
-
customFlags?: string[];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface UpdateServerRequest {
|
|
67
|
-
model?: string;
|
|
68
|
-
port?: number;
|
|
69
|
-
host?: string;
|
|
70
|
-
threads?: number;
|
|
71
|
-
ctxSize?: number;
|
|
72
|
-
gpuLayers?: number;
|
|
73
|
-
verbose?: boolean;
|
|
74
|
-
customFlags?: string[];
|
|
75
|
-
restart?: boolean;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export interface ApiError {
|
|
79
|
-
error: string;
|
|
80
|
-
details?: string;
|
|
81
|
-
code?: string;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// HuggingFace model search types
|
|
85
|
-
export interface HFModelResult {
|
|
86
|
-
modelId: string;
|
|
87
|
-
author: string;
|
|
88
|
-
modelName: string;
|
|
89
|
-
downloads: number;
|
|
90
|
-
likes: number;
|
|
91
|
-
tags: string[];
|
|
92
|
-
lastModified: string;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Download job types
|
|
96
|
-
export type DownloadJobStatus = 'pending' | 'downloading' | 'completed' | 'failed' | 'cancelled';
|
|
97
|
-
|
|
98
|
-
export interface DownloadJob {
|
|
99
|
-
id: string;
|
|
100
|
-
repo: string;
|
|
101
|
-
filename: string;
|
|
102
|
-
status: DownloadJobStatus;
|
|
103
|
-
progress: {
|
|
104
|
-
downloaded: number;
|
|
105
|
-
total: number;
|
|
106
|
-
percentage: number;
|
|
107
|
-
speed: string;
|
|
108
|
-
} | null;
|
|
109
|
-
error?: string;
|
|
110
|
-
createdAt: string;
|
|
111
|
-
completedAt?: string;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Router types
|
|
115
|
-
export type RouterStatus = 'not_configured' | 'running' | 'stopped';
|
|
116
|
-
|
|
117
|
-
export interface RouterInfo {
|
|
118
|
-
status: RouterStatus;
|
|
119
|
-
config: {
|
|
120
|
-
port: number;
|
|
121
|
-
host: string;
|
|
122
|
-
verbose: boolean;
|
|
123
|
-
requestTimeout: number;
|
|
124
|
-
healthCheckInterval: number;
|
|
125
|
-
} | null;
|
|
126
|
-
pid: number | null;
|
|
127
|
-
isRunning: boolean;
|
|
128
|
-
availableModels: string[];
|
|
129
|
-
createdAt?: string;
|
|
130
|
-
lastStarted?: string;
|
|
131
|
-
lastStopped?: string;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export interface UpdateRouterRequest {
|
|
135
|
-
port?: number;
|
|
136
|
-
host?: string;
|
|
137
|
-
verbose?: boolean;
|
|
138
|
-
requestTimeout?: number;
|
|
139
|
-
healthCheckInterval?: number;
|
|
140
|
-
}
|
package/web/tailwind.config.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/** @type {import('tailwindcss').Config} */
|
|
2
|
-
export default {
|
|
3
|
-
content: [
|
|
4
|
-
"./index.html",
|
|
5
|
-
"./src/**/*.{js,ts,jsx,tsx}",
|
|
6
|
-
],
|
|
7
|
-
theme: {
|
|
8
|
-
extend: {
|
|
9
|
-
colors: {
|
|
10
|
-
neutral: {
|
|
11
|
-
50: '#fafafa',
|
|
12
|
-
100: '#f5f5f5',
|
|
13
|
-
150: '#ededed',
|
|
14
|
-
200: '#e5e5e5',
|
|
15
|
-
300: '#d4d4d4',
|
|
16
|
-
400: '#a3a3a3',
|
|
17
|
-
500: '#737373',
|
|
18
|
-
600: '#525252',
|
|
19
|
-
700: '#404040',
|
|
20
|
-
800: '#262626',
|
|
21
|
-
900: '#171717',
|
|
22
|
-
950: '#0a0a0a',
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
fontFamily: {
|
|
26
|
-
sans: ['-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'sans-serif'],
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
plugins: [],
|
|
31
|
-
}
|
package/web/tsconfig.app.json
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
-
"target": "ES2022",
|
|
5
|
-
"useDefineForClassFields": true,
|
|
6
|
-
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
-
"module": "ESNext",
|
|
8
|
-
"types": ["vite/client"],
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
|
|
11
|
-
/* Bundler mode */
|
|
12
|
-
"moduleResolution": "bundler",
|
|
13
|
-
"allowImportingTsExtensions": true,
|
|
14
|
-
"verbatimModuleSyntax": true,
|
|
15
|
-
"moduleDetection": "force",
|
|
16
|
-
"noEmit": true,
|
|
17
|
-
"jsx": "react-jsx",
|
|
18
|
-
|
|
19
|
-
/* Linting */
|
|
20
|
-
"strict": true,
|
|
21
|
-
"noUnusedLocals": true,
|
|
22
|
-
"noUnusedParameters": true,
|
|
23
|
-
"erasableSyntaxOnly": true,
|
|
24
|
-
"noFallthroughCasesInSwitch": true,
|
|
25
|
-
"noUncheckedSideEffectImports": true
|
|
26
|
-
},
|
|
27
|
-
"include": ["src"]
|
|
28
|
-
}
|
package/web/tsconfig.json
DELETED
package/web/tsconfig.node.json
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
-
"target": "ES2023",
|
|
5
|
-
"lib": ["ES2023"],
|
|
6
|
-
"module": "ESNext",
|
|
7
|
-
"types": ["node"],
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
|
|
10
|
-
/* Bundler mode */
|
|
11
|
-
"moduleResolution": "bundler",
|
|
12
|
-
"allowImportingTsExtensions": true,
|
|
13
|
-
"verbatimModuleSyntax": true,
|
|
14
|
-
"moduleDetection": "force",
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
|
|
17
|
-
/* Linting */
|
|
18
|
-
"strict": true,
|
|
19
|
-
"noUnusedLocals": true,
|
|
20
|
-
"noUnusedParameters": true,
|
|
21
|
-
"erasableSyntaxOnly": true,
|
|
22
|
-
"noFallthroughCasesInSwitch": true,
|
|
23
|
-
"noUncheckedSideEffectImports": true
|
|
24
|
-
},
|
|
25
|
-
"include": ["vite.config.ts"]
|
|
26
|
-
}
|
package/web/vite.config.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vite'
|
|
2
|
-
import react from '@vitejs/plugin-react'
|
|
3
|
-
import path from 'path'
|
|
4
|
-
|
|
5
|
-
// https://vite.dev/config/
|
|
6
|
-
export default defineConfig({
|
|
7
|
-
plugins: [react()],
|
|
8
|
-
resolve: {
|
|
9
|
-
alias: {
|
|
10
|
-
'@': path.resolve(__dirname, './src'),
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
server: {
|
|
14
|
-
proxy: {
|
|
15
|
-
'/api': {
|
|
16
|
-
target: 'http://localhost:9200',
|
|
17
|
-
changeOrigin: true,
|
|
18
|
-
},
|
|
19
|
-
'/health': {
|
|
20
|
-
target: 'http://localhost:9200',
|
|
21
|
-
changeOrigin: true,
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
})
|
|
File without changes
|