3
3
import "@tensorflow/tfjs-backend-webgl"
4
4
import * as tf from "@tensorflow/tfjs"
5
5
import { ObjectDetection , load } from "@tensorflow-models/coco-ssd"
6
- import { Card , CardHeader , CardTitle , CardContent } from "@/components/ui/card"
7
- import { Button } from "@/components/ui/button"
8
- import { Input } from "@/components/ui/input"
9
- import {
10
- DropdownMenu ,
11
- DropdownMenuTrigger ,
12
- DropdownMenuContent ,
13
- DropdownMenuItem ,
14
- } from "@/components/ui/dropdown-menu"
15
6
import { UserView } from "@/lib/identity/definition"
16
- import { useEffect , useState , useRef } from "react"
7
+ import { useEffect , useState } from "react"
17
8
import { ModelComputerVision , ModelList , modelList } from "@/models/model-list"
18
9
import { cocossdVideoInference } from "@/lib/cocossd/detect"
19
10
import { detectVideo } from "@/lib/yolov8n/detect"
20
11
import ModelLoader from "./model-loader"
21
12
import { segmentVideo } from "@/lib/yolov8n-seg/detect"
13
+ import ModelSelection from "./model-selection"
14
+ import { useModelStore } from "@/lib/store/model-store"
15
+ import VideoReader from "./video-reader"
16
+ import VideoSelect from "./video-select"
17
+ import { useVideoStore } from "@/hooks/use-video-store"
22
18
23
19
interface IProps {
24
20
user : UserView
@@ -34,12 +30,10 @@ export default function VideoInference({ user }: IProps) {
34
30
net : null ,
35
31
inputShape : [ 1 , 0 , 0 , 3 ] ,
36
32
} ) // init model & input shape of YOLO SEGMENTATION
37
- const [ modelName , setModelName ] = useState < string > ( "" )
38
33
const [ loadModel , setLoadModel ] = useState < boolean > ( false )
39
- const [ videoSrc , setVideoSrc ] = useState < string | null > ( null )
40
- const videoRef = useRef < HTMLVideoElement | null > ( null )
41
- const canvasRef = useRef < HTMLCanvasElement | null > ( null )
42
34
const [ percentLoaded , setPercentLoaded ] = useState < number > ( 0 )
35
+ const { modelName } = useModelStore ( )
36
+ const { canvasRef, videoRef, videoSrc, setVideoSrc } = useVideoStore ( )
43
37
44
38
useEffect ( ( ) => {
45
39
tf . setBackend ( "webgl" )
@@ -152,80 +146,21 @@ export default function VideoInference({ user }: IProps) {
152
146
return (
153
147
< main className = "grid flex-1 items-start gap-4 p-4 sm:px-6 sm:py-0 md:gap-8 lg:grid-cols-3 xl:grid-cols-3 m-10" >
154
148
< div className = "lg:col-span-2" >
155
- < Card className = "overflow-hidden bg-background" >
156
- < CardHeader className = "flex flex-row items-start bg-muted/50 " >
157
- < div className = "grid gap-0.5" >
158
- < CardTitle className = "text-lg" > Lecteur Vidéo</ CardTitle >
159
- </ div >
160
- </ CardHeader >
161
- < CardContent className = "p-6" >
162
- < div className = "relative w-full max-w-2xl overflow-hidden rounded-lg aspect-video" >
163
- < video ref = { videoRef } className = "w-full" autoPlay controls >
164
- { videoSrc && < source src = { videoSrc } type = "video/mp4" /> }
165
- </ video >
166
- < canvas
167
- ref = { canvasRef }
168
- className = "absolute top-0 left-0 w-full h-full pointer-events-none"
169
- />
170
- </ div >
171
- </ CardContent >
172
- </ Card >
149
+ < VideoReader
150
+ videoRef = { videoRef }
151
+ canvasRef = { canvasRef }
152
+ videoSrc = { videoSrc }
153
+ />
173
154
</ div >
174
155
< div className = "grid gap-4" >
175
- < Card className = "bg-background" >
176
- < CardHeader className = "flex flex-row items-start bg-muted/50" >
177
- < div className = "grid gap-0.5" >
178
- < CardTitle className = "text-lg" > Vidéo Sélection</ CardTitle >
179
- </ div >
180
- </ CardHeader >
181
- < CardContent className = "p-6" >
182
- < div className = "grid gap-4" >
183
- < Input
184
- type = "file"
185
- id = "inputFile"
186
- accept = "video/*"
187
- placeholder = "Choose a video file"
188
- onChange = { handleFileChange }
189
- className = "cursor-pointer"
190
- />
191
- < Button
192
- variant = "outline"
193
- onClick = { handleCreateVideoWithBoundingBox }
194
- disabled = { ! modelName || ! videoSrc }
195
- className = "w-full" >
196
- Traiter la vidéo
197
- </ Button >
198
- < Button
199
- variant = "destructive"
200
- className = "hover:bg-red-500"
201
- onClick = { ( ) => {
202
- setVideoSrc ( null )
203
- const inputFile = document . getElementById ( "inputFile" )
204
- if ( inputFile ) {
205
- inputFile . setAttribute ( "value" , "" )
206
- }
207
- if ( videoRef . current ) {
208
- videoRef . current . load ( )
209
- }
210
-
211
- if ( canvasRef . current ) {
212
- const context = canvasRef . current . getContext ( "2d" )
213
- if ( context ) {
214
- context . clearRect (
215
- 0 ,
216
- 0 ,
217
- canvasRef . current . width ,
218
- canvasRef . current . height
219
- )
220
- }
221
- }
222
- } }
223
- disabled = { ! videoSrc } >
224
- Vider le lecteur vidéo
225
- </ Button >
226
- </ div >
227
- </ CardContent >
228
- </ Card >
156
+ < VideoSelect
157
+ handleFileChange = { handleFileChange }
158
+ handleCreateVideoWithBoundingBox = { handleCreateVideoWithBoundingBox }
159
+ videoRef = { videoRef }
160
+ canvasRef = { canvasRef }
161
+ videoSrc = { videoSrc }
162
+ setVideoSrc = { setVideoSrc }
163
+ />
229
164
{ loadModel ? (
230
165
< ModelLoader
231
166
percent = { percentLoaded }
@@ -234,95 +169,9 @@ export default function VideoInference({ user }: IProps) {
234
169
}
235
170
/>
236
171
) : (
237
- < Card >
238
- < CardHeader className = "flex flex-row items-start bg-muted/50" >
239
- < div className = "grid gap-0.5" >
240
- < CardTitle className = "text-lg" > Modèle Sélection</ CardTitle >
241
- </ div >
242
- </ CardHeader >
243
- < CardContent className = "p-6" >
244
- < div className = "grid gap-4" >
245
- < DropdownMenu >
246
- < DropdownMenuTrigger asChild >
247
- < Button
248
- variant = "outline"
249
- className = "w-full justify-between" >
250
- < span >
251
- { modelName ? modelName : "Choisissez un modèle" }
252
- </ span >
253
- < ChevronDownIcon className = "h-4 w-4" />
254
- </ Button >
255
- </ DropdownMenuTrigger >
256
- < DropdownMenuContent >
257
- { Object . keys ( ModelComputerVision ) . map ( ( key , index ) => (
258
- < DropdownMenuItem
259
- key = { index }
260
- onClick = { ( ) => setModelName ( ModelComputerVision [ key ] ) } >
261
- { ModelComputerVision [ key ] }
262
- </ DropdownMenuItem >
263
- ) ) }
264
- </ DropdownMenuContent >
265
- </ DropdownMenu >
266
- </ div >
267
- </ CardContent >
268
- </ Card >
172
+ < ModelSelection />
269
173
) }
270
174
</ div >
271
175
</ main >
272
176
)
273
177
}
274
-
275
- function ChevronDownIcon ( props ) {
276
- return (
277
- < svg
278
- { ...props }
279
- xmlns = "http://www.w3.org/2000/svg"
280
- width = "24"
281
- height = "24"
282
- viewBox = "0 0 24 24"
283
- fill = "none"
284
- stroke = "currentColor"
285
- strokeWidth = "2"
286
- strokeLinecap = "round"
287
- strokeLinejoin = "round" >
288
- < path d = "m6 9 6 6 6-6" />
289
- </ svg >
290
- )
291
- }
292
-
293
- function PlayIcon ( props ) {
294
- return (
295
- < svg
296
- { ...props }
297
- xmlns = "http://www.w3.org/2000/svg"
298
- width = "24"
299
- height = "24"
300
- viewBox = "0 0 24 24"
301
- fill = "none"
302
- stroke = "currentColor"
303
- strokeWidth = "2"
304
- strokeLinecap = "round"
305
- strokeLinejoin = "round" >
306
- < polygon points = "6 3 20 12 6 21 6 3" />
307
- </ svg >
308
- )
309
- }
310
-
311
- function XIcon ( props ) {
312
- return (
313
- < svg
314
- { ...props }
315
- xmlns = "http://www.w3.org/2000/svg"
316
- width = "24"
317
- height = "24"
318
- viewBox = "0 0 24 24"
319
- fill = "none"
320
- stroke = "currentColor"
321
- strokeWidth = "2"
322
- strokeLinecap = "round"
323
- strokeLinejoin = "round" >
324
- < path d = "M18 6 6 18" />
325
- < path d = "m6 6 12 12" />
326
- </ svg >
327
- )
328
- }
0 commit comments