diff --git a/config.ts b/config.ts index 7de739b74d..a99bff41af 100644 --- a/config.ts +++ b/config.ts @@ -824,6 +824,8 @@ export const FONTS = [ 'Zeyada', ] as const; +// TODO: !!! MAX_CHARS_IN_TITLE_WORD + export const COPILOT_PLACEHOLDERS: Array = [ // Note: ⏣ Describe the change> 'Translate to Chinese', diff --git a/prompts/templates/enhance-post.cs.prompt.txt b/prompts/templates/enhance-post.cs.md similarity index 100% rename from prompts/templates/enhance-post.cs.prompt.txt rename to prompts/templates/enhance-post.cs.md diff --git a/prompts/templates/enhance-post.en.prompt.txt b/prompts/templates/enhance-post.en.md similarity index 100% rename from prompts/templates/enhance-post.en.prompt.txt rename to prompts/templates/enhance-post.en.md diff --git a/prompts/templates/enhance-prompt.en.prompt.txt b/prompts/templates/enhance-prompt.en.md similarity index 100% rename from prompts/templates/enhance-prompt.en.prompt.txt rename to prompts/templates/enhance-prompt.en.md diff --git a/prompts/templates/modify-website-content.md b/prompts/templates/modify-website-content.md new file mode 100644 index 0000000000..be6af29868 --- /dev/null +++ b/prompts/templates/modify-website-content.md @@ -0,0 +1,16 @@ +Craft a webpage content which incorporates the following wallpaper description as an alt text: + +"${block(wallpaperDescription)}" + +Guidelines: +- The webpage title should not directly copy the alt text but should be creatively derived from it. +- Utilize markdown format. +- Begin with a concise heading. +- Aim for content that realistically portrays a functioning website, not a mere display of the wallpaper. +- The heading should not include words like "wallpaper" or "background". +- The content should feature real sections such as references, contact information, user stories, etc., as per the objective of the page. +- Structure the content with headings, bullets, numbering, blockquotes, paragraphs, horizontal lines, etc. +- Feel free to use bold or _italic_ text for emphasis. +- Incorporate UTF-8 emojis for added appeal. +- Links should be only #hash anchors referring to the document itself. +- Avoid including any images. \ No newline at end of file diff --git a/prompts/templates/write-website-claim.md b/prompts/templates/write-website-claim.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prompts/templates/write-website-content.md b/prompts/templates/write-website-content.md new file mode 100644 index 0000000000..b249a66cc0 --- /dev/null +++ b/prompts/templates/write-website-content.md @@ -0,0 +1,5 @@ +Following is markdown content of a webpage: + +# {TITLE} + +> {TOPIC} \ No newline at end of file diff --git a/prompts/templates/write-website-font.md b/prompts/templates/write-website-font.md new file mode 100644 index 0000000000..cbf81d7129 --- /dev/null +++ b/prompts/templates/write-website-font.md @@ -0,0 +1,12 @@ +Write me a Google font which is best fitting for the website. + +Pick from the list: +${block( + [...FONTS] + .sort(() => Math.random() - 0.5) + .map((fontName) => `- ${fontName}`) + .join('\n'), +)} + + +Write just the font name nothing else. \ No newline at end of file diff --git a/prompts/templates/write-website-title.md b/prompts/templates/write-website-title.md new file mode 100644 index 0000000000..8cfa5c597a --- /dev/null +++ b/prompts/templates/write-website-title.md @@ -0,0 +1,8 @@ +Craft a title for webpage which incorporates the following wallpaper description as an alt text: + +"${block(wallpaperAssigment)}" + +Guidelines: +- This is a title for real website +- Be short and concise +- The title should not include parasitic words like "wallpaper" or "background". \ No newline at end of file diff --git a/src/ai/text-to-text/ChatThread.ts b/src/ai/text-to-text/ChatThread.ts index 88efcd6409..666ec702e7 100644 --- a/src/ai/text-to-text/ChatThread.ts +++ b/src/ai/text-to-text/ChatThread.ts @@ -1,6 +1,7 @@ import { getSupabaseForServer } from '../../utils/supabase/getSupabaseForServer'; -import { string_chat_prompt, string_model_name, uuid } from '../../utils/typeAliases'; +import { string_model_name, uuid } from '../../utils/typeAliases'; import { getOpenaiForServer } from './getOpenaiForServer'; +import { Prompt } from './prompt-templates/PromptTemplate'; /** * Thread to the ChotGPT @@ -14,7 +15,7 @@ export class ChatThread { * @param request text to send to the OpenAI API * @returns response from the OpenAI API wrapped in ChatThread */ - public static async ask(request: string_chat_prompt, clientId: uuid /* <-[🌺] */): Promise { + public static async ask(request: Prompt<'CHAT'>, clientId: uuid /* <-[🌺] */): Promise { return /* not await */ ChatThread.create(null, request, clientId); } @@ -24,7 +25,7 @@ export class ChatThread { */ private static async create( parentChatThread: null | ChatThread, - request: string_chat_prompt, + request: Prompt<'CHAT'>, clientId: uuid /* <-[🌺] */, ): Promise { const mark = `ask-gpt-${parentChatThread ? parentChatThread.chatSize : 1}`; @@ -38,7 +39,7 @@ export class ChatThread { messages: [ { role: 'user', - content: request, + content: request.toString(), }, ], }); @@ -109,7 +110,7 @@ export class ChatThread { public readonly clientId: uuid /* <-[🌺] */, public readonly parent: null | ChatThread, public readonly model: string_model_name, - public readonly request: string_chat_prompt, + public readonly request: Prompt<'CHAT'>, public readonly response: string, ) {} @@ -119,7 +120,7 @@ export class ChatThread { * @param request text to send to the OpenAI API * @returns response from the OpenAI API wrapped in ChatThread */ - public async ask(request: string_chat_prompt): Promise { + public async ask(request: Prompt<'CHAT'>): Promise { return /* not await */ ChatThread.create(this, request, this.clientId); } @@ -129,8 +130,8 @@ export class ChatThread { } /** - * TODO: [🚞] DRY ChatThread+completeWithGpt * TODO: [🧠] Wording: response or answer? + * TODO: [🚞] DRY ChatThread+completeWithGpt * TODO: [5] Log also failed requests as in completeWithGpt * TODO: Make IAskOptions */ diff --git a/src/ai/text-to-text/completeWithGpt.ts b/src/ai/text-to-text/completeWithGpt.ts index 81c03df205..6d88de2c19 100644 --- a/src/ai/text-to-text/completeWithGpt.ts +++ b/src/ai/text-to-text/completeWithGpt.ts @@ -1,6 +1,7 @@ import { getSupabaseForServer } from '../../utils/supabase/getSupabaseForServer'; -import { string_completion_prompt, string_model_name, uuid } from '../../utils/typeAliases'; +import { string_model_name, uuid } from '../../utils/typeAliases'; import { getOpenaiForServer } from './getOpenaiForServer'; +import { Prompt } from './prompt-templates/PromptTemplate'; export interface ICompleteWithGptResult { response: string; @@ -13,14 +14,14 @@ export interface ICompleteWithGptResult { * Note: This function is aviable only on the server */ export async function completeWithGpt( - prompt: string_completion_prompt, + prompt: Prompt<'COMPLETION'>, clientId: uuid /* <-[🌺] */, ): Promise { const model = 'text-davinci-003'; const modelSettings = { model, max_tokens: 500, - // <- TODO: [🤡] Tweak, hardcode+note or put in config + Pick the best model, max_tokens, top_t,... other params + // <- TODO: Tweak, hardcode+note or put in config + Pick the best model, max_tokens, top_t,... other params }; const promptAt = new Date(); @@ -75,7 +76,7 @@ export async function completeWithGpt( performance.mark('complete-gpt-start'); const completion = await getOpenaiForServer().completions.create({ ...modelSettings, - prompt, + prompt: prompt.toString(), }); performance.mark('complete-gpt-end'); const answerAt = new Date(); diff --git a/src/ai/text-to-text/prompt-templates/PromptTemplate.ts b/src/ai/text-to-text/prompt-templates/PromptTemplate.ts new file mode 100644 index 0000000000..ecddf219b7 --- /dev/null +++ b/src/ai/text-to-text/prompt-templates/PromptTemplate.ts @@ -0,0 +1,42 @@ +import spaceTrim from 'spacetrim'; +import { string_prompt, string_template } from '../../../utils/typeAliases'; + +/** + * + */ +type PromptTemplateParams = Record; + +/** + * !!! Annotate all + + */ +export class PromptTemplate { + public constructor(public readonly templateContent: string_prompt & string_template) {} + + makePrompt(params: PromptTemplateParams): Prompt { + return new Prompt(this, params); + } +} + +/** + * !!! Annotate all + + */ +export class Prompt { + public constructor(public readonly template: PromptTemplate, public readonly params: PromptTemplateParams) {} + + toString(): string_prompt { + let prompt = this.template.templateContent; + prompt = spaceTrim(prompt); + // TODO: !!! Replace all params + // TODO: !!! Remove comments + + return prompt; + } +} + +/** + * TODO: !!! Model requirements like modelName + * TODO: !!! Model requirements like COMPLETION vs CHAT + ACRY DRY + * TODO: !!! template version + * TODO: !!! template language + * TODO: !!! Log the template + */ diff --git a/src/ai/text-to-text/prompt-templates/TODO.txt b/src/ai/text-to-text/prompt-templates/TODO.txt deleted file mode 100644 index 05ca2e3012..0000000000 --- a/src/ai/text-to-text/prompt-templates/TODO.txt +++ /dev/null @@ -1,2 +0,0 @@ -TODO: !! Prompt templates should be in .txt files in /promps folder -TODO: !! Record all prompt (template) performance to be able to A/B test them \ No newline at end of file diff --git a/src/ai/text-to-text/prompt-templates/createContentPromptTemplate.ts b/src/ai/text-to-text/prompt-templates/createContentPromptTemplate.ts deleted file mode 100644 index 232361ca92..0000000000 --- a/src/ai/text-to-text/prompt-templates/createContentPromptTemplate.ts +++ /dev/null @@ -1,38 +0,0 @@ -import spaceTrim from 'spacetrim'; -import { image_description, string_chat_prompt, string_midjourney_prompt } from '../../../utils/typeAliases'; - -/** - * Generates a template for creating web content based on a given wallpaper description - * - * @param wallpaperDescription: A description of the wallpaper. This could be a plain description of the image or a prompt created from Azure's image cognition or MidJourney services. - * @returns A template that can be used with ChatGPT to generate a webpage content. - */ -export function createContentPromptTemplate( - wallpaperDescription: Exclude | string_midjourney_prompt, -): string_chat_prompt { - return spaceTrim( - (block) => - ` - Craft a webpage content which incorporates the following wallpaper description as an alt text: - - "${block(wallpaperDescription)}" - - Guidelines: - - The webpage title should not directly copy the alt text but should be creatively derived from it. - - Utilize markdown format. - - Begin with a concise heading. - - Aim for content that realistically portrays a functioning website, not a mere display of the wallpaper. - - The heading should not include words like "wallpaper" or "background". - - The content should feature real sections such as references, contact information, user stories, etc., as per the objective of the page. - - Structure the content with headings, bullets, numbering, blockquotes, paragraphs, horizontal lines, etc. - - Feel free to use bold or _italic_ text for emphasis. - - Incorporate UTF-8 emojis for added appeal. - - Links should be only #hash anchors referring to the document itself. - - Avoid including any images. - `, - ); -} - -/** - * TODO: [🤡] Make some model comparision - */ diff --git a/src/ai/text-to-text/prompt-templates/createFontPromptTemplate.ts b/src/ai/text-to-text/prompt-templates/createFontPromptTemplate.ts deleted file mode 100644 index 893e50458a..0000000000 --- a/src/ai/text-to-text/prompt-templates/createFontPromptTemplate.ts +++ /dev/null @@ -1,32 +0,0 @@ -import spaceTrim from 'spacetrim'; -import { FONTS } from '../../../../config'; -import { string_chat_prompt } from '../../../utils/typeAliases'; - -/** - * Generates a template for figuring out best fitting font for the website. - * - * Note: This should be a second message in the conversation after the createTitlePromptTemplate - * - * @returns A template that can be used with ChatGPT to detect best fitting font for the website. - */ -export function createFontPromptTemplate(): string_chat_prompt { - return spaceTrim( - (block) => - ` - Write me a Google font which is best fitting for the website. - - Pick from the list: - ${block( - [...FONTS] - .sort(() => Math.random() - 0.5) - .map((fontName) => `- ${fontName}`) - .join('\n'), - )} - - - Write just the font name nothing else. - - - `, - ); -} diff --git a/src/ai/text-to-text/prompt-templates/createTitlePromptTemplate.ts b/src/ai/text-to-text/prompt-templates/createTitlePromptTemplate.ts deleted file mode 100644 index 48255b2d04..0000000000 --- a/src/ai/text-to-text/prompt-templates/createTitlePromptTemplate.ts +++ /dev/null @@ -1,30 +0,0 @@ -import spaceTrim from 'spacetrim'; -import { image_description, string_chat_prompt, string_midjourney_prompt } from '../../../utils/typeAliases'; - -/** - * Generates a template for creating web title based on a given wallpaper description - * - * @param wallpaperAssigment: A description of the wallpaper. This could be a plain description of the image or a prompt created from Azure's image cognition or MidJourney services. - * @returns A title of the web - */ -export function createTitlePromptTemplate( - wallpaperAssigment: Exclude | string_midjourney_prompt, -): string_chat_prompt { - return spaceTrim( - (block) => - ` - Craft a title for webpage which incorporates the following wallpaper description as an alt text: - - "${block(wallpaperAssigment)}" - - Guidelines: - - This is a title for real website - - Be short and concise - - The title should not include parasitic words like "wallpaper" or "background". - `, - ); -} - -/** - * TODO: [🤡] Make some model comparision - */ diff --git a/src/ai/text-to-text/prompt-templates/index.ts b/src/ai/text-to-text/prompt-templates/index.ts new file mode 100644 index 0000000000..0b2598e28e --- /dev/null +++ b/src/ai/text-to-text/prompt-templates/index.ts @@ -0,0 +1,16 @@ +import modifyWebsiteContent from '../../../../prompts/templates/modify-website-content.md'; +import writeWebsiteClaim from '../../../../prompts/templates/write-website-claim.md'; +import writeWebsiteContent from '../../../../prompts/templates/write-website-content.md'; +import writeWebsiteFont from '../../../../prompts/templates/write-website-font.md'; +import writeWebsiteTitle from '../../../../prompts/templates/write-website-title.md'; +import { PromptTemplate } from './PromptTemplate'; + +export const MODIFY_WEBSITE_CONTENT_TEMPLATE = new PromptTemplate<'CHAT'>(modifyWebsiteContent); +export const WRITE_WEBSITE_TITLE_TEMPLATE = new PromptTemplate<'CHAT'>(writeWebsiteTitle); +export const WRITE_WEBSITE_CLAIM_TEMPLATE = new PromptTemplate<'CHAT'>(writeWebsiteClaim); +export const WRITE_WEBSITE_CONTENT_TEMPLATE = new PromptTemplate<'CHAT'>(writeWebsiteContent); +export const WRITE_WEBSITE_FONT_TEMPLATE = new PromptTemplate<'CHAT'>(writeWebsiteFont); + +/** + * TODO: This should be auto-generated from the /prompts/templates/ folder + */ diff --git a/src/ai/text-to-text/writeWallpaperContent.ts b/src/ai/text-to-text/writeWallpaperContent.ts index 3b03f40b3f..80ad5f5900 100644 --- a/src/ai/text-to-text/writeWallpaperContent.ts +++ b/src/ai/text-to-text/writeWallpaperContent.ts @@ -140,6 +140,8 @@ export async function writeWallpaperContent(options: WriteWallpaperContentOption clientId, ); + // TODO: !!! Use or makeWrite WRITE_WEBSITE_CONTENT_TEMPLATE + /* TODO: !!! Better const chatThreadFont = await chatThread.ask(createFontPromptTemplate()); diff --git a/src/utils/typeAliases.ts b/src/utils/typeAliases.ts index 3c9a84529b..2e72a4c5b1 100644 --- a/src/utils/typeAliases.ts +++ b/src/utils/typeAliases.ts @@ -38,6 +38,13 @@ export type string_model_name = */ export type string_prompt = string; +/** + * Semantic helper + * + * For example `"A cat wearing a {ITEM}"` + */ +export type string_template = string; + /** * Semantic helper *