diff --git a/lama_cleaner/app/src/adapters/inpainting.ts b/lama_cleaner/app/src/adapters/inpainting.ts
index 2cf291a..5f74eb7 100644
--- a/lama_cleaner/app/src/adapters/inpainting.ts
+++ b/lama_cleaner/app/src/adapters/inpainting.ts
@@ -9,6 +9,7 @@ export default async function inpaint(
settings: Settings,
croperRect: Rect,
prompt?: string,
+ negativePrompt?: string,
sizeLimit?: string,
seed?: number
) {
@@ -34,6 +35,10 @@ export default async function inpaint(
)
fd.append('prompt', prompt === undefined ? '' : prompt)
+ fd.append(
+ 'negativePrompt',
+ negativePrompt === undefined ? '' : negativePrompt
+ )
fd.append('croperX', croperRect.x.toString())
fd.append('croperY', croperRect.y.toString())
fd.append('croperHeight', croperRect.height.toString())
diff --git a/lama_cleaner/app/src/components/Editor/Editor.tsx b/lama_cleaner/app/src/components/Editor/Editor.tsx
index 128e184..da2e445 100644
--- a/lama_cleaner/app/src/components/Editor/Editor.tsx
+++ b/lama_cleaner/app/src/components/Editor/Editor.tsx
@@ -36,6 +36,7 @@ import {
fileState,
isInpaintingState,
isSDState,
+ negativePropmtState,
propmtState,
runManuallyState,
seedState,
@@ -88,6 +89,7 @@ function mouseXY(ev: SyntheticEvent) {
export default function Editor() {
const [file, setFile] = useRecoilState(fileState)
const promptVal = useRecoilValue(propmtState)
+ const negativePromptVal = useRecoilValue(negativePropmtState)
const settings = useRecoilValue(settingState)
const [seedVal, setSeed] = useRecoilState(seedState)
const croperRect = useRecoilValue(croperState)
@@ -261,6 +263,7 @@ export default function Editor() {
settings,
croperRect,
prompt,
+ negativePromptVal,
sizeLimit.toString(),
sdSeed
)
@@ -311,6 +314,7 @@ export default function Editor() {
croperRect,
sizeLimit,
promptVal,
+ negativePromptVal,
drawOnCurrentRender,
hadDrawSomething,
drawLinesOnMask,
diff --git a/lama_cleaner/app/src/components/Settings/SettingBlock.scss b/lama_cleaner/app/src/components/Settings/SettingBlock.scss
index 9dce547..85befdd 100644
--- a/lama_cleaner/app/src/components/Settings/SettingBlock.scss
+++ b/lama_cleaner/app/src/components/Settings/SettingBlock.scss
@@ -25,6 +25,14 @@
gap: 12rem;
}
+.setting-block-content-v {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: flex-start;
+ gap: 1rem;
+}
+
.setting-block-content-title {
display: flex;
flex-direction: row;
diff --git a/lama_cleaner/app/src/components/Settings/SettingBlock.tsx b/lama_cleaner/app/src/components/Settings/SettingBlock.tsx
index 5f3fcc0..0a297bc 100644
--- a/lama_cleaner/app/src/components/Settings/SettingBlock.tsx
+++ b/lama_cleaner/app/src/components/Settings/SettingBlock.tsx
@@ -8,13 +8,18 @@ interface SettingBlockProps {
input: ReactNode
optionDesc?: ReactNode
className?: string
+ layout?: string
}
function SettingBlock(props: SettingBlockProps) {
- const { title, titleSuffix, desc, input, optionDesc, className } = props
+ const { title, titleSuffix, desc, input, optionDesc, className, layout } =
+ props
+ const contentClass =
+ layout === 'h' ? 'setting-block-content' : 'setting-block-content-v'
+
return (
-
+
{desc ? (
@@ -34,4 +39,8 @@ function SettingBlock(props: SettingBlockProps) {
)
}
+SettingBlock.defaultProps = {
+ layout: 'h',
+}
+
export default SettingBlock
diff --git a/lama_cleaner/app/src/components/SidePanel/SidePanel.scss b/lama_cleaner/app/src/components/SidePanel/SidePanel.scss
index ff54c20..0b87408 100644
--- a/lama_cleaner/app/src/components/SidePanel/SidePanel.scss
+++ b/lama_cleaner/app/src/components/SidePanel/SidePanel.scss
@@ -55,3 +55,31 @@
// // border-radius: 4px;
// }
}
+
+.negative-prompt {
+ all: unset;
+ border-width: 0;
+ border-radius: 0.5rem;
+ min-height: 150px;
+ max-width: 200px;
+ width: 100%;
+ padding: 12px 0.8rem;
+ outline: 1px solid var(--border-color);
+
+ &:focus-visible {
+ border-width: 0;
+ outline: 1px solid var(--yellow-accent);
+ }
+
+ &:-webkit-input-placeholder {
+ padding-top: 10px;
+ }
+
+ &:-moz-input-placeholder {
+ padding-top: 10px;
+ }
+
+ &:-ms-input-placeholder {
+ padding-top: 10px;
+ }
+}
diff --git a/lama_cleaner/app/src/components/SidePanel/SidePanel.tsx b/lama_cleaner/app/src/components/SidePanel/SidePanel.tsx
index fa8fd37..c2fd1a5 100644
--- a/lama_cleaner/app/src/components/SidePanel/SidePanel.tsx
+++ b/lama_cleaner/app/src/components/SidePanel/SidePanel.tsx
@@ -1,12 +1,13 @@
-import React, { useState } from 'react'
+import React, { FormEvent, useState } from 'react'
import { useRecoilState } from 'recoil'
import * as PopoverPrimitive from '@radix-ui/react-popover'
import { useToggle } from 'react-use'
-import { SDSampler, settingState } from '../../store/Atoms'
+import { negativePropmtState, SDSampler, settingState } from '../../store/Atoms'
import NumberInputSetting from '../Settings/NumberInputSetting'
import SettingBlock from '../Settings/SettingBlock'
import Selector from '../shared/Selector'
import { Switch, SwitchThumb } from '../shared/Switch'
+import TextAreaInput from '../shared/Textarea'
const INPUT_WIDTH = 30
@@ -14,6 +15,15 @@ const INPUT_WIDTH = 30
const SidePanel = () => {
const [open, toggleOpen] = useToggle(true)
const [setting, setSettingState] = useRecoilState(settingState)
+ const [negativePrompt, setNegativePrompt] =
+ useRecoilState(negativePropmtState)
+
+ const handleOnInput = (evt: FormEvent
) => {
+ evt.preventDefault()
+ evt.stopPropagation()
+ const target = evt.target as HTMLTextAreaElement
+ setNegativePrompt(target.value)
+ }
return (
@@ -59,7 +69,7 @@ const SidePanel = () => {
title="Steps"
width={INPUT_WIDTH}
value={`${setting.sdSteps}`}
- desc="Large steps result in better result, but more time-consuming"
+ desc="The number of denoising steps. More denoising steps usually lead to a higher quality image at the expense of slower inference."
onValue={value => {
const val = value.length === 0 ? 0 : parseInt(value, 10)
setSettingState(old => {
@@ -88,7 +98,7 @@ const SidePanel = () => {
width={INPUT_WIDTH}
allowFloat
value={`${setting.sdGuidanceScale}`}
- desc="TODO"
+ desc="Higher guidance scale encourages to generate images that are closely linked to the text prompt, usually at the expense of lower image quality."
onValue={value => {
const val = value.length === 0 ? 0 : parseFloat(value)
setSettingState(old => {
@@ -101,7 +111,7 @@ const SidePanel = () => {
title="Mask Blur"
width={INPUT_WIDTH}
value={`${setting.sdMaskBlur}`}
- desc="TODO"
+ desc="Blur the edge of mask area. The higher the number the smoother blend with the original image"
onValue={value => {
const val = value.length === 0 ? 0 : parseInt(value, 10)
setSettingState(old => {
@@ -167,6 +177,20 @@ const SidePanel = () => {
}
/>
+
+
+ }
+ />
diff --git a/lama_cleaner/app/src/components/shared/Input.tsx b/lama_cleaner/app/src/components/shared/Input.tsx
index 1537748..37199f8 100644
--- a/lama_cleaner/app/src/components/shared/Input.tsx
+++ b/lama_cleaner/app/src/components/shared/Input.tsx
@@ -1,5 +1,4 @@
import React, { FocusEvent, InputHTMLAttributes, RefObject } from 'react'
-import { useClickAway } from 'react-use'
import { useRecoilState } from 'recoil'
import { appState } from '../../store/Atoms'
diff --git a/lama_cleaner/app/src/components/shared/Textarea.tsx b/lama_cleaner/app/src/components/shared/Textarea.tsx
new file mode 100644
index 0000000..94623aa
--- /dev/null
+++ b/lama_cleaner/app/src/components/shared/Textarea.tsx
@@ -0,0 +1,45 @@
+import React, { FocusEvent, TextareaHTMLAttributes } from 'react'
+import { useRecoilState } from 'recoil'
+import { appState } from '../../store/Atoms'
+
+const TextAreaInput = React.forwardRef<
+ HTMLTextAreaElement,
+ TextareaHTMLAttributes
+>((props, ref) => {
+ const { onFocus, onBlur, ...itemProps } = props
+ const [_, setAppState] = useRecoilState(appState)
+
+ const handleOnFocus = (evt: FocusEvent) => {
+ setAppState(old => {
+ return { ...old, disableShortCuts: true }
+ })
+ onFocus?.(evt)
+ }
+
+ const handleOnBlur = (evt: FocusEvent) => {
+ setAppState(old => {
+ return { ...old, disableShortCuts: false }
+ })
+ onBlur?.(evt)
+ }
+
+ return (
+