aboutsummaryrefslogtreecommitdiff
path: root/apps/web/app/components/editor/plugins/ai-plugins.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/app/components/editor/plugins/ai-plugins.tsx')
-rw-r--r--apps/web/app/components/editor/plugins/ai-plugins.tsx195
1 files changed, 195 insertions, 0 deletions
diff --git a/apps/web/app/components/editor/plugins/ai-plugins.tsx b/apps/web/app/components/editor/plugins/ai-plugins.tsx
new file mode 100644
index 00000000..727e0148
--- /dev/null
+++ b/apps/web/app/components/editor/plugins/ai-plugins.tsx
@@ -0,0 +1,195 @@
+'use client';
+
+import React from 'react';
+
+import { withProps } from '@udecode/cn';
+import { AIChatPlugin, AIPlugin } from '@udecode/plate-ai/react';
+import {
+ BoldPlugin,
+ CodePlugin,
+ ItalicPlugin,
+ StrikethroughPlugin,
+ UnderlinePlugin,
+} from '@udecode/plate-basic-marks/react';
+import { BlockquotePlugin } from '@udecode/plate-block-quote/react';
+import {
+ CodeBlockPlugin,
+ CodeLinePlugin,
+ CodeSyntaxPlugin,
+} from '@udecode/plate-code-block/react';
+import {
+ ParagraphPlugin,
+ PlateLeaf,
+ createPlateEditor,
+} from '@udecode/plate-common/react';
+import { HEADING_KEYS } from '@udecode/plate-heading';
+import { HorizontalRulePlugin } from '@udecode/plate-horizontal-rule/react';
+import { LinkPlugin } from '@udecode/plate-link/react';
+import { MarkdownPlugin } from '@udecode/plate-markdown';
+import { BlockSelectionPlugin } from '@udecode/plate-selection/react';
+
+import { AIMenu } from '~/components/plate-ui/ai-menu';
+import { BlockquoteElement } from '~/components/plate-ui/blockquote-element';
+import { CodeBlockElement } from '~/components/plate-ui/code-block-element';
+import { CodeLeaf } from '~/components/plate-ui/code-leaf';
+import { CodeLineElement } from '~/components/plate-ui/code-line-element';
+import { CodeSyntaxLeaf } from '~/components/plate-ui/code-syntax-leaf';
+import { HeadingElement } from '~/components/plate-ui/heading-element';
+import { HrElement } from '~/components/plate-ui/hr-element';
+import { LinkElement } from '~/components/plate-ui/link-element';
+import { ParagraphElement } from '~/components/plate-ui/paragraph-element';
+
+import { basicNodesPlugins } from './basic-nodes-plugins';
+import { indentListPlugins } from './indent-list-plugins';
+import { linkPlugin } from './link-plugin';
+
+const createAIEditor = () => {
+ const editor = createPlateEditor({
+ id: 'ai',
+ override: {
+ components: {
+ [BlockquotePlugin.key]: BlockquoteElement,
+ [BoldPlugin.key]: withProps(PlateLeaf, { as: 'strong' }),
+ [CodeBlockPlugin.key]: CodeBlockElement,
+ [CodeLinePlugin.key]: CodeLineElement,
+ [CodePlugin.key]: CodeLeaf,
+ [CodeSyntaxPlugin.key]: CodeSyntaxLeaf,
+ [HEADING_KEYS.h1]: withProps(HeadingElement, { variant: 'h1' }),
+ [HEADING_KEYS.h2]: withProps(HeadingElement, { variant: 'h2' }),
+ [HEADING_KEYS.h3]: withProps(HeadingElement, { variant: 'h3' }),
+ [HorizontalRulePlugin.key]: HrElement,
+ [ItalicPlugin.key]: withProps(PlateLeaf, { as: 'em' }),
+ [LinkPlugin.key]: LinkElement,
+ [ParagraphPlugin.key]: ParagraphElement,
+ [StrikethroughPlugin.key]: withProps(PlateLeaf, { as: 's' }),
+ [UnderlinePlugin.key]: withProps(PlateLeaf, { as: 'u' }),
+ },
+ },
+ plugins: [
+ ParagraphPlugin,
+ ...basicNodesPlugins,
+ HorizontalRulePlugin,
+ linkPlugin,
+ ...indentListPlugins,
+ MarkdownPlugin.configure({ options: { indentList: true } }),
+ // FIXME
+ BlockSelectionPlugin.configure({
+ api: {},
+ extendEditor: null,
+ options: {},
+ render: {},
+ useHooks: null,
+ handlers: {},
+ }),
+ ],
+ value: [{ children: [{ text: '' }], type: 'p' }],
+ });
+
+ return editor;
+};
+
+const systemCommon = `\
+You are an advanced AI-powered note-taking assistant, designed to enhance productivity and creativity in note management.
+Respond directly to user prompts with clear, concise, and relevant content. Maintain a neutral, helpful tone.
+
+Rules:
+- <Document> is the entire note the user is working on.
+- <Reminder> is a reminder of how you should reply to INSTRUCTIONS. It does not apply to questions.
+- Anything else is the user prompt.
+- Your response should be tailored to the user's prompt, providing precise assistance to optimize note management.
+- For INSTRUCTIONS: Follow the <Reminder> exactly. Provide ONLY the content to be inserted or replaced. No explanations or comments.
+- For QUESTIONS: Provide a helpful and concise answer. You may include brief explanations if necessary.
+- CRITICAL: Distinguish between INSTRUCTIONS and QUESTIONS. Instructions typically ask you to modify or add content. Questions ask for information or clarification.
+`;
+
+const systemDefault = `\
+${systemCommon}
+- <Block> is the current block of text the user is working on.
+- Ensure your output can seamlessly fit into the existing <Block> structure.
+- CRITICAL: Provide only a single block of text. DO NOT create multiple paragraphs or separate blocks.
+<Block>
+{block}
+</Block>
+`;
+
+const systemSelecting = `\
+${systemCommon}
+- <Block> is the block of text containing the user's selection, providing context.
+- Ensure your output can seamlessly fit into the existing <Block> structure.
+- <Selection> is the specific text the user has selected in the block and wants to modify or ask about.
+- Consider the context provided by <Block>, but only modify <Selection>. Your response should be a direct replacement for <Selection>.
+<Block>
+{block}
+</Block>
+<Selection>
+{selection}
+</Selection>
+`;
+
+const systemBlockSelecting = `\
+${systemCommon}
+- <Selection> represents the full blocks of text the user has selected and wants to modify or ask about.
+- Your response should be a direct replacement for the entire <Selection>.
+- Maintain the overall structure and formatting of the selected blocks, unless explicitly instructed otherwise.
+- CRITICAL: Provide only the content to replace <Selection>. Do not add additional blocks or change the block structure unless specifically requested.
+<Selection>
+{block}
+</Selection>
+`;
+
+const userDefault = `<Reminder>
+CRITICAL: DO NOT use block formatting. You can only use inline formatting.
+CRITICAL: DO NOT start new lines or paragraphs.
+NEVER write <Block>.
+</Reminder>
+{prompt}`;
+
+const userSelecting = `<Reminder>
+If this is a question, provide a helpful and concise answer about <Selection>.
+If this is an instruction, provide ONLY the text to replace <Selection>. No explanations.
+Ensure it fits seamlessly within <Block>. If <Block> is empty, write ONE random sentence.
+NEVER write <Block> or <Selection>.
+</Reminder>
+{prompt} about <Selection>`;
+
+const userBlockSelecting = `<Reminder>
+If this is a question, provide a helpful and concise answer about <Selection>.
+If this is an instruction, provide ONLY the content to replace the entire <Selection>. No explanations.
+Maintain the overall structure unless instructed otherwise.
+NEVER write <Block> or <Selection>.
+</Reminder>
+{prompt} about <Selection>`;
+
+export const PROMPT_TEMPLATES = {
+ systemBlockSelecting,
+ systemDefault,
+ systemSelecting,
+ userBlockSelecting,
+ userDefault,
+ userSelecting,
+};
+
+export const aiPlugins = [
+ MarkdownPlugin.configure({ options: { indentList: true } }),
+ AIPlugin,
+ AIChatPlugin.configure({
+ options: {
+ createAIEditor,
+ promptTemplate: ({ isBlockSelecting, isSelecting }) => {
+ return isBlockSelecting
+ ? PROMPT_TEMPLATES.userBlockSelecting
+ : isSelecting
+ ? PROMPT_TEMPLATES.userSelecting
+ : PROMPT_TEMPLATES.userDefault;
+ },
+ systemTemplate: ({ isBlockSelecting, isSelecting }) => {
+ return isBlockSelecting
+ ? PROMPT_TEMPLATES.systemBlockSelecting
+ : isSelecting
+ ? PROMPT_TEMPLATES.systemSelecting
+ : PROMPT_TEMPLATES.systemDefault;
+ },
+ },
+ render: { afterEditable: () => <AIMenu /> },
+ }),
+] as const;