blanchon commited on
Commit
3ecee8e
·
1 Parent(s): 5c5615d
TODO.md ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # TODO:
2
+
3
+ - [ ] Remove default video in add sensor and add something else
4
+ - [ ] Review the flow of add model
5
+ - [ ] Enable the others model types
6
+ - [ ]
src/lib/components/3d/elements/compute/modal/AIModelConfigurationModal.svelte ADDED
@@ -0,0 +1,297 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import * as Dialog from "@/components/ui/dialog";
3
+ import { Button } from "@/components/ui/button";
4
+ import * as Card from "@/components/ui/card";
5
+ import { Badge } from "@/components/ui/badge";
6
+ import { Input } from "@/components/ui/input";
7
+ import { Label } from "@/components/ui/label";
8
+ import { Textarea } from "@/components/ui/textarea";
9
+ import * as Select from "@/components/ui/select";
10
+ import {
11
+ remoteComputeManager,
12
+ MODEL_TYPES,
13
+ type ModelType,
14
+ type AISessionConfig
15
+ } from "$lib/elements/compute";
16
+ import { settings } from "$lib/runes/settings.svelte";
17
+ import { toast } from "svelte-sonner";
18
+ import { generateName } from "$lib/utils/generateName";
19
+
20
+ interface Props {
21
+ workspaceId: string;
22
+ open: boolean;
23
+ initialModelType?: ModelType;
24
+ }
25
+
26
+ let { open = $bindable(), workspaceId, initialModelType = "act" }: Props = $props();
27
+
28
+ let isCreating = $state(false);
29
+ let selectedModelType = $state<ModelType>(initialModelType);
30
+
31
+ // Update selectedModelType when initialModelType changes
32
+ $effect(() => {
33
+ selectedModelType = initialModelType;
34
+ });
35
+ let sessionId = $state("");
36
+ let policyPath = $state("");
37
+ let cameraNames = $state("");
38
+ let languageInstruction = $state("");
39
+ let computeName = $state("");
40
+
41
+ // Get model config based on selected type
42
+ const modelConfig = $derived(MODEL_TYPES[selectedModelType]);
43
+
44
+ // Set defaults when modal opens with a specific model type
45
+ $effect(() => {
46
+ if (open && selectedModelType) {
47
+ const config = MODEL_TYPES[selectedModelType];
48
+ sessionId = `${selectedModelType}-session-${Date.now()}`;
49
+ policyPath = config.defaultPolicyPath;
50
+ cameraNames = config.defaultCameraNames.join(", ");
51
+ computeName = `${config.label} ${generateName()}`;
52
+ languageInstruction = ""; // Reset language instruction
53
+ }
54
+ });
55
+
56
+ async function handleCreateModel() {
57
+ if (!sessionId.trim() || !policyPath.trim() || !computeName.trim()) {
58
+ toast.error("Please fill in all required fields");
59
+ return;
60
+ }
61
+
62
+ const config = MODEL_TYPES[selectedModelType];
63
+ if (config.requiresLanguageInstruction && !languageInstruction.trim()) {
64
+ toast.error("Language instruction is required for this model type");
65
+ return;
66
+ }
67
+
68
+ isCreating = true;
69
+ try {
70
+ const cameras = cameraNames
71
+ .split(",")
72
+ .map((name) => name.trim())
73
+ .filter((name) => name);
74
+ if (cameras.length === 0) {
75
+ cameras.push("front");
76
+ }
77
+
78
+ const sessionConfig: AISessionConfig = {
79
+ sessionId: sessionId.trim(),
80
+ modelType: selectedModelType,
81
+ policyPath: policyPath.trim(),
82
+ cameraNames: cameras,
83
+ transportServerUrl: settings.transportServerUrl,
84
+ workspaceId: workspaceId,
85
+ languageInstruction: languageInstruction.trim() || undefined
86
+ };
87
+
88
+ const result = await remoteComputeManager.createComputeWithSession(
89
+ sessionConfig,
90
+ undefined, // auto-generate compute ID
91
+ computeName.trim()
92
+ );
93
+
94
+ if (result.success) {
95
+ toast.success(`${config.label} model created successfully!`, {
96
+ description: `Session ${sessionId} is ready for inference`
97
+ });
98
+ open = false;
99
+ // Reset form
100
+ resetForm();
101
+ } else {
102
+ toast.error(`Failed to create ${config.label}`, {
103
+ description: result.error
104
+ });
105
+ }
106
+ } catch (error) {
107
+ console.error("Model creation error:", error);
108
+ toast.error("Failed to create AI model");
109
+ } finally {
110
+ isCreating = false;
111
+ }
112
+ }
113
+
114
+ function resetForm() {
115
+ sessionId = "";
116
+ policyPath = "";
117
+ cameraNames = "";
118
+ languageInstruction = "";
119
+ computeName = "";
120
+ }
121
+
122
+ // Reset form when modal closes
123
+ $effect(() => {
124
+ if (!open) {
125
+ resetForm();
126
+ }
127
+ });
128
+ </script>
129
+
130
+ <Dialog.Root bind:open>
131
+ <Dialog.Content
132
+ class="max-h-[80vh] max-w-3xl overflow-y-auto border-slate-300 bg-slate-100 text-slate-900 dark:border-slate-600 dark:bg-slate-900 dark:text-slate-100"
133
+ >
134
+ <Dialog.Header class="pb-3">
135
+ <Dialog.Title
136
+ class="flex items-center gap-2 text-lg font-bold text-slate-900 dark:text-slate-100"
137
+ >
138
+ <span class="{modelConfig.icon} size-5 text-purple-500 dark:text-purple-400"></span>
139
+ Create AI Model - {modelConfig.label}
140
+ </Dialog.Title>
141
+ <Dialog.Description class="text-sm text-slate-600 dark:text-slate-400">
142
+ Configure and deploy an AI model for robot control and inference
143
+ </Dialog.Description>
144
+ </Dialog.Header>
145
+
146
+ <div class="space-y-6">
147
+ <!-- Model Type Display (Read-only) -->
148
+ <div
149
+ class="rounded-lg border border-purple-300/30 bg-purple-100/20 p-3 dark:border-purple-500/30 dark:bg-purple-900/20"
150
+ >
151
+ <div class="flex items-center gap-3">
152
+ <span class="{modelConfig.icon} size-6 text-purple-500 dark:text-purple-400"></span>
153
+ <div>
154
+ <h3 class="font-medium text-purple-700 dark:text-purple-200">
155
+ {modelConfig.label}
156
+ </h3>
157
+ <p class="text-sm text-purple-600 dark:text-purple-300">
158
+ {modelConfig.description}
159
+ </p>
160
+ </div>
161
+ </div>
162
+ </div>
163
+
164
+ <!-- Basic Configuration -->
165
+ <Card.Root
166
+ class="border-green-300/30 bg-green-100/5 dark:border-green-500/30 dark:bg-green-500/5"
167
+ >
168
+ <Card.Header>
169
+ <Card.Title class="flex items-center gap-2 text-base text-green-700 dark:text-green-200">
170
+ <span class="icon-[mdi--cog] size-4"></span>
171
+ Basic Configuration
172
+ </Card.Title>
173
+ </Card.Header>
174
+ <Card.Content>
175
+ <div class="space-y-4">
176
+ <div class="grid grid-cols-2 gap-4">
177
+ <div class="space-y-2">
178
+ <Label for="computeName" class="text-green-700 dark:text-green-300">
179
+ Compute Name
180
+ </Label>
181
+ <Input
182
+ id="computeName"
183
+ bind:value={computeName}
184
+ placeholder="My AI Model"
185
+ class="border-slate-300 bg-slate-50 text-slate-900 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-100"
186
+ />
187
+ </div>
188
+ <div class="space-y-2">
189
+ <Label for="sessionId" class="text-green-700 dark:text-green-300">Session ID</Label>
190
+ <Input
191
+ id="sessionId"
192
+ bind:value={sessionId}
193
+ placeholder="my-session-01"
194
+ class="border-slate-300 bg-slate-50 text-slate-900 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-100"
195
+ />
196
+ </div>
197
+ </div>
198
+
199
+ <div class="space-y-2">
200
+ <Label for="policyPath" class="text-green-700 dark:text-green-300">Policy Path</Label>
201
+ <Input
202
+ id="policyPath"
203
+ bind:value={policyPath}
204
+ placeholder={modelConfig.defaultPolicyPath}
205
+ class="border-slate-300 bg-slate-50 text-slate-900 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-100"
206
+ />
207
+ <p class="text-xs text-slate-600 dark:text-slate-400">
208
+ HuggingFace model path or local model identifier
209
+ </p>
210
+ </div>
211
+
212
+ <div class="space-y-2">
213
+ <Label for="cameraNames" class="text-green-700 dark:text-green-300">
214
+ Camera Names
215
+ </Label>
216
+ <Input
217
+ id="cameraNames"
218
+ bind:value={cameraNames}
219
+ placeholder="front, wrist, overhead"
220
+ class="border-slate-300 bg-slate-50 text-slate-900 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-100"
221
+ />
222
+ <p class="text-xs text-slate-600 dark:text-slate-400">Comma-separated camera names</p>
223
+ </div>
224
+
225
+ {#if modelConfig.requiresLanguageInstruction}
226
+ <div class="space-y-2">
227
+ <Label for="languageInstruction" class="text-green-700 dark:text-green-300">
228
+ Language Instruction
229
+ </Label>
230
+ <Textarea
231
+ id="languageInstruction"
232
+ bind:value={languageInstruction}
233
+ placeholder="Pick up the red cup and place it on the table"
234
+ class="border-slate-300 bg-slate-50 text-slate-900 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-100"
235
+ rows={3}
236
+ />
237
+ <p class="text-xs text-slate-600 dark:text-slate-400">
238
+ Natural language instruction for the task (required for {modelConfig.label})
239
+ </p>
240
+ </div>
241
+ {/if}
242
+ </div>
243
+ </Card.Content>
244
+ </Card.Root>
245
+
246
+ <!-- Workspace Info -->
247
+ <div
248
+ class="rounded-lg border border-blue-300/30 bg-blue-100/20 p-3 dark:border-blue-500/30 dark:bg-blue-900/20"
249
+ >
250
+ <div class="flex items-center gap-2">
251
+ <span class="icon-[mdi--folder] size-4 text-blue-600 dark:text-blue-400"></span>
252
+ <span class="text-sm font-medium text-blue-700 dark:text-blue-300">
253
+ Workspace: {workspaceId}
254
+ </span>
255
+ </div>
256
+ <p class="mt-1 text-xs text-blue-600 dark:text-blue-400">
257
+ The model will be deployed in the current workspace with dedicated communication rooms
258
+ </p>
259
+ </div>
260
+
261
+ <!-- Action Buttons -->
262
+ <div class="flex gap-3">
263
+ <Button
264
+ variant="outline"
265
+ onclick={() => (open = false)}
266
+ class="flex-1"
267
+ disabled={isCreating}
268
+ >
269
+ Cancel
270
+ </Button>
271
+ <Button
272
+ variant="default"
273
+ onclick={handleCreateModel}
274
+ disabled={isCreating || !sessionId.trim() || !policyPath.trim() || !computeName.trim()}
275
+ class="flex-1 bg-purple-500 hover:bg-purple-600 disabled:opacity-50 dark:bg-purple-600 dark:hover:bg-purple-700"
276
+ >
277
+ {#if isCreating}
278
+ <span class="icon-[mdi--loading] mr-2 size-4 animate-spin"></span>
279
+ Creating {modelConfig.label}...
280
+ {:else}
281
+ <span class="icon-[mdi--rocket-launch] mr-2 size-4"></span>
282
+ Create {modelConfig.label}
283
+ {/if}
284
+ </Button>
285
+ </div>
286
+
287
+ <!-- Quick Info -->
288
+ <div
289
+ class="rounded border border-slate-300 bg-slate-100/30 p-2 text-xs text-slate-600 dark:border-slate-700 dark:bg-slate-800/30 dark:text-slate-500"
290
+ >
291
+ <span class="icon-[mdi--information] mr-1 size-3"></span>
292
+ This will create a complete AI model setup with inference session, communication rooms, and a
293
+ 3D representation ready for connections.
294
+ </div>
295
+ </div>
296
+ </Dialog.Content>
297
+ </Dialog.Root>