Skip to content

Commit

Permalink
AI Improvements (#298)
Browse files Browse the repository at this point in the history
* Remove force-dynamic

* Improve AI link analysis

* Further AI improvements

* Fix typo
  • Loading branch information
timoclsn authored May 2, 2024
1 parent 9e0fcc0 commit 0befbad
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 56 deletions.
2 changes: 0 additions & 2 deletions src/app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { query } from '@/api/query';
import { MetadataRoute } from 'next';

export const dynamic = 'force-dynamic';

const sitemap = async (): Promise<MetadataRoute.Sitemap> => {
const pages = [
{
Expand Down
169 changes: 121 additions & 48 deletions src/components/AddOrEditResource/AddOrEditResourceSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,12 @@ import {
SheetTrigger,
} from '@/ui/sheet';
import { Textarea } from '@/ui/textarea';
import { ToastAction } from '@/ui/toast';
import { useToast } from '@/ui/use-toast';
import { AlertTriangle, Loader2, Plus, WandSparkles } from 'lucide-react';
import { AlertTriangle, Info, Loader2, Plus, WandSparkles } from 'lucide-react';
import { ReactNode, useRef, useState } from 'react';
import { AddCategorySheet } from './AddCategorySheet';
import { AddTopicSheet } from './AddTopicSheet';
import { AddTypeSheet } from './AddTypeSheet';
import { Info } from 'lucide-react';

interface Props {
children: ReactNode;
Expand All @@ -65,24 +63,100 @@ export const AddOrEditResourceSheet = ({
const [open, setOpen] = useState(false);
const { toast } = useToast();

// Inputs
const [link, setLink] = useState('');
const [name, setName] = useState('');
const [slug, setSlug] = useState('');
const [typeId, setTypeId] = useState('');
const [categoryId, setCategoryId] = useState('');
const [topicIds, setTopicIds] = useState<Array<string>>([]);
const [shortDescription, setShortDescription] = useState('');
const [details, setDetails] = useState('');
const [description, setDescription] = useState('');
const [date, setDate] = useState<Date>();
const [datePlain, setDatePlain] = useState('');
const [relatedResourceIds, setRelatedrelatedResourceIds] = useState<
Array<string>
>([]);
const [relatedResourcesPlain, setRelatedResourcesPlain] = useState('');
const [suggestion, setSuggestion] = useState<boolean | 'indeterminate'>(
false,
);
const [note, setNote] = useState('');

// Actions

// getTypes
const { data: types, runAction: fetchTypes } = useAction(
action.types.getTypes,
{
onError: ({ error }) => {
toast({
title: '❌ Error fetching types',
description: error,
variant: 'destructive',
});
},
},
);

// getCategories
const { data: categories, runAction: fetchCategories } = useAction(
action.categories.getCategories,
{
onError: ({ error }) => {
toast({
title: '❌ Error fetching categories',
description: error,
variant: 'destructive',
});
},
},
);

// getTopics
const { data: topics, runAction: fetchTopics } = useAction(
action.topics.getTopics,
{
onError: ({ error }) => {
toast({
title: '❌ Error fetching topics',
description: error,
variant: 'destructive',
});
},
},
);

// getResources
const { data: resources, runAction: fetchResources } = useAction(
action.resources.getResources,
{
onError: ({ error }) => {
toast({
title: '❌ Error fetching resources',
description: error,
variant: 'destructive',
});
},
},
);

// analizeLink
const { runAction: analyzeLink, isRunning: isAnalyzeLinkRunning } = useAction(
action.resources.analizeLink,
{
onSuccess: (data) => {
if (!data) return;
const { name, type, category, topics, description } = data;
const {
name,
type,
category,
topics,
shortDescription,
description,
date,
} = data;

setName(name);
setSlug(sluggify(name));
Expand All @@ -91,6 +165,14 @@ export const AddOrEditResourceSheet = ({
setTopicIds(topics.map(String));
setDescription(description);

if (shortDescription) {
setShortDescription(shortDescription);
}

if (date) {
setDate(date);
}

toast({
title: '✅ Succesfully analized link',
});
Expand All @@ -100,56 +182,78 @@ export const AddOrEditResourceSheet = ({
title: '❌ Error analizing link',
description: error,
variant: 'destructive',
action: (
<ToastAction
altText="Try again"
onClick={() => {
analyzeLink({ link });
}}
>
Try again
</ToastAction>
),
});
},
},
);

// addResource
const {
runAction: addResource,
isRunning: isAddResourceRunning,
error: addResourceError,
validationErrors: addResourceValidationErrors,
} = useAction(action.resources.addResource, {
onSuccess: () => {
toast({
title: '✅ Succesfully added resource',
});
onAdd?.();
onOpenChange(false);
resetForm();
},
onError: ({ error }) => {
toast({
title: '❌ Error adding resource',
description: error,
variant: 'destructive',
});
},
});

// editResource
const {
runAction: editResource,
isRunning: isEditResourceRunning,
error: editResourceError,
validationErrors: editResourceValidationErrors,
} = useAction(action.resources.editResource, {
onSuccess: () => {
toast({
title: '✅ Succesfully edited resource',
});
onOpenChange(false);
resetForm();
},
onError: ({ error }) => {
toast({
title: '❌ Error editing resource',
description: error,
variant: 'destructive',
});
},
});

// deleteResource
const { runAction: deleteResource, isRunning: isDeleteResourceRunning } =
useAction(action.resources.deleteResource, {
onSuccess: () => {
toast({
title: '✅ Succesfully deleted resource',
});
onOpenChange(false);
resetForm();
},
onError: ({ error }) => {
toast({
title: `❌ ${error}`,
title: '❌ Error deleting resource',
description: error,
variant: 'destructive',
});
},
});

// revalidateCache
const { runAction: revalidateCache, isRunning: isRevalidateCacheRunning } =
useAction(action.cache.revalidateCache, {
onSuccess: () => {
Expand All @@ -159,44 +263,13 @@ export const AddOrEditResourceSheet = ({
},
onError: ({ error }) => {
toast({
title: '❌ Error revalidateCache',
title: '❌ Error revalidating cache',
description: error,
variant: 'destructive',
action: (
<ToastAction
altText="Try again"
onClick={() => {
analyzeLink({ link });
}}
>
Try again
</ToastAction>
),
});
},
});

// Controlled inputs
const [link, setLink] = useState('');
const [name, setName] = useState('');
const [slug, setSlug] = useState('');
const [typeId, setTypeId] = useState('');
const [categoryId, setCategoryId] = useState('');
const [topicIds, setTopicIds] = useState<Array<string>>([]);
const [shortDescription, setShortDescription] = useState('');
const [details, setDetails] = useState('');
const [description, setDescription] = useState('');
const [date, setDate] = useState<Date>();
const [datePlain, setDatePlain] = useState('');
const [relatedResourceIds, setRelatedrelatedResourceIds] = useState<
Array<string>
>([]);
const [relatedResourcesPlain, setRelatedResourcesPlain] = useState('');
const [suggestion, setSuggestion] = useState<boolean | 'indeterminate'>(
false,
);
const [note, setNote] = useState('');

const onOpenChange = (open: boolean) => {
if (open) {
if (isEditMode) {
Expand Down Expand Up @@ -385,7 +458,7 @@ export const AddOrEditResourceSheet = ({

{isEditMode && (
<InfoBox variant="info" icon={<Info />}>
Add redirect when changing the slug.
Consider adding a redirect when changing the slug!
</InfoBox>
)}

Expand Down
29 changes: 23 additions & 6 deletions src/data/resources/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { revalidateTag } from '../tags';
import { selectTopics } from '../topics/topics';
import { selectTypes } from '../types/types';

const { SUGGESTION_MAIL_PASSWORD } = process.env;
const { SUGGESTION_MAIL_PASSWORD, OPENAI_API_KEY } = process.env;

export const getResources = createAction({
action: async ({ ctx }) => {
Expand Down Expand Up @@ -471,7 +471,13 @@ const analizeLinkSchema = z.object({
type: z.number(),
category: z.number(),
topics: z.array(z.number()),
shortDescription: z.string().nullable(),
description: z.string(),
date: z
.string()
.date()
.transform((date) => new Date(date))
.nullable(),
});

export const analizeLink = createAdminAction({
Expand Down Expand Up @@ -550,16 +556,27 @@ export const analizeLink = createAdminAction({
});

const prompt = `
I am going to give you the content of a website i am also goinf to give you input data that you are going to use to categorize the website. These are your instructions:
I am going to give you the content of a website that you are going to use to categorize the website.
These are your instructions:
- Choose which type, categroy and topcis are the most relevant for the website.
- You are going to answer in JSON format. This is the format you are going to use:
- If the website is of a single person the type is most likely "Thoughtleader".
- If the type is "Thoughtleader" the name should be the name of the person.
- If the type is "Thoughtleader" the short description should be their job title or profession otherwise it should be null.
- Don't set more than 3 topics. Only set the most relevant ones that you are very confident with (7 or higher in a scale from 0 to 10).
- Answer in english only.
- If the website content is of a peace of media (book, article, podcast etc.) fill the date with the date of the publication (ISO date string) otherwise it should be null.
- Keep the description short and to the point (3 sentences max).
You are going to answer in JSON format. This is the format you are going to use:
{
name: 'Name of the website',
type: 1,
category: 1,
topics: [1, 2, 3],
shortDescription: 'UX Designer',
description: 'Description of the website',
date: '2022-01-01'
}
TYPES: ${JSON.stringify(types)}
Expand All @@ -576,7 +593,7 @@ export const analizeLink = createAdminAction({
`;

const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY!,
apiKey: OPENAI_API_KEY,
});

const aiResponse = await openai.chat.completions
Expand All @@ -588,7 +605,7 @@ export const analizeLink = createAdminAction({
{
role: 'system',
content:
'You are my AI web scraper. Your job is to make sense of the text content of a website and put it into a category.',
'You are my AI web scraper. Your job is to make sense of the text content of a website and categorize it.',
},
{
role: 'user',
Expand Down

0 comments on commit 0befbad

Please sign in to comment.