Integrate ai auto-fill into edit form

This commit is contained in:
Sam Becker 2024-03-20 23:20:42 -05:00
parent e2e8c8edda
commit 097496a739
5 changed files with 50 additions and 14 deletions

View File

@ -99,7 +99,7 @@ export default function FieldSetWithStatus({
options={tagOptions}
onChange={onChange}
className={clsx(Boolean(error) && 'error')}
readOnly={readOnly || pending}
readOnly={readOnly || pending || loading}
/>
: <input
ref={inputRef}
@ -114,7 +114,7 @@ export default function FieldSetWithStatus({
type={type}
autoComplete="off"
autoCapitalize={!capitalize ? 'off' : undefined}
readOnly={readOnly || pending}
readOnly={readOnly || pending || loading}
className={clsx(
type === 'text' && 'w-full',
Boolean(error) && 'error',

View File

@ -10,7 +10,7 @@ export type AiImageQuery =
'description-small' |
'description' |
'description-large' |
'semantic';
'description-semantic';
export const AI_IMAGE_QUERIES: Record<AiImageQuery, string> = {
'title': 'Provide a short title for this image in 3 words or less',
@ -20,7 +20,7 @@ export const AI_IMAGE_QUERIES: Record<AiImageQuery, string> = {
'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) =>

View File

@ -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,

View File

@ -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 (
<div className="space-y-8 max-w-[38rem]">
{debugBlur && blurError &&
@ -158,10 +185,6 @@ export default function PhotoForm({
height={height}
/>}
</div>
<div>Title: {aiContent?.title}</div>
<div>Caption: {aiContent?.caption}</div>
<div>Tags: {aiContent?.tags}</div>
<div>Semantic: {aiContent?.semantic}</div>
<form
action={type === 'create' ? createPhotoAction : updatePhotoAction}
onSubmit={() => 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}
/>)}
<div className="flex gap-3">

View File

@ -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,