jbilcke-hf HF staff commited on
Commit
a296341
β€’
1 Parent(s): a5e4a1b

working to fix the config

Browse files
.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
- NEXT_PUBLIC_MAX_NB_PAGES=
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
- NEXT_PUBLIC_ENABLE_HUGGING_FACE_OAUTH=
24
- NEXT_PUBLIC_ENABLE_HUGGING_FACE_OAUTH_WALL=
25
- NEXT_PUBLIC_HUGGING_FACE_OAUTH_CLIENT_ID=""
26
- HUGGING_FACE_OAUTH_SECRET=""
 
 
 
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
- import { allLayoutAspectRatios, allLayouts, allLayoutsNbPanels } from "@/app/layouts"
 
 
 
 
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 nbPanels = ((allLayoutsNbPanels as any)[layout] as number) || 4
18
- const nbPages = Math.round(nbPanels / NB_PANELS_PER_PAGE)
 
 
 
 
 
 
 
 
 
 
 
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 && <p className="w-full text-center pt-4 font-sans text-2xs font-semibold text-stone-600">Page {page + 1} / {nbPages}</p>}
 
 
 
 
 
 
 
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
- const enableAuthWall = `${process.env.NEXT_PUBLIC_ENABLE_HUGGING_FACE_OAUTH_WALL || "false"}` === "true"
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 isGeneratingStory = useStore(state => state.isGeneratingStory)
22
- const setGeneratingStory = useStore(state => state.setGeneratingStory)
 
23
 
24
- const font = useStore(state => state.font)
25
- const preset = useStore(state => state.preset)
26
- const prompt = useStore(state => state.prompt)
27
 
28
- const nbPages = useStore(state => state.nbPages)
29
- const nbTotalPanels = useStore(state => state.nbTotalPanels)
 
 
 
30
 
31
- const setPanels = useStore(state => state.setPanels)
32
- const setCaptions = useStore(state => state.setCaptions)
33
 
34
- const zoomLevel = useStore(state => state.zoomLevel)
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(MAX_NB_PAGES).fill(0).map((_, i) => <Page key={i} page={i} />)}
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
- nbPages: MAX_NB_PAGES,
57
-
58
- // TODO: make this dynamic!
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
- <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
  </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) || defaultValue
5
  } catch (err) {
6
- return defaultValue
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 { OAuthResult, oauthHandleRedirectIfPresent, oauthLoginUrl } from "@huggingface/hub"
4
  import { useSearchParams } from "next/navigation"
5
- import { useEffect, useState } from "react"
6
- import { useOAuthClientId } from "./useOAuthClientId"
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 [oauthResult, setOAuthResult] = usePersistedOAuth()
28
 
29
- const clientId = useOAuthClientId()
30
- const redirectUrl = "https://huggingface.co/spaces/jbilcke-hf/ai-comic-factory"
31
- const scopes = "openid profile inference-api"
32
 
33
- const isOAuthEnabled = useOAuthEnabled()
 
 
 
 
34
 
35
  const searchParams = useSearchParams()
36
- const code = searchParams.get("code")
37
- const state = searchParams.get("state")
38
 
39
  const hasReceivedFreshOAuth = Boolean(code && state)
40
 
41
- const canLogin: boolean = Boolean(clientId && isOAuthEnabled)
42
  const isLoggedIn = Boolean(oauthResult)
43
 
44
  if (debug) {
@@ -47,7 +50,8 @@ export function useOAuth({
47
  clientId,
48
  redirectUrl,
49
  scopes,
50
- isOAuthEnabled,
 
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
+ }