jbilcke-hf HF staff commited on
Commit
4905b6b
1 Parent(s): 660842c

use stable cascade

Browse files
.env CHANGED
@@ -4,11 +4,4 @@ HF_INFERENCE_API_BASE_MODEL="stabilityai/stable-diffusion-xl-base-1.0"
4
  HF_INFERENCE_API_REFINER_MODEL="stabilityai/stable-diffusion-xl-refiner-1.0"
5
  HF_INFERENCE_API_MODEL_TRIGGER=""
6
  HF_INFERENCE_API_FILE_TYPE="image/png"
7
-
8
- STABLE_CASCADE_API_GRADIO_TOKEN="<USE YOUR OWN>"
9
-
10
- IMAGE_UPSCALING_API_GRADIO_URL="https://jbilcke-hf-image-upscaling-api.hf.space"
11
- IMAGE_UPSCALING_API_GRADIO_TOKEN="<USE YOUR OWN>"
12
-
13
- BACKGROUND_REMOVAL_API_GRADIO_URL="https://jbilcke-hf-background-removal-api.hf.space"
14
- BACKGROUND_REMOVAL_API_GRADIO_TOKEN="<USE YOUR OWN>"
 
4
  HF_INFERENCE_API_REFINER_MODEL="stabilityai/stable-diffusion-xl-refiner-1.0"
5
  HF_INFERENCE_API_MODEL_TRIGGER=""
6
  HF_INFERENCE_API_FILE_TYPE="image/png"
7
+ MICROSERVICE_API_SECRET_TOKEN="<USE YOUR OWN>"
 
 
 
 
 
 
 
README.md CHANGED
@@ -1,52 +1,10 @@
1
  ---
2
- title: AI Clip Factory
3
- emoji: 🧞
4
- colorFrom: yellow
5
- colorTo: purple
6
- sdk: docker
7
  pinned: true
8
- app_port: 3000
9
- disable_embedding: true
10
- hf_oauth_redirect_path: /api/oauth/callback
11
  ---
12
 
13
- # The AI Clip Factory
14
-
15
- The AI Clip Factory is a space to create animated videos in an ultra simple and fun way. It is meant to be a child's play.
16
-
17
- ## Text-to-video model
18
-
19
- The AI Clip Factory is a space about clip generation and providing a fun UI, and is not meant to promote a specific AI model.
20
-
21
- As a consequence, a model currently defined as default may be replaced at anytime by a newer SOTA model.
22
-
23
- Right now (2023-10-19) the default model is the base Hotshot-XL (use the official website for faster inference at [https://hotshot.co](https://hotshot.co)).
24
-
25
- # Interpolation model
26
-
27
- The default model used for interpolation is [ST-MFNet](https://github.com/zsxkib/ST-MFNet)
28
-
29
- ## Setup
30
-
31
- If you run the app locally you need to create a `.env.local` file
32
- (If you deploy to Hugging Face, just set the environment variable from the settings)
33
-
34
- ### Video rendering engine
35
-
36
- Note: the app is in heavy development, not all backends are supported
37
-
38
- Set `VIDEO_ENGINE` to one of:
39
-
40
- - `VIDEO_ENGINE="VIDEO_HOTSHOT_XL_API_GRADIO"`
41
- - `VIDEO_ENGINE="VIDEO_HOTSHOT_XL_API_REPLICATE"`
42
- - `VIDEO_ENGINE="VIDEO_HOTSHOT_XL_API_NODE"` <- not working yet
43
- - `VIDEO_ENGINE="VIDEO_HOTSHOT_XL_API_OFFICIAL"` <- not working yet
44
-
45
-
46
- ### Authentication
47
-
48
- If you intent to use a special provider (eg. Replicate) you need to setup your token
49
-
50
- - `AUTH_REPLICATE_API_TOKEN="<YOUR SECRET>"`
51
-
52
-
 
1
  ---
2
+ title: Illustrateur (cloud)
3
+ emoji:
4
+ colorFrom: purple
5
+ colorTo: green
 
6
  pinned: true
7
+ header: mini
 
 
8
  ---
9
 
10
+ This is the "cloud" version of Illustrateur, which means you do not need a GPU in your laptop!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
next.config.js CHANGED
@@ -1,6 +1,12 @@
1
  /** @type {import('next').NextConfig} */
2
  const nextConfig = {
3
  output: 'standalone',
 
 
 
 
 
 
4
  }
5
 
6
  module.exports = nextConfig
 
1
  /** @type {import('next').NextConfig} */
2
  const nextConfig = {
3
  output: 'standalone',
4
+
5
+ experimental: {
6
+ serverActions: {
7
+ bodySizeLimit: '10mb'
8
+ }
9
+ }
10
  }
11
 
12
  module.exports = nextConfig
src/app/main.tsx CHANGED
@@ -20,11 +20,14 @@ import { SliderField } from '@/components/form/slider-field'
20
  import { Toaster } from '@/components/ui/sonner'
21
  import { cn } from '@/lib/utils'
22
  import { CharacterExpression, CharacterGender, CharacterPose, MIN_AGE, DEFAULT_AGE, MAX_AGE, DEFAULT_WEIGHT, GenerationMode, HairColor, HairStyle, PhotoshootMode, characterExpressions, characterGenders, characterPoses, hairColors, hairStyles, photoshootModes } from '../lib/config'
23
- import { getGenerationParams } from '@/lib/getGenerationParams'
24
- import { generate } from './server/generate'
 
 
25
  import { generateSeed } from '@/lib/generateSeed'
26
  import { BackgroundRemovalParams, GenerationStatus, UpscalingParams } from '@/types'
27
  import { removeBackground } from './server/background'
 
28
 
29
  /*
30
  Maybe we should use this classification instead:
@@ -47,19 +50,21 @@ export function Main() {
47
  )
48
  const [characterWeight, setCharacterWeight] = useState(DEFAULT_WEIGHT)
49
  const [characterHairStyle, setCharacterHairStyle] = useState<HairStyle>(
50
- "Cornrows" // pick<HairStyle>(hairStyles)
51
  )
52
  const [characterHairColor, setCharacterHairColor] = useState<HairColor>(
53
- "braids" // pick<HairColor>(hairColors)
54
  )
55
  const [characterExpression, setCharacterExpression] = useState<CharacterExpression>("neutral")
56
  const [characterPose, setCharacterPose] = useState<CharacterPose>("side-on pose")
57
- const [photoshootMode, setPhotoshootMode] = useState<PhotoshootMode>(photoshootModes[1])
58
 
59
  const [prompt, setPrompt] = useState('llamacookie')
60
  const [negativePrompt, setNegativePrompt] = useState('')
61
  const [inferenceSteps, setInferenceSteps] = useState(20)
62
- const [guidanceScale, setGuidanceScale] = useState(5)
 
 
63
  const [seed, setSeed] = useState('')
64
  const [strength, setStrength] = useState(0.8)
65
  const [runVaeOnEachStep, setRunVaeOnEachStep] = useState(false)
@@ -73,7 +78,8 @@ export function Main() {
73
 
74
  const showAdvancedSettings = true
75
 
76
- const generationParams = getGenerationParams({
 
77
  generationMode,
78
  negativePrompt,
79
  characterAge,
@@ -85,21 +91,6 @@ export function Main() {
85
  characterPose
86
  })
87
 
88
- const upscalingParams: UpscalingParams = {
89
- imageAsBase64: "",
90
- prompt: generationParams.prompt,
91
- negativePrompt: generationParams.negativePrompt,
92
- scaleFactor: 2,
93
- seed: generateSeed(),
94
-
95
- // // for a single image we can afford a higher rate, such as 25
96
- nbSteps: 25,
97
- }
98
-
99
- const backgroundRemovalParams: BackgroundRemovalParams = {
100
- imageAsBase64: ""
101
- }
102
-
103
  const onDraw = async () => {
104
  console.log("onRender")
105
 
@@ -107,53 +98,80 @@ export function Main() {
107
  let upscaledImageUrl = ""
108
  let croppedImageUrl = ""
109
 
110
- // startTransition(() => {
111
- setStatus("generating")
112
- setBaseImageUrl(baseImageUrl)
113
- setUpscaledImageUrl(upscaledImageUrl)
114
- setCroppedImageUrl(croppedImageUrl)
115
- // })
116
 
117
  try {
118
- baseImageUrl = await generate(generationParams)
 
119
  } catch (err) {
120
  console.error(`failed to generate:`, err)
121
  }
122
 
123
  if (!baseImageUrl) {
124
- // startTransition(() => {
125
- setStatus("error")
126
- // })
127
-
128
  return
129
  }
130
 
131
- // startTransition(() => {
132
- setBaseImageUrl(baseImageUrl)
133
- // })
134
 
 
135
  try {
136
  croppedImageUrl = await removeBackground({
137
- ...backgroundRemovalParams,
138
  imageAsBase64: baseImageUrl,
139
  })
140
  } catch (err) {
141
- console.error(`failed to crop:`, err)
142
  }
143
 
144
  if (!croppedImageUrl) {
145
- // startTransition(() => {
146
- setStatus( "error")
147
- // })
148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  return
150
  }
151
 
152
- // startTransition(() => {
153
- setCroppedImageUrl(croppedImageUrl)
154
- setStatus("finished")
155
- // })
156
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  }
158
 
159
  const isBusy = status === "generating" || status === "cropping" || status === "upscaling"
@@ -343,13 +361,13 @@ export function Main() {
343
  label="Guidance Scale"
344
  type='number'
345
  min={1}
346
- max={20}
347
- step={0.5}
348
  // disabled={modelState != 'ready'}
349
  onChange={(e) => setGuidanceScale(parseFloat(e.target.value))}
350
  value={guidanceScale}
351
  className={cn({
352
- hidden: !showAdvancedSettings
353
  })}
354
  />
355
  <SliderField
@@ -418,7 +436,7 @@ export function Main() {
418
  defaultValue={[inferenceSteps]}
419
  value={[inferenceSteps]}
420
  className={cn({
421
- hidden: !showAdvancedSettings
422
  })}
423
  />
424
 
@@ -432,7 +450,7 @@ export function Main() {
432
  onChange={(e) => setGuidanceScale(parseFloat(e.target.value))}
433
  value={guidanceScale}
434
  className={cn({
435
- hidden: !showAdvancedSettings
436
  })}
437
  />
438
  {/*
 
20
  import { Toaster } from '@/components/ui/sonner'
21
  import { cn } from '@/lib/utils'
22
  import { CharacterExpression, CharacterGender, CharacterPose, MIN_AGE, DEFAULT_AGE, MAX_AGE, DEFAULT_WEIGHT, GenerationMode, HairColor, HairStyle, PhotoshootMode, characterExpressions, characterGenders, characterPoses, hairColors, hairStyles, photoshootModes } from '../lib/config'
23
+ import { getStableDiffusionParams } from '@/lib/getStableDiffusionParams'
24
+ import { getStableCascadeParams } from '@/lib/getStableCascadeParams'
25
+ import { stableDiffusion } from './server/stableDiffusion'
26
+ import { stableCascade } from './server/stableCascade'
27
  import { generateSeed } from '@/lib/generateSeed'
28
  import { BackgroundRemovalParams, GenerationStatus, UpscalingParams } from '@/types'
29
  import { removeBackground } from './server/background'
30
+ import { upscale } from './server/upscale'
31
 
32
  /*
33
  Maybe we should use this classification instead:
 
50
  )
51
  const [characterWeight, setCharacterWeight] = useState(DEFAULT_WEIGHT)
52
  const [characterHairStyle, setCharacterHairStyle] = useState<HairStyle>(
53
+ "Braids" // pick<HairStyle>(hairStyles)
54
  )
55
  const [characterHairColor, setCharacterHairColor] = useState<HairColor>(
56
+ "chesnut" // pick<HairColor>(hairColors)
57
  )
58
  const [characterExpression, setCharacterExpression] = useState<CharacterExpression>("neutral")
59
  const [characterPose, setCharacterPose] = useState<CharacterPose>("side-on pose")
60
+ const [photoshootMode, setPhotoshootMode] = useState<PhotoshootMode>(photoshootModes[0])
61
 
62
  const [prompt, setPrompt] = useState('llamacookie')
63
  const [negativePrompt, setNegativePrompt] = useState('')
64
  const [inferenceSteps, setInferenceSteps] = useState(20)
65
+ const [nbPriorInferenceSteps, setNbPriorInferenceSteps] = useState(20)
66
+ const [nbDecoderInferenceSteps, setNbDecoderInferenceSteps] = useState(10)
67
+ const [guidanceScale, setGuidanceScale] = useState(4)
68
  const [seed, setSeed] = useState('')
69
  const [strength, setStrength] = useState(0.8)
70
  const [runVaeOnEachStep, setRunVaeOnEachStep] = useState(false)
 
78
 
79
  const showAdvancedSettings = true
80
 
81
+ const stableCascadeParams = getStableCascadeParams({
82
+ prompt,
83
  generationMode,
84
  negativePrompt,
85
  characterAge,
 
91
  characterPose
92
  })
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  const onDraw = async () => {
95
  console.log("onRender")
96
 
 
98
  let upscaledImageUrl = ""
99
  let croppedImageUrl = ""
100
 
101
+ setStatus("generating")
102
+ setBaseImageUrl(baseImageUrl)
103
+ setUpscaledImageUrl(upscaledImageUrl)
104
+ setCroppedImageUrl(croppedImageUrl)
 
 
105
 
106
  try {
107
+ // baseImageUrl = await stableDiffusion(stableDiffusionParams)
108
+ baseImageUrl = await stableCascade(stableCascadeParams)
109
  } catch (err) {
110
  console.error(`failed to generate:`, err)
111
  }
112
 
113
  if (!baseImageUrl) {
114
+ setStatus("error")
 
 
 
115
  return
116
  }
117
 
118
+ setBaseImageUrl(baseImageUrl)
 
 
119
 
120
+ /*
121
  try {
122
  croppedImageUrl = await removeBackground({
 
123
  imageAsBase64: baseImageUrl,
124
  })
125
  } catch (err) {
126
+ console.error(`failed to crop the low-resolution image:`, err)
127
  }
128
 
129
  if (!croppedImageUrl) {
130
+ setStatus( "error")
131
+ return
132
+ }
133
 
134
+ setCroppedImageUrl(croppedImageUrl)
135
+ */
136
+ setStatus("upscaling")
137
+
138
+ try {
139
+ upscaledImageUrl = await upscale({
140
+ imageAsBase64: baseImageUrl,
141
+ prompt: stableCascadeParams.prompt,
142
+ negativePrompt: stableCascadeParams.negativePrompt,
143
+ scaleFactor: 2,
144
+ seed: generateSeed(),
145
+
146
+ // // for a single image we can afford a higher rate, such as 25
147
+ nbSteps: 20,
148
+ })
149
+ } catch (err) {
150
+ console.error(`failed to upscale:`, err)
151
+ }
152
+
153
+ if (!upscaledImageUrl) {
154
+ setStatus( "error")
155
  return
156
  }
157
 
158
+ setUpscaledImageUrl(upscaledImageUrl)
 
 
 
159
 
160
+ try {
161
+ croppedImageUrl = await removeBackground({
162
+ imageAsBase64: upscaledImageUrl,
163
+ })
164
+ } catch (err) {
165
+ console.error(`failed to crop the upscaled image:`, err)
166
+ }
167
+
168
+ if (!croppedImageUrl) {
169
+ setStatus( "error")
170
+ return
171
+ }
172
+
173
+ setCroppedImageUrl(croppedImageUrl)
174
+ setStatus("finished")
175
  }
176
 
177
  const isBusy = status === "generating" || status === "cropping" || status === "upscaling"
 
361
  label="Guidance Scale"
362
  type='number'
363
  min={1}
364
+ max={15}
365
+ step={0.1}
366
  // disabled={modelState != 'ready'}
367
  onChange={(e) => setGuidanceScale(parseFloat(e.target.value))}
368
  value={guidanceScale}
369
  className={cn({
370
+ hidden: true, // !showAdvancedSettings
371
  })}
372
  />
373
  <SliderField
 
436
  defaultValue={[inferenceSteps]}
437
  value={[inferenceSteps]}
438
  className={cn({
439
+ hidden: true, // !showAdvancedSettings
440
  })}
441
  />
442
 
 
450
  onChange={(e) => setGuidanceScale(parseFloat(e.target.value))}
451
  value={guidanceScale}
452
  className={cn({
453
+ hidden: true, // !showAdvancedSettings
454
  })}
455
  />
456
  {/*
src/app/server/background.ts CHANGED
@@ -1,14 +1,15 @@
1
  "use server"
2
 
3
  import { BackgroundRemovalParams } from "@/types"
 
4
  import { addBase64HeaderToPng } from "./addBase64HeaderToPng"
5
 
6
- const gradioApi = `${process.env.BACKGROUND_REMOVAL_API_GRADIO_URL || ""}`
7
- const accessToken = `${process.env.BACKGROUND_REMOVAL_API_GRADIO_TOKEN || ""}`
8
 
9
- export const removeBackground = async ({
10
  imageAsBase64,
11
- }: BackgroundRemovalParams): Promise<string> => {
12
 
13
  // remember: a space needs to be public for the classic fetch() to work
14
  const res = await fetch(gradioApi + (gradioApi.endsWith("/") ? "" : "/") + "api/predict", {
@@ -20,7 +21,7 @@ export const removeBackground = async ({
20
  body: JSON.stringify({
21
  fn_index: 0, // <- is it 0 or 1?
22
  data: [
23
- accessToken,
24
  imageAsBase64,
25
  ],
26
  }),
 
1
  "use server"
2
 
3
  import { BackgroundRemovalParams } from "@/types"
4
+
5
  import { addBase64HeaderToPng } from "./addBase64HeaderToPng"
6
 
7
+ const gradioApi = `https://jbilcke-hf-background-removal-api.hf.space`
8
+ const microserviceApiKey = `${process.env.MICROSERVICE_API_SECRET_TOKEN || ""}`
9
 
10
+ export async function removeBackground({
11
  imageAsBase64,
12
+ }: BackgroundRemovalParams): Promise<string> {
13
 
14
  // remember: a space needs to be public for the classic fetch() to work
15
  const res = await fetch(gradioApi + (gradioApi.endsWith("/") ? "" : "/") + "api/predict", {
 
21
  body: JSON.stringify({
22
  fn_index: 0, // <- is it 0 or 1?
23
  data: [
24
+ microserviceApiKey,
25
  imageAsBase64,
26
  ],
27
  }),
src/app/server/stableCascade.ts ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use server"
2
+
3
+ import { generateSeed } from "@/lib/generateSeed"
4
+ import { StableCascadeParams } from "@/types"
5
+ import { addBase64HeaderToPng } from "./addBase64HeaderToPng"
6
+
7
+ const gradioApi = `https://jbilcke-hf-stable-cascade-api.hf.space`
8
+ const microserviceApiKey = `${process.env.MICROSERVICE_API_SECRET_TOKEN || ""}`
9
+
10
+ export async function stableCascade({
11
+ prompt,
12
+ negativePrompt,
13
+ guidanceScale,
14
+ nbPriorInferenceSteps,
15
+ nbDecoderInferenceSteps,
16
+ seed,
17
+ width,
18
+ height,
19
+ }: StableCascadeParams): Promise<string> {
20
+
21
+ // console.log(`calling `+ gradioApi + (gradioApi.endsWith("/") ? "" : "/") + "api/predict")
22
+
23
+ // remember: a space needs to be public for the classic fetch() to work
24
+ const res = await fetch(gradioApi + (gradioApi.endsWith("/") ? "" : "/") + "api/predict", {
25
+ method: "POST",
26
+ headers: {
27
+ "Content-Type": "application/json",
28
+ // Authorization: `Bearer ${hfApiToken}`,
29
+ },
30
+ body: JSON.stringify({
31
+ fn_index: 0, // <- is it 0 or 1?
32
+ data: [
33
+ microserviceApiKey,
34
+ prompt,
35
+ negativePrompt,
36
+ height,
37
+ width,
38
+ guidanceScale,
39
+ seed || generateSeed(),
40
+ nbPriorInferenceSteps,
41
+ nbDecoderInferenceSteps
42
+ ],
43
+ }),
44
+ cache: "no-store",
45
+ // we can also use this (see https://vercel.com/blog/vercel-cache-api-nextjs-cache)
46
+ // next: { revalidate: 1 }
47
+ })
48
+
49
+ const { data } = await res.json()
50
+
51
+ // console.log("data:", data)
52
+ // Recommendation: handle errors
53
+ if (res.status !== 200 || !Array.isArray(data)) {
54
+ // This will activate the closest `error.js` Error Boundary
55
+ throw new Error(`Failed to fetch data (status: ${res.status})`)
56
+ }
57
+ // console.log("data:", data.slice(0, 50))
58
+
59
+ const base64Content = (data?.[0] || "") as string
60
+
61
+ if (!base64Content) {
62
+ throw new Error(`invalid response (no content)`)
63
+ }
64
+
65
+ return addBase64HeaderToPng(base64Content)
66
+ }
src/app/server/{generate.ts → stableDiffusion.ts} RENAMED
@@ -1,9 +1,9 @@
1
  "use server"
2
 
3
- import { Settings, GenerationParams } from "@/types"
4
  import { serverHuggingfaceApiKey, serverHuggingfaceInferenceApiFileType, serverHuggingfaceInferenceApiModel, serverHuggingfaceInferenceApiModelRefinerModel, serverHuggingfaceInferenceApiModelTrigger } from "./config"
5
 
6
- export async function generate({
7
  prompt,
8
  negativePrompt,
9
  guidanceScale,
@@ -12,7 +12,7 @@ export async function generate({
12
  height,
13
  numInferenceSteps,
14
  hfApiKey,
15
- }: GenerationParams) {
16
  // throw new Error("Planned maintenance")
17
  if (!prompt) {
18
  const error = `cannot call the rendering API without a prompt, aborting..`
 
1
  "use server"
2
 
3
+ import { StableDiffusionParams } from "@/types"
4
  import { serverHuggingfaceApiKey, serverHuggingfaceInferenceApiFileType, serverHuggingfaceInferenceApiModel, serverHuggingfaceInferenceApiModelRefinerModel, serverHuggingfaceInferenceApiModelTrigger } from "./config"
5
 
6
+ export async function stableDiffusion({
7
  prompt,
8
  negativePrompt,
9
  guidanceScale,
 
12
  height,
13
  numInferenceSteps,
14
  hfApiKey,
15
+ }: StableDiffusionParams) {
16
  // throw new Error("Planned maintenance")
17
  if (!prompt) {
18
  const error = `cannot call the rendering API without a prompt, aborting..`
src/app/server/upscale.ts CHANGED
@@ -4,17 +4,17 @@ import { generateSeed } from "@/lib/generateSeed"
4
  import { UpscalingParams } from "@/types"
5
  import { addBase64HeaderToPng } from "./addBase64HeaderToPng"
6
 
7
- const gradioApi = `${process.env.IMAGE_UPSCALING_API_GRADIO_URL || ""}`
8
- const accessToken = `${process.env.IMAGE_UPSCALING_API_GRADIO_TOKEN || ""}`
9
 
10
- export const upscale = async ({
11
  imageAsBase64,
12
  prompt,
13
  negativePrompt,
14
  scaleFactor,
15
  nbSteps,
16
  seed,
17
- }: UpscalingParams): Promise<string> => {
18
 
19
  const addedPrompt = [
20
  "clean",
@@ -66,7 +66,7 @@ export const upscale = async ({
66
  body: JSON.stringify({
67
  fn_index: 0, // <- is it 0 or 1?
68
  data: [
69
- accessToken, // <- this is new, need a redeployment of the upscaler
70
  imageAsBase64, // blob in 'parameter_5' Image component
71
  prompt, // string in 'Prompt' Textbox component
72
  addedPrompt, // string in 'Added Prompt' Textbox component
 
4
  import { UpscalingParams } from "@/types"
5
  import { addBase64HeaderToPng } from "./addBase64HeaderToPng"
6
 
7
+ const gradioApi = `https://jbilcke-hf-image-upscaling-api.hf.space`
8
+ const microserviceApiKey = `${process.env.MICROSERVICE_API_SECRET_TOKEN || ""}`
9
 
10
+ export async function upscale({
11
  imageAsBase64,
12
  prompt,
13
  negativePrompt,
14
  scaleFactor,
15
  nbSteps,
16
  seed,
17
+ }: UpscalingParams): Promise<string> {
18
 
19
  const addedPrompt = [
20
  "clean",
 
66
  body: JSON.stringify({
67
  fn_index: 0, // <- is it 0 or 1?
68
  data: [
69
+ microserviceApiKey,
70
  imageAsBase64, // blob in 'parameter_5' Image component
71
  prompt, // string in 'Prompt' Textbox component
72
  addedPrompt, // string in 'Added Prompt' Textbox component
src/lib/config.ts CHANGED
@@ -100,8 +100,10 @@ export const characterExpressions = [
100
  export type CharacterExpression = typeof characterExpressions[number]
101
 
102
  export const photoshootModes = [
103
- "portrait photo",
104
- "gopro webcam portrait photo",
 
105
  ]
 
106
  export type PhotoshootMode = typeof photoshootModes[number]
107
 
 
100
  export type CharacterExpression = typeof characterExpressions[number]
101
 
102
  export const photoshootModes = [
103
+ "realistic photo",
104
+ "gopro webcam photo",
105
+ "instagram influencer"
106
  ]
107
+
108
  export type PhotoshootMode = typeof photoshootModes[number]
109
 
src/lib/getStableCascadeParams.ts ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { StableCascadeParams } from "@/types"
2
+
3
+ import { CharacterExpression, CharacterGender, CharacterPose, GenerationMode, HairColor, HairStyle } from './config'
4
+ import { generateSeed } from "./generateSeed"
5
+
6
+ export function getStableCascadeParams({
7
+ prompt,
8
+ generationMode,
9
+ negativePrompt,
10
+ characterAge,
11
+ characterExpression,
12
+ characterGender,
13
+ characterHairColor,
14
+ characterHairStyle,
15
+ characterName,
16
+ characterPose
17
+ }: {
18
+ prompt: string
19
+ generationMode: GenerationMode
20
+ negativePrompt: string
21
+ characterAge: number
22
+ characterExpression: CharacterExpression
23
+ characterGender: CharacterGender
24
+ characterHairColor: HairColor
25
+ characterHairStyle: HairStyle
26
+ characterName: string
27
+ characterPose: CharacterPose
28
+ }): StableCascadeParams {
29
+
30
+ const baseParams: StableCascadeParams = {
31
+ prompt: "",
32
+ negativePrompt: "",
33
+
34
+ // between 0.1 and 15 (default 4)
35
+ guidanceScale: 4,
36
+
37
+ seed: generateSeed(),
38
+ width: 1024,
39
+ height: 1024,
40
+
41
+ // between 1 and 50 (default 20)
42
+ nbPriorInferenceSteps: 20,
43
+
44
+ // between 1 and 50 (default 10)
45
+ nbDecoderInferenceSteps: 10,
46
+ }
47
+
48
+ const params: StableCascadeParams = {
49
+ ...baseParams,
50
+ ...generationMode === "characters" ? {
51
+ prompt: [
52
+ `${characterAge} years old $${characterGender}`,
53
+ `${characterHairColor} ${characterHairStyle}`,
54
+ `looking ${characterExpression}`,
55
+ `${characterPose}`,
56
+ `named ${characterName}`,
57
+ 'beautiful',
58
+ 'award winning',
59
+ 'sharp',
60
+ 'crisp',
61
+ 'centered',
62
+ 'aligned'
63
+ ].filter(x => x).join(", "),
64
+ negativePrompt: [
65
+ negativePrompt,
66
+ 'drawing',
67
+ 'painting',
68
+ 'unrealistic',
69
+ 'sitting',
70
+ 'chair',
71
+ '3D render',
72
+ 'unaligned',
73
+ 'cropped',
74
+ 'bad hands',
75
+ 'wrong hands',
76
+ 'deformed',
77
+ 'glitch',
78
+ 'blurry',
79
+ 'overexposed'
80
+ ].join(", "),
81
+ } : {
82
+ prompt: [
83
+ 'picture of a single',
84
+ prompt,
85
+ '3D render',
86
+ 'logo',
87
+ 'ios icon',
88
+ 'illustration',
89
+ 'vector graphics',
90
+ 'svg',
91
+ 'beautiful',
92
+ 'award winning',
93
+ 'sharp',
94
+ 'crisp',
95
+ 'centered',
96
+ 'aligned',
97
+ ].join(", "),
98
+ negativePrompt: [
99
+ negativePrompt,
100
+ 'photo',
101
+ 'gradient',
102
+ 'many',
103
+ 'realistic',
104
+ 'shadow',
105
+ 'multiple',
106
+ 'various',
107
+ 'unaligned',
108
+ 'cropped',
109
+ 'bad hands',
110
+ 'wrong hands',
111
+ 'deformed',
112
+ 'glitch',
113
+ 'blurry',
114
+ 'overexposed'
115
+ ].join(", "),
116
+ }
117
+ }
118
+ return params
119
+ }
src/lib/{getGenerationParams.ts → getStableDiffusionParams.ts} RENAMED
@@ -1,9 +1,9 @@
1
- import { GenerationParams } from "@/types"
2
 
3
  import { CharacterExpression, CharacterGender, CharacterPose, GenerationMode, HairColor, HairStyle } from './config'
4
  import { generateSeed } from "./generateSeed"
5
 
6
- export function getGenerationParams({
7
  generationMode,
8
  negativePrompt,
9
  characterAge,
@@ -23,9 +23,9 @@ export function getGenerationParams({
23
  characterHairStyle: HairStyle
24
  characterName: string
25
  characterPose: CharacterPose
26
- }): GenerationParams {
27
 
28
- const baseParams: GenerationParams = {
29
  prompt: "",
30
  negativePrompt: "",
31
  guidanceScale: 9,
@@ -36,7 +36,7 @@ export function getGenerationParams({
36
  hfApiKey: "",
37
  }
38
 
39
- const params: GenerationParams = {
40
  ...baseParams,
41
  ...generationMode === "characters" ? {
42
  prompt: [
 
1
+ import { StableDiffusionParams } from "@/types"
2
 
3
  import { CharacterExpression, CharacterGender, CharacterPose, GenerationMode, HairColor, HairStyle } from './config'
4
  import { generateSeed } from "./generateSeed"
5
 
6
+ export function getStableDiffusionParams({
7
  generationMode,
8
  negativePrompt,
9
  characterAge,
 
23
  characterHairStyle: HairStyle
24
  characterName: string
25
  characterPose: CharacterPose
26
+ }): StableDiffusionParams {
27
 
28
+ const baseParams: StableDiffusionParams = {
29
  prompt: "",
30
  negativePrompt: "",
31
  guidanceScale: 9,
 
36
  hfApiKey: "",
37
  }
38
 
39
+ const params: StableDiffusionParams = {
40
  ...baseParams,
41
  ...generationMode === "characters" ? {
42
  prompt: [
src/types.ts CHANGED
@@ -13,7 +13,8 @@ export type Settings = {
13
  huggingfaceInferenceApiFileType: string
14
  }
15
 
16
- export interface GenerationParams {
 
17
  prompt: string
18
  negativePrompt: string
19
  guidanceScale: number
@@ -24,6 +25,24 @@ export interface GenerationParams {
24
  hfApiKey: string
25
  }
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  export type UpscalingParams = {
28
  imageAsBase64: string
29
  prompt: string
 
13
  huggingfaceInferenceApiFileType: string
14
  }
15
 
16
+
17
+ export interface StableDiffusionParams {
18
  prompt: string
19
  negativePrompt: string
20
  guidanceScale: number
 
25
  hfApiKey: string
26
  }
27
 
28
+ export interface StableCascadeParams {
29
+ prompt: string
30
+ negativePrompt: string
31
+
32
+
33
+ // between 0.1 and 15 (default 4)
34
+ guidanceScale: number
35
+ seed: number
36
+ width: number
37
+ height: number
38
+
39
+ // between 1 and 50 (default 20)
40
+ nbPriorInferenceSteps: number
41
+
42
+ // between 1 and 50 (default 10)
43
+ nbDecoderInferenceSteps: number
44
+ }
45
+
46
  export type UpscalingParams = {
47
  imageAsBase64: string
48
  prompt: string