From 097496a7394309fdbf150e9a068a7bfed0d786ba Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Wed, 20 Mar 2024 23:20:42 -0500 Subject: [PATCH] Integrate ai auto-fill into edit form --- src/components/FieldSetWithStatus.tsx | 4 +-- src/photo/ai/index.ts | 4 +-- src/photo/ai/useImageQueries.ts | 19 ++++++++++++--- src/photo/form/PhotoForm.tsx | 35 +++++++++++++++++++++++---- src/photo/form/index.ts | 2 +- 5 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/components/FieldSetWithStatus.tsx b/src/components/FieldSetWithStatus.tsx index 19e7ab01..85677d12 100644 --- a/src/components/FieldSetWithStatus.tsx +++ b/src/components/FieldSetWithStatus.tsx @@ -99,7 +99,7 @@ export default function FieldSetWithStatus({ options={tagOptions} onChange={onChange} className={clsx(Boolean(error) && 'error')} - readOnly={readOnly || pending} + readOnly={readOnly || pending || loading} /> : = { 'title': 'Provide a short title for this image in 3 words or less', @@ -20,7 +20,7 @@ export const AI_IMAGE_QUERIES: Record = { 'description-small': 'Describe this image succinctly', 'description': 'Describe this image', 'description-large': 'Describe this image in detail', - 'semantic': 'List up to 5 things in this image without description as a comma-separated list', + 'description-semantic': 'List up to 5 things in this image without description as a comma-separated list', }; export const streamAiImageQuery = (imageBase64: string, query: AiImageQuery) => diff --git a/src/photo/ai/useImageQueries.ts b/src/photo/ai/useImageQueries.ts index 1fffe33a..f0fd504d 100644 --- a/src/photo/ai/useImageQueries.ts +++ b/src/photo/ai/useImageQueries.ts @@ -24,11 +24,21 @@ export default function useImageQueries() { const [ requestSemantic, - semantic, + semanticDescription, isLoadingSemantic, - ] = useImageQuery(imageData, 'semantic'); + ] = useImageQuery(imageData, 'description-semantic'); - const isLoading = isLoadingTitleCaption || isLoadingTags || isLoadingSemantic; + const hasContent = Boolean( + title || + caption || + tags || + semanticDescription + ); + + const isLoading = + isLoadingTitleCaption || + isLoadingTags || + isLoadingSemantic; const request = useCallback(async () => { if (!isLoading) { @@ -44,8 +54,9 @@ export default function useImageQueries() { title, caption, tags, - semantic, + semanticDescription, isReady, + hasContent, isLoading, isLoadingTitleCaption, isLoadingTags, diff --git a/src/photo/form/PhotoForm.tsx b/src/photo/form/PhotoForm.tsx index c2708e51..b730f086 100644 --- a/src/photo/form/PhotoForm.tsx +++ b/src/photo/form/PhotoForm.tsx @@ -120,6 +120,33 @@ export default function PhotoForm({ } }, []); + useEffect(() => { + if (aiContent?.hasContent) { + setFormData(data => ({ + ...data, + title: aiContent.title, + caption: aiContent.caption, + tags: aiContent.tags, + semanticDescription: aiContent.semanticDescription, + })); + } + }, [aiContent]); + + const isFieldGeneratingAi = (key: keyof PhotoFormData) => { + switch (key) { + case 'title': + return aiContent?.isLoadingTitleCaption; + case 'caption': + return aiContent?.isLoadingTitleCaption; + case 'tags': + return aiContent?.isLoadingTags; + case 'semanticDescription': + return aiContent?.isLoadingSemantic; + default: + return false; + } + }; + return (
{debugBlur && blurError && @@ -158,10 +185,6 @@ export default function PhotoForm({ height={height} />}
-
Title: {aiContent?.title}
-
Caption: {aiContent?.caption}
-
Tags: {aiContent?.tags}
-
Semantic: {aiContent?.semantic}
blur()} @@ -228,7 +251,9 @@ export default function PhotoForm({ placeholder={loadingMessage && !formData[key] ? loadingMessage : undefined} - loading={loadingMessage && !formData[key] ? true : false} + loading={ + (loadingMessage && !formData[key] ? true : false) || + isFieldGeneratingAi(key)} type={type} />)}
diff --git a/src/photo/form/index.ts b/src/photo/form/index.ts index 0e4a05cd..f602dd4d 100644 --- a/src/photo/form/index.ts +++ b/src/photo/form/index.ts @@ -80,7 +80,7 @@ const FORM_METADATA = ( : undefined, }, semanticDescription: { - label: 'semantic description', + label: 'semantic description (not visible)', capitalize: true, validateStringMaxLength: STRING_MAX_LENGTH_LONG, hide: !aiTextGeneration,