@effectnode/media 0.1.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/bin/effectnode-media +2 -0
- package/dist/backend/index.d.ts +8 -0
- package/dist/backend/index.js +13 -0
- package/dist/backend/movie-backend/agent/agent-backend.d.ts +16 -0
- package/dist/backend/movie-backend/agent/agent-backend.js +703 -0
- package/dist/backend/movie-backend/agent/storyprompt.d.ts +1 -0
- package/dist/backend/movie-backend/agent/storyprompt.js +90 -0
- package/dist/backend/movie-backend/agent/tools/edit-image.d.ts +3 -0
- package/dist/backend/movie-backend/agent/tools/edit-image.js +192 -0
- package/dist/backend/movie-backend/agent/tools/get-time.d.ts +3 -0
- package/dist/backend/movie-backend/agent/tools/get-time.js +7 -0
- package/dist/backend/movie-backend/agent/tools/grep-files.d.ts +3 -0
- package/dist/backend/movie-backend/agent/tools/grep-files.js +59 -0
- package/dist/backend/movie-backend/agent/tools/image-to-video-generation.d.ts +3 -0
- package/dist/backend/movie-backend/agent/tools/image-to-video-generation.js +160 -0
- package/dist/backend/movie-backend/agent/tools/index.d.ts +7 -0
- package/dist/backend/movie-backend/agent/tools/index.js +59 -0
- package/dist/backend/movie-backend/agent/tools/list-files.d.ts +3 -0
- package/dist/backend/movie-backend/agent/tools/list-files.js +17 -0
- package/dist/backend/movie-backend/agent/tools/read-file.d.ts +3 -0
- package/dist/backend/movie-backend/agent/tools/read-file.js +28 -0
- package/dist/backend/movie-backend/agent/tools/remove-file.d.ts +3 -0
- package/dist/backend/movie-backend/agent/tools/remove-file.js +22 -0
- package/dist/backend/movie-backend/agent/tools/rename-file.d.ts +3 -0
- package/dist/backend/movie-backend/agent/tools/rename-file.js +37 -0
- package/dist/backend/movie-backend/agent/tools/show-image.d.ts +3 -0
- package/dist/backend/movie-backend/agent/tools/show-image.js +28 -0
- package/dist/backend/movie-backend/agent/tools/stitch-videos.d.ts +3 -0
- package/dist/backend/movie-backend/agent/tools/stitch-videos.js +96 -0
- package/dist/backend/movie-backend/agent/tools/text-to-video-generation.d.ts +3 -0
- package/dist/backend/movie-backend/agent/tools/text-to-video-generation.js +125 -0
- package/dist/backend/movie-backend/agent/tools/types.d.ts +15 -0
- package/dist/backend/movie-backend/agent/tools/types.js +1 -0
- package/dist/backend/movie-backend/agent/tools/update-file.d.ts +3 -0
- package/dist/backend/movie-backend/agent/tools/update-file.js +27 -0
- package/dist/backend/movie-backend/agent/tools/write-file.d.ts +3 -0
- package/dist/backend/movie-backend/agent/tools/write-file.js +26 -0
- package/dist/backend/movie-backend/agent/workspace.d.ts +25 -0
- package/dist/backend/movie-backend/agent/workspace.js +124 -0
- package/dist/backend/movie-backend/core.d.ts +4 -0
- package/dist/backend/movie-backend/core.js +1167 -0
- package/dist/backend/movie-backend/generation-queue.d.ts +24 -0
- package/dist/backend/movie-backend/generation-queue.js +766 -0
- package/dist/backend/movie-backend/process.d.ts +21 -0
- package/dist/backend/movie-backend/process.js +98 -0
- package/dist/backend/movie-backend/render-media.d.ts +48 -0
- package/dist/backend/movie-backend/render-media.js +3311 -0
- package/dist/backend/routes/health.d.ts +1 -0
- package/dist/backend/routes/health.js +9 -0
- package/dist/backend/routes/index.d.ts +1 -0
- package/dist/backend/routes/index.js +11 -0
- package/dist/backend/routes/media.d.ts +1 -0
- package/dist/backend/routes/media.js +13 -0
- package/dist/backend/routes/projects.d.ts +8 -0
- package/dist/backend/routes/projects.js +68 -0
- package/dist/backend/routes/voice.d.ts +1 -0
- package/dist/backend/routes/voice.js +39 -0
- package/dist/backend/routes.d.ts +1 -0
- package/dist/backend/routes.js +20 -0
- package/dist/backend/server.d.ts +1 -0
- package/dist/backend/server.js +23 -0
- package/dist/backend/workspace.d.ts +5 -0
- package/dist/backend/workspace.js +27 -0
- package/dist/backend/ws/index.d.ts +3 -0
- package/dist/backend/ws/index.js +27 -0
- package/dist/backend/ws/messages.d.ts +8 -0
- package/dist/backend/ws/messages.js +21 -0
- package/dist/backend/ws.d.ts +3 -0
- package/dist/backend/ws.js +29 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +80 -0
- package/frontend/index.html +22 -0
- package/frontend/public/ffmpeg/ffmpeg-core.js +16 -0
- package/frontend/public/ffmpeg/ffmpeg-core.wasm +0 -0
- package/frontend/src/index.css +46 -0
- package/frontend/src/main.tsx +13 -0
- package/frontend/src/movie-app/AppRouter.tsx +14 -0
- package/frontend/src/movie-app/MediaStudio.tsx +9 -0
- package/frontend/src/movie-app/SetupPage.tsx +293 -0
- package/frontend/src/movie-app/components/AgentWorkspace.tsx +574 -0
- package/frontend/src/movie-app/components/ChatUI/ChatUI.tsx +655 -0
- package/frontend/src/movie-app/components/ChatUI/MarkdownMessage.tsx +267 -0
- package/frontend/src/movie-app/components/EditorTabs/AgentTab.tsx +61 -0
- package/frontend/src/movie-app/components/EditorTabs/BatchImageToVideoTab.tsx +927 -0
- package/frontend/src/movie-app/components/EditorTabs/BatchVideoTab.tsx +777 -0
- package/frontend/src/movie-app/components/EditorTabs/BatchVoiceVideoTab.tsx +913 -0
- package/frontend/src/movie-app/components/EditorTabs/CharacterSheet.tsx +234 -0
- package/frontend/src/movie-app/components/EditorTabs/CharactersTab.tsx +664 -0
- package/frontend/src/movie-app/components/EditorTabs/CropTool.tsx +251 -0
- package/frontend/src/movie-app/components/EditorTabs/ExtendVideoTab.tsx +305 -0
- package/frontend/src/movie-app/components/EditorTabs/ExtractImageTab.tsx +249 -0
- package/frontend/src/movie-app/components/EditorTabs/FastImageEditTab.tsx +555 -0
- package/frontend/src/movie-app/components/EditorTabs/GenerateVideoTab.tsx +722 -0
- package/frontend/src/movie-app/components/EditorTabs/LlmServerTab.tsx +40 -0
- package/frontend/src/movie-app/components/EditorTabs/MlxVlmServerPanel.tsx +490 -0
- package/frontend/src/movie-app/components/EditorTabs/MovieStudioTab.tsx +938 -0
- package/frontend/src/movie-app/components/EditorTabs/ReferencesToVideoTab.tsx +881 -0
- package/frontend/src/movie-app/components/EditorTabs/SceneVisualTab.tsx +267 -0
- package/frontend/src/movie-app/components/EditorTabs/StoryWriterTab.tsx +51 -0
- package/frontend/src/movie-app/components/EditorTabs/TaskQueuePanel.tsx +246 -0
- package/frontend/src/movie-app/components/EditorTabs/TerminalLogPanel.tsx +49 -0
- package/frontend/src/movie-app/components/EditorTabs/TextToImageTab.tsx +574 -0
- package/frontend/src/movie-app/components/EditorTabs/VoiceChatPanel.tsx +320 -0
- package/frontend/src/movie-app/components/ProjectEditorPage.tsx +636 -0
- package/frontend/src/movie-app/components/ProjectManager.tsx +381 -0
- package/frontend/src/movie-app/index.css +46 -0
- package/frontend/src/movie-app/index.html +16 -0
- package/frontend/src/movie-app/lambobo.png +0 -0
- package/frontend/src/movie-app/lib/batchImageToVideoStorage.ts +69 -0
- package/frontend/src/movie-app/lib/batchVideoStorage.ts +68 -0
- package/frontend/src/movie-app/lib/batchVoiceStorage.ts +75 -0
- package/frontend/src/movie-app/lib/ffmpeg.ts +42 -0
- package/frontend/src/movie-app/lib/referencesToVideoStorage.ts +64 -0
- package/frontend/src/movie-app/lib/textToImageStorage.ts +61 -0
- package/frontend/src/movie-app/public/ffmpeg/ffmpeg-core.js +16 -0
- package/frontend/src/movie-app/public/ffmpeg/ffmpeg-core.wasm +0 -0
- package/frontend/src/movie-app/stores/batchImageToVideoStore.ts +736 -0
- package/frontend/src/movie-app/stores/batchVideoStore.ts +670 -0
- package/frontend/src/movie-app/stores/batchVoiceStore.ts +990 -0
- package/frontend/src/movie-app/stores/characterStore.ts +109 -0
- package/frontend/src/movie-app/stores/chatStore.ts +459 -0
- package/frontend/src/movie-app/stores/generationStore.ts +2140 -0
- package/frontend/src/movie-app/stores/logStore.ts +25 -0
- package/frontend/src/movie-app/stores/movieStudioStore.ts +709 -0
- package/frontend/src/movie-app/stores/projectStore.ts +124 -0
- package/frontend/src/movie-app/stores/queueStore.ts +214 -0
- package/frontend/src/movie-app/stores/referencesToVideoStore.ts +467 -0
- package/frontend/src/movie-app/stores/sceneVisualStore.ts +251 -0
- package/frontend/src/movie-app/stores/voiceChatStore.ts +170 -0
- package/frontend/src/movie-app/stores/workspaceStore.ts +158 -0
- package/frontend/src/vite-env.d.ts +1 -0
- package/frontend/tsconfig.json +19 -0
- package/package.json +65 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import MlxVlmServerPanel from "./MlxVlmServerPanel";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dedicated LLM Server tab. Reuses the shared mlx-vlm server panel so it
|
|
5
|
+
* controls the same single backend server process as the Agent and
|
|
6
|
+
* References-to-Video pages.
|
|
7
|
+
*/
|
|
8
|
+
export default function LlmServerTab() {
|
|
9
|
+
const ServerIcon = (
|
|
10
|
+
<svg
|
|
11
|
+
width="18"
|
|
12
|
+
height="18"
|
|
13
|
+
viewBox="0 0 24 24"
|
|
14
|
+
fill="none"
|
|
15
|
+
stroke="currentColor"
|
|
16
|
+
strokeWidth="2"
|
|
17
|
+
strokeLinecap="round"
|
|
18
|
+
strokeLinejoin="round"
|
|
19
|
+
className="text-tiffany-600"
|
|
20
|
+
>
|
|
21
|
+
<rect x="2" y="2" width="20" height="8" rx="2" ry="2" />
|
|
22
|
+
<rect x="2" y="14" width="20" height="8" rx="2" ry="2" />
|
|
23
|
+
<line x1="6" y1="6" x2="6.01" y2="6" />
|
|
24
|
+
<line x1="6" y1="18" x2="6.01" y2="18" />
|
|
25
|
+
</svg>
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div className="flex flex-col gap-7">
|
|
30
|
+
<div className="flex items-center gap-2">
|
|
31
|
+
{ServerIcon}
|
|
32
|
+
<h2 className="text-base font-semibold text-ink-900">
|
|
33
|
+
LLM Server
|
|
34
|
+
</h2>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<MlxVlmServerPanel />
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import { useGenerationStore } from "../../stores/generationStore";
|
|
3
|
+
|
|
4
|
+
const MODEL_PRESETS = [
|
|
5
|
+
"mlx-community/gemma-4-e2b-it-8bit",
|
|
6
|
+
"mlx-community/gemma-4-e4b-it-8bit",
|
|
7
|
+
"mlx-community/gemma-4-26b-a4b-it-8bit",
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
const InstallIcon = (
|
|
11
|
+
<svg
|
|
12
|
+
width="16"
|
|
13
|
+
height="16"
|
|
14
|
+
viewBox="0 0 24 24"
|
|
15
|
+
fill="none"
|
|
16
|
+
stroke="currentColor"
|
|
17
|
+
strokeWidth="2"
|
|
18
|
+
strokeLinecap="round"
|
|
19
|
+
strokeLinejoin="round"
|
|
20
|
+
>
|
|
21
|
+
<polyline points="16 18 22 12 16 6" />
|
|
22
|
+
<polyline points="8 6 2 12 8 18" />
|
|
23
|
+
</svg>
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const PlayIcon = (
|
|
27
|
+
<svg
|
|
28
|
+
width="16"
|
|
29
|
+
height="16"
|
|
30
|
+
viewBox="0 0 24 24"
|
|
31
|
+
fill="none"
|
|
32
|
+
stroke="currentColor"
|
|
33
|
+
strokeWidth="2"
|
|
34
|
+
strokeLinecap="round"
|
|
35
|
+
strokeLinejoin="round"
|
|
36
|
+
>
|
|
37
|
+
<polygon points="6 3 20 12 6 21 6 3" />
|
|
38
|
+
</svg>
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const StopIcon = (
|
|
42
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
|
43
|
+
<rect x="5" y="5" width="14" height="14" rx="2" />
|
|
44
|
+
</svg>
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const SpinnerIcon = (
|
|
48
|
+
<svg
|
|
49
|
+
className="animate-spin text-tiffany-600"
|
|
50
|
+
width="16"
|
|
51
|
+
height="16"
|
|
52
|
+
viewBox="0 0 24 24"
|
|
53
|
+
fill="none"
|
|
54
|
+
stroke="currentColor"
|
|
55
|
+
strokeWidth="2"
|
|
56
|
+
>
|
|
57
|
+
<circle cx="12" cy="12" r="10" strokeOpacity="0.25" />
|
|
58
|
+
<path d="M12 2a10 10 0 0 1 10 10" strokeOpacity="0.75" />
|
|
59
|
+
</svg>
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const CheckCircleIcon = (
|
|
63
|
+
<svg
|
|
64
|
+
width="14"
|
|
65
|
+
height="14"
|
|
66
|
+
viewBox="0 0 24 24"
|
|
67
|
+
fill="none"
|
|
68
|
+
stroke="currentColor"
|
|
69
|
+
strokeWidth="2"
|
|
70
|
+
strokeLinecap="round"
|
|
71
|
+
strokeLinejoin="round"
|
|
72
|
+
>
|
|
73
|
+
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
|
|
74
|
+
<polyline points="22 4 12 14.01 9 11.01" />
|
|
75
|
+
</svg>
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const AlertCircleIcon = (
|
|
79
|
+
<svg
|
|
80
|
+
width="14"
|
|
81
|
+
height="14"
|
|
82
|
+
viewBox="0 0 24 24"
|
|
83
|
+
fill="none"
|
|
84
|
+
stroke="currentColor"
|
|
85
|
+
strokeWidth="2"
|
|
86
|
+
strokeLinecap="round"
|
|
87
|
+
strokeLinejoin="round"
|
|
88
|
+
>
|
|
89
|
+
<circle cx="12" cy="12" r="10" />
|
|
90
|
+
<line x1="12" y1="8" x2="12" y2="12" />
|
|
91
|
+
<line x1="12" y1="16" x2="12.01" y2="16" />
|
|
92
|
+
</svg>
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const ExternalLinkIcon = (
|
|
96
|
+
<svg
|
|
97
|
+
width="14"
|
|
98
|
+
height="14"
|
|
99
|
+
viewBox="0 0 24 24"
|
|
100
|
+
fill="none"
|
|
101
|
+
stroke="currentColor"
|
|
102
|
+
strokeWidth="2"
|
|
103
|
+
strokeLinecap="round"
|
|
104
|
+
strokeLinejoin="round"
|
|
105
|
+
>
|
|
106
|
+
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
|
|
107
|
+
<polyline points="15 3 21 3 21 9" />
|
|
108
|
+
<line x1="10" y1="14" x2="21" y2="3" />
|
|
109
|
+
</svg>
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
export function OnlyStartButton() {
|
|
113
|
+
const store = useGenerationStore();
|
|
114
|
+
// const serverUrl = `http://localhost:${store.agent.port}`;
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<>
|
|
118
|
+
<div className="flex flex-wrap items-end gap-3">
|
|
119
|
+
{/* <div>
|
|
120
|
+
<label className="block text-xs font-medium text-ink-700 mb-1.5">
|
|
121
|
+
Port
|
|
122
|
+
</label>
|
|
123
|
+
<input
|
|
124
|
+
type="number"
|
|
125
|
+
min={1}
|
|
126
|
+
max={65535}
|
|
127
|
+
value={store.agent.port}
|
|
128
|
+
onChange={(e) => store.setAgentPort(Number(e.target.value))}
|
|
129
|
+
disabled={store.agent.serverRunning || store.agent.starting}
|
|
130
|
+
className="w-32 px-3 py-2 bg-ink-50 border border-ink-200 rounded-xl text-ink-900 text-sm focus:outline-none focus:border-tiffany-500 focus:ring-2 focus:ring-tiffany-500/30 transition-all disabled:opacity-50"
|
|
131
|
+
/>
|
|
132
|
+
</div> */}
|
|
133
|
+
|
|
134
|
+
{store.agent.serverRunning || store.agent.starting ? (
|
|
135
|
+
<button
|
|
136
|
+
onClick={() => store.stopAgentServer()}
|
|
137
|
+
className="flex items-center gap-2 px-4 py-2 text-xs font-medium rounded-xl border transition-all bg-red-50 border-red-200 text-red-600 hover:border-red-300"
|
|
138
|
+
>
|
|
139
|
+
{StopIcon}
|
|
140
|
+
Stop Server
|
|
141
|
+
</button>
|
|
142
|
+
) : (
|
|
143
|
+
<button
|
|
144
|
+
onClick={() => store.startAgentServer()}
|
|
145
|
+
disabled={store.agent.installing || store.agent.installed === false}
|
|
146
|
+
className="flex items-center gap-2 px-4 py-2 text-xs font-medium rounded-xl border transition-all bg-white border-ink-200 text-ink-600 hover:border-ink-300 disabled:opacity-50"
|
|
147
|
+
>
|
|
148
|
+
{PlayIcon}
|
|
149
|
+
Start Server
|
|
150
|
+
</button>
|
|
151
|
+
)}
|
|
152
|
+
</div>
|
|
153
|
+
</>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Shared mlx-vlm LLM server management panel (Setup + Server sections).
|
|
159
|
+
* Both the Agent page and the References-to-Video page reuse this so they
|
|
160
|
+
* control the same single backend server process.
|
|
161
|
+
*/
|
|
162
|
+
export default function MlxVlmServerPanel() {
|
|
163
|
+
const store = useGenerationStore();
|
|
164
|
+
const serverLogsRef = useRef<HTMLDivElement>(null);
|
|
165
|
+
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
store.checkAgentStatus();
|
|
168
|
+
store.checkServerOnline();
|
|
169
|
+
const interval = setInterval(() => {
|
|
170
|
+
store.checkServerOnline();
|
|
171
|
+
}, 3000);
|
|
172
|
+
return () => clearInterval(interval);
|
|
173
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
174
|
+
}, []);
|
|
175
|
+
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
if (serverLogsRef.current) {
|
|
178
|
+
serverLogsRef.current.scrollTop = serverLogsRef.current.scrollHeight;
|
|
179
|
+
}
|
|
180
|
+
}, [store.agent.serverLogs]);
|
|
181
|
+
|
|
182
|
+
const serverUrl = `http://localhost:${store.agent.port}`;
|
|
183
|
+
const modelOptions = MODEL_PRESETS.includes(store.agent.model)
|
|
184
|
+
? MODEL_PRESETS
|
|
185
|
+
: [store.agent.model, ...MODEL_PRESETS];
|
|
186
|
+
|
|
187
|
+
// ========== SVG Icons ==========
|
|
188
|
+
|
|
189
|
+
const InstallIcon = (
|
|
190
|
+
<svg
|
|
191
|
+
width="16"
|
|
192
|
+
height="16"
|
|
193
|
+
viewBox="0 0 24 24"
|
|
194
|
+
fill="none"
|
|
195
|
+
stroke="currentColor"
|
|
196
|
+
strokeWidth="2"
|
|
197
|
+
strokeLinecap="round"
|
|
198
|
+
strokeLinejoin="round"
|
|
199
|
+
>
|
|
200
|
+
<polyline points="16 18 22 12 16 6" />
|
|
201
|
+
<polyline points="8 6 2 12 8 18" />
|
|
202
|
+
</svg>
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const PlayIcon = (
|
|
206
|
+
<svg
|
|
207
|
+
width="16"
|
|
208
|
+
height="16"
|
|
209
|
+
viewBox="0 0 24 24"
|
|
210
|
+
fill="none"
|
|
211
|
+
stroke="currentColor"
|
|
212
|
+
strokeWidth="2"
|
|
213
|
+
strokeLinecap="round"
|
|
214
|
+
strokeLinejoin="round"
|
|
215
|
+
>
|
|
216
|
+
<polygon points="6 3 20 12 6 21 6 3" />
|
|
217
|
+
</svg>
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
const StopIcon = (
|
|
221
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
|
222
|
+
<rect x="5" y="5" width="14" height="14" rx="2" />
|
|
223
|
+
</svg>
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
const SpinnerIcon = (
|
|
227
|
+
<svg
|
|
228
|
+
className="animate-spin text-tiffany-600"
|
|
229
|
+
width="16"
|
|
230
|
+
height="16"
|
|
231
|
+
viewBox="0 0 24 24"
|
|
232
|
+
fill="none"
|
|
233
|
+
stroke="currentColor"
|
|
234
|
+
strokeWidth="2"
|
|
235
|
+
>
|
|
236
|
+
<circle cx="12" cy="12" r="10" strokeOpacity="0.25" />
|
|
237
|
+
<path d="M12 2a10 10 0 0 1 10 10" strokeOpacity="0.75" />
|
|
238
|
+
</svg>
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
const CheckCircleIcon = (
|
|
242
|
+
<svg
|
|
243
|
+
width="14"
|
|
244
|
+
height="14"
|
|
245
|
+
viewBox="0 0 24 24"
|
|
246
|
+
fill="none"
|
|
247
|
+
stroke="currentColor"
|
|
248
|
+
strokeWidth="2"
|
|
249
|
+
strokeLinecap="round"
|
|
250
|
+
strokeLinejoin="round"
|
|
251
|
+
>
|
|
252
|
+
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
|
|
253
|
+
<polyline points="22 4 12 14.01 9 11.01" />
|
|
254
|
+
</svg>
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
const AlertCircleIcon = (
|
|
258
|
+
<svg
|
|
259
|
+
width="14"
|
|
260
|
+
height="14"
|
|
261
|
+
viewBox="0 0 24 24"
|
|
262
|
+
fill="none"
|
|
263
|
+
stroke="currentColor"
|
|
264
|
+
strokeWidth="2"
|
|
265
|
+
strokeLinecap="round"
|
|
266
|
+
strokeLinejoin="round"
|
|
267
|
+
>
|
|
268
|
+
<circle cx="12" cy="12" r="10" />
|
|
269
|
+
<line x1="12" y1="8" x2="12" y2="12" />
|
|
270
|
+
<line x1="12" y1="16" x2="12.01" y2="16" />
|
|
271
|
+
</svg>
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
const ExternalLinkIcon = (
|
|
275
|
+
<svg
|
|
276
|
+
width="14"
|
|
277
|
+
height="14"
|
|
278
|
+
viewBox="0 0 24 24"
|
|
279
|
+
fill="none"
|
|
280
|
+
stroke="currentColor"
|
|
281
|
+
strokeWidth="2"
|
|
282
|
+
strokeLinecap="round"
|
|
283
|
+
strokeLinejoin="round"
|
|
284
|
+
>
|
|
285
|
+
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
|
|
286
|
+
<polyline points="15 3 21 3 21 9" />
|
|
287
|
+
<line x1="10" y1="14" x2="21" y2="3" />
|
|
288
|
+
</svg>
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
const renderStatus = (
|
|
292
|
+
value: boolean | null,
|
|
293
|
+
okText: string,
|
|
294
|
+
missingText: string,
|
|
295
|
+
) => {
|
|
296
|
+
if (value === null) {
|
|
297
|
+
return (
|
|
298
|
+
<span className="inline-flex items-center gap-1.5 text-ink-500">
|
|
299
|
+
{SpinnerIcon}
|
|
300
|
+
Checking...
|
|
301
|
+
</span>
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
if (value) {
|
|
305
|
+
return (
|
|
306
|
+
<span className="inline-flex items-center gap-1.5 text-emerald-600">
|
|
307
|
+
{CheckCircleIcon}
|
|
308
|
+
{okText}
|
|
309
|
+
</span>
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
return (
|
|
313
|
+
<span className="inline-flex items-center gap-1.5 text-amber-600">
|
|
314
|
+
{AlertCircleIcon}
|
|
315
|
+
{missingText}
|
|
316
|
+
</span>
|
|
317
|
+
);
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
return (
|
|
321
|
+
<>
|
|
322
|
+
{/* ===== Install mlx-vlm ===== */}
|
|
323
|
+
<div>
|
|
324
|
+
<label className="block text-xs font-semibold text-ink-700 uppercase tracking-wider mb-2">
|
|
325
|
+
Setup
|
|
326
|
+
</label>
|
|
327
|
+
<div className="flex flex-wrap gap-2">
|
|
328
|
+
<button
|
|
329
|
+
onClick={() => store.installMlxVlm()}
|
|
330
|
+
disabled={store.agent.installing}
|
|
331
|
+
className="flex items-center gap-2 px-4 py-2 text-xs font-medium rounded-xl border transition-all bg-white border-ink-200 text-ink-600 hover:border-ink-300 disabled:opacity-50"
|
|
332
|
+
>
|
|
333
|
+
{store.agent.installing ? SpinnerIcon : InstallIcon}
|
|
334
|
+
Install mlx-vlm
|
|
335
|
+
</button>
|
|
336
|
+
</div>
|
|
337
|
+
|
|
338
|
+
<div className="flex flex-wrap items-center gap-x-4 gap-y-1.5 mt-2 text-xs font-medium">
|
|
339
|
+
{renderStatus(
|
|
340
|
+
store.agent.installed,
|
|
341
|
+
"mlx-vlm installed",
|
|
342
|
+
"mlx-vlm not installed",
|
|
343
|
+
)}
|
|
344
|
+
</div>
|
|
345
|
+
|
|
346
|
+
{store.agent.installingLogs.length > 0 && (
|
|
347
|
+
<div className="mt-2 p-4 bg-ink-50 border border-ink-200 rounded-2xl max-h-32 overflow-y-auto">
|
|
348
|
+
<pre className="text-xs text-ink-600 font-mono whitespace-pre-wrap">
|
|
349
|
+
{store.agent.installingLogs.join("")}
|
|
350
|
+
</pre>
|
|
351
|
+
</div>
|
|
352
|
+
)}
|
|
353
|
+
{store.agent.installingError && (
|
|
354
|
+
<div className="mt-2 p-4 bg-red-50 border border-red-200 rounded-2xl text-red-600 text-xs">
|
|
355
|
+
{store.agent.installingError}
|
|
356
|
+
</div>
|
|
357
|
+
)}
|
|
358
|
+
</div>
|
|
359
|
+
|
|
360
|
+
{/* ===== Server ===== */}
|
|
361
|
+
<div>
|
|
362
|
+
<label className="block text-xs font-semibold text-ink-700 uppercase tracking-wider mb-2">
|
|
363
|
+
Server
|
|
364
|
+
</label>
|
|
365
|
+
|
|
366
|
+
<div className="flex flex-wrap items-end gap-3 mb-3">
|
|
367
|
+
<div className="flex-1 min-w-[260px]">
|
|
368
|
+
<label className="block text-xs font-medium text-ink-700 mb-1.5">
|
|
369
|
+
Model
|
|
370
|
+
</label>
|
|
371
|
+
<div className=" gap-2 mb-2">
|
|
372
|
+
<select
|
|
373
|
+
value={store.agent.model}
|
|
374
|
+
onChange={(e) => store.setAgentModel(e.target.value)}
|
|
375
|
+
disabled={store.agent.serverRunning || store.agent.starting}
|
|
376
|
+
title="Choose a model"
|
|
377
|
+
className="shrink-0 w-[350px] px-2 py-2 bg-ink-50 border border-ink-200 rounded-xl text-ink-900 text-sm focus:outline-none focus:border-tiffany-500 focus:ring-2 focus:ring-tiffany-500/30 transition-all disabled:opacity-50 cursor-pointer"
|
|
378
|
+
>
|
|
379
|
+
{modelOptions.map((m) => (
|
|
380
|
+
<option key={m} value={m}>
|
|
381
|
+
{m}
|
|
382
|
+
</option>
|
|
383
|
+
))}
|
|
384
|
+
</select>
|
|
385
|
+
</div>
|
|
386
|
+
<div className=" gap-2">
|
|
387
|
+
<input
|
|
388
|
+
value={store.agent.model}
|
|
389
|
+
onChange={(e) => store.setAgentModel(e.target.value)}
|
|
390
|
+
disabled={store.agent.serverRunning || store.agent.starting}
|
|
391
|
+
title="enter a model name"
|
|
392
|
+
className="shrink-0 w-[350px] px-2 py-2 bg-ink-50 border border-ink-200 rounded-xl text-ink-900 text-sm focus:outline-none focus:border-tiffany-500 focus:ring-2 focus:ring-tiffany-500/30 transition-all disabled:opacity-50 cursor-pointer"
|
|
393
|
+
></input>
|
|
394
|
+
</div>
|
|
395
|
+
</div>
|
|
396
|
+
</div>
|
|
397
|
+
|
|
398
|
+
<div className="flex flex-wrap items-end gap-3">
|
|
399
|
+
<div>
|
|
400
|
+
<label className="block text-xs font-medium text-ink-700 mb-1.5">
|
|
401
|
+
Port
|
|
402
|
+
</label>
|
|
403
|
+
<input
|
|
404
|
+
type="number"
|
|
405
|
+
min={1}
|
|
406
|
+
max={65535}
|
|
407
|
+
value={store.agent.port}
|
|
408
|
+
onChange={(e) => store.setAgentPort(Number(e.target.value))}
|
|
409
|
+
disabled={store.agent.serverRunning || store.agent.starting}
|
|
410
|
+
className="w-32 px-3 py-2 bg-ink-50 border border-ink-200 rounded-xl text-ink-900 text-sm focus:outline-none focus:border-tiffany-500 focus:ring-2 focus:ring-tiffany-500/30 transition-all disabled:opacity-50"
|
|
411
|
+
/>
|
|
412
|
+
</div>
|
|
413
|
+
|
|
414
|
+
{store.agent.serverRunning || store.agent.starting ? (
|
|
415
|
+
<button
|
|
416
|
+
onClick={() => store.stopAgentServer()}
|
|
417
|
+
className="flex items-center gap-2 px-4 py-2 text-xs font-medium rounded-xl border transition-all bg-red-50 border-red-200 text-red-600 hover:border-red-300"
|
|
418
|
+
>
|
|
419
|
+
{StopIcon}
|
|
420
|
+
Stop Server
|
|
421
|
+
</button>
|
|
422
|
+
) : (
|
|
423
|
+
<button
|
|
424
|
+
onClick={() => store.startAgentServer()}
|
|
425
|
+
disabled={
|
|
426
|
+
store.agent.installing || store.agent.installed === false
|
|
427
|
+
}
|
|
428
|
+
className="flex items-center gap-2 px-4 py-2 text-xs font-medium rounded-xl border transition-all bg-white border-ink-200 text-ink-600 hover:border-ink-300 disabled:opacity-50"
|
|
429
|
+
>
|
|
430
|
+
{PlayIcon}
|
|
431
|
+
Start Server
|
|
432
|
+
</button>
|
|
433
|
+
)}
|
|
434
|
+
</div>
|
|
435
|
+
|
|
436
|
+
<div className="flex flex-wrap items-center gap-x-4 gap-y-1.5 mt-2 text-xs font-medium">
|
|
437
|
+
{store.agent.starting ? (
|
|
438
|
+
<span className="inline-flex items-center gap-1.5 text-ink-500">
|
|
439
|
+
{SpinnerIcon}
|
|
440
|
+
Starting server...
|
|
441
|
+
</span>
|
|
442
|
+
) : store.agent.serverOnline === true ? (
|
|
443
|
+
<span className="inline-flex items-center gap-1.5 text-emerald-600">
|
|
444
|
+
{CheckCircleIcon}
|
|
445
|
+
Server online at {serverUrl}
|
|
446
|
+
</span>
|
|
447
|
+
) : store.agent.serverOnline === false ? (
|
|
448
|
+
<span className="inline-flex items-center gap-1.5 text-amber-600">
|
|
449
|
+
{AlertCircleIcon}
|
|
450
|
+
Server offline
|
|
451
|
+
</span>
|
|
452
|
+
) : (
|
|
453
|
+
<span className="inline-flex items-center gap-1.5 text-ink-500">
|
|
454
|
+
{SpinnerIcon}
|
|
455
|
+
Checking server...
|
|
456
|
+
</span>
|
|
457
|
+
)}
|
|
458
|
+
{store.agent.serverOnline === true && (
|
|
459
|
+
<button
|
|
460
|
+
onClick={() => store.openAgentServer()}
|
|
461
|
+
className="inline-flex items-center gap-1.5 text-ink-600 hover:text-ink-900 transition-colors cursor-pointer"
|
|
462
|
+
>
|
|
463
|
+
{ExternalLinkIcon}
|
|
464
|
+
Open {serverUrl}
|
|
465
|
+
</button>
|
|
466
|
+
)}
|
|
467
|
+
</div>
|
|
468
|
+
|
|
469
|
+
{store.agent.serverLogs.length > 0 && (
|
|
470
|
+
<div
|
|
471
|
+
ref={serverLogsRef}
|
|
472
|
+
className="mt-2 p-4 bg-ink-50 border border-ink-200 rounded-2xl max-h-48 overflow-y-auto"
|
|
473
|
+
>
|
|
474
|
+
<p className="text-xs font-semibold text-ink-700 uppercase tracking-wider mb-2">
|
|
475
|
+
Server Logs
|
|
476
|
+
</p>
|
|
477
|
+
<pre className="text-xs text-ink-600 font-mono whitespace-pre-wrap">
|
|
478
|
+
{store.agent.serverLogs.join("")}
|
|
479
|
+
</pre>
|
|
480
|
+
</div>
|
|
481
|
+
)}
|
|
482
|
+
{store.agent.serverError && (
|
|
483
|
+
<div className="mt-2 p-4 bg-red-50 border border-red-200 rounded-2xl text-red-600 text-xs">
|
|
484
|
+
{store.agent.serverError}
|
|
485
|
+
</div>
|
|
486
|
+
)}
|
|
487
|
+
</div>
|
|
488
|
+
</>
|
|
489
|
+
);
|
|
490
|
+
}
|