lots of update 2
This commit is contained in:
parent
a22536becc
commit
a7240eedb5
@ -18,12 +18,14 @@
|
|||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@testing-library/jest-dom": "^5.14.1",
|
||||||
"@testing-library/react": "^12.1.2",
|
"@testing-library/react": "^12.1.2",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
|
"@types/flexsearch": "^0.7.3",
|
||||||
"@types/jest": "^27.0.2",
|
"@types/jest": "^27.0.2",
|
||||||
"@types/lodash": "^4.14.182",
|
"@types/lodash": "^4.14.182",
|
||||||
"@types/node": "^16.11.1",
|
"@types/node": "^16.11.1",
|
||||||
"@types/react": "^17.0.30",
|
"@types/react": "^17.0.30",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^17.0.9",
|
||||||
"cross-env": "7.x",
|
"cross-env": "7.x",
|
||||||
|
"flexsearch": "0.7.21",
|
||||||
"hacktimer": "^1.1.3",
|
"hacktimer": "^1.1.3",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mitt": "^3.0.0",
|
"mitt": "^3.0.0",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useCallback, useEffect, useMemo } from 'react'
|
import React, { useCallback, useEffect, useMemo } from 'react'
|
||||||
import { useRecoilState } from 'recoil'
|
import { useRecoilState, useSetRecoilState } from 'recoil'
|
||||||
import { nanoid } from 'nanoid'
|
import { nanoid } from 'nanoid'
|
||||||
import useInputImage from './hooks/useInputImage'
|
import useInputImage from './hooks/useInputImage'
|
||||||
import { themeState } from './components/Header/ThemeChanger'
|
import { themeState } from './components/Header/ThemeChanger'
|
||||||
@ -30,14 +30,10 @@ const SUPPORTED_FILE_TYPE = [
|
|||||||
function App() {
|
function App() {
|
||||||
const [file, setFile] = useRecoilState(fileState)
|
const [file, setFile] = useRecoilState(fileState)
|
||||||
const [theme, setTheme] = useRecoilState(themeState)
|
const [theme, setTheme] = useRecoilState(themeState)
|
||||||
const [toastVal, setToastState] = useRecoilState(toastState)
|
const setToastState = useSetRecoilState(toastState)
|
||||||
const userInputImage = useInputImage()
|
const userInputImage = useInputImage()
|
||||||
const [isDisableModelSwitch, setIsDisableModelSwitch] = useRecoilState(
|
const setIsDisableModelSwitch = useSetRecoilState(isDisableModelSwitchState)
|
||||||
isDisableModelSwitchState
|
const setEnableFileManager = useSetRecoilState(enableFileManagerState)
|
||||||
)
|
|
||||||
const [enableFileManager, setEnableFileManager] = useRecoilState(
|
|
||||||
enableFileManagerState
|
|
||||||
)
|
|
||||||
|
|
||||||
// Set Input Image
|
// Set Input Image
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -70,7 +66,7 @@ function App() {
|
|||||||
setEnableFileManager(isEnabled === 'true')
|
setEnableFileManager(isEnabled === 'true')
|
||||||
}
|
}
|
||||||
fetchData2()
|
fetchData2()
|
||||||
}, [])
|
}, [setEnableFileManager, setIsDisableModelSwitch])
|
||||||
|
|
||||||
// Dark Mode Hotkey
|
// Dark Mode Hotkey
|
||||||
useHotKey(
|
useHotKey(
|
||||||
@ -118,7 +114,8 @@ function App() {
|
|||||||
setIsDragging(false)
|
setIsDragging(false)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const handleDrop = React.useCallback(event => {
|
const handleDrop = React.useCallback(
|
||||||
|
event => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
setIsDragging(false)
|
setIsDragging(false)
|
||||||
@ -146,7 +143,9 @@ function App() {
|
|||||||
}
|
}
|
||||||
event.dataTransfer.clearData()
|
event.dataTransfer.clearData()
|
||||||
}
|
}
|
||||||
}, [])
|
},
|
||||||
|
[setToastState, setFile]
|
||||||
|
)
|
||||||
|
|
||||||
const onPaste = useCallback((event: any) => {
|
const onPaste = useCallback((event: any) => {
|
||||||
// TODO: when sd side panel open, ctrl+v not work
|
// TODO: when sd side panel open, ctrl+v not work
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.react-photo-album--photo {
|
.react-photo-album--photo {
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
|
|
||||||
@ -82,3 +85,17 @@
|
|||||||
.ScrollAreaCorner {
|
.ScrollAreaCorner {
|
||||||
background: var(--blackA8);
|
background: var(--blackA8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.file-search-input {
|
||||||
|
width: 250px;
|
||||||
|
padding-left: 30px;
|
||||||
|
height: 32px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-btn-inactive {
|
||||||
|
svg {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,13 +4,25 @@ import React, {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
useCallback,
|
useCallback,
|
||||||
|
useRef,
|
||||||
|
FormEvent,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { useRecoilState } from 'recoil'
|
import _ from 'lodash'
|
||||||
import PhotoAlbum, { RenderPhoto } from 'react-photo-album'
|
import { useSetRecoilState } from 'recoil'
|
||||||
|
import PhotoAlbum from 'react-photo-album'
|
||||||
|
import { BarsArrowDownIcon, BarsArrowUpIcon } from '@heroicons/react/24/outline'
|
||||||
|
import { MagnifyingGlassIcon } from '@radix-ui/react-icons'
|
||||||
|
import { useDebounce } from 'react-use'
|
||||||
|
import { Id, Index, IndexSearchResult } from 'flexsearch'
|
||||||
import * as ScrollArea from '@radix-ui/react-scroll-area'
|
import * as ScrollArea from '@radix-ui/react-scroll-area'
|
||||||
import Modal from '../shared/Modal'
|
import Modal from '../shared/Modal'
|
||||||
|
import Flex from '../shared/Layout'
|
||||||
import { toastState } from '../../store/Atoms'
|
import { toastState } from '../../store/Atoms'
|
||||||
import { getMedias } from '../../adapters/inpainting'
|
import { getMedias } from '../../adapters/inpainting'
|
||||||
|
import Selector from '../shared/Selector'
|
||||||
|
import Button from '../shared/Button'
|
||||||
|
import TextInput from '../shared/Input'
|
||||||
|
import { useAsyncMemo } from '../../hooks/useAsyncMemo'
|
||||||
|
|
||||||
interface Photo {
|
interface Photo {
|
||||||
src: string
|
src: string
|
||||||
@ -22,26 +34,26 @@ interface Filename {
|
|||||||
name: string
|
name: string
|
||||||
height: number
|
height: number
|
||||||
width: number
|
width: number
|
||||||
|
ctime: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderPhoto: RenderPhoto = ({
|
enum SortOrder {
|
||||||
layout,
|
DESCENDING = 'desc',
|
||||||
layoutOptions,
|
ASCENDING = 'asc',
|
||||||
imageProps: { alt, style, ...restImageProps },
|
}
|
||||||
}) => (
|
|
||||||
<div
|
enum SortBy {
|
||||||
style={{
|
NAME = 'name',
|
||||||
boxSizing: 'content-box',
|
CTIME = 'ctime',
|
||||||
alignItems: 'center',
|
}
|
||||||
}}
|
|
||||||
>
|
const SORT_BY_NAME = 'Name'
|
||||||
<img
|
const SORT_BY_CREATED_TIME = 'Created time'
|
||||||
alt={alt}
|
|
||||||
style={{ ...style, width: '100%', padding: 0 }}
|
const SortByMap = {
|
||||||
{...restImageProps}
|
[SortBy.NAME]: SORT_BY_NAME,
|
||||||
/>
|
[SortBy.CTIME]: SORT_BY_CREATED_TIME,
|
||||||
</div>
|
}
|
||||||
)
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
show: boolean
|
show: boolean
|
||||||
@ -55,7 +67,20 @@ export default function FileManager(props: Props) {
|
|||||||
const [filenames, setFileNames] = useState<Filename[]>([])
|
const [filenames, setFileNames] = useState<Filename[]>([])
|
||||||
const [scrollTop, setScrollTop] = useState(0)
|
const [scrollTop, setScrollTop] = useState(0)
|
||||||
const [closeScrollTop, setCloseScrollTop] = useState(0)
|
const [closeScrollTop, setCloseScrollTop] = useState(0)
|
||||||
const [toastVal, setToastState] = useRecoilState(toastState)
|
const setToastState = useSetRecoilState(toastState)
|
||||||
|
const [sortBy, setSortBy] = useState<SortBy>(SortBy.CTIME)
|
||||||
|
const [sortOrder, setSortOrder] = useState<SortOrder>(SortOrder.DESCENDING)
|
||||||
|
const ref = useRef(null)
|
||||||
|
const [searchText, setSearchText] = useState('')
|
||||||
|
const [debouncedSearchText, setDebouncedSearchText] = useState('')
|
||||||
|
|
||||||
|
const [, cancel] = useDebounce(
|
||||||
|
() => {
|
||||||
|
setDebouncedSearchText(searchText)
|
||||||
|
},
|
||||||
|
500,
|
||||||
|
[searchText]
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!show) {
|
if (!show) {
|
||||||
@ -98,20 +123,37 @@ export default function FileManager(props: Props) {
|
|||||||
if (show) {
|
if (show) {
|
||||||
fetchData()
|
fetchData()
|
||||||
}
|
}
|
||||||
}, [show])
|
}, [show, setToastState])
|
||||||
|
|
||||||
const onScroll = (event: SyntheticEvent) => {
|
const onScroll = (event: SyntheticEvent) => {
|
||||||
setScrollTop(event.currentTarget.scrollTop)
|
setScrollTop(event.currentTarget.scrollTop)
|
||||||
}
|
}
|
||||||
|
|
||||||
const photos = useMemo(() => {
|
const filteredFilenames: Filename[] | undefined = useAsyncMemo(async () => {
|
||||||
return filenames.map((filename: Filename) => {
|
if (!debouncedSearchText) {
|
||||||
|
return filenames
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = new Index()
|
||||||
|
filenames.forEach((filename: Filename, id: number) =>
|
||||||
|
index.add(id, filename.name)
|
||||||
|
)
|
||||||
|
const results: IndexSearchResult = await index.searchAsync(
|
||||||
|
debouncedSearchText
|
||||||
|
)
|
||||||
|
return results.map((id: Id) => filenames[id as number])
|
||||||
|
}, [filenames, debouncedSearchText])
|
||||||
|
|
||||||
|
const photos: Photo[] = useMemo(() => {
|
||||||
|
return _.orderBy(filteredFilenames, sortBy, sortOrder).map(
|
||||||
|
(filename: Filename) => {
|
||||||
const width = photoWidth
|
const width = photoWidth
|
||||||
const height = filename.height * (width / filename.width)
|
const height = filename.height * (width / filename.width)
|
||||||
const src = `/media_thumbnail/${filename.name}?width=${width}&height=${height}`
|
const src = `/media_thumbnail/${filename.name}?width=${width}&height=${height}`
|
||||||
return { src, height, width }
|
return { src, height, width }
|
||||||
})
|
}
|
||||||
}, [filenames])
|
)
|
||||||
|
}, [filteredFilenames, photoWidth, sortBy, sortOrder])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -120,6 +162,66 @@ export default function FileManager(props: Props) {
|
|||||||
className="file-manager-modal"
|
className="file-manager-modal"
|
||||||
show={show}
|
show={show}
|
||||||
>
|
>
|
||||||
|
<Flex style={{ justifyContent: 'end', gap: 8 }}>
|
||||||
|
<Flex
|
||||||
|
style={{
|
||||||
|
position: 'relative',
|
||||||
|
justifyContent: 'start',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MagnifyingGlassIcon style={{ position: 'absolute', left: 8 }} />
|
||||||
|
<TextInput
|
||||||
|
ref={ref}
|
||||||
|
value={searchText}
|
||||||
|
className="file-search-input"
|
||||||
|
tabIndex={-1}
|
||||||
|
onInput={(evt: FormEvent<HTMLInputElement>) => {
|
||||||
|
evt.preventDefault()
|
||||||
|
evt.stopPropagation()
|
||||||
|
const target = evt.target as HTMLInputElement
|
||||||
|
setSearchText(target.value)
|
||||||
|
}}
|
||||||
|
placeholder="Search by file name"
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<Flex style={{ gap: 8 }}>
|
||||||
|
<Selector
|
||||||
|
width={130}
|
||||||
|
value={SortByMap[sortBy]}
|
||||||
|
options={Object.values(SortByMap)}
|
||||||
|
onChange={val => {
|
||||||
|
if (val === SORT_BY_CREATED_TIME) {
|
||||||
|
setSortBy(SortBy.CTIME)
|
||||||
|
} else {
|
||||||
|
setSortBy(SortBy.NAME)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
chevronDirection="down"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon={<BarsArrowDownIcon />}
|
||||||
|
toolTip="Descending order"
|
||||||
|
tooltipPosition="bottom"
|
||||||
|
onClick={() => {
|
||||||
|
setSortOrder(SortOrder.DESCENDING)
|
||||||
|
}}
|
||||||
|
className={
|
||||||
|
sortOrder !== SortOrder.DESCENDING ? 'sort-btn-inactive' : ''
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon={<BarsArrowUpIcon />}
|
||||||
|
toolTip="Ascending order"
|
||||||
|
tooltipPosition="bottom"
|
||||||
|
onClick={() => {
|
||||||
|
setSortOrder(SortOrder.ASCENDING)
|
||||||
|
}}
|
||||||
|
className={
|
||||||
|
sortOrder !== SortOrder.ASCENDING ? 'sort-btn-inactive' : ''
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
<ScrollArea.Root className="ScrollAreaRoot">
|
<ScrollArea.Root className="ScrollAreaRoot">
|
||||||
<ScrollArea.Viewport
|
<ScrollArea.Viewport
|
||||||
className="ScrollAreaViewport"
|
className="ScrollAreaViewport"
|
||||||
@ -129,9 +231,8 @@ export default function FileManager(props: Props) {
|
|||||||
<PhotoAlbum
|
<PhotoAlbum
|
||||||
layout="masonry"
|
layout="masonry"
|
||||||
photos={photos}
|
photos={photos}
|
||||||
renderPhoto={renderPhoto}
|
|
||||||
spacing={8}
|
spacing={8}
|
||||||
padding={8}
|
padding={0}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
/>
|
/>
|
||||||
</ScrollArea.Viewport>
|
</ScrollArea.Viewport>
|
||||||
@ -141,12 +242,12 @@ export default function FileManager(props: Props) {
|
|||||||
>
|
>
|
||||||
<ScrollArea.Thumb className="ScrollAreaThumb" />
|
<ScrollArea.Thumb className="ScrollAreaThumb" />
|
||||||
</ScrollArea.Scrollbar>
|
</ScrollArea.Scrollbar>
|
||||||
<ScrollArea.Scrollbar
|
{/* <ScrollArea.Scrollbar
|
||||||
className="ScrollAreaScrollbar"
|
className="ScrollAreaScrollbar"
|
||||||
orientation="horizontal"
|
orientation="horizontal"
|
||||||
>
|
>
|
||||||
<ScrollArea.Thumb className="ScrollAreaThumb" />
|
<ScrollArea.Thumb className="ScrollAreaThumb" />
|
||||||
</ScrollArea.Scrollbar>
|
</ScrollArea.Scrollbar> */}
|
||||||
<ScrollArea.Corner className="ScrollAreaCorner" />
|
<ScrollArea.Corner className="ScrollAreaCorner" />
|
||||||
</ScrollArea.Root>
|
</ScrollArea.Root>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useRef } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
|
||||||
import Editor from './Editor/Editor'
|
import Editor from './Editor/Editor'
|
||||||
import ShortcutsModal from './Shortcuts/ShortcutsModal'
|
import ShortcutsModal from './Shortcuts/ShortcutsModal'
|
||||||
import SettingModal from './Settings/SettingsModal'
|
import SettingModal from './Settings/SettingsModal'
|
||||||
@ -24,7 +24,7 @@ import PESidePanel from './SidePanel/PESidePanel'
|
|||||||
import FileManager from './FileManager/FileManager'
|
import FileManager from './FileManager/FileManager'
|
||||||
|
|
||||||
const Workspace = () => {
|
const Workspace = () => {
|
||||||
const [file, setFile] = useRecoilState(fileState)
|
const setFile = useSetRecoilState(fileState)
|
||||||
const [settings, setSettingState] = useRecoilState(settingState)
|
const [settings, setSettingState] = useRecoilState(settingState)
|
||||||
const [toastVal, setToastState] = useRecoilState(toastState)
|
const [toastVal, setToastState] = useRecoilState(toastState)
|
||||||
const isSD = useRecoilValue(isSDState)
|
const isSD = useRecoilValue(isSDState)
|
||||||
|
27
lama_cleaner/app/src/components/shared/Layout.tsx
Normal file
27
lama_cleaner/app/src/components/shared/Layout.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import React, { ReactNode } from 'react'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: ReactNode
|
||||||
|
className?: string
|
||||||
|
style?: React.CSSProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
const Flex: React.FC<Props> = props => {
|
||||||
|
const { children, className, style } = props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
...style,
|
||||||
|
}}
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Flex
|
33
lama_cleaner/app/src/hooks/useAsyncMemo.tsx
Normal file
33
lama_cleaner/app/src/hooks/useAsyncMemo.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { DependencyList, useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
export function useAsyncMemo<T>(
|
||||||
|
factory: () => Promise<T> | undefined | null,
|
||||||
|
deps: DependencyList
|
||||||
|
): T | undefined
|
||||||
|
export function useAsyncMemo<T>(
|
||||||
|
factory: () => Promise<T> | undefined | null,
|
||||||
|
deps: DependencyList,
|
||||||
|
initial: T
|
||||||
|
): T
|
||||||
|
export function useAsyncMemo<T>(
|
||||||
|
factory: () => Promise<T> | undefined | null,
|
||||||
|
deps: DependencyList,
|
||||||
|
initial?: T
|
||||||
|
) {
|
||||||
|
const [val, setVal] = useState<T | undefined>(initial)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let cancel = false
|
||||||
|
const promise = factory()
|
||||||
|
if (promise === undefined || promise === null) return
|
||||||
|
promise.then(v => {
|
||||||
|
if (!cancel) {
|
||||||
|
setVal(v)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return () => {
|
||||||
|
cancel = true
|
||||||
|
}
|
||||||
|
}, deps)
|
||||||
|
return val
|
||||||
|
}
|
@ -3526,6 +3526,11 @@
|
|||||||
"@types/qs" "*"
|
"@types/qs" "*"
|
||||||
"@types/serve-static" "*"
|
"@types/serve-static" "*"
|
||||||
|
|
||||||
|
"@types/flexsearch@^0.7.3":
|
||||||
|
version "0.7.3"
|
||||||
|
resolved "https://registry.npmmirror.com/@types/flexsearch/-/flexsearch-0.7.3.tgz#ee79b1618035c82284278e05652e91116765b634"
|
||||||
|
integrity sha512-HXwADeHEP4exXkCIwy2n1+i0f1ilP1ETQOH5KDOugjkTFZPntWo0Gr8stZOaebkxsdx+k0X/K6obU/+it07ocg==
|
||||||
|
|
||||||
"@types/graceful-fs@^4.1.2":
|
"@types/graceful-fs@^4.1.2":
|
||||||
version "4.1.5"
|
version "4.1.5"
|
||||||
resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz"
|
resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz"
|
||||||
@ -6411,6 +6416,11 @@ flatted@^3.1.0:
|
|||||||
resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz"
|
resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz"
|
||||||
integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==
|
integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==
|
||||||
|
|
||||||
|
flexsearch@0.7.21:
|
||||||
|
version "0.7.21"
|
||||||
|
resolved "https://registry.npmmirror.com/flexsearch/-/flexsearch-0.7.21.tgz#0f5ede3f2aae67ddc351efbe3b24b69d29e9d48b"
|
||||||
|
integrity sha512-W7cHV7Hrwjid6lWmy0IhsWDFQboWSng25U3VVywpHOTJnnAZNPScog67G+cVpeX9f7yDD21ih0WDrMMT+JoaYg==
|
||||||
|
|
||||||
follow-redirects@^1.0.0:
|
follow-redirects@^1.0.0:
|
||||||
version "1.14.4"
|
version "1.14.4"
|
||||||
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz"
|
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz"
|
||||||
|
@ -85,8 +85,9 @@ class FileManager:
|
|||||||
names = sorted([it.name for it in glob_img(self.root_directory)])
|
names = sorted([it.name for it in glob_img(self.root_directory)])
|
||||||
res = []
|
res = []
|
||||||
for name in names:
|
for name in names:
|
||||||
img = Image.open(os.path.join(self.root_directory, name))
|
path = os.path.join(self.root_directory, name)
|
||||||
res.append({"name": name, "height": img.height, "width": img.width})
|
img = Image.open(path)
|
||||||
|
res.append({"name": name, "height": img.height, "width": img.width, "ctime": os.path.getctime(path)})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -48,7 +48,7 @@ def aspect_to_string(size):
|
|||||||
return "x".join(map(str, size))
|
return "x".join(map(str, size))
|
||||||
|
|
||||||
|
|
||||||
IMG_SUFFIX = {'.jpg', '.jpeg', '.png'}
|
IMG_SUFFIX = {'.jpg', '.jpeg', '.png', '.JPG', '.JPEG', '.PNG'}
|
||||||
|
|
||||||
|
|
||||||
def glob_img(p: Union[Path, str], recursive: bool = False):
|
def glob_img(p: Union[Path, str], recursive: bool = False):
|
||||||
|
@ -62,6 +62,7 @@ class SD(InpaintModel):
|
|||||||
|
|
||||||
if kwargs.get('cpu_offload', False) and torch.cuda.is_available():
|
if kwargs.get('cpu_offload', False) and torch.cuda.is_available():
|
||||||
# TODO: gpu_id
|
# TODO: gpu_id
|
||||||
|
logger.info("Enable sequential cpu offload")
|
||||||
self.model.enable_sequential_cpu_offload(gpu_id=0)
|
self.model.enable_sequential_cpu_offload(gpu_id=0)
|
||||||
else:
|
else:
|
||||||
if kwargs['sd_cpu_textencoder']:
|
if kwargs['sd_cpu_textencoder']:
|
||||||
|
@ -78,3 +78,18 @@ def test_paint_by_example_cpu_offload(strategy):
|
|||||||
fy=0.9,
|
fy=0.9,
|
||||||
fx=1.3
|
fx=1.3
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("strategy", [HDStrategy.ORIGINAL])
|
||||||
|
def test_paint_by_example_cpu_offload_cpu_device(strategy):
|
||||||
|
model = ModelManager(name="paint_by_example", device = torch.device('cpu'), cpu_offload=True)
|
||||||
|
cfg = get_config(strategy, paint_by_example_steps=1, sd_scale=0.85)
|
||||||
|
assert_equal(
|
||||||
|
model,
|
||||||
|
cfg,
|
||||||
|
f"paint_by_example_{strategy.capitalize()}_cpu_offload_cpu_device.png",
|
||||||
|
img_p=current_dir / "overture-creations-5sI6fQgYIuo.png",
|
||||||
|
mask_p=current_dir / "overture-creations-5sI6fQgYIuo_mask.png",
|
||||||
|
fy=0.9,
|
||||||
|
fx=1.3
|
||||||
|
)
|
||||||
|
@ -181,3 +181,28 @@ def test_runway_sd_1_5_cpu_offload(sd_device, strategy, sampler):
|
|||||||
img_p=current_dir / "overture-creations-5sI6fQgYIuo.png",
|
img_p=current_dir / "overture-creations-5sI6fQgYIuo.png",
|
||||||
mask_p=current_dir / "overture-creations-5sI6fQgYIuo_mask.png",
|
mask_p=current_dir / "overture-creations-5sI6fQgYIuo_mask.png",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("sd_device", ['cpu'])
|
||||||
|
@pytest.mark.parametrize("strategy", [HDStrategy.ORIGINAL])
|
||||||
|
@pytest.mark.parametrize("sampler", [SDSampler.k_euler_a])
|
||||||
|
def test_runway_sd_1_5_cpu_offload_cpu_device(sd_device, strategy, sampler):
|
||||||
|
model = ModelManager(name="sd1.5",
|
||||||
|
device=torch.device(sd_device),
|
||||||
|
hf_access_token="",
|
||||||
|
sd_run_local=True,
|
||||||
|
sd_disable_nsfw=False,
|
||||||
|
sd_cpu_textencoder=False,
|
||||||
|
cpu_offload=True)
|
||||||
|
cfg = get_config(strategy, prompt='a fox sitting on a bench', sd_steps=1, sd_scale=0.85)
|
||||||
|
cfg.sd_sampler = sampler
|
||||||
|
|
||||||
|
name = f"device_{sd_device}_{sampler}"
|
||||||
|
|
||||||
|
assert_equal(
|
||||||
|
model,
|
||||||
|
cfg,
|
||||||
|
f"runway_sd_{strategy.capitalize()}_{name}_cpu_offload_cpu_device.png",
|
||||||
|
img_p=current_dir / "overture-creations-5sI6fQgYIuo.png",
|
||||||
|
mask_p=current_dir / "overture-creations-5sI6fQgYIuo_mask.png",
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user