|
|
|
@ -8,7 +8,7 @@ import { useRouter } from 'next/router'
|
|
|
|
|
import { AnimatePresence, motion } from 'framer-motion'
|
|
|
|
|
import { HexAlphaColorPicker, HexColorInput } from 'react-colorful'
|
|
|
|
|
import { MdFileUpload, MdHelpOutline } from 'react-icons/md'
|
|
|
|
|
import { FaQuestion } from 'react-icons/fa'
|
|
|
|
|
import { FaCoffee, FaQuestion } from 'react-icons/fa'
|
|
|
|
|
import TextareaAutosize from 'react-textarea-autosize'
|
|
|
|
|
import JSZip from 'jszip'
|
|
|
|
|
import { saveAs } from 'file-saver'
|
|
|
|
@ -64,7 +64,7 @@ import Checkbox from '../components/controls/checkbox'
|
|
|
|
|
import { getStorage } from '../data/storage/storage'
|
|
|
|
|
import { getUserSetting } from '../data/user/settings'
|
|
|
|
|
import { useReload } from '../hooks/useReload'
|
|
|
|
|
import { BackendURLTagSearch } from '../globals/constants'
|
|
|
|
|
import { BackendURLTagSearch, IsIsekai } from '../globals/constants'
|
|
|
|
|
import Tooltip from '../components/tooltip'
|
|
|
|
|
import { WorkerInterface } from '../tokenizer/interface'
|
|
|
|
|
import { EncoderType } from '../tokenizer/encoder'
|
|
|
|
@ -561,7 +561,7 @@ function ImageGenContent(): JSX.Element {
|
|
|
|
|
|
|
|
|
|
const [purchaseModalOpen, setPurchaseModalOpen] = useState(false)
|
|
|
|
|
|
|
|
|
|
useEffect(() => {}, [
|
|
|
|
|
useEffect(() => { }, [
|
|
|
|
|
params,
|
|
|
|
|
selectedModel,
|
|
|
|
|
session,
|
|
|
|
@ -604,10 +604,10 @@ function ImageGenContent(): JSX.Element {
|
|
|
|
|
lastPromptTokensGood.current = false
|
|
|
|
|
toast.warn(
|
|
|
|
|
'Prompt is too long and will be cut off. Using ' +
|
|
|
|
|
promptTokens +
|
|
|
|
|
' out of ' +
|
|
|
|
|
SD_TOKEN_LIMIT +
|
|
|
|
|
' available tokens.'
|
|
|
|
|
promptTokens +
|
|
|
|
|
' out of ' +
|
|
|
|
|
SD_TOKEN_LIMIT +
|
|
|
|
|
' available tokens.'
|
|
|
|
|
)
|
|
|
|
|
} else if (promptTokens.every((t) => t <= SD_TOKEN_LIMIT)) {
|
|
|
|
|
lastPromptTokensGood.current = true
|
|
|
|
@ -646,10 +646,10 @@ function ImageGenContent(): JSX.Element {
|
|
|
|
|
lastNegPromptTokensGood.current = false
|
|
|
|
|
toast.warn(
|
|
|
|
|
'Negative prompt is too long and will be cut off. Using ' +
|
|
|
|
|
negPromptTokens +
|
|
|
|
|
' out of ' +
|
|
|
|
|
SD_TOKEN_LIMIT +
|
|
|
|
|
' available tokens.'
|
|
|
|
|
negPromptTokens +
|
|
|
|
|
' out of ' +
|
|
|
|
|
SD_TOKEN_LIMIT +
|
|
|
|
|
' available tokens.'
|
|
|
|
|
)
|
|
|
|
|
} else if (negPromptTokens <= SD_TOKEN_LIMIT) {
|
|
|
|
|
lastNegPromptTokensGood.current = true
|
|
|
|
@ -673,8 +673,8 @@ function ImageGenContent(): JSX.Element {
|
|
|
|
|
lastTagSearchRequest.current = requestId
|
|
|
|
|
fetch(
|
|
|
|
|
BackendURLTagSearch +
|
|
|
|
|
//`?model=${encodeURIComponent(selectedModel.toString())}&prompt=${encodeURIComponent(
|
|
|
|
|
`?prompt=${encodeURIComponent(prompt.trim())}`,
|
|
|
|
|
//`?model=${encodeURIComponent(selectedModel.toString())}&prompt=${encodeURIComponent(
|
|
|
|
|
`?prompt=${encodeURIComponent(prompt.trim())}`,
|
|
|
|
|
{
|
|
|
|
|
mode: 'cors',
|
|
|
|
|
cache: 'default',
|
|
|
|
@ -2004,18 +2004,43 @@ function ImageGenContent(): JSX.Element {
|
|
|
|
|
<HistoryIcon />
|
|
|
|
|
</OpenHistoryButton>
|
|
|
|
|
<FlexSpaceFull />
|
|
|
|
|
<ImportImageLink
|
|
|
|
|
href="//docs.novelai.net"
|
|
|
|
|
target="_blank"
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: '0.875rem',
|
|
|
|
|
opacity: 0.8,
|
|
|
|
|
width: 'max-content',
|
|
|
|
|
padding: '0 0 0 10px',
|
|
|
|
|
display: 'flex',
|
|
|
|
|
gap: '10px',
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
justifyContent: 'space-between'
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<FaQuestion />
|
|
|
|
|
</ImportImageLink>
|
|
|
|
|
{IsIsekai && (
|
|
|
|
|
<ImportImageLink
|
|
|
|
|
href="https://www.isekai.cn"
|
|
|
|
|
target="_blank"
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: '0.875rem',
|
|
|
|
|
opacity: 0.8,
|
|
|
|
|
width: 'max-content',
|
|
|
|
|
padding: '0 0 0 10px',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<FaCoffee />
|
|
|
|
|
|
|
|
|
|
异世界百科
|
|
|
|
|
</ImportImageLink>
|
|
|
|
|
)}
|
|
|
|
|
<ImportImageLink
|
|
|
|
|
href="//docs.novelai.net"
|
|
|
|
|
target="_blank"
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: '0.875rem',
|
|
|
|
|
opacity: 0.8,
|
|
|
|
|
width: 'max-content',
|
|
|
|
|
padding: '0 0 0 10px',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<FaQuestion />
|
|
|
|
|
</ImportImageLink>
|
|
|
|
|
</div>
|
|
|
|
|
</HideMobileInline>
|
|
|
|
|
</MainTopperInnerRight>
|
|
|
|
|
</MainTopper>
|
|
|
|
@ -2244,12 +2269,12 @@ function ImageGenContent(): JSX.Element {
|
|
|
|
|
} else {
|
|
|
|
|
return e.key === 'ArrowUp'
|
|
|
|
|
? (suggestionSelectionIndex +
|
|
|
|
|
tagSuggestions.length -
|
|
|
|
|
1) %
|
|
|
|
|
tagSuggestions.length
|
|
|
|
|
tagSuggestions.length -
|
|
|
|
|
1) %
|
|
|
|
|
tagSuggestions.length
|
|
|
|
|
: (suggestionSelectionIndex +
|
|
|
|
|
1) %
|
|
|
|
|
tagSuggestions.length
|
|
|
|
|
1) %
|
|
|
|
|
tagSuggestions.length
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
@ -2267,7 +2292,7 @@ function ImageGenContent(): JSX.Element {
|
|
|
|
|
e.stopPropagation()
|
|
|
|
|
insertTagToPrompt(
|
|
|
|
|
tagSuggestions[
|
|
|
|
|
suggestionSelectionIndex
|
|
|
|
|
suggestionSelectionIndex
|
|
|
|
|
][0],
|
|
|
|
|
promptid
|
|
|
|
|
)
|
|
|
|
@ -2322,11 +2347,10 @@ function ImageGenContent(): JSX.Element {
|
|
|
|
|
SD_TOKEN_LIMIT
|
|
|
|
|
}
|
|
|
|
|
style={{
|
|
|
|
|
height: `${
|
|
|
|
|
((promptTokens[promptid] ?? 0) /
|
|
|
|
|
SD_TOKEN_LIMIT) *
|
|
|
|
|
height: `${((promptTokens[promptid] ?? 0) /
|
|
|
|
|
SD_TOKEN_LIMIT) *
|
|
|
|
|
100
|
|
|
|
|
}%`,
|
|
|
|
|
}%`,
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</TokenLimitBarOuter>
|
|
|
|
@ -2483,19 +2507,19 @@ function ImageGenContent(): JSX.Element {
|
|
|
|
|
/>
|
|
|
|
|
{(shownHover === i ||
|
|
|
|
|
images[selectedImage].length === 1) && (
|
|
|
|
|
<>
|
|
|
|
|
{images[selectedImage].length === 1 &&
|
|
|
|
|
img &&
|
|
|
|
|
topButtonGroup(img, 0)}
|
|
|
|
|
|
|
|
|
|
{images[selectedImage].length !== 1 &&
|
|
|
|
|
specialButtonGroup(img, i)}
|
|
|
|
|
{saveButtonGroup(img)}
|
|
|
|
|
|
|
|
|
|
{images[selectedImage].length === 1 &&
|
|
|
|
|
seedButtonGroup(img, i)}
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
<>
|
|
|
|
|
{images[selectedImage].length === 1 &&
|
|
|
|
|
img &&
|
|
|
|
|
topButtonGroup(img, 0)}
|
|
|
|
|
|
|
|
|
|
{images[selectedImage].length !== 1 &&
|
|
|
|
|
specialButtonGroup(img, i)}
|
|
|
|
|
{saveButtonGroup(img)}
|
|
|
|
|
|
|
|
|
|
{images[selectedImage].length === 1 &&
|
|
|
|
|
seedButtonGroup(img, i)}
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
{img.isVariationOriginal && (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
@ -2585,9 +2609,9 @@ function ImageGenContent(): JSX.Element {
|
|
|
|
|
src={
|
|
|
|
|
showOld === expandedImage
|
|
|
|
|
? images[selectedImage][expandedImage]
|
|
|
|
|
.enhanceOriginal
|
|
|
|
|
.enhanceOriginal
|
|
|
|
|
: images[selectedImage][expandedImage]
|
|
|
|
|
.url
|
|
|
|
|
.url
|
|
|
|
|
}
|
|
|
|
|
alt={images[selectedImage][
|
|
|
|
|
expandedImage
|
|
|
|
@ -3051,7 +3075,7 @@ const ExpandedImageContainer = styled(motion.div)`
|
|
|
|
|
align-items: center;
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
const HistoryButton = styled(SubtleButton)<{ selected: boolean; img: string }>`
|
|
|
|
|
const HistoryButton = styled(SubtleButton) <{ selected: boolean; img: string }>`
|
|
|
|
|
border: ${(props) =>
|
|
|
|
|
props.selected ? `2px solid ${props.theme.colors.textHeadings}` : `2px solid transparent`};
|
|
|
|
|
border-radius: 3px;
|
|
|
|
@ -3323,7 +3347,7 @@ function GenerationOptions(props: {
|
|
|
|
|
onMouseDown: (e: any) => {
|
|
|
|
|
if (e.target !== document.activeElement) {
|
|
|
|
|
e.preventDefault()
|
|
|
|
|
;(e.target as HTMLInputElement).select()
|
|
|
|
|
; (e.target as HTMLInputElement).select()
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -3692,7 +3716,6 @@ function GenerationOptions(props: {
|
|
|
|
|
maxRows={6}
|
|
|
|
|
placeholder="Anything in here is added to the preset selected above."
|
|
|
|
|
value={props.negPrompt ?? ''}
|
|
|
|
|
warn={props.negPromptTokens > SD_TOKEN_LIMIT}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
props.setNegPrompt((e.target.value || '').replace(/(\n|\r)/g, ''))
|
|
|
|
|
}}
|
|
|
|
@ -3888,7 +3911,7 @@ const Input = styled.input<{ warn?: boolean }>`
|
|
|
|
|
}
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
const LargeInput = styled(TextareaAutosize)<{ warn?: boolean }>`
|
|
|
|
|
const LargeInput = styled(TextareaAutosize) <{ warn?: boolean }>`
|
|
|
|
|
padding: 12px 20px;
|
|
|
|
|
border: 1px solid ${(props) => (props.warn ? props.theme.colors.warning : props.theme.colors.bg3)};
|
|
|
|
|
border-radius: 3px;
|
|
|
|
@ -4907,7 +4930,7 @@ function Canvas(props: {
|
|
|
|
|
onMouseDown: (e: any) => {
|
|
|
|
|
if (e.target !== document.activeElement) {
|
|
|
|
|
e.preventDefault()
|
|
|
|
|
;(e.target as HTMLInputElement).select()
|
|
|
|
|
; (e.target as HTMLInputElement).select()
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -5537,7 +5560,7 @@ function Canvas(props: {
|
|
|
|
|
backgroundImage: props.rerollImage
|
|
|
|
|
? `url(${props.rerollImage?.url})`
|
|
|
|
|
: // eslint-disable-next-line max-len
|
|
|
|
|
`linear-gradient(45deg, #A0A0A0 25%, transparent 25%), linear-gradient(-45deg, #A0A0A0 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #A0A0A0 75%), linear-gradient(-45deg, transparent 75%, #A0A0A0 75%)`,
|
|
|
|
|
`linear-gradient(45deg, #A0A0A0 25%, transparent 25%), linear-gradient(-45deg, #A0A0A0 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #A0A0A0 75%), linear-gradient(-45deg, transparent 75%, #A0A0A0 75%)`,
|
|
|
|
|
backgroundSize: props.rerollImage?.url ? '100%' : '30px 30px',
|
|
|
|
|
backgroundPosition: '0 0, 0 15px, 15px -15px, -15px 0px',
|
|
|
|
|
}}
|
|
|
|
@ -5882,7 +5905,7 @@ const Filler = styled.div`
|
|
|
|
|
height: 30px;
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
const CanvasControlButton = styled(SubtleButton)<{ selected?: boolean }>`
|
|
|
|
|
const CanvasControlButton = styled(SubtleButton) <{ selected?: boolean }>`
|
|
|
|
|
padding: 8px;
|
|
|
|
|
height: 44px;
|
|
|
|
|
min-width: 58px;
|
|
|
|
@ -5902,13 +5925,13 @@ const CanvasControlButton = styled(SubtleButton)<{ selected?: boolean }>`
|
|
|
|
|
width: 18px;
|
|
|
|
|
height: 18px;
|
|
|
|
|
background-color: ${(props) =>
|
|
|
|
|
props.selected ? props.theme.colors.bg0 : props.theme.colors.textMain};
|
|
|
|
|
props.selected ? props.theme.colors.bg0 : props.theme.colors.textMain};
|
|
|
|
|
}
|
|
|
|
|
&:hover {
|
|
|
|
|
color: ${(props) => (props.selected ? props.theme.colors.bg3 : props.theme.colors.textHeadings)};
|
|
|
|
|
> div {
|
|
|
|
|
background-color: ${(props) =>
|
|
|
|
|
props.selected ? props.theme.colors.bg0 : props.theme.colors.textHeadings};
|
|
|
|
|
props.selected ? props.theme.colors.bg0 : props.theme.colors.textHeadings};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|