Fine-tune AI text generation
This commit is contained in:
parent
6d9f207cdf
commit
a351999e37
@ -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));
|
||||
}
|
||||
|
||||
@ -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) =>
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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()}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user