Fine-tune AI text generation

This commit is contained in:
Sam Becker 2024-03-20 13:18:10 -05:00
parent 6d9f207cdf
commit a351999e37
4 changed files with 99 additions and 40 deletions

View File

@ -72,18 +72,20 @@ export default function CanvasBlurCapture({
edgeCompensation * 2,
);
onCapture(canvas.toDataURL('image/jpeg', quality));
onError?.('');
refTimeouts.current.forEach(clearTimeout);
refShouldCapture.current = false;
} else {
console.error('Cannot get 2d context');
onError?.('Cannot get 2d context');
console.error('Cannot get 2d context ... retrying');
onError?.('Cannot get 2d context ... retrying');
// Retry capture in case canvas is not available
refTimeouts.current.push(setTimeout(capture, RETRY_DELAY));
}
} else {
// eslint-disable-next-line max-len
console.error('Cannot generate blur data: canvas/image not ready');
onError?.('Cannot generate blur data: canvas/image not ready');
console.error('Cannot generate blur data: canvas/image not ready ... retrying');
// eslint-disable-next-line max-len
onError?.('Cannot generate blur data: canvas/image not ready ... retrying');
// Retry capture in case canvas is not available
refTimeouts.current.push(setTimeout(capture, RETRY_DELAY));
}

View File

@ -6,15 +6,23 @@ export type ImageQuery =
'tags' |
'descriptionSmall' |
'descriptionMedium' |
'descriptionLarge';
'descriptionLarge' |
'rich' |
'semantic';
export const IMAGE_QUERIES: Record<ImageQuery, string> = {
title: 'Provide a short title for this image',
caption: 'What is the caption of this image?',
tags: 'Describe this image three or less comma-separated keywords',
// title: 'Provide a short title for this image',
title: 'Provide a short title for this image in 3 words or less',
caption: 'What is a pithy caption for this image in 8 words or less?',
// eslint-disable-next-line max-len
tags: 'Describe this image three or less comma-separated keywords with no adjective or adverbs',
descriptionSmall: 'Describe this image succinctly',
descriptionMedium: 'Describe this image',
descriptionLarge: 'Describe this image in detail',
// eslint-disable-next-line max-len
rich: 'What is a short title and pithy caption of 8 words or less for this image?',
// eslint-disable-next-line max-len
semantic: 'List up to 5 things in this image without description as a comma-separated list',
};
export const streamImageQuery = (imageBase64: string, query: ImageQuery) =>

View File

@ -16,7 +16,7 @@ export default function useImageQuery(
setIsLoading(true);
try {
const textStream = await streamImageQueryAction(
imageBase64 ?? '',
imageBase64,
query,
);
for await (const text of readStreamableValue(textStream)) {
@ -30,9 +30,12 @@ export default function useImageQuery(
}
}, [imageBase64, query]);
// Withhold streaming text if it's a null response
const isTextError = text.toLocaleLowerCase().startsWith('sorry');
return [
request,
text,
isTextError ? '' : text,
isLoading,
error,
] as const;

View File

@ -120,12 +120,19 @@ export default function PhotoForm({
}
}, []);
const [
requestTitle,
title,
isLoadingTitle,
errorTitle,
] = useImageQuery(imageData, 'title');
// const [
// requestTitle,
// title,
// isLoadingTitle,
// errorTitle,
// ] = useImageQuery(imageData, 'title');
// const [
// requestCaption,
// caption,
// isLoadingCaption,
// errorCaption,
// ] = useImageQuery(imageData, 'caption');
const [
requestTags,
@ -135,18 +142,25 @@ export default function PhotoForm({
] = useImageQuery(imageData, 'tags');
const [
requestDescriptionSmall,
descriptionSmall,
isLoadingDescriptionSmall,
errorDescriptionSmall,
] = useImageQuery(imageData, 'descriptionSmall');
requestRich,
rich,
isLoadingRich,
errorRich,
] = useImageQuery(imageData, 'rich');
// const [
// requestDescriptionSmall,
// descriptionSmall,
// isLoadingDescriptionSmall,
// errorDescriptionSmall,
// ] = useImageQuery(imageData, 'descriptionSmall');
const [
requestDescriptionLarge,
descriptionLarge,
isLoadingDescriptionLarge,
errorDescriptionLarge,
] = useImageQuery(imageData, 'descriptionLarge');
requestSemantic,
semantic,
isLoadingSemantic,
errorSemantic,
] = useImageQuery(imageData, 'semantic');
const renderAiButton = (
label: string,
@ -180,12 +194,30 @@ export default function PhotoForm({
{blurError}
</div>}
<div className="flex gap-2 flex-wrap">
{renderAiButton(
{/* {renderAiButton(
'Title',
requestTitle,
isLoadingTitle,
errorTitle,
)}
{renderAiButton(
'Caption',
requestCaption,
isLoadingCaption,
errorCaption,
)}
{renderAiButton(
'Tags',
requestTags,
isLoadingTags,
errorTags,
)} */}
{renderAiButton(
'Rich',
requestRich,
isLoadingRich,
errorRich,
)}
{renderAiButton(
'Tags',
requestTags,
@ -193,17 +225,17 @@ export default function PhotoForm({
errorTags,
)}
{renderAiButton(
'Description (S)',
'Semantic',
requestSemantic,
isLoadingSemantic,
errorSemantic,
)}
{/* {renderAiButton(
'Description',
requestDescriptionSmall,
isLoadingDescriptionSmall,
errorDescriptionSmall,
)}
{renderAiButton(
'Description (L)',
requestDescriptionLarge,
isLoadingDescriptionLarge,
errorDescriptionLarge,
)}
)} */}
</div>
<div className="flex gap-2">
<ImageBlurFallback
@ -237,13 +269,27 @@ export default function PhotoForm({
height={height}
/>}
</div>
<p>
{/* <p>
TITLE: {title} {isLoadingTitle && <>
<span className="inline-flex translate-y-[1.5px]">
<Spinner />
</span>
</>}
</p>
<p>
CAPTION: {caption} {isLoadingCaption && <>
<span className="inline-flex translate-y-[1.5px]">
<Spinner />
</span>
</>}
</p> */}
<p>
RICH: {rich} {isLoadingRich && <>
<span className="inline-flex translate-y-[1.5px]">
<Spinner />
</span>
</>}
</p>
<p>
TAGS: {tags} {isLoadingTags && <>
<span className="inline-flex translate-y-[1.5px]">
@ -252,19 +298,19 @@ export default function PhotoForm({
</>}
</p>
<p>
DESCRIPTION (S): {descriptionSmall} {isLoadingDescriptionSmall && <>
SEMANTIC: {semantic} {isLoadingSemantic && <>
<span className="inline-flex translate-y-[1.5px]">
<Spinner />
</span>
</>}
</p>
<p>
DESCRIPTION (L): {descriptionLarge} {isLoadingDescriptionLarge && <>
{/* <p>
DESCRIPTION: {descriptionSmall} {isLoadingDescriptionSmall && <>
<span className="inline-flex translate-y-[1.5px]">
<Spinner />
</span>
</>}
</p>
</p> */}
<form
action={type === 'create' ? createPhotoAction : updatePhotoAction}
onSubmit={() => blur()}