Skip to content

Commit

Permalink
Add error handling to PromptForm and update state management; enhance…
Browse files Browse the repository at this point in the history
… ControlNetSelector and ColorGradingSelector with error display; refactor prompt submission logic
  • Loading branch information
Precious-Macaulay committed Nov 7, 2024
1 parent 158db0b commit ff24adf
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 58 deletions.
94 changes: 57 additions & 37 deletions src/components/PromptForm/AdvancedControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,34 @@ import AddLoraText from "./AddLoraText";
import { usePromptFormStore } from '@/store/promptFormStore';
import { ChevronUp, ChevronDown } from "lucide-react";


interface RangeInputProps {
label: string;
value: number;
onChange: (value: number) => void;
min?: string;
max?: string;
step?: string;
error?: string | string[] | null;
}

const RangeInput = ({ label, value, onChange, min = "0.0", max = "1.0", step = "0.01" }: RangeInputProps) => (
<div className="flex items-center justify-between gap-1">
<label className="text-sm font-[400] text-gray-700 dark:text-gray-200">
{label}
</label>
<input
type="range"
min={min}
max={max}
step={step}
value={value}
onChange={(e) => onChange(parseFloat(e.target.value))}
className="col-span-2 w-3/5 h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>
const RangeInput = ({ label, value, onChange, min = "0.0", max = "1.0", step = "0.01", error }: RangeInputProps) => (
<div className="leading-0">
<div className="flex items-center justify-between gap-1 my-2">
<label className="text-sm font-[400] text-gray-700 dark:text-gray-200">
{label}
</label>
<input
type="range"
min={min}
max={max}
step={step}
value={value}
onChange={(e) => onChange(parseFloat(e.target.value))}
className="col-span-2 w-3/5 h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>
</div>
{error && <p className="text-red-500 text-xs">{error}</p>}
</div>
);

Expand All @@ -40,31 +45,42 @@ interface SwitchInputProps {
disabled?: boolean;
}

const SwitchInput = ({ label, checked, onCheckedChange, disabled = false }: SwitchInputProps) => (
<div className="flex items-center justify-between mt-3">
<label className="text-sm font-[400] text-gray-700 dark:text-gray-200 gap-1">
{label}
</label>
<Switch className="justify-self-end" checked={checked} onCheckedChange={onCheckedChange} disabled={disabled} />
const SwitchInput = ({ label, checked, onCheckedChange, disabled = false, error }: SwitchInputProps & { error?: string }) => (
<div className="leading-0">
<div className="flex items-center justify-between mt-3">
<label className="text-sm font-[400] text-gray-700 dark:text-gray-200 gap-1">
{label}
</label>
<Switch className="justify-self-end" checked={checked} onCheckedChange={onCheckedChange} disabled={disabled} />
</div>
{error && <p className="text-red-500 text-xs">{error}</p>}
</div>
);

export const AdvancedControls = () => {
interface AdvancedControlsProps {
image: File | null;
imageUrl: string | null;
}

export const AdvancedControls = ({
image,
imageUrl
}: AdvancedControlsProps) => {
const [showAdvancedOptions, setShowAdvancedOptions] = useState(false);
const { controlNet, setControlNet, colorGrading, setColorGrading, filmGrain, setFilmGrain,
superResolution, setSuperResolution, hiresFix, setHiresFix, inpaintFaces, setInpaintFaces,
faceCorrect, setFaceCorrect, faceSwap, setFaceSwap, denoisingStrength, setDenoisingStrength,
conditioningScale, setConditioningScale, numImages, setNumImages, promptText, setPromptText
conditioningScale, setConditioningScale, numImages, setNumImages, promptText, setPromptText, error,
} = usePromptFormStore();

return (
<div className="advanced-controls grid grid-rows-2 grid-cols-1 md:grid-cols-2 gap-2 overflow-auto h-[480px] scrollbar dark:bg-zinc-900 dark:border-zinc-800">
<div className="advanced-controls grid md:grid-rows-2 grid-cols-1 md:grid-cols-2 gap-1 overflow-auto h-[400px] md:h-[480px] scrollbar dark:bg-zinc-900 dark:border-zinc-800">
<AspectRatioSlider
baseSize={1024}
className="my-1 h-fit"
className="rounded-t-lg md:rounded-tr-none md:rounded-tl-lg"
/>

<div className={`row-span-2 scrollbar bg-gray-50 p-4 rounded-md`}>
<div className={`md:row-span-2 scrollbar bg-gray-50 p-4 rounded-bl-lg rounded-br-lg md:rounded-bl-none md:rounded-r-lg order-3 md:order-2`}>
<div className="flex justify-between items-center mb-1">
<h2 className="text-sm font-medium text-gray-800">Advance Settings</h2>
</div>
Expand All @@ -73,7 +89,7 @@ export const AdvancedControls = () => {
}} onRemove={(loraText) => {
setPromptText(promptText.replace(loraText, ""));
}} />
<SwitchInput label="Super Resolution" checked={superResolution} onCheckedChange={setSuperResolution} />
<SwitchInput label="Super Resolution" checked={superResolution} onCheckedChange={setSuperResolution} error={error?.super_resolution?.join(" ")} />
<div className="col-span-full justify-center flex items-center mt-6">
<button onClick={() => setShowAdvancedOptions(!showAdvancedOptions)} className="text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 text-sm">
<ChevronDown className={`w-6 h-6 ${showAdvancedOptions ? 'hidden' : 'block'}`} />
Expand All @@ -82,9 +98,9 @@ export const AdvancedControls = () => {

{showAdvancedOptions && (
<div className="space-y-3">
<SwitchInput label="Inpaint Faces" checked={inpaintFaces} onCheckedChange={setInpaintFaces} disabled={!superResolution} />
<SwitchInput label="Hi-Res Fix" checked={hiresFix} onCheckedChange={setHiresFix} disabled={!superResolution} />
<ColorGradingSelector value={colorGrading} onChange={setColorGrading} />
<SwitchInput label="Inpaint Faces" checked={inpaintFaces} onCheckedChange={setInpaintFaces} disabled={!superResolution} error={error?.inpaint_faces?.join(" ")} />
<SwitchInput label="Hi-Res Fix" checked={hiresFix} onCheckedChange={setHiresFix} disabled={!superResolution} error={error?.hires_fix?.join(" ")} />
<ColorGradingSelector value={colorGrading} onChange={setColorGrading} error={error?.color_grading?.join(" ")} />
<div className="flex items-center justify-between">
<label className="text-sm font-[400] text-gray-700 dark:text-gray-200">
Number of Images
Expand All @@ -97,26 +113,30 @@ export const AdvancedControls = () => {
onChange={(e) => setNumImages(parseInt(e.target.value, 10))}
className="col-span-2 border rounded-full h-6 py-1 text-center bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-200"
/>
{error?.num_images && <p className="text-red-500 text-xs ml-2">{error.num_images.join(" ")}</p>}
</div>
<SwitchInput label="Film Grain" checked={filmGrain} onCheckedChange={setFilmGrain} />
<SwitchInput label="Face Correct" checked={faceCorrect} onCheckedChange={setFaceCorrect} />
<SwitchInput label="Face Swap" checked={faceSwap} onCheckedChange={setFaceSwap} />
<SwitchInput label="Film Grain" checked={filmGrain} onCheckedChange={setFilmGrain} error={error?.film_grain?.join(" ")} />
<SwitchInput label="Face Correct" checked={faceCorrect} onCheckedChange={setFaceCorrect} error={error?.face_correct?.join(" ")} />
<SwitchInput label="Face Swap" checked={faceSwap} onCheckedChange={setFaceSwap} error={error?.face_swap?.join(" ")} />
</div>
)}
<div className="col-span-full justify-center flex items-center mt-6">
<div className="col-span-full justify-center flex items-center mt-4">
<button onClick={() => setShowAdvancedOptions(!showAdvancedOptions)} className="text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 text-sm">
<ChevronUp className={`w-6 h-6 ${showAdvancedOptions ? 'block' : 'hidden'}`} />
</button>
</div>
</div>

<div className={`w-full grid grid-cols-1 p-4 bg-gray-50 rounded-lg`}>
<div className={`w-full grid grid-cols-1 p-4 bg-gray-50 rounded-bl-lg md:order-3 order-2 ${!image && !imageUrl ? 'opacity-50 pointer-events-none' : ''}`}>
<div className="flex justify-between items-center mb-4">
<h2 className="text-sm font-medium text-gray-800">ControlNet/Img2Img</h2>
</div>
<ControlNetSelector value={controlNet} onChange={setControlNet} />
<RangeInput label="Denoising Strength" value={denoisingStrength} onChange={setDenoisingStrength} />
<RangeInput label="Conditioning Scale" value={conditioningScale} onChange={setConditioningScale} />
{(!image && !imageUrl) && (
<p className="text-sm text-gray-500 mb-4">Please upload an image to use these controls</p>
)}
<ControlNetSelector error={error?.controlnet?.join(" ")} value={controlNet} onChange={setControlNet} />
<RangeInput error={error?.denoising_strength?.join(" ") || null} label="Denoising Strength" value={denoisingStrength} onChange={setDenoisingStrength} />
<RangeInput error={error?.controlnet_conditioning_scale?.join(" ") || null} label="Conditioning Scale" value={conditioningScale} onChange={setConditioningScale} />
</div>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/PromptForm/AspectRatioSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const AspectRatioSlider: React.FC<AspectRatioSliderProps> = ({
const handleReset = () => handleSliderChange(0);

return (
<div className={`w-full ${className} p-4 bg-gray-50 rounded-lg`}>
<div className={`w-full ${className} p-4 bg-gray-50`}>
<div className="flex justify-between items-center mb-4">
<h2 className="text-sm font-medium text-gray-800">Aspect Ratio</h2>
<div className="flex items-center gap-2">
Expand Down
8 changes: 7 additions & 1 deletion src/components/PromptForm/ColorGradingSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,22 @@ interface ColorGradingSelectorProps {
value?: string;
onChange?: (grading: string) => void;
className?: string;
error?: string;
}

const ColorGradingSelector: React.FC<ColorGradingSelectorProps> = ({
value = 'film-velvia',
onChange,
className = '',
error,
}) => {
const handleValueChange = (grading: string) => {
onChange?.(grading);
};


return (
<div className="leading-0">
<div className={cn("color-grading-selector gap-1 grid grid-cols-3 items-center", className)}>
<label htmlFor="color-grading" className="text-gray-700 font-[400] text-sm mb-2">
Color Grading
Expand All @@ -40,7 +44,7 @@ const ColorGradingSelector: React.FC<ColorGradingSelectorProps> = ({
key={option.value}
value={option.value}
className={cn(
"px-3 py-1 rounded-md text-sm font-medium",
"px-3 py-1 rounded-md text-sm font-medium leading-3",
value === option.value ? "bg-blue-500 text-white" : "text-gray-700",
index === 1 ? 'rounded-none' : index === 0 ? 'rounded-l-full' : 'rounded-r-full'
)}
Expand All @@ -52,6 +56,8 @@ const ColorGradingSelector: React.FC<ColorGradingSelectorProps> = ({
</ToggleGroup.Root>
</div>
</div>
{error && <p className="text-red-500 text-xs">{error}</p>}
</div>
);
};

Expand Down
5 changes: 5 additions & 0 deletions src/components/PromptForm/ControlNetSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,21 @@ interface ControlNetSelectorProps {
value?: string;
onChange?: (model: string) => void;
className?: string;
error?: string;
}

const ControlNetSelector: React.FC<ControlNetSelectorProps> = ({
value = '',
onChange,
className = '',
error
}) => {
const handleValueChange = (model: string) => {
onChange?.(model);
};

return (
<div className="leading-0">
<div className={cn("color-grading-selector gap-1 grid grid-cols-3 items-center", className)}>
<label htmlFor="color-grading" className="text-gray-700 text-sm font-[400] mb-2">
ControlNet
Expand Down Expand Up @@ -51,6 +54,8 @@ const ControlNetSelector: React.FC<ControlNetSelectorProps> = ({
</ToggleGroup.Root>
</div>
</div>
{error && <p className="text-red-500 text-xs">{error}</p>}
</div>
);
};

Expand Down
43 changes: 25 additions & 18 deletions src/components/PromptForm/PromptForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import usePaste from '@/hooks/usePaste';
import { SendIcon } from 'lucide-react';
import { useStore } from '@/store/promptStore';
import { useAPrompt } from '@/hooks/useAPrompt';
import { AxiosError } from 'axios';

interface PromptFormProps {
tabDisplay?: boolean;
Expand All @@ -30,7 +31,7 @@ const PromptForm: React.FC<PromptFormProps> = () => {
controlNet, setControlNet, colorGrading, setColorGrading,
superResolution, setSuperResolution, hiresFix, setHiresFix, inpaintFaces, setInpaintFaces,
faceCorrect, setFaceCorrect, faceSwap, setFaceSwap, denoisingStrength, setDenoisingStrength,
conditioningScale, setConditioningScale, numImages, setNumImages, isLoading, setIsLoading,
conditioningScale, setConditioningScale, numImages, setNumImages, isLoading, setIsLoading, setError
} = usePromptFormStore();

const { userPrompts, refreshUserPrompts } = useStore();
Expand All @@ -39,6 +40,7 @@ const PromptForm: React.FC<PromptFormProps> = () => {

usePaste((pasteText, pasteObject) => {
if (pasteText) setPromptText(pasteText);
console.log(pasteObject);
if (pasteObject) {
setControlNet(pasteObject.controlnet || controlNet);
setColorGrading(pasteObject.color_grading || colorGrading);
Expand Down Expand Up @@ -66,29 +68,34 @@ const PromptForm: React.FC<PromptFormProps> = () => {
const formData = new FormData();
formData.append('prompt[text]', promptText);
formData.append('prompt[tune_id]', "1504944");
if (image) formData.append('prompt[image]', image);
formData.append('prompt[control_net]', controlNet);
formData.append('prompt[color_grading]', colorGrading);
formData.append('prompt[super_resolution]', `${superResolution}`);
formData.append('prompt[hires_fix]', `${hiresFix}`);
formData.append('prompt[inpaint_faces]', `${inpaintFaces}`);
formData.append('prompt[face_correct]', `${faceCorrect}`);
formData.append('prompt[face_swap]', `${faceSwap}`);
formData.append('prompt[denoising_strength]', denoisingStrength.toString());
formData.append('prompt[conditioning_scale]', conditioningScale.toString());
formData.append('prompt[num_images]', numImages.toString());
formData.append('prompt[w]', width.toString());
formData.append('prompt[h]', height.toString());
if (image) formData.append('prompt[input_image]', image);
if (urlImage) formData.append('prompt[input_image_url]', urlImage);
if (controlNet) formData.append('prompt[control_net]', controlNet);
if (colorGrading) formData.append('prompt[color_grading]', colorGrading);
if (superResolution !== undefined) formData.append('prompt[super_resolution]', `${superResolution}`);
if (hiresFix !== undefined) formData.append('prompt[hires_fix]', `${hiresFix}`);
if (inpaintFaces !== undefined) formData.append('prompt[inpaint_faces]', `${inpaintFaces}`);
if (faceCorrect !== undefined) formData.append('prompt[face_correct]', `${faceCorrect}`);
if (faceSwap !== undefined) formData.append('prompt[face_swap]', `${faceSwap}`);
if (denoisingStrength !== undefined) formData.append('prompt[denoising_strength]', `${denoisingStrength}`);
if (conditioningScale !== undefined) formData.append('prompt[conditioning_scale]', `${conditioningScale}`);
if (numImages !== undefined) formData.append('prompt[num_images]', `${numImages}`);
if (width !== undefined) formData.append('prompt[w]', `${width}`);
if (height !== undefined) formData.append('prompt[h]', `${height}`);
formData.append('prompt[backend_version]', '0');

await createPrompt(formData);
toast.success('Prompt created successfully!');
refreshUserPrompts();
setShowImageControls(false);
setShowAdvancedControls(false);
} catch (error) {
toast.error(`Error creating prompt: ${(error as any)?.response?.data?.text?.join(', ') || (error as any).message}`);
console.error(error);
} catch (error: AxiosError | any) {
console.error(error.response?.data);
if (error.response?.data) {
setError(error.response.data);
} else {
toast.error('Error creating prompt');
}
} finally {
setIsLoading(false);
}
Expand Down Expand Up @@ -196,7 +203,7 @@ const PromptForm: React.FC<PromptFormProps> = () => {
</div>
<Card className="w-full">
<CardContent className="p-2 z-20">
<AdvancedControls />
<AdvancedControls image={image} imageUrl={urlImage} />
</CardContent>
</Card>
</>
Expand Down
1 change: 1 addition & 0 deletions src/store/promptFormStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const usePromptFormStore = create<PromptFormState>((set) => ({
conditioningScale: 0.8, setConditioningScale: (conditioningScale) => set({ conditioningScale }),
numImages: 4, setNumImages: (numImages) => set({ numImages }),
loraTextList: [], setLoraTextList: (loraTextList) => set({ loraTextList }),
error: {}, setError: (error) => set({ error }),
isLoading: false, setIsLoading: (isLoading) => set({ isLoading }),
}));

6 changes: 5 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ export interface PromptDetailsProps {
imageUrl: string;
}

export type ErrorObject = {
[key in keyof Prompt]?: string[];
};


export interface PromptFormState {
promptText: string; setPromptText: (text: string) => void;
Expand All @@ -99,6 +103,6 @@ export interface PromptFormState {
conditioningScale: number; setConditioningScale: (conditioningScale: number) => void;
numImages: number; setNumImages: (numImages: number) => void;
loraTextList: string[]; setLoraTextList: (loraTextList: string[]) => void;

error: ErrorObject; setError: (error: ErrorObject) => void;
isLoading: boolean; setIsLoading: (isLoading: boolean) => void;
}

0 comments on commit ff24adf

Please sign in to comment.