Skip to content

Commit 06e94c5

Browse files
committed
⚡️(frontend) improve prompt of some actions
Some answers were a bit too concise or not detailed enough. Improve some prompts to get better answers from the AI.
1 parent dd12723 commit 06e94c5

File tree

3 files changed

+176
-15
lines changed

3 files changed

+176
-15
lines changed
Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,24 @@
11
import { createOpenAI } from '@ai-sdk/openai';
2-
import { createAIExtension, createBlockNoteAIClient } from '@blocknote/xl-ai';
2+
import { createAIExtension, llmFormats } from '@blocknote/xl-ai';
33
import { useMemo } from 'react';
44

55
import { fetchAPI } from '@/api';
66
import { useConfig } from '@/core';
77
import { Doc } from '@/docs/doc-management';
88

9-
const client = createBlockNoteAIClient({
10-
baseURL: ``,
11-
apiKey: '',
12-
});
13-
14-
/**
15-
* Custom implementation of the PromptBuilder that allows for using predefined prompts.
16-
*
17-
* This extends the default HTML promptBuilder from BlockNote to support custom prompt templates.
18-
* Custom prompts can be invoked using the pattern !promptName in the AI input field.
19-
*/
9+
import { usePromptAI } from './usePromptAI';
10+
2011
export const useAI = (docId: Doc['id']) => {
2112
const conf = useConfig().data;
13+
const promptBuilder = usePromptAI();
2214

2315
return useMemo(() => {
2416
if (!conf?.AI_MODEL) {
25-
return null;
17+
return;
2618
}
2719

2820
const openai = createOpenAI({
29-
...client.getProviderSettings('openai'),
21+
apiKey: '', // The API key will be set by the AI proxy
3022
fetch: (input, init) => {
3123
// Create a new headers object without the Authorization header
3224
const headers = new Headers(init?.headers);
@@ -44,8 +36,9 @@ export const useAI = (docId: Doc['id']) => {
4436
stream: false,
4537
model,
4638
agentCursor: conf?.AI_BOT,
39+
promptBuilder: promptBuilder(llmFormats.html.defaultPromptBuilder),
4740
});
4841

4942
return extension;
50-
}, [docId, conf?.AI_BOT, conf?.AI_MODEL]);
43+
}, [conf, docId, promptBuilder]);
5144
};
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import { Block } from '@blocknote/core';
2+
import { CoreMessage } from 'ai';
3+
import { useCallback } from 'react';
4+
import { useTranslation } from 'react-i18next';
5+
6+
import { DocsBlockNoteEditor } from '../../types';
7+
8+
export type PromptBuilderInput = {
9+
userPrompt: string;
10+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
11+
selectedBlocks?: Block<any, any, any>[];
12+
excludeBlockIds?: string[];
13+
previousMessages?: Array<CoreMessage>;
14+
};
15+
16+
type PromptBuilder = (
17+
editor: DocsBlockNoteEditor,
18+
opts: PromptBuilderInput,
19+
) => Promise<Array<CoreMessage>>;
20+
21+
/**
22+
* Custom implementation of the PromptBuilder that allows for using predefined prompts.
23+
*
24+
* This extends the default HTML promptBuilder from BlockNote to support custom prompt templates.
25+
* Custom prompts can be invoked using the pattern !promptName in the AI input field.
26+
*/
27+
export const usePromptAI = () => {
28+
const { t } = useTranslation();
29+
30+
return useCallback(
31+
(defaultPromptBuilder: PromptBuilder) =>
32+
async (
33+
editor: DocsBlockNoteEditor,
34+
opts: PromptBuilderInput,
35+
): Promise<Array<CoreMessage>> => {
36+
const systemPrompts: Record<
37+
| 'add-edit-instruction'
38+
| 'add-formatting'
39+
| 'add-markdown'
40+
| 'assistant'
41+
| 'language'
42+
| 'referenceId',
43+
CoreMessage
44+
> = {
45+
assistant: {
46+
role: 'system',
47+
content: t(`You are an AI assistant that edits user documents.`),
48+
},
49+
referenceId: {
50+
role: 'system',
51+
content: t(
52+
`Keep block IDs exactly as provided when referencing them (including the trailing "$").`,
53+
),
54+
},
55+
'add-markdown': {
56+
role: 'system',
57+
content: t(`Answer the user prompt in markdown format.`),
58+
},
59+
'add-formatting': {
60+
role: 'system',
61+
content: t(`Add formatting to the text to make it more readable.`),
62+
},
63+
'add-edit-instruction': {
64+
role: 'system',
65+
content: t(
66+
`Add content; do not delete or alter existing blocks unless explicitly told.`,
67+
),
68+
},
69+
language: {
70+
role: 'system',
71+
content: t(
72+
`Detect the dominant language inside the provided blocks. YOU MUST PROVIDE A ANSWER IN THE DETECTED LANGUAGE.`,
73+
),
74+
},
75+
};
76+
77+
const userPrompts: Record<string, string> = {
78+
'continue writing': t(
79+
'Keep writing about the content send in the prompt, expanding on the ideas.',
80+
),
81+
'improve writing': t(
82+
'Improve the writing of the selected text. Make it more professional and clear.',
83+
),
84+
summarize: t('Summarize the document into a concise paragraph.'),
85+
'fix spelling': t(
86+
'Fix the spelling and grammar mistakes in the selected text.',
87+
),
88+
};
89+
90+
// Modify userPrompt if it matches a custom prompt
91+
const customPromptMatch = opts.userPrompt.match(/^([^:]+)(?=[:]|$)/);
92+
let modifiedOpts = opts;
93+
const promptKey = customPromptMatch?.[0].trim().toLowerCase();
94+
if (promptKey) {
95+
if (userPrompts[promptKey]) {
96+
modifiedOpts = {
97+
...opts,
98+
userPrompt: userPrompts[promptKey],
99+
};
100+
}
101+
}
102+
103+
let prompts = await defaultPromptBuilder(editor, modifiedOpts);
104+
const isTransformExistingContent = !!opts.selectedBlocks?.length;
105+
if (!isTransformExistingContent) {
106+
prompts = prompts.map((prompt) => {
107+
if (!prompt.content || typeof prompt.content !== 'string') {
108+
return prompt;
109+
}
110+
111+
/**
112+
* Fix a bug when the initial content is empty
113+
* TODO: Remove this when the bug is fixed in BlockNote
114+
*/
115+
if (prompt.content === '[]') {
116+
const lastBlockId =
117+
editor.document[editor.document.length - 1].id;
118+
119+
prompt.content = `[{\"id\":\"${lastBlockId}$\",\"block\":\"<p></p>\"}]`;
120+
return prompt;
121+
}
122+
123+
if (
124+
prompt.content.includes(
125+
"You're manipulating a text document using HTML blocks.",
126+
)
127+
) {
128+
prompt = systemPrompts['add-markdown'];
129+
return prompt;
130+
}
131+
132+
if (
133+
prompt.content.includes(
134+
'First, determine what part of the document the user is talking about.',
135+
)
136+
) {
137+
prompt = systemPrompts['add-edit-instruction'];
138+
}
139+
140+
return prompt;
141+
});
142+
143+
prompts.push(systemPrompts['add-formatting']);
144+
}
145+
146+
prompts.unshift(systemPrompts['assistant']);
147+
prompts.push(systemPrompts['referenceId']);
148+
149+
// Try to keep the language of the document except when we are translating
150+
if (!promptKey?.includes('Translate into')) {
151+
prompts.push(systemPrompts['language']);
152+
}
153+
154+
return prompts;
155+
},
156+
[t],
157+
);
158+
};

src/frontend/apps/impress/src/i18n/translations.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,16 @@
590590
"Warning": "Attention",
591591
"Why can't I edit?": "Pourquoi ne puis-je pas éditer ?",
592592
"Write": "Écrire",
593+
"You are an AI assistant that helps users to edit their documents.": "Vous êtes un assistant IA qui aide les utilisateurs à éditer leurs documents.",
594+
"Answer the user prompt in markdown format.": "Répondez à la demande de l'utilisateur au format markdown.",
595+
"Add formatting to the text to make it more readable.": "Ajoutez du formatage au texte pour le rendre plus lisible.",
596+
"Keep adding to the document, do not delete or modify existing blocks.": "Continuez à ajouter au document, ne supprimez ni ne modifiez les blocs existants.",
597+
"Your answer must be in the same language as the document.": "Votre réponse doit être dans la même langue que le document.",
598+
"Fix the spelling and grammar mistakes in the selected text.": "Corrigez les fautes d'orthographe et de grammaire dans le texte sélectionné.",
599+
"Improve the writing of the selected text. Make it more professional and clear.": "Améliorez l'écriture du texte sélectionné. Rendez-le plus professionnel et clair.",
600+
"Summarize the document into a concise paragraph.": "Résumez le document en un paragraphe concis.",
601+
"Keep writing about the content send in the prompt, expanding on the ideas.": "Continuez à écrire sur le contenu envoyé dans la demande, en développant les idées.",
602+
"Important, verified the language of the document! Your answer MUST be in the same language as the document. If the document is in English, your answer MUST be in English. If the document is in Spanish, your answer MUST be in Spanish, etc.": "Important, vérifiez la langue du document ! Votre réponse DOIT être dans la même langue que le document. Si le document est en anglais, votre réponse DOIT être en anglais. Si le document est en espagnol, votre réponse DOIT être en espagnol, etc.",
593603
"You are the sole owner of this group, make another member the group owner before you can change your own role or be removed from your document.": "Vous êtes le seul propriétaire de ce groupe, faites d'un autre membre le propriétaire du groupe, avant de pouvoir modifier votre propre rôle ou vous supprimer du document.",
594604
"You do not have permission to view this document.": "Vous n'avez pas la permission de voir ce document.",
595605
"You do not have permission to view users sharing this document or modify link settings.": "Vous n'avez pas la permission de voir les utilisateurs partageant ce document ou de modifier les paramètres du lien.",

0 commit comments

Comments
 (0)