241 lines
6.7 KiB
TypeScript
241 lines
6.7 KiB
TypeScript
/**
|
|
* Internal dependencies
|
|
*/
|
|
import {
|
|
PROMPT_TYPE_SUMMARY_BY_TITLE,
|
|
PROMPT_TYPE_CONTINUE,
|
|
PROMPT_TYPE_SIMPLIFY,
|
|
PROMPT_TYPE_CORRECT_SPELLING,
|
|
PROMPT_TYPE_GENERATE_TITLE,
|
|
PROMPT_TYPE_MAKE_LONGER,
|
|
PROMPT_TYPE_MAKE_SHORTER,
|
|
PROMPT_TYPE_CHANGE_TONE,
|
|
PROMPT_TYPE_SUMMARIZE,
|
|
PROMPT_TYPE_CHANGE_LANGUAGE,
|
|
PROMPT_TYPE_USER_PROMPT,
|
|
PromptTypeProp,
|
|
PromptItemProps,
|
|
BuildPromptProps,
|
|
} from './index';
|
|
|
|
/**
|
|
* Constants
|
|
*/
|
|
const SUBJECT_TITLE = 'title';
|
|
const SUBJECT_CONTENT = 'content';
|
|
const SUBJECT_DEFAULT = null;
|
|
|
|
/**
|
|
* Builds the initial message, that will be transformed on the
|
|
* system prompt.
|
|
*
|
|
* @param {PromptTypeProp} promptType - The internal type of the prompt.
|
|
* @returns {PromptItemProps} The initial message.
|
|
*/
|
|
export function buildInitialMessageForBackendPrompt( promptType: PromptTypeProp ): PromptItemProps {
|
|
// The basic template for the message.
|
|
return {
|
|
role: 'jetpack-ai' as const,
|
|
context: {
|
|
type: 'ai-assistant-initial-prompt',
|
|
for: mapInternalPromptTypeToBackendPromptType( promptType ),
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Builds the relevant content message, if applicable.
|
|
*
|
|
* @param {boolean} isContentGenerated - Whether the current content was generated.
|
|
* @param {string} relevantContent - The relevant content.
|
|
* @returns {PromptItemProps} The initial message.
|
|
*/
|
|
export function buildRelevantContentMessageForBackendPrompt(
|
|
isContentGenerated?: boolean,
|
|
relevantContent?: string | null
|
|
): PromptItemProps | null {
|
|
if ( ! isContentGenerated && relevantContent && relevantContent.length > 0 ) {
|
|
return {
|
|
role: 'jetpack-ai',
|
|
context: {
|
|
type: 'ai-assistant-relevant-content',
|
|
content: relevantContent,
|
|
},
|
|
};
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Builds backend prompt message list
|
|
* based on the type of prompt.
|
|
*
|
|
* @param {BuildPromptProps} options - The prompt options.
|
|
* @returns {Array< PromptItemProps >} The prompt.
|
|
*/
|
|
export function buildMessagesForBackendPrompt( {
|
|
generatedContent,
|
|
allPostContent,
|
|
postContentAbove,
|
|
currentPostTitle,
|
|
options,
|
|
type,
|
|
userPrompt,
|
|
isGeneratingTitle,
|
|
}: BuildPromptProps ): Array< PromptItemProps > {
|
|
const messages: PromptItemProps[] = [];
|
|
|
|
const isContentGenerated = options?.contentType === 'generated';
|
|
let relevantContent: string | null | undefined = null;
|
|
|
|
switch ( type ) {
|
|
case PROMPT_TYPE_SUMMARY_BY_TITLE:
|
|
relevantContent = currentPostTitle;
|
|
break;
|
|
case PROMPT_TYPE_CONTINUE:
|
|
case PROMPT_TYPE_SIMPLIFY:
|
|
case PROMPT_TYPE_CORRECT_SPELLING:
|
|
relevantContent = postContentAbove;
|
|
break;
|
|
case PROMPT_TYPE_GENERATE_TITLE:
|
|
relevantContent = allPostContent;
|
|
break;
|
|
case PROMPT_TYPE_MAKE_LONGER:
|
|
case PROMPT_TYPE_MAKE_SHORTER:
|
|
relevantContent = generatedContent;
|
|
break;
|
|
case PROMPT_TYPE_CHANGE_TONE:
|
|
case PROMPT_TYPE_SUMMARIZE:
|
|
case PROMPT_TYPE_CHANGE_LANGUAGE:
|
|
relevantContent = isContentGenerated ? generatedContent : allPostContent;
|
|
break;
|
|
case PROMPT_TYPE_USER_PROMPT:
|
|
relevantContent = generatedContent || allPostContent;
|
|
break;
|
|
}
|
|
|
|
const relevantContentMessage = buildRelevantContentMessageForBackendPrompt(
|
|
type === PROMPT_TYPE_USER_PROMPT ? !! generatedContent?.length : isContentGenerated,
|
|
relevantContent
|
|
);
|
|
|
|
// If we have relevant content, send it as a message.
|
|
if ( relevantContentMessage ) {
|
|
messages.push( relevantContentMessage );
|
|
}
|
|
|
|
messages.push( {
|
|
role: 'jetpack-ai',
|
|
context: buildMessageContextForUserPrompt( {
|
|
generatedContent,
|
|
allPostContent,
|
|
postContentAbove,
|
|
currentPostTitle,
|
|
options,
|
|
type,
|
|
userPrompt,
|
|
isGeneratingTitle,
|
|
} ),
|
|
} );
|
|
|
|
return messages;
|
|
}
|
|
|
|
/**
|
|
* Gets the subject of the prompt.
|
|
*
|
|
* @param {boolean} isGeneratingTitle - Whether the action is to generate a title.
|
|
* @param {boolean} isContentGenerated - Whether the current content was generated.
|
|
* @param {boolean} isFromExtension - Whether the content is from the extension.
|
|
* @returns {string} The subject.
|
|
*/
|
|
function getSubject(
|
|
isGeneratingTitle?: boolean,
|
|
isContentGenerated?: boolean,
|
|
isFromExtension?: boolean
|
|
): string | null {
|
|
if ( isGeneratingTitle ) {
|
|
return SUBJECT_TITLE;
|
|
}
|
|
if ( ! isContentGenerated || isFromExtension ) {
|
|
return SUBJECT_CONTENT;
|
|
}
|
|
|
|
return SUBJECT_DEFAULT;
|
|
}
|
|
|
|
/**
|
|
* Builds backend message context based on the type
|
|
* and the options of the prompt.
|
|
*
|
|
* @param {BuildPromptProps} options - The prompt options.
|
|
* @returns {object} The context.
|
|
*/
|
|
export function buildMessageContextForUserPrompt( {
|
|
options,
|
|
type,
|
|
userPrompt,
|
|
isGeneratingTitle,
|
|
}: BuildPromptProps ): object {
|
|
const isContentGenerated = options?.contentType === 'generated';
|
|
const isFromExtension = options?.fromExtension || false;
|
|
|
|
// Determine the subject of the action
|
|
const subject = getSubject( isGeneratingTitle, isContentGenerated, isFromExtension );
|
|
|
|
/*
|
|
* Each type of prompt has a different context.
|
|
* The context is used to identify the prompt type in the backend,
|
|
* as well as provide relevant pieces for the prompt building.
|
|
*/
|
|
|
|
return {
|
|
type: mapInternalPromptTypeToBackendPromptType( type ),
|
|
...( subject ? { subject } : {} ),
|
|
...( type === PROMPT_TYPE_CHANGE_TONE && options?.tone ? { tone: options.tone } : {} ),
|
|
...( type === PROMPT_TYPE_CHANGE_LANGUAGE && options?.language
|
|
? { language: options.language }
|
|
: {} ),
|
|
...( type === PROMPT_TYPE_USER_PROMPT && userPrompt ? { request: userPrompt } : {} ),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Maps the internal prompt type to the backend prompt type.
|
|
*
|
|
* @param {PromptTypeProp} promptType - The internal type of the prompt.
|
|
* @param {string} extension - The extension of the prompt, if any.
|
|
* @returns {string} The backend type of the prompt.
|
|
*/
|
|
export function mapInternalPromptTypeToBackendPromptType(
|
|
promptType: PromptTypeProp,
|
|
extension?: string
|
|
): string {
|
|
const map = {
|
|
[ PROMPT_TYPE_SUMMARY_BY_TITLE ]: 'ai-assistant-summary-by-title',
|
|
[ PROMPT_TYPE_CONTINUE ]: 'ai-assistant-continue-writing',
|
|
[ PROMPT_TYPE_SIMPLIFY ]: 'ai-assistant-simplify',
|
|
[ PROMPT_TYPE_CORRECT_SPELLING ]: 'ai-assistant-correct-spelling',
|
|
[ PROMPT_TYPE_GENERATE_TITLE ]: 'ai-assistant-generate-title',
|
|
[ PROMPT_TYPE_MAKE_LONGER ]: 'ai-assistant-make-longer',
|
|
[ PROMPT_TYPE_MAKE_SHORTER ]: 'ai-assistant-make-shorter',
|
|
[ PROMPT_TYPE_CHANGE_TONE ]: 'ai-assistant-change-tone',
|
|
[ PROMPT_TYPE_SUMMARIZE ]: 'ai-assistant-summarize',
|
|
[ PROMPT_TYPE_CHANGE_LANGUAGE ]: 'ai-assistant-change-language',
|
|
[ PROMPT_TYPE_USER_PROMPT ]: 'ai-assistant-user-prompt',
|
|
};
|
|
|
|
// Handle specific Jetpack Form AI migration.
|
|
// This should be an exception since it's was feature made before inline extensions.
|
|
if ( extension === 'form-ai' ) {
|
|
return 'form-ai-extension';
|
|
}
|
|
|
|
if ( extension ) {
|
|
return `${ map[ promptType ] }-${ extension }-extension`;
|
|
}
|
|
|
|
return map[ promptType ];
|
|
}
|