Commit
•
a296341
1
Parent(s):
a5e4a1b
working to fix the config
Browse files- .env +8 -5
- Dockerfile +0 -34
- src/app/interface/page/index.tsx +26 -7
- src/app/interface/top-menu/index.tsx +6 -9
- src/app/layouts/index.tsx +0 -10
- src/app/main.tsx +23 -13
- src/app/queries/getDynamicConfig.ts +25 -0
- src/app/store/index.ts +26 -6
- src/components/ui/dialog.tsx +2 -1
- src/config.ts +0 -8
- src/lib/getDefaultDynamicConfig.ts +12 -0
- src/lib/getValidString.ts +2 -2
- src/lib/useDynamicConfig.ts +31 -0
- src/lib/useOAuth.ts +20 -14
- src/lib/useOAuthClientId.ts +0 -6
- src/lib/useOAuthEnabled.ts +0 -6
- src/types.ts +12 -1
.env
CHANGED
@@ -14,16 +14,19 @@ RENDERING_ENGINE="INFERENCE_API"
|
|
14 |
LLM_ENGINE="INFERENCE_API"
|
15 |
|
16 |
# set this to control the number of pages
|
17 |
-
|
18 |
|
19 |
# Set to "true" to create artificial delays and smooth out traffic
|
20 |
NEXT_PUBLIC_ENABLE_RATE_LIMITER="false"
|
21 |
|
22 |
# ------------- HUGGING FACE OAUTH -------------
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
|
|
|
|
|
|
27 |
|
28 |
# ------------- PROVIDER AUTH ------------
|
29 |
# You only need to configure the access token(s) for the provider(s) you want to use
|
|
|
14 |
LLM_ENGINE="INFERENCE_API"
|
15 |
|
16 |
# set this to control the number of pages
|
17 |
+
MAX_NB_PAGES=1
|
18 |
|
19 |
# Set to "true" to create artificial delays and smooth out traffic
|
20 |
NEXT_PUBLIC_ENABLE_RATE_LIMITER="false"
|
21 |
|
22 |
# ------------- HUGGING FACE OAUTH -------------
|
23 |
+
ENABLE_HUGGING_FACE_OAUTH=
|
24 |
+
ENABLE_HUGGING_FACE_OAUTH_WALL=
|
25 |
+
HUGGING_FACE_OAUTH_CLIENT_ID=
|
26 |
+
HUGGING_FACE_OAUTH_REDIRECT_URL=
|
27 |
+
|
28 |
+
# this one must be kept secret (and is unused for now)
|
29 |
+
HUGGING_FACE_OAUTH_SECRET=
|
30 |
|
31 |
# ------------- PROVIDER AUTH ------------
|
32 |
# You only need to configure the access token(s) for the provider(s) you want to use
|
Dockerfile
CHANGED
@@ -1,37 +1,3 @@
|
|
1 |
-
ARG RENDERING_ENGINE
|
2 |
-
ARG LLM_ENGINE
|
3 |
-
ARG NEXT_PUBLIC_MAX_NB_PAGES
|
4 |
-
ARG NEXT_PUBLIC_ENABLE_RATE_LIMITER
|
5 |
-
ARG NEXT_PUBLIC_ENABLE_HUGGING_FACE_OAUTH
|
6 |
-
ARG NEXT_PUBLIC_ENABLE_HUGGING_FACE_OAUTH_WALL
|
7 |
-
ARG NEXT_PUBLIC_HUGGING_FACE_OAUTH_CLIENT_ID
|
8 |
-
ARG HUGGING_FACE_OAUTH_SECRET
|
9 |
-
ARG AUTH_HF_API_TOKEN
|
10 |
-
ARG AUTH_REPLICATE_API_TOKEN
|
11 |
-
ARG AUTH_OPENAI_API_KEY
|
12 |
-
ARG AUTH_VIDEOCHAIN_API_TOKEN
|
13 |
-
ARG AUTH_GROQ_API_KEY
|
14 |
-
ARG RENDERING_REPLICATE_API_MODEL
|
15 |
-
ARG ENDERING_REPLICATE_API_MODEL_VERSION
|
16 |
-
ARG RENDERING_HF_INFERENCE_ENDPOINT_URL
|
17 |
-
ARG RENDERING_HF_INFERENCE_API_BASE_MODEL
|
18 |
-
ARG RENDERING_HF_INFERENCE_API_REFINER_MODEL
|
19 |
-
ARG RENDERING_HF_INFERENCE_API_FILE_TYPE
|
20 |
-
ARG RENDERING_VIDEOCHAIN_API_URL
|
21 |
-
ARG RENDERING_OPENAI_API_BASE_URL
|
22 |
-
ARG RENDERING_OPENAI_API_MODEL
|
23 |
-
ARG LLM_GROQ_API_MODEL
|
24 |
-
ARG LLM_OPENAI_API_BASE_URL
|
25 |
-
ARG LLM_OPENAI_API_MODEL
|
26 |
-
ARG LLM_HF_INFERENCE_ENDPOINT_URL
|
27 |
-
ARG LLM_HF_INFERENCE_API_MODEL
|
28 |
-
ARG NEXT_PUBLIC_ENABLE_COMMUNITY_SHARING
|
29 |
-
ARG COMMUNITY_API_URL
|
30 |
-
ARG COMMUNITY_API_TOKEN
|
31 |
-
ARG COMMUNITY_API_ID
|
32 |
-
ARG ENABLE_CENSORSHIP
|
33 |
-
ARG SECRET_FINGERPRINT
|
34 |
-
|
35 |
FROM node:20-alpine AS base
|
36 |
|
37 |
# Install dependencies only when needed
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
FROM node:20-alpine AS base
|
2 |
|
3 |
# Install dependencies only when needed
|
src/app/interface/page/index.tsx
CHANGED
@@ -1,21 +1,33 @@
|
|
1 |
-
|
|
|
|
|
|
|
|
|
2 |
import { useStore } from "@/app/store"
|
3 |
-
import { NB_PANELS_PER_PAGE } from "@/config"
|
4 |
import { cn } from "@/lib/utils"
|
5 |
-
import { useEffect, useRef } from "react"
|
6 |
|
7 |
export function Page({ page }: { page: number}) {
|
8 |
const zoomLevel = useStore(state => state.zoomLevel)
|
9 |
const layouts = useStore(state => state.layouts)
|
10 |
-
// const prompt = useStore(state => state.prompt)
|
11 |
|
12 |
const layout = layouts[page]
|
13 |
|
14 |
const LayoutElement = (allLayouts as any)[layout]
|
15 |
const aspectRatio = ((allLayoutAspectRatios as any)[layout] as string) || "aspect-[250/297]"
|
16 |
|
17 |
-
const
|
18 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
/*
|
21 |
const [canLoad, setCanLoad] = useState(false)
|
@@ -67,7 +79,14 @@ export function Page({ page }: { page: number}) {
|
|
67 |
>
|
68 |
<LayoutElement page={page} nbPanels={nbPanels} />
|
69 |
</div>
|
70 |
-
{nbPages > 1 &&
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
</div>
|
72 |
)
|
73 |
}
|
|
|
1 |
+
"use client"
|
2 |
+
|
3 |
+
import { useEffect, useRef } from "react"
|
4 |
+
|
5 |
+
import { allLayoutAspectRatios, allLayouts } from "@/app/layouts"
|
6 |
import { useStore } from "@/app/store"
|
|
|
7 |
import { cn } from "@/lib/utils"
|
|
|
8 |
|
9 |
export function Page({ page }: { page: number}) {
|
10 |
const zoomLevel = useStore(state => state.zoomLevel)
|
11 |
const layouts = useStore(state => state.layouts)
|
|
|
12 |
|
13 |
const layout = layouts[page]
|
14 |
|
15 |
const LayoutElement = (allLayouts as any)[layout]
|
16 |
const aspectRatio = ((allLayoutAspectRatios as any)[layout] as string) || "aspect-[250/297]"
|
17 |
|
18 |
+
const nbPages = useStore(s => s.nbPages)
|
19 |
+
const nbPanelsPerPage = useStore(s => s.nbPanelsPerPage)
|
20 |
+
|
21 |
+
// in the future, different layouts might have different numbers of panels
|
22 |
+
const allLayoutsNbPanels = {
|
23 |
+
Layout0: nbPanelsPerPage,
|
24 |
+
Layout1: nbPanelsPerPage,
|
25 |
+
Layout2: nbPanelsPerPage,
|
26 |
+
Layout3: nbPanelsPerPage,
|
27 |
+
// Layout4: nbPanelsPerPage
|
28 |
+
}
|
29 |
+
|
30 |
+
const nbPanels = ((allLayoutsNbPanels as any)[layout] as number) || nbPanelsPerPage
|
31 |
|
32 |
/*
|
33 |
const [canLoad, setCanLoad] = useState(false)
|
|
|
79 |
>
|
80 |
<LayoutElement page={page} nbPanels={nbPanels} />
|
81 |
</div>
|
82 |
+
{nbPages > 1 &&
|
83 |
+
<p className="w-full text-center pt-4 font-sans text-2xs font-semibold text-stone-600">
|
84 |
+
Page {page + 1}
|
85 |
+
{/*
|
86 |
+
alternative style:
|
87 |
+
Page {page + 1} / {nbPages}
|
88 |
+
*/}
|
89 |
+
</p>}
|
90 |
</div>
|
91 |
)
|
92 |
}
|
src/app/interface/top-menu/index.tsx
CHANGED
@@ -3,6 +3,8 @@
|
|
3 |
import { useEffect, useState } from "react"
|
4 |
import { useSearchParams } from "next/navigation"
|
5 |
import Image from "next/image"
|
|
|
|
|
6 |
|
7 |
import {
|
8 |
Select,
|
@@ -19,15 +21,13 @@ import { PresetName, defaultPreset, nonRandomPresets, presets } from "@/app/engi
|
|
19 |
import { useStore } from "@/app/store"
|
20 |
import { Button } from "@/components/ui/button"
|
21 |
import { LayoutName, allLayoutLabels, defaultLayout, nonRandomLayouts } from "@/app/layouts"
|
|
|
|
|
22 |
|
23 |
import layoutPreview0 from "../../../../public/layouts/layout0.jpg"
|
24 |
import layoutPreview1 from "../../../../public/layouts/layout1.jpg"
|
25 |
import layoutPreview2 from "../../../../public/layouts/layout2.jpg"
|
26 |
import layoutPreview3 from "../../../../public/layouts/layout3.jpg"
|
27 |
-
import { StaticImageData } from "next/image"
|
28 |
-
import { Switch } from "@/components/ui/switch"
|
29 |
-
import { useLocalStorage } from "usehooks-ts"
|
30 |
-
import { useOAuth } from "@/lib/useOAuth"
|
31 |
import { localStorageKeys } from "../settings-dialog/localStorageKeys"
|
32 |
import { defaultSettings } from "../settings-dialog/defaultSettings"
|
33 |
import { AuthWall } from "../auth-wall"
|
@@ -71,8 +71,7 @@ export function TopMenu() {
|
|
71 |
const [draftPreset, setDraftPreset] = useState<PresetName>(requestedPreset)
|
72 |
const [draftLayout, setDraftLayout] = useState<LayoutName>(requestedLayout)
|
73 |
|
74 |
-
|
75 |
-
const { canLogin, login, isLoggedIn, oauthResult } = useOAuth({ debug: false })
|
76 |
|
77 |
const [hasGeneratedAtLeastOnce, setHasGeneratedAtLeastOnce] = useLocalStorage<boolean>(
|
78 |
localStorageKeys.hasGeneratedAtLeastOnce,
|
@@ -82,9 +81,7 @@ export function TopMenu() {
|
|
82 |
const [showAuthWall, setShowAuthWall] = useState(false)
|
83 |
|
84 |
const handleSubmit = () => {
|
85 |
-
|
86 |
-
|
87 |
-
if (enableAuthWall && hasGeneratedAtLeastOnce && !isLoggedIn) {
|
88 |
setShowAuthWall(true)
|
89 |
return
|
90 |
}
|
|
|
3 |
import { useEffect, useState } from "react"
|
4 |
import { useSearchParams } from "next/navigation"
|
5 |
import Image from "next/image"
|
6 |
+
import { StaticImageData } from "next/image"
|
7 |
+
import { useLocalStorage } from "usehooks-ts"
|
8 |
|
9 |
import {
|
10 |
Select,
|
|
|
21 |
import { useStore } from "@/app/store"
|
22 |
import { Button } from "@/components/ui/button"
|
23 |
import { LayoutName, allLayoutLabels, defaultLayout, nonRandomLayouts } from "@/app/layouts"
|
24 |
+
import { Switch } from "@/components/ui/switch"
|
25 |
+
import { useOAuth } from "@/lib/useOAuth"
|
26 |
|
27 |
import layoutPreview0 from "../../../../public/layouts/layout0.jpg"
|
28 |
import layoutPreview1 from "../../../../public/layouts/layout1.jpg"
|
29 |
import layoutPreview2 from "../../../../public/layouts/layout2.jpg"
|
30 |
import layoutPreview3 from "../../../../public/layouts/layout3.jpg"
|
|
|
|
|
|
|
|
|
31 |
import { localStorageKeys } from "../settings-dialog/localStorageKeys"
|
32 |
import { defaultSettings } from "../settings-dialog/defaultSettings"
|
33 |
import { AuthWall } from "../auth-wall"
|
|
|
71 |
const [draftPreset, setDraftPreset] = useState<PresetName>(requestedPreset)
|
72 |
const [draftLayout, setDraftLayout] = useState<LayoutName>(requestedLayout)
|
73 |
|
74 |
+
const { isLoggedIn, enableOAuthWall } = useOAuth({ debug: false })
|
|
|
75 |
|
76 |
const [hasGeneratedAtLeastOnce, setHasGeneratedAtLeastOnce] = useLocalStorage<boolean>(
|
77 |
localStorageKeys.hasGeneratedAtLeastOnce,
|
|
|
81 |
const [showAuthWall, setShowAuthWall] = useState(false)
|
82 |
|
83 |
const handleSubmit = () => {
|
84 |
+
if (enableOAuthWall && hasGeneratedAtLeastOnce && !isLoggedIn) {
|
|
|
|
|
85 |
setShowAuthWall(true)
|
86 |
return
|
87 |
}
|
src/app/layouts/index.tsx
CHANGED
@@ -4,7 +4,6 @@ import { Panel } from "@/app/interface/panel"
|
|
4 |
import { pick } from "@/lib/pick"
|
5 |
import { Grid } from "@/app/interface/grid"
|
6 |
import { LayoutProps } from "@/types"
|
7 |
-
import { NB_PANELS_PER_PAGE } from "@/config"
|
8 |
|
9 |
export function Layout0({ page, nbPanels }: LayoutProps) {
|
10 |
return (
|
@@ -426,15 +425,6 @@ export const allLayoutAspectRatios = {
|
|
426 |
// Layout4: "aspect-[1/3]",
|
427 |
}
|
428 |
|
429 |
-
export const allLayoutsNbPanels = {
|
430 |
-
// TODO: this is gonna be tricky to implement, but this should be unique / dynamic
|
431 |
-
Layout0: NB_PANELS_PER_PAGE,
|
432 |
-
Layout1: NB_PANELS_PER_PAGE,
|
433 |
-
Layout2: NB_PANELS_PER_PAGE,
|
434 |
-
Layout3: NB_PANELS_PER_PAGE,
|
435 |
-
// Layout4: NB_PANELS_PER_PAGE
|
436 |
-
}
|
437 |
-
|
438 |
export type LayoutName = keyof typeof allLayouts
|
439 |
|
440 |
export const defaultLayout: LayoutName = "Layout1"
|
|
|
4 |
import { pick } from "@/lib/pick"
|
5 |
import { Grid } from "@/app/interface/grid"
|
6 |
import { LayoutProps } from "@/types"
|
|
|
7 |
|
8 |
export function Layout0({ page, nbPanels }: LayoutProps) {
|
9 |
return (
|
|
|
425 |
// Layout4: "aspect-[1/3]",
|
426 |
}
|
427 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
428 |
export type LayoutName = keyof typeof allLayouts
|
429 |
|
430 |
export const defaultLayout: LayoutName = "Layout1"
|
src/app/main.tsx
CHANGED
@@ -6,7 +6,6 @@ import { cn } from "@/lib/utils"
|
|
6 |
import { fonts } from "@/lib/fonts"
|
7 |
import { GeneratedPanel } from "@/types"
|
8 |
import { joinWords } from "@/lib/joinWords"
|
9 |
-
import { MAX_NB_PAGES } from "@/config"
|
10 |
|
11 |
import { TopMenu } from "./interface/top-menu"
|
12 |
import { useStore } from "./store"
|
@@ -14,27 +13,38 @@ import { Zoom } from "./interface/zoom"
|
|
14 |
import { BottomBar } from "./interface/bottom-bar"
|
15 |
import { Page } from "./interface/page"
|
16 |
import { getStoryContinuation } from "./queries/getStoryContinuation"
|
|
|
17 |
|
18 |
export default function Main() {
|
19 |
const [_isPending, startTransition] = useTransition()
|
20 |
|
21 |
-
const
|
22 |
-
const
|
|
|
23 |
|
24 |
-
const font = useStore(
|
25 |
-
const preset = useStore(
|
26 |
-
const prompt = useStore(
|
27 |
|
28 |
-
const nbPages = useStore(
|
29 |
-
const
|
|
|
|
|
|
|
30 |
|
31 |
-
const setPanels = useStore(
|
32 |
-
const setCaptions = useStore(
|
33 |
|
34 |
-
const zoomLevel = useStore(
|
35 |
|
36 |
const [waitABitMore, setWaitABitMore] = useState(false)
|
37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
// react to prompt changes
|
39 |
useEffect(() => {
|
40 |
if (!prompt) { return }
|
@@ -137,7 +147,7 @@ export default function Main() {
|
|
137 |
*/
|
138 |
|
139 |
})
|
140 |
-
}, [prompt, preset?.label, nbTotalPanels]) // important: we need to react to preset changes too
|
141 |
|
142 |
return (
|
143 |
<div>
|
@@ -163,7 +173,7 @@ export default function Main() {
|
|
163 |
style={{
|
164 |
width: `${zoomLevel}%`
|
165 |
}}>
|
166 |
-
{Array(
|
167 |
</div>
|
168 |
</div>
|
169 |
</div>
|
|
|
6 |
import { fonts } from "@/lib/fonts"
|
7 |
import { GeneratedPanel } from "@/types"
|
8 |
import { joinWords } from "@/lib/joinWords"
|
|
|
9 |
|
10 |
import { TopMenu } from "./interface/top-menu"
|
11 |
import { useStore } from "./store"
|
|
|
13 |
import { BottomBar } from "./interface/bottom-bar"
|
14 |
import { Page } from "./interface/page"
|
15 |
import { getStoryContinuation } from "./queries/getStoryContinuation"
|
16 |
+
import { useDynamicConfig } from "@/lib/useDynamicConfig"
|
17 |
|
18 |
export default function Main() {
|
19 |
const [_isPending, startTransition] = useTransition()
|
20 |
|
21 |
+
const { config, isConfigReady } = useDynamicConfig()
|
22 |
+
const isGeneratingStory = useStore(s => s.isGeneratingStory)
|
23 |
+
const setGeneratingStory = useStore(s => s.setGeneratingStory)
|
24 |
|
25 |
+
const font = useStore(s => s.font)
|
26 |
+
const preset = useStore(s => s.preset)
|
27 |
+
const prompt = useStore(s => s.prompt)
|
28 |
|
29 |
+
const nbPages = useStore(s => s.nbPages)
|
30 |
+
const nbPanelsPerPage = useStore(s => s.nbPanelsPerPage)
|
31 |
+
const nbTotalPanels = useStore(s => s.nbTotalPanels)
|
32 |
+
const setNbPages = useStore(s => s.setNbPages)
|
33 |
+
const setNbPanelsPerPage = useStore(s => s.setNbPanelsPerPage)
|
34 |
|
35 |
+
const setPanels = useStore(s => s.setPanels)
|
36 |
+
const setCaptions = useStore(s => s.setCaptions)
|
37 |
|
38 |
+
const zoomLevel = useStore(s => s.zoomLevel)
|
39 |
|
40 |
const [waitABitMore, setWaitABitMore] = useState(false)
|
41 |
|
42 |
+
useEffect(() => {
|
43 |
+
if (isConfigReady) {
|
44 |
+
setNbPages(config.maxNbPages)
|
45 |
+
setNbPanelsPerPage(config.nbPanelsPerPage)
|
46 |
+
}
|
47 |
+
}, [JSON.stringify(config), isConfigReady])
|
48 |
// react to prompt changes
|
49 |
useEffect(() => {
|
50 |
if (!prompt) { return }
|
|
|
147 |
*/
|
148 |
|
149 |
})
|
150 |
+
}, [prompt, preset?.label, nbPages, nbPanelsPerPage, nbTotalPanels]) // important: we need to react to preset changes too
|
151 |
|
152 |
return (
|
153 |
<div>
|
|
|
173 |
style={{
|
174 |
width: `${zoomLevel}%`
|
175 |
}}>
|
176 |
+
{Array(nbPages).fill(0).map((_, i) => <Page key={i} page={i} />)}
|
177 |
</div>
|
178 |
</div>
|
179 |
</div>
|
src/app/queries/getDynamicConfig.ts
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use server"
|
2 |
+
|
3 |
+
import { getValidBoolean } from "@/lib/getValidBoolean"
|
4 |
+
import { getValidNumber } from "@/lib/getValidNumber"
|
5 |
+
import { getValidString } from "@/lib/getValidString"
|
6 |
+
import { DynamicConfig } from "@/types"
|
7 |
+
|
8 |
+
export async function getDynamicConfig(): Promise<DynamicConfig> {
|
9 |
+
const maxNbPages = getValidNumber(process.env.MAX_NB_PAGES, 1, 16, 1)
|
10 |
+
const nbPanelsPerPage = 4
|
11 |
+
const nbTotalPanelsToGenerate = maxNbPages * nbPanelsPerPage
|
12 |
+
|
13 |
+
const config = {
|
14 |
+
maxNbPages,
|
15 |
+
nbPanelsPerPage,
|
16 |
+
nbTotalPanelsToGenerate,
|
17 |
+
oauthClientId: getValidString(process.env.HUGGING_FACE_OAUTH_CLIENT_ID, ""),
|
18 |
+
oauthRedirectUrl: getValidString(process.env.HUGGING_FACE_OAUTH_REDIRECT_URL, ""),
|
19 |
+
oauthScopes: "openid profile inference-api",
|
20 |
+
enableHuggingFaceOAuth: getValidBoolean(process.env.ENABLE_HUGGING_FACE_OAUTH, false),
|
21 |
+
enableHuggingFaceOAuthWall: getValidBoolean(process.env.ENABLE_HUGGING_FACE_OAUTH_WALL, false),
|
22 |
+
}
|
23 |
+
|
24 |
+
return config
|
25 |
+
}
|
src/app/store/index.ts
CHANGED
@@ -7,12 +7,12 @@ import { FontName } from "@/lib/fonts"
|
|
7 |
import { Preset, PresetName, defaultPreset, getPreset, getRandomPreset } from "@/app/engine/presets"
|
8 |
import { RenderedScene } from "@/types"
|
9 |
import { LayoutName, defaultLayout, getRandomLayoutName } from "../layouts"
|
10 |
-
import { MAX_NB_PAGES, NB_PANELS_PER_PAGE } from "@/config"
|
11 |
|
12 |
export const useStore = create<{
|
13 |
prompt: string
|
14 |
font: FontName
|
15 |
preset: Preset
|
|
|
16 |
nbPages: number
|
17 |
nbTotalPanels: number
|
18 |
panels: string[]
|
@@ -28,6 +28,9 @@ export const useStore = create<{
|
|
28 |
panelGenerationStatus: Record<number, boolean>
|
29 |
isGeneratingText: boolean
|
30 |
atLeastOnePanelIsBusy: boolean
|
|
|
|
|
|
|
31 |
setRendered: (panelId: string, renderedScene: RenderedScene) => void
|
32 |
addToUpscaleQueue: (panelId: string, renderedScene: RenderedScene) => void
|
33 |
removeFromUpscaleQueue: (panelId: string) => void
|
@@ -53,11 +56,9 @@ export const useStore = create<{
|
|
53 |
prompt: "",
|
54 |
font: "actionman",
|
55 |
preset: getPreset(defaultPreset),
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
nbTotalPanels: NB_PANELS_PER_PAGE * MAX_NB_PAGES,
|
60 |
-
|
61 |
panels: [],
|
62 |
captions: [],
|
63 |
upscaleQueue: {} as Record<string, RenderedScene>,
|
@@ -71,6 +72,25 @@ export const useStore = create<{
|
|
71 |
panelGenerationStatus: {},
|
72 |
isGeneratingText: false,
|
73 |
atLeastOnePanelIsBusy: false,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
setRendered: (panelId: string, renderedScene: RenderedScene) => {
|
75 |
const { renderedScenes } = get()
|
76 |
set({
|
|
|
7 |
import { Preset, PresetName, defaultPreset, getPreset, getRandomPreset } from "@/app/engine/presets"
|
8 |
import { RenderedScene } from "@/types"
|
9 |
import { LayoutName, defaultLayout, getRandomLayoutName } from "../layouts"
|
|
|
10 |
|
11 |
export const useStore = create<{
|
12 |
prompt: string
|
13 |
font: FontName
|
14 |
preset: Preset
|
15 |
+
nbPanelsPerPage: number
|
16 |
nbPages: number
|
17 |
nbTotalPanels: number
|
18 |
panels: string[]
|
|
|
28 |
panelGenerationStatus: Record<number, boolean>
|
29 |
isGeneratingText: boolean
|
30 |
atLeastOnePanelIsBusy: boolean
|
31 |
+
setNbPanelsPerPage: (nbPanelsPerPage: number) => void
|
32 |
+
setNbPages: (nbPages: number) => void
|
33 |
+
setTotalPanels: (nbTotalPanels: number) => void
|
34 |
setRendered: (panelId: string, renderedScene: RenderedScene) => void
|
35 |
addToUpscaleQueue: (panelId: string, renderedScene: RenderedScene) => void
|
36 |
removeFromUpscaleQueue: (panelId: string) => void
|
|
|
56 |
prompt: "",
|
57 |
font: "actionman",
|
58 |
preset: getPreset(defaultPreset),
|
59 |
+
nbPanelsPerPage: 4,
|
60 |
+
nbPages: 1,
|
61 |
+
nbTotalPanels: 4,
|
|
|
|
|
62 |
panels: [],
|
63 |
captions: [],
|
64 |
upscaleQueue: {} as Record<string, RenderedScene>,
|
|
|
72 |
panelGenerationStatus: {},
|
73 |
isGeneratingText: false,
|
74 |
atLeastOnePanelIsBusy: false,
|
75 |
+
setNbPanelsPerPage: (nbPanelsPerPage: number) => {
|
76 |
+
const { nbPages } = get()
|
77 |
+
set({
|
78 |
+
nbPanelsPerPage,
|
79 |
+
nbTotalPanels: nbPanelsPerPage * nbPages,
|
80 |
+
})
|
81 |
+
},
|
82 |
+
setNbPages: (nbPages: number) => {
|
83 |
+
const { nbPanelsPerPage } = get()
|
84 |
+
set({
|
85 |
+
nbPages,
|
86 |
+
nbTotalPanels: nbPanelsPerPage * nbPages,
|
87 |
+
})
|
88 |
+
},
|
89 |
+
setTotalPanels: (nbTotalPanels: number) => {
|
90 |
+
set({
|
91 |
+
nbTotalPanels,
|
92 |
+
})
|
93 |
+
},
|
94 |
setRendered: (panelId: string, renderedScene: RenderedScene) => {
|
95 |
const { renderedScenes } = get()
|
96 |
set({
|
src/components/ui/dialog.tsx
CHANGED
@@ -47,10 +47,11 @@ const DialogContent = React.forwardRef<
|
|
47 |
{...props}
|
48 |
>
|
49 |
{children}
|
50 |
-
|
51 |
<X className="h-4 w-4" />
|
52 |
<span className="sr-only">Close</span>
|
53 |
</DialogPrimitive.Close>
|
|
|
54 |
</DialogPrimitive.Content>
|
55 |
</DialogPortal>
|
56 |
))
|
|
|
47 |
{...props}
|
48 |
>
|
49 |
{children}
|
50 |
+
{/*<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-stone-400 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-stone-100 data-[state=open]:text-stone-500 dark:ring-offset-stone-950 dark:focus:ring-stone-800 dark:data-[state=open]:bg-stone-800 dark:data-[state=open]:text-stone-400">
|
51 |
<X className="h-4 w-4" />
|
52 |
<span className="sr-only">Close</span>
|
53 |
</DialogPrimitive.Close>
|
54 |
+
*/}
|
55 |
</DialogPrimitive.Content>
|
56 |
</DialogPortal>
|
57 |
))
|
src/config.ts
DELETED
@@ -1,8 +0,0 @@
|
|
1 |
-
import { getValidNumber } from "./lib/getValidNumber"
|
2 |
-
|
3 |
-
export const MAX_NB_PAGES = getValidNumber(process.env.NEXT_PUBLIC_MAX_NB_PAGES, 1, 8, 1)
|
4 |
-
|
5 |
-
// TODO: this one should be dynamic and depend upon the page layout type
|
6 |
-
export const NB_PANELS_PER_PAGE = 4
|
7 |
-
|
8 |
-
export const NB_TOTAL_PANELS_TO_GENERATE = MAX_NB_PAGES * NB_PANELS_PER_PAGE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/getDefaultDynamicConfig.ts
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { DynamicConfig } from "@/types"
|
2 |
+
|
3 |
+
export const getDefaultDynamicConfig = (): DynamicConfig => ({
|
4 |
+
maxNbPages: 1,
|
5 |
+
nbPanelsPerPage: 4,
|
6 |
+
nbTotalPanelsToGenerate: 4,
|
7 |
+
oauthClientId: "",
|
8 |
+
oauthRedirectUrl: "http://localhost:3000",
|
9 |
+
oauthScopes: "openid profile inference-api",
|
10 |
+
enableHuggingFaceOAuth: false,
|
11 |
+
enableHuggingFaceOAuthWall: false,
|
12 |
+
})
|
src/lib/getValidString.ts
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
export function getValidString(something: any, defaultValue: string) {
|
2 |
const strValue = `${something || defaultValue}`
|
3 |
try {
|
4 |
-
return JSON.parse(strValue)
|
5 |
} catch (err) {
|
6 |
-
return
|
7 |
}
|
8 |
}
|
|
|
1 |
export function getValidString(something: any, defaultValue: string) {
|
2 |
const strValue = `${something || defaultValue}`
|
3 |
try {
|
4 |
+
return JSON.parse(strValue)
|
5 |
} catch (err) {
|
6 |
+
return strValue
|
7 |
}
|
8 |
}
|
src/lib/useDynamicConfig.ts
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use client"
|
2 |
+
|
3 |
+
import { useEffect, useState, useTransition } from "react"
|
4 |
+
|
5 |
+
import { getDynamicConfig } from "@/app/queries/getDynamicConfig"
|
6 |
+
import { DynamicConfig } from "@/types"
|
7 |
+
|
8 |
+
import { getDefaultDynamicConfig } from "./getDefaultDynamicConfig"
|
9 |
+
|
10 |
+
export function useDynamicConfig(): {
|
11 |
+
config: DynamicConfig;
|
12 |
+
isConfigReady: boolean;
|
13 |
+
} {
|
14 |
+
const [_isPending, startTransition] = useTransition()
|
15 |
+
const [config, setConfig] = useState<DynamicConfig>(getDefaultDynamicConfig())
|
16 |
+
const [isConfigReady, setConfigReady] = useState(false)
|
17 |
+
|
18 |
+
useEffect(() => {
|
19 |
+
startTransition(async () => {
|
20 |
+
if (isConfigReady) { return }
|
21 |
+
const newConfig = await getDynamicConfig()
|
22 |
+
setConfig(newConfig)
|
23 |
+
setConfigReady(true)
|
24 |
+
})
|
25 |
+
}, [isConfigReady])
|
26 |
+
|
27 |
+
return {
|
28 |
+
config,
|
29 |
+
isConfigReady
|
30 |
+
}
|
31 |
+
}
|
src/lib/useOAuth.ts
CHANGED
@@ -1,13 +1,12 @@
|
|
1 |
"use client"
|
2 |
|
3 |
-
import {
|
4 |
import { useSearchParams } from "next/navigation"
|
5 |
-
import {
|
6 |
-
|
7 |
-
import { useOAuthEnabled } from "./useOAuthEnabled"
|
8 |
-
import { useBetaEnabled } from "./useBetaEnabled"
|
9 |
import { usePersistedOAuth } from "./usePersistedOAuth"
|
10 |
import { getValidOAuth } from "./getValidOAuth"
|
|
|
11 |
|
12 |
export function useOAuth({
|
13 |
debug = false
|
@@ -22,23 +21,27 @@ export function useOAuth({
|
|
22 |
canLogin: boolean
|
23 |
login: () => Promise<void>
|
24 |
isLoggedIn: boolean
|
|
|
|
|
25 |
oauthResult?: OAuthResult
|
26 |
} {
|
27 |
-
const
|
28 |
|
29 |
-
const
|
30 |
-
const redirectUrl = "https://huggingface.co/spaces/jbilcke-hf/ai-comic-factory"
|
31 |
-
const scopes = "openid profile inference-api"
|
32 |
|
33 |
-
const
|
|
|
|
|
|
|
|
|
34 |
|
35 |
const searchParams = useSearchParams()
|
36 |
-
const code = searchParams
|
37 |
-
const state = searchParams
|
38 |
|
39 |
const hasReceivedFreshOAuth = Boolean(code && state)
|
40 |
|
41 |
-
const canLogin: boolean = Boolean(clientId &&
|
42 |
const isLoggedIn = Boolean(oauthResult)
|
43 |
|
44 |
if (debug) {
|
@@ -47,7 +50,8 @@ export function useOAuth({
|
|
47 |
clientId,
|
48 |
redirectUrl,
|
49 |
scopes,
|
50 |
-
|
|
|
51 |
code,
|
52 |
state,
|
53 |
hasReceivedFreshOAuth,
|
@@ -128,6 +132,8 @@ export function useOAuth({
|
|
128 |
canLogin,
|
129 |
login,
|
130 |
isLoggedIn,
|
|
|
|
|
131 |
oauthResult
|
132 |
}
|
133 |
}
|
|
|
1 |
"use client"
|
2 |
|
3 |
+
import { useEffect } from "react"
|
4 |
import { useSearchParams } from "next/navigation"
|
5 |
+
import { OAuthResult, oauthHandleRedirectIfPresent, oauthLoginUrl } from "@huggingface/hub"
|
6 |
+
|
|
|
|
|
7 |
import { usePersistedOAuth } from "./usePersistedOAuth"
|
8 |
import { getValidOAuth } from "./getValidOAuth"
|
9 |
+
import { useDynamicConfig } from "./useDynamicConfig"
|
10 |
|
11 |
export function useOAuth({
|
12 |
debug = false
|
|
|
21 |
canLogin: boolean
|
22 |
login: () => Promise<void>
|
23 |
isLoggedIn: boolean
|
24 |
+
enableOAuth: boolean
|
25 |
+
enableOAuthWall: boolean
|
26 |
oauthResult?: OAuthResult
|
27 |
} {
|
28 |
+
const { config, isConfigReady } = useDynamicConfig()
|
29 |
|
30 |
+
const [oauthResult, setOAuthResult] = usePersistedOAuth()
|
|
|
|
|
31 |
|
32 |
+
const clientId = config.oauthClientId
|
33 |
+
const redirectUrl = config.oauthRedirectUrl
|
34 |
+
const scopes = config.oauthScopes
|
35 |
+
const enableOAuth = config.enableHuggingFaceOAuth
|
36 |
+
const enableOAuthWall = config.enableHuggingFaceOAuthWall
|
37 |
|
38 |
const searchParams = useSearchParams()
|
39 |
+
const code = searchParams?.get("code") || ""
|
40 |
+
const state = searchParams?.get("state") || ""
|
41 |
|
42 |
const hasReceivedFreshOAuth = Boolean(code && state)
|
43 |
|
44 |
+
const canLogin: boolean = Boolean(isConfigReady && clientId && enableOAuth)
|
45 |
const isLoggedIn = Boolean(oauthResult)
|
46 |
|
47 |
if (debug) {
|
|
|
50 |
clientId,
|
51 |
redirectUrl,
|
52 |
scopes,
|
53 |
+
enableOAuth,
|
54 |
+
enableOAuthWall,
|
55 |
code,
|
56 |
state,
|
57 |
hasReceivedFreshOAuth,
|
|
|
132 |
canLogin,
|
133 |
login,
|
134 |
isLoggedIn,
|
135 |
+
enableOAuth,
|
136 |
+
enableOAuthWall,
|
137 |
oauthResult
|
138 |
}
|
139 |
}
|
src/lib/useOAuthClientId.ts
DELETED
@@ -1,6 +0,0 @@
|
|
1 |
-
"use client"
|
2 |
-
|
3 |
-
export function useOAuthClientId(): string {
|
4 |
-
const oauthClientId = `${process.env.NEXT_PUBLIC_HUGGING_FACE_OAUTH_CLIENT_ID || ""}`
|
5 |
-
return oauthClientId
|
6 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/useOAuthEnabled.ts
DELETED
@@ -1,6 +0,0 @@
|
|
1 |
-
"use client"
|
2 |
-
|
3 |
-
export function useOAuthEnabled(): boolean {
|
4 |
-
const isOAuthEnabled = `${process.env.NEXT_PUBLIC_ENABLE_HUGGING_FACE_OAUTH || "false"}` === "true"
|
5 |
-
return isOAuthEnabled
|
6 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/types.ts
CHANGED
@@ -174,4 +174,15 @@ export type Settings = {
|
|
174 |
groqApiKey: string
|
175 |
groqApiLanguageModel: string
|
176 |
hasGeneratedAtLeastOnce: boolean
|
177 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
groqApiKey: string
|
175 |
groqApiLanguageModel: string
|
176 |
hasGeneratedAtLeastOnce: boolean
|
177 |
+
}
|
178 |
+
|
179 |
+
export type DynamicConfig = {
|
180 |
+
maxNbPages: number
|
181 |
+
nbPanelsPerPage: number
|
182 |
+
nbTotalPanelsToGenerate: number
|
183 |
+
oauthClientId: string
|
184 |
+
oauthRedirectUrl: string
|
185 |
+
oauthScopes: string
|
186 |
+
enableHuggingFaceOAuth: boolean
|
187 |
+
enableHuggingFaceOAuthWall: boolean
|
188 |
+
}
|