Julian Bilcke
commited on
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 |
+
|