Spaces:
Paused
Paused
Commit
•
01c8568
1
Parent(s):
cd7b7cc
preparing the code for interactivityg
Browse files
src/app/main.tsx
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
import { useEffect, useRef, useState, useTransition } from "react"
|
4 |
|
5 |
-
import {
|
6 |
|
7 |
import {
|
8 |
Select,
|
@@ -44,7 +44,7 @@ export default function Main() {
|
|
44 |
|
45 |
[]
|
46 |
// note: using actionnables will add +30sec to the query
|
47 |
-
// scene.actionnables
|
48 |
)
|
49 |
|
50 |
if (type !== ref?.current) {
|
@@ -54,9 +54,9 @@ export default function Main() {
|
|
54 |
}
|
55 |
|
56 |
|
57 |
-
if (rendered.
|
58 |
// console.log(`got a new url: ${newUrl}`)
|
59 |
-
setUrl(rendered.
|
60 |
setScene(scene)
|
61 |
setSegments(rendered.segments)
|
62 |
setTimeout(() => { updateView()}, 1000)
|
@@ -106,7 +106,7 @@ export default function Main() {
|
|
106 |
</div>)}
|
107 |
</div>
|
108 |
</div>
|
109 |
-
<
|
110 |
</div>
|
111 |
)
|
112 |
}
|
|
|
2 |
|
3 |
import { useEffect, useRef, useState, useTransition } from "react"
|
4 |
|
5 |
+
import { VideoRenderer } from "@/components/business/video-renderer"
|
6 |
|
7 |
import {
|
8 |
Select,
|
|
|
44 |
|
45 |
[]
|
46 |
// note: using actionnables will add +30sec to the query
|
47 |
+
// scene.actionnables.slice(0, 5) // too many can slow us down it seems
|
48 |
)
|
49 |
|
50 |
if (type !== ref?.current) {
|
|
|
54 |
}
|
55 |
|
56 |
|
57 |
+
if (rendered.assetUrl) {
|
58 |
// console.log(`got a new url: ${newUrl}`)
|
59 |
+
setUrl(rendered.assetUrl)
|
60 |
setScene(scene)
|
61 |
setSegments(rendered.segments)
|
62 |
setTimeout(() => { updateView()}, 1000)
|
|
|
106 |
</div>)}
|
107 |
</div>
|
108 |
</div>
|
109 |
+
<VideoRenderer url={url} />
|
110 |
</div>
|
111 |
)
|
112 |
}
|
src/app/render.ts
CHANGED
@@ -1,14 +1,14 @@
|
|
1 |
"use server"
|
2 |
|
3 |
-
import {
|
4 |
|
5 |
// note: there is no / at the end in the variable
|
6 |
// so we have to add it ourselves if needed
|
7 |
const apiUrl = process.env.RENDERING_ENGINE_API
|
8 |
|
9 |
export async function render(prompt: string, actionnables: string[] = []) {
|
10 |
-
let defaulResult:
|
11 |
-
|
12 |
maskBase64: "",
|
13 |
error: "",
|
14 |
segments: []
|
@@ -28,8 +28,8 @@ export async function render(prompt: string, actionnables: string[] = []) {
|
|
28 |
// nbFrames: 8 and nbSteps: 15 --> ~10 sec generation
|
29 |
nbFrames: 8,
|
30 |
nbSteps: 20,
|
31 |
-
segmentation: "firstframe",
|
32 |
actionnables,
|
|
|
33 |
}),
|
34 |
cache: 'no-store',
|
35 |
// we can also use this (see https://vercel.com/blog/vercel-cache-api-nextjs-cache)
|
@@ -46,7 +46,7 @@ export async function render(prompt: string, actionnables: string[] = []) {
|
|
46 |
throw new Error('Failed to fetch data')
|
47 |
}
|
48 |
|
49 |
-
const response = (await res.json()) as
|
50 |
// console.log("response:", response)
|
51 |
return response
|
52 |
} catch (err) {
|
|
|
1 |
"use server"
|
2 |
|
3 |
+
import { RenderedScene } from "./types"
|
4 |
|
5 |
// note: there is no / at the end in the variable
|
6 |
// so we have to add it ourselves if needed
|
7 |
const apiUrl = process.env.RENDERING_ENGINE_API
|
8 |
|
9 |
export async function render(prompt: string, actionnables: string[] = []) {
|
10 |
+
let defaulResult: RenderedScene = {
|
11 |
+
assetUrl: "",
|
12 |
maskBase64: "",
|
13 |
error: "",
|
14 |
segments: []
|
|
|
28 |
// nbFrames: 8 and nbSteps: 15 --> ~10 sec generation
|
29 |
nbFrames: 8,
|
30 |
nbSteps: 20,
|
|
|
31 |
actionnables,
|
32 |
+
segmentation: "firstframe", // one day we will remove this param, to make it automatic
|
33 |
}),
|
34 |
cache: 'no-store',
|
35 |
// we can also use this (see https://vercel.com/blog/vercel-cache-api-nextjs-cache)
|
|
|
46 |
throw new Error('Failed to fetch data')
|
47 |
}
|
48 |
|
49 |
+
const response = (await res.json()) as RenderedScene
|
50 |
// console.log("response:", response)
|
51 |
return response
|
52 |
} catch (err) {
|
src/app/types.ts
CHANGED
@@ -27,20 +27,13 @@ export interface RenderRequest {
|
|
27 |
export interface ImageSegment {
|
28 |
id: number
|
29 |
box: number[]
|
|
|
30 |
label: string
|
31 |
score: number
|
32 |
}
|
33 |
|
34 |
-
|
35 |
-
|
36 |
-
id: number
|
37 |
-
box: number[]
|
38 |
-
label: string
|
39 |
-
score: number
|
40 |
-
}
|
41 |
-
|
42 |
-
export interface RenderAPIResponse {
|
43 |
-
videoUrl: string
|
44 |
error: string
|
45 |
maskBase64: string
|
46 |
segments: ImageSegment[]
|
|
|
27 |
export interface ImageSegment {
|
28 |
id: number
|
29 |
box: number[]
|
30 |
+
color: number[]
|
31 |
label: string
|
32 |
score: number
|
33 |
}
|
34 |
|
35 |
+
export interface RenderedScene {
|
36 |
+
assetUrl: string
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
error: string
|
38 |
maskBase64: string
|
39 |
segments: ImageSegment[]
|
src/components/business/image-renderer.tsx
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { useRef } from "react"
|
2 |
+
|
3 |
+
import { ImageSegment, RenderedScene } from "@/app/types"
|
4 |
+
|
5 |
+
export const ImageRenderer = ({
|
6 |
+
assetUrl = "",
|
7 |
+
maskBase64 = "",
|
8 |
+
segments = []
|
9 |
+
}: RenderedScene) => {
|
10 |
+
const imgRef = useRef<HTMLImageElement | null>(null)
|
11 |
+
const canvas = document.createElement('canvas')
|
12 |
+
const context = canvas.getContext('2d')
|
13 |
+
|
14 |
+
const getPixelColor = (x: number, y: number) => {
|
15 |
+
console.log("getting pixel color")
|
16 |
+
if (!context) {
|
17 |
+
throw new Error("Unable to get context from canvas")
|
18 |
+
}
|
19 |
+
|
20 |
+
const imgData = context.getImageData(x, y, 1, 1).data
|
21 |
+
|
22 |
+
return `[${imgData[0]},${imgData[1]},${imgData[2]},${imgData[3]/255}]`
|
23 |
+
}
|
24 |
+
|
25 |
+
const handleMouseDown = (event: React.MouseEvent) => {
|
26 |
+
const boundingRect = imgRef.current!.getBoundingClientRect()
|
27 |
+
|
28 |
+
const x = event.clientX - boundingRect.left
|
29 |
+
const y = event.clientY - boundingRect.top
|
30 |
+
|
31 |
+
if (maskBase64) {
|
32 |
+
const image = new Image()
|
33 |
+
|
34 |
+
image.onload = function () {
|
35 |
+
if (context) {
|
36 |
+
context.drawImage(image, 0, 0)
|
37 |
+
|
38 |
+
const clickedColor = getPixelColor(x, y) as any
|
39 |
+
|
40 |
+
let closestSegment: ImageSegment | null = null
|
41 |
+
|
42 |
+
let minDistance = Infinity
|
43 |
+
|
44 |
+
segments.forEach(segment => {
|
45 |
+
const segmentColor = segment.color.slice(0,3) // get the RGB part only
|
46 |
+
|
47 |
+
const distance = Math.sqrt(
|
48 |
+
Math.pow(clickedColor[0] - segmentColor[0], 2) +
|
49 |
+
Math.pow(clickedColor[1] - segmentColor[1], 2) +
|
50 |
+
Math.pow(clickedColor[2] - segmentColor[2], 2)
|
51 |
+
)
|
52 |
+
|
53 |
+
if(distance < minDistance) {
|
54 |
+
minDistance = distance;
|
55 |
+
closestSegment = segment;
|
56 |
+
}
|
57 |
+
})
|
58 |
+
|
59 |
+
console.log("closestSegment:", closestSegment)
|
60 |
+
console.log(closestSegment) // Here is the closest matching segment
|
61 |
+
}
|
62 |
+
}
|
63 |
+
|
64 |
+
image.src = maskBase64
|
65 |
+
// image.src = "data:image/png;base64," + maskBase64;
|
66 |
+
} else {
|
67 |
+
console.log("No mask available, aborting..")
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
|
72 |
+
if (!assetUrl) {
|
73 |
+
return <div className="flex w-full h-screen items-center justify-center text-center">
|
74 |
+
<div>Rendering first frame.. (might take around 30s)</div>
|
75 |
+
</div>
|
76 |
+
}
|
77 |
+
|
78 |
+
return (
|
79 |
+
<div className="w-full py-8 px-2">
|
80 |
+
<img
|
81 |
+
src={assetUrl}
|
82 |
+
ref={imgRef}
|
83 |
+
className="w-full rounded-md overflow-hidden"
|
84 |
+
onMouseDown={handleMouseDown}
|
85 |
+
/>
|
86 |
+
</div>
|
87 |
+
)
|
88 |
+
}
|
src/components/business/{video-player.tsx → video-renderer.tsx}
RENAMED
@@ -1,10 +1,10 @@
|
|
1 |
"use client"
|
2 |
|
3 |
-
export const
|
4 |
|
5 |
if (!url) {
|
6 |
return <div className="flex w-full h-screen items-center justify-center text-center">
|
7 |
-
<div>Rendering first
|
8 |
</div>
|
9 |
}
|
10 |
|
|
|
1 |
"use client"
|
2 |
|
3 |
+
export const VideoRenderer = ({ url }: { url?: string }) => {
|
4 |
|
5 |
if (!url) {
|
6 |
return <div className="flex w-full h-screen items-center justify-center text-center">
|
7 |
+
<div>Rendering first frames.. (might take around 30s)</div>
|
8 |
</div>
|
9 |
}
|
10 |
|