Merge pull request #29 from caranicas/beta-react-loading-and-cache

Beta react loading and cache
This commit is contained in:
caranicas 2022-09-19 15:08:37 -04:00 committed by GitHub
commit 9f2ae75fa2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 166 additions and 331 deletions

View File

@ -35,6 +35,7 @@ module.exports = {
yoda: ["off"],
eqeqeq: ["off"],
"spaced-comment": ["off"],
"padded-blocks": ["off"],
// TS things turned off for now
"@typescript-eslint/ban-ts-comment": "off",

View File

@ -59,7 +59,6 @@ export const toggleBetaConfig = async (branch: string) => {
export const MakeImageKey = "MakeImage";
export const doMakeImage = async (reqBody: ImageRequest) => {
const { seed, num_outputs } = reqBody;
const res = await fetch(`${API_URL}/image`, {
method: "POST",

View File

@ -8,8 +8,8 @@ import {
} from "./generatedImage.css.ts";
interface GeneretaedImageProps {
imageData: string;
metadata: ImageRequest;
imageData: string | undefined;
metadata: ImageRequest | undefined;
className?: string;
// children: never[];
}
@ -21,7 +21,7 @@ export default function GeneratedImage({
}: GeneretaedImageProps) {
return (
<div className={[generatedImageMain, className].join(" ")}>
<img className={image} src={imageData} alt={metadata.prompt} />
<img className={image} src={imageData} alt={metadata!.prompt} />
</div>
);
}

View File

@ -43,8 +43,6 @@ export default function ImprovementSettings() {
const [isFilteringDisabled, setIsFilteringDisabled] = useState(false);
// should probably be a store selector
useEffect(() => {
console.log("isUsingUpscaling", isUsingUpscaling);
console.log("isUsingFaceCorrection", isUsingFaceCorrection);
// if either are true we arent disabled
if (isUsingFaceCorrection || use_upscale) {

View File

@ -14,7 +14,6 @@ import {
} from //@ts-expect-error
"./imageModifiers.css.ts";
import { useImageCreate } from "../../../../stores/imageCreateStore";
import { useCreateUI } from "../creationPanelUIStore";
@ -88,7 +87,9 @@ export default function ImageModifers() {
<ul className={ImagerModifierGroups}>
{allModifiers.map((item, index) => {
return (
// @ts-ignore
<li key={item[0]}>
{/* @ts-ignore */}
<ModifierGrouping title={item[0]} tags={item[1]} />
</li>
);

View File

@ -10,4 +10,6 @@ const AudioDing = React.forwardRef((props, ref) => (
</audio>
));
AudioDing.displayName = "AudioDing";
export default AudioDing;

View File

@ -4,15 +4,37 @@ import { style, globalStyle } from "@vanilla-extract/css";
import { vars } from "../../../../styles/theme/index.css.ts";
export const completedImagesMain = style({
height: "100%",
width: "100%",
display: "flex",
paddingBottom: vars.spacing.medium,
});
export const completedImagesList = style({
display: "flex",
flexDirection: "row",
flexWrap: "nowrap",
height: "100%",
width: "100%",
overflow: "auto",
paddingBottom: vars.spacing.medium,
paddingLeft: vars.spacing.none,
});
globalStyle(`${completedImagesMain} li`, {
position: "relative",
});
globalStyle(`${completedImagesMain} > li:first-of-type`, {
marginLeft: vars.spacing.medium,
});
globalStyle(`${completedImagesMain} > li:last-of-type`, {
marginRight: 0,
});
export const imageContain = style({
width: "206px",
backgroundColor: "black",
@ -26,15 +48,18 @@ export const imageContain = style({
cursor: "pointer",
});
globalStyle(`${imageContain} img`, {
width: "100%",
objectFit: "contain",
});
globalStyle(`${completedImagesMain} > ${imageContain}:first-of-type`, {
marginLeft: vars.spacing.medium,
});
globalStyle(`${imageContain} > ${imageContain}:last-of-type`, {
marginRight: 0,
});
export const RemoveButton = style({
marginLeft: vars.spacing.small,
backgroundColor: vars.colors.brand,
border: "0 none",
padding: vars.spacing.small,
cursor: "pointer",
borderRadius: vars.trim.borderRadiusSmall,
});

View File

@ -4,17 +4,22 @@ import { CompletedImagesType } from "../index";
import {
completedImagesMain,
imageContain, // @ts-expect-error
completedImagesList,
imageContain,
RemoveButton,
// @ts-expect-error
} from "./completedImages.css.ts";
interface CurrentDisplayProps {
images: CompletedImagesType[] | null;
setCurrentDisplay: (image: CompletedImagesType) => void;
removeImages: () => void;
}
export default function CompletedImages({
images,
setCurrentDisplay,
removeImages,
}: CurrentDisplayProps) {
const _handleSetCurrentDisplay = (index: number) => {
const image = images![index];
@ -23,25 +28,37 @@ export default function CompletedImages({
return (
<div className={completedImagesMain}>
{images != null &&
images.map((image, index) => {
if (void 0 === image) {
console.warn(`image ${index} is undefined`);
return null;
{/* Adjust the dom do we dont do this check twice */}
{images != null && images.length > 0 && (
<button className={RemoveButton} onClick={
() => {
removeImages();
}
}>REMOVE</button>
)}
<ul className={completedImagesList}>
{images != null &&
images.map((image, index) => {
if (void 0 === image) {
console.warn(`image ${index} is undefined`);
return null;
}
return (
<button
key={index}
className={imageContain}
onClick={() => {
_handleSetCurrentDisplay(index);
}}
>
<img src={image.data} alt={image.info.prompt} />
</button>
);
})}
return (
<li key={image.id}>
<button
className={imageContain}
onClick={() => {
_handleSetCurrentDisplay(index);
}}
>
<img src={image.data} alt={image.info.prompt} />
</button>
</li>
);
})}
</ul>
</div>
);
}

View File

@ -8,12 +8,12 @@ import {
import { CompletedImagesType } from "../index";
interface CurrentDisplayProps {
isLoading: boolean;
image: CompletedImagesType | null;
}
export default function CurrentDisplay({ image }: CurrentDisplayProps) {
// @ts-ignore
const { info, data } = image != null || { info: null, data: null };
export default function CurrentDisplay({ isLoading, image }: CurrentDisplayProps) {
const { info, data } = image ?? {};
const setRequestOption = useImageCreate((state) => state.setRequestOptions);
@ -27,7 +27,8 @@ export default function CurrentDisplay({ image }: CurrentDisplayProps) {
use_upscale,
width,
height,
} = info;
} = info!;
// Most important information is the prompt
let underscoreName = prompt.replace(/[^a-zA-Z0-9]/g, "_");
@ -60,20 +61,22 @@ export default function CurrentDisplay({ image }: CurrentDisplayProps) {
setRequestOption("init_image", data);
};
return (
<div className="current-display">
{image != null && (
<div>
<p> {info.prompt}</p>
<GeneratedImage imageData={data} metadata={info}></GeneratedImage>
{isLoading
? <h4 className="loading">Loading...</h4>
: (image != null && (
<div>
<button onClick={_handleSave}>Save</button>
<button onClick={_handleUseAsInput}>Use as Input</button>
<p> {info?.prompt}</p>
<GeneratedImage imageData={data} metadata={info}></GeneratedImage>
<div>
<button onClick={_handleSave}>Save</button>
<button onClick={_handleUseAsInput}>Use as Input</button>
</div>
</div>
</div>
)}
<div></div>
)) || <h4 className="no-image">Try Making a new image!</h4>}
</div>
);
}

View File

@ -29,24 +29,48 @@ export interface CompletedImagesType {
info: ImageRequest;
}
const idDelim = '_batch';
export default function DisplayPanel() {
const dingRef = useRef<HTMLAudioElement>(null);
const isSoundEnabled = useImageCreate((state) => state.isSoundEnabled());
// @ts-expect-error
const { id, options } = useImageQueue((state) => state.firstInQueue());
const removeFirstInQueue = useImageQueue((state) => state.removeFirstInQueue);
const [currentImage, setCurrentImage] = useState<CompletedImagesType | null>(
null
);
const [isEnabled, setIsEnabled] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const { status, data } = useQuery(
[MakeImageKey, id],
async () => await doMakeImage(options),
{
enabled: void 0 !== id,
enabled: isEnabled
// void 0 !== id,
}
);
// update the enabled state when the id changes
useEffect(() => {
setIsEnabled(void 0 !== id)
}, [id]);
// helper for the loading state to be enabled aware
useEffect(() => {
if (isEnabled && status === "loading") {
setIsLoading(true);
} else {
setIsLoading(false);
}
}, [isEnabled, status]);
// this is where there loading actually happens
useEffect(() => {
// query is done
if (status === "success") {
@ -60,23 +84,23 @@ export default function DisplayPanel() {
}
}, [status, data, removeFirstInQueue, dingRef, isSoundEnabled]);
/* COMPLETED IMAGES */
const queryClient = useQueryClient();
const [completedImages, setCompletedImages] = useState<CompletedImagesType[]>(
[]
);
const completedIds = useImageQueue((state) => state.completedImageIds);
const clearCachedIds = useImageQueue((state) => state.clearCachedIds);
// const init_image = useImageCreate((state) =>
// state.getValueForRequestKey("init_image")
// );
// this is where we generate the list of completed images
useEffect(() => {
const testReq = {} as ImageRequest;
const completedQueries = completedIds.map((id) => {
const imageData = queryClient.getQueryData([MakeImageKey, id]);
return imageData;
});
}) as ImageRequest[];
if (completedQueries.length > 0) {
// map the completedImagesto a new array
@ -85,10 +109,10 @@ export default function DisplayPanel() {
.map((query, index) => {
if (void 0 !== query) {
// @ts-ignore
return query.output.map((data) => {
return query.output.map((data, index) => {
// @ts-ignore
return {
id: `${completedIds[index]}-${data.seed}`,
id: `${completedIds[index]}${idDelim}-${data.seed}-${data.index}`,
data: data.data,
// @ts-ignore
info: { ...query.request, seed: data.seed },
@ -98,10 +122,9 @@ export default function DisplayPanel() {
})
.flat()
.reverse()
.filter((item) => void 0 !== item); // remove undefined items
.filter((item) => void 0 !== item) as CompletedImagesType[]; // remove undefined items
setCompletedImages(temp);
debugger;
setCurrentImage(temp[0] || null);
} else {
setCompletedImages([]);
@ -109,14 +132,25 @@ export default function DisplayPanel() {
}
}, [setCompletedImages, setCurrentImage, queryClient, completedIds]);
// this is how we remove them
const removeImages = () => {
completedIds.forEach((id) => {
queryClient.removeQueries([MakeImageKey, id]);
});
clearCachedIds();
};
return (
<div className={displayPanel}>
<AudioDing ref={dingRef}></AudioDing>
<div className={displayContainer}>
<CurrentDisplay image={currentImage}></CurrentDisplay>
<CurrentDisplay isLoading={isLoading} image={currentImage}></CurrentDisplay>
</div>
<div className={previousImages}>
<CompletedImages
removeImages={removeImages}
images={completedImages}
setCurrentDisplay={setCurrentImage}
></CompletedImages>

View File

@ -11,6 +11,7 @@ interface ImageQueueState {
hasQueuedImages: () => boolean;
firstInQueue: () => ImageRequest | [];
removeFirstInQueue: () => void;
clearCachedIds: () => void;
}
// figure out why TS is complaining about this
@ -46,4 +47,12 @@ export const useImageQueue = create<ImageQueueState>((set, get) => ({
})
);
},
clearCachedIds: () => {
set(
produce((state) => {
state.completedImageIds = [];
})
);
}
}));

File diff suppressed because one or more lines are too long

View File

@ -12,259 +12,5 @@
<!-- The react app entry point. Currently no ui just poc importing and logging -->
<div id="root"></div>
<!-- ORIGINAL CODE BELOW FOR REFENCE -->
<!-- KEEP FOR NOW -->
<!-- THE STYLES ARE BEING USED IN THE REACT APP -->
<!-- WE NEED TO PORT OVER THE STYLES OVER TO THE REACT COMPONENTS -->
<style>
/* label {
font-size: 10pt;
}
#prompt {
width: 100%;
height: 50pt;
}
@media screen and (max-width: 600px) {
#prompt {
width: 95%;
}
}
.image_preview_container {
display: none;
margin-top: 10pt;
}
.image_clear_btn {
position: absolute;
transform: translateX(-50%) translateY(-35%);
background: black;
color: white;
border: 2pt solid #ccc;
padding: 0;
cursor: pointer;
outline: inherit;
border-radius: 8pt;
width: 16pt;
height: 16pt;
font-family: Verdana;
font-size: 8pt;
}
#editor-settings-entries {
font-size: 9pt;
margin-bottom: 5px;
padding-left: 10px;
list-style-type: none;
}
#editor-settings-entries li {
padding-bottom: 3pt;
}
#guidance_scale {
transform: translateY(30%);
} */
#outputMsg {
font-size: small;
}
#footer {
font-size: small;
padding-left: 10pt;
background: none;
}
#footer-legal {
font-size: 8pt;
}
.imgSeedLabel {
position: absolute;
transform: translateX(-100%);
margin-top: 5pt;
margin-left: -5pt;
font-size: 10pt;
background-color: #333;
opacity: 0.8;
color: #ddd;
border-radius: 3pt;
padding: 1pt 3pt;
}
.imgUseBtn {
position: absolute;
transform: translateX(-100%);
margin-top: 30pt;
margin-left: -5pt;
}
.imgSaveBtn {
position: absolute;
transform: translateX(-100%);
margin-top: 55pt;
margin-left: -5pt;
}
.imgItem {
display: inline;
padding-right: 10px;
}
.imgItemInfo {
opacity: 0.5;
}
#container {
width: 75%;
margin-left: auto;
margin-right: auto;
}
@media screen and (max-width: 1400px) {
#container {
width: 100%;
}
}
#meta small {
font-size: 11pt;
}
#editor {
padding: 5px;
}
#editor label {
font-weight: bold;
}
#preview {
padding: 5px;
}
#editor-inputs {
margin-bottom: 20px;
}
#editor-inputs-prompt {
flex: 1;
}
#editor-inputs .row {
padding-bottom: 10px;
}
#makeImage {
border-radius: 6px;
}
#editor-modifiers h5 {
padding: 5pt 0;
margin: 0;
}
#makeImage {
flex: 0 0 70px;
background: rgb(80, 0, 185);
border: 2px solid rgb(40, 0, 78);
color: rgb(255, 221, 255);
width: 100%;
height: 30pt;
}
#makeImage:hover {
background: rgb(93, 0, 214);
}
.flex-container {
display: flex;
}
.col-50 {
flex: 50%;
}
.col-free {
flex: 1;
}
.collapsible {
cursor: pointer;
}
.collapsible-content {
display: none;
padding-left: 15px;
}
.collapsible-content h5 {
padding: 5pt 0pt;
margin: 0;
font-size: 10pt;
}
.collapsible-handle {
color: white;
padding-right: 5px;
}
.panel-box {
background: rgb(44, 45, 48);
border: 1px solid rgb(47, 49, 53);
border-radius: 7px;
padding: 5px;
margin-bottom: 15px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.15),
0 6px 20px 0 rgba(0, 0, 0, 0.15);
}
.panel-box h4 {
margin: 0;
padding: 2px 0;
}
.prompt-modifier-tag {
border: 1px solid rgb(10, 0, 24);
border-radius: 4px;
padding: 0pt 3pt;
margin-right: 2pt;
cursor: pointer;
display: inline;
background: rgb(163, 163, 163);
color: black;
line-height: 25pt;
float: left;
font-size: 9pt;
}
.prompt-modifier-tag:hover {
background: black;
color: white;
}
#editor-modifiers-entries .prompt-modifier-tag {
background: #110f0f;
color: rgb(212, 212, 212);
margin-bottom: 4pt;
font-size: 10pt;
}
#editor-modifiers-entries .prompt-modifier-tag:hover {
background: rgb(163, 163, 163);
color: black;
}
#editor-modifiers .editor-modifiers-leaf {
padding-top: 10pt;
padding-bottom: 10pt;
}
#preview {
margin-left: 20pt;
}
img {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.15),
0 6px 20px 0 rgba(0, 0, 0, 0.15);
}
.line-separator {
background: rgb(56, 56, 56);
height: 1pt;
margin: 15pt 0;
}
#editor-inputs-tags-container {
margin-top: 5pt;
display: none;
}
#server-status {
float: right;
}
#server-status-color {
width: 8pt;
height: 8pt;
border-radius: 4pt;
background-color: rgb(128, 87, 0);
/* background-color: rgb(197, 1, 1); */
float: left;
transform: translateY(15%);
}
#server-status-msg {
color: rgb(128, 87, 0);
padding-left: 2pt;
font-size: 10pt;
}
#preview-prompt {
font-size: 16pt;
margin-bottom: 10pt;
}
#coffeeButton {
height: 23px;
transform: translateY(25%);
}
</style>
</body>
</html>

File diff suppressed because one or more lines are too long