Spaces:
Runtime error
Runtime error
Commit
•
f39b1f2
1
Parent(s):
74224a2
working to add the firehose
Browse files- .env +8 -1
- src/app/engine/community.ts +127 -0
- src/app/engine/render.ts +4 -4
- src/app/interface/top-menu/index.tsx +1 -1
- src/app/main.tsx +1 -1
- src/app/todo.tsx +21 -0
- src/types.ts +25 -1
.env
CHANGED
@@ -10,4 +10,11 @@ VIDEOCHAIN_API_TOKEN=
|
|
10 |
# Not supported yet
|
11 |
REPLICATE_API_TOKEN=
|
12 |
REPLICATE_API_MODEL="lucataco/sdxl-panoramic"
|
13 |
-
REPLICATE_API_MODEL_VERSION="76acc4075d0633dcb3823c1fed0419de21d42001b65c816c7b5b9beff30ec8cd"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
# Not supported yet
|
11 |
REPLICATE_API_TOKEN=
|
12 |
REPLICATE_API_MODEL="lucataco/sdxl-panoramic"
|
13 |
+
REPLICATE_API_MODEL_VERSION="76acc4075d0633dcb3823c1fed0419de21d42001b65c816c7b5b9beff30ec8cd"
|
14 |
+
|
15 |
+
# ----------- COMMUNITY SHARING (OPTIONAL, YOU DON'T NEED THIS IN LOCAL) -----------
|
16 |
+
# You don't need those community sharing options to run Panoremix
|
17 |
+
# locally or on your own server (they are meant to be used by the Hugging Face team)
|
18 |
+
COMMUNITY_API_URL=
|
19 |
+
COMMUNITY_API_TOKEN=
|
20 |
+
COMMUNITY_API_ID=
|
src/app/engine/community.ts
ADDED
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use server"
|
2 |
+
|
3 |
+
import { v4 as uuidv4 } from "uuid"
|
4 |
+
|
5 |
+
import { CreatePostResponse, GetAppPostsResponse, Post } from "@/types"
|
6 |
+
|
7 |
+
const apiUrl = `${process.env.COMMUNITY_API_URL || ""}`
|
8 |
+
const apiToken = `${process.env.COMMUNITY_API_TOKEN || ""}`
|
9 |
+
const appId = `${process.env.APP_ID || ""}`
|
10 |
+
|
11 |
+
export async function postToCommunity({
|
12 |
+
prompt,
|
13 |
+
assetUrl,
|
14 |
+
}: {
|
15 |
+
prompt: string
|
16 |
+
assetUrl: string
|
17 |
+
}): Promise<Post> {
|
18 |
+
// if the community API is disabled,
|
19 |
+
// we don't fail, we just mock
|
20 |
+
if (!apiUrl) {
|
21 |
+
const mockPost: Post = {
|
22 |
+
postId: uuidv4(),
|
23 |
+
appId: "mock",
|
24 |
+
prompt,
|
25 |
+
previewUrl: assetUrl,
|
26 |
+
assetUrl,
|
27 |
+
createdAt: new Date().toISOString(),
|
28 |
+
upvotes: 0,
|
29 |
+
downvotes: 0
|
30 |
+
}
|
31 |
+
return mockPost
|
32 |
+
}
|
33 |
+
|
34 |
+
if (!prompt) {
|
35 |
+
console.error(`cannot call the community API without a prompt, aborting..`)
|
36 |
+
throw new Error(`cannot call the community API without a prompt, aborting..`)
|
37 |
+
}
|
38 |
+
if (!assetUrl) {
|
39 |
+
console.error(`cannot call the community API without an assetUrl, aborting..`)
|
40 |
+
throw new Error(`cannot call the community API without an assetUrl, aborting..`)
|
41 |
+
}
|
42 |
+
|
43 |
+
try {
|
44 |
+
console.log(`calling POST ${apiUrl}/post with prompt: ${prompt}`)
|
45 |
+
|
46 |
+
const postId = uuidv4()
|
47 |
+
|
48 |
+
const post: Partial<Post> = { postId, appId, prompt, assetUrl }
|
49 |
+
|
50 |
+
console.table(post)
|
51 |
+
|
52 |
+
const res = await fetch(`${apiUrl}/post`, {
|
53 |
+
method: "POST",
|
54 |
+
headers: {
|
55 |
+
Accept: "application/json",
|
56 |
+
"Content-Type": "application/json",
|
57 |
+
Authorization: `Bearer ${apiToken}`,
|
58 |
+
},
|
59 |
+
body: JSON.stringify(post),
|
60 |
+
cache: 'no-store',
|
61 |
+
// we can also use this (see https://vercel.com/blog/vercel-cache-api-nextjs-cache)
|
62 |
+
// next: { revalidate: 1 }
|
63 |
+
})
|
64 |
+
|
65 |
+
// console.log("res:", res)
|
66 |
+
// The return value is *not* serialized
|
67 |
+
// You can return Date, Map, Set, etc.
|
68 |
+
|
69 |
+
// Recommendation: handle errors
|
70 |
+
if (res.status !== 200) {
|
71 |
+
// This will activate the closest `error.js` Error Boundary
|
72 |
+
throw new Error('Failed to fetch data')
|
73 |
+
}
|
74 |
+
|
75 |
+
const response = (await res.json()) as CreatePostResponse
|
76 |
+
// console.log("response:", response)
|
77 |
+
return response.post
|
78 |
+
} catch (err) {
|
79 |
+
const error = `failed to post to community: ${err}`
|
80 |
+
console.error(error)
|
81 |
+
throw new Error(error)
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
export async function getLatestPosts(): Promise<Post[]> {
|
86 |
+
|
87 |
+
let posts: Post[] = []
|
88 |
+
|
89 |
+
// if the community API is disabled we don't fail,
|
90 |
+
// we just mock
|
91 |
+
if (!apiUrl) {
|
92 |
+
return posts
|
93 |
+
}
|
94 |
+
|
95 |
+
try {
|
96 |
+
// console.log(`calling GET ${apiUrl}/posts with renderId: ${renderId}`)
|
97 |
+
const res = await fetch(`${apiUrl}/posts/${appId}`, {
|
98 |
+
method: "GET",
|
99 |
+
headers: {
|
100 |
+
Accept: "application/json",
|
101 |
+
"Content-Type": "application/json",
|
102 |
+
Authorization: `Bearer ${apiToken}`,
|
103 |
+
},
|
104 |
+
cache: 'no-store',
|
105 |
+
// we can also use this (see https://vercel.com/blog/vercel-cache-api-nextjs-cache)
|
106 |
+
// next: { revalidate: 1 }
|
107 |
+
})
|
108 |
+
|
109 |
+
// console.log("res:", res)
|
110 |
+
// The return value is *not* serialized
|
111 |
+
// You can return Date, Map, Set, etc.
|
112 |
+
|
113 |
+
// Recommendation: handle errors
|
114 |
+
if (res.status !== 200) {
|
115 |
+
// This will activate the closest `error.js` Error Boundary
|
116 |
+
throw new Error('Failed to fetch data')
|
117 |
+
}
|
118 |
+
|
119 |
+
const response = (await res.json()) as GetAppPostsResponse
|
120 |
+
// console.log("response:", response)
|
121 |
+
return Array.isArray(response?.posts) ? response?.posts : []
|
122 |
+
} catch (err) {
|
123 |
+
const error = `failed to get posts: ${err}`
|
124 |
+
console.error(error)
|
125 |
+
throw new Error(error)
|
126 |
+
}
|
127 |
+
}
|
src/app/engine/render.ts
CHANGED
@@ -29,10 +29,10 @@ export async function newRender({
|
|
29 |
}
|
30 |
|
31 |
prompt = [
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
].join(', ')
|
37 |
|
38 |
// return await Gorgon.get(cacheKey, async () => {
|
|
|
29 |
}
|
30 |
|
31 |
prompt = [
|
32 |
+
`hdri view`,
|
33 |
+
`highly detailed`,
|
34 |
+
`intricate details`,
|
35 |
+
prompt
|
36 |
].join(', ')
|
37 |
|
38 |
// return await Gorgon.get(cacheKey, async () => {
|
src/app/interface/top-menu/index.tsx
CHANGED
@@ -45,7 +45,7 @@ export function TopMenu() {
|
|
45 |
)}>
|
46 |
<div className="flex flex-row flex-grow w-full">
|
47 |
<Input
|
48 |
-
placeholder={`Type a location
|
49 |
className="w-full bg-neutral-300 text-neutral-800 dark:bg-neutral-300 dark:text-neutral-800 rounded-r-none"
|
50 |
// disabled={atLeastOnePanelIsBusy}
|
51 |
onChange={(e) => {
|
|
|
45 |
)}>
|
46 |
<div className="flex flex-row flex-grow w-full">
|
47 |
<Input
|
48 |
+
placeholder={`Type a location e.g. "Jurassic Park entrance", "Spaceport in Mos Eisley"..`}
|
49 |
className="w-full bg-neutral-300 text-neutral-800 dark:bg-neutral-300 dark:text-neutral-800 rounded-r-none"
|
50 |
// disabled={atLeastOnePanelIsBusy}
|
51 |
onChange={(e) => {
|
src/app/main.tsx
CHANGED
@@ -12,7 +12,7 @@ import { SphericalImage } from "./interface/spherical-image"
|
|
12 |
import { getRender, newRender } from "./engine/render"
|
13 |
import { RenderedScene } from "@/types"
|
14 |
|
15 |
-
export default function
|
16 |
const [_isPending, startTransition] = useTransition()
|
17 |
|
18 |
const prompt = useStore(state => state.prompt)
|
|
|
12 |
import { getRender, newRender } from "./engine/render"
|
13 |
import { RenderedScene } from "@/types"
|
14 |
|
15 |
+
export default function Generator() {
|
16 |
const [_isPending, startTransition] = useTransition()
|
17 |
|
18 |
const prompt = useStore(state => state.prompt)
|
src/app/todo.tsx
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use client"
|
2 |
+
|
3 |
+
import { useState, useTransition } from "react"
|
4 |
+
|
5 |
+
import { Post } from "@/types"
|
6 |
+
|
7 |
+
export default function Main() {
|
8 |
+
const [_isPending, startTransition] = useTransition()
|
9 |
+
const posts = useState<Post[]>([])
|
10 |
+
|
11 |
+
return (
|
12 |
+
<div>
|
13 |
+
<h1>Panoremix</h1>
|
14 |
+
<h2>Generate 360° panoramas from text!</h2>
|
15 |
+
|
16 |
+
<h2>Explore latent locations discovered by the community</h2>
|
17 |
+
|
18 |
+
|
19 |
+
</div>
|
20 |
+
)
|
21 |
+
}
|
src/types.ts
CHANGED
@@ -86,4 +86,28 @@ export interface ImageAnalysisResponse {
|
|
86 |
export type RenderingEngine =
|
87 |
| "VIDEOCHAIN"
|
88 |
| "OPENAI"
|
89 |
-
| "REPLICATE"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
export type RenderingEngine =
|
87 |
| "VIDEOCHAIN"
|
88 |
| "OPENAI"
|
89 |
+
| "REPLICATE"
|
90 |
+
|
91 |
+
export type Post = {
|
92 |
+
postId: string
|
93 |
+
appId: string
|
94 |
+
prompt: string
|
95 |
+
previewUrl: string
|
96 |
+
assetUrl: string
|
97 |
+
createdAt: string
|
98 |
+
upvotes: number
|
99 |
+
downvotes: number
|
100 |
+
}
|
101 |
+
|
102 |
+
export type CreatePostResponse = {
|
103 |
+
success?: boolean
|
104 |
+
error?: string
|
105 |
+
post: Post
|
106 |
+
}
|
107 |
+
|
108 |
+
export type GetAppPostsResponse = {
|
109 |
+
success?: boolean
|
110 |
+
error?: string
|
111 |
+
posts: Post[]
|
112 |
+
}
|
113 |
+
|