Skip to content

Commit 8694359

Browse files
committed
📄(frontend) remove AI feature when MIT
AI feature is under AGPL license, so it is removed when the project is under MIT license. NEXT_PUBLIC_PUBLISH_AS_MIT manage this.
1 parent 63e4a38 commit 8694359

File tree

9 files changed

+160
-36
lines changed

9 files changed

+160
-36
lines changed

src/frontend/apps/e2e/__tests__/app-impress/language.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ test.describe.serial('Language', () => {
7777
page,
7878
browserName,
7979
}) => {
80-
await createDoc(page, 'doc-toolbar', browserName, 1);
80+
await createDoc(page, 'doc-translations-slash', browserName, 1);
8181

8282
const header = page.locator('header').first();
8383
const editor = page.locator('.ProseMirror');

src/frontend/apps/impress/src/features/docs/doc-editor/components/AI/AIUI.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
import { useBlockNoteEditor, useComponentsContext } from '@blocknote/react';
2-
import {
3-
AIMenu as AIMenuDefault,
4-
getAIExtension,
5-
getDefaultAIMenuItems,
6-
} from '@blocknote/xl-ai';
72
import { useTranslation } from 'react-i18next';
83
import { css } from 'styled-components';
94

@@ -18,6 +13,12 @@ import {
1813
DocsStyleSchema,
1914
} from '../../types';
2015

16+
import {
17+
AIMenuDefault,
18+
getAIExtension,
19+
getDefaultAIMenuItems,
20+
} from './libAGPL';
21+
2122
export function AIMenu() {
2223
return (
2324
<AIMenuDefault
Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,30 @@
1-
export * from './AIUI';
2-
export * from './useAI';
1+
import dynamic from 'next/dynamic';
2+
import { FC } from 'react';
3+
4+
export { useAI } from './useAI';
5+
export * from './useModuleAI';
6+
7+
const AIMenuController = dynamic(() =>
8+
process.env.NEXT_PUBLIC_PUBLISH_AS_MIT === 'false'
9+
? import('./libAGPL').then((mod) => mod.AIMenuController)
10+
: Promise.resolve(() => null),
11+
);
12+
13+
const AIToolbarButton = dynamic(() =>
14+
process.env.NEXT_PUBLIC_PUBLISH_AS_MIT === 'false'
15+
? import('./AIUI').then((mod) => mod.AIToolbarButton)
16+
: Promise.resolve(() => null),
17+
);
18+
19+
const AIMenu = dynamic(() =>
20+
process.env.NEXT_PUBLIC_PUBLISH_AS_MIT === 'false'
21+
? import('./AIUI').then((mod) => mod.AIMenu)
22+
: Promise.resolve(() => null),
23+
) as FC<unknown>;
24+
25+
const modGetAISlashMenuItems =
26+
process.env.NEXT_PUBLIC_PUBLISH_AS_MIT === 'false'
27+
? import('./libAGPL').then((mod) => mod.getAISlashMenuItems)
28+
: Promise.resolve(null);
29+
30+
export { AIMenu, AIMenuController, AIToolbarButton, modGetAISlashMenuItems };
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export {
2+
AIMenu as AIMenuDefault,
3+
AIMenuController,
4+
createAIExtension,
5+
createBlockNoteAIClient,
6+
getAIExtension,
7+
getAISlashMenuItems,
8+
getDefaultAIMenuItems,
9+
llmFormats,
10+
} from '@blocknote/xl-ai';
11+
export * as localesAI from '@blocknote/xl-ai/locales';
12+
import '@blocknote/xl-ai/style.css';

src/frontend/apps/impress/src/features/docs/doc-editor/components/AI/useAI.tsx

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
import { createOpenAI } from '@ai-sdk/openai';
2-
import {
3-
createAIExtension,
4-
createBlockNoteAIClient,
5-
llmFormats,
6-
} from '@blocknote/xl-ai';
72
import { CoreMessage } from 'ai';
83
import { useMemo } from 'react';
94

105
import { fetchAPI } from '@/api';
116
import { useConfig } from '@/core';
127
import { Doc } from '@/docs/doc-management';
138

9+
import { useModuleAI } from './useModuleAI';
10+
1411
const systemPrompts: Record<
1512
'add-assistant' | 'add-formatting' | 'add-edit-instruction',
1613
CoreMessage
@@ -39,11 +36,6 @@ const userPrompts: Record<string, string> = {
3936
'Summarize the selected text into a concise paragraph. Add a small summarize title above the text.',
4037
};
4138

42-
const client = createBlockNoteAIClient({
43-
baseURL: ``,
44-
apiKey: '',
45-
});
46-
4739
/**
4840
* Custom implementation of the PromptBuilder that allows for using predefined prompts.
4941
*
@@ -52,14 +44,22 @@ const client = createBlockNoteAIClient({
5244
*/
5345
export const useAI = (docId: Doc['id']) => {
5446
const conf = useConfig().data;
47+
const modules = useModuleAI();
5548

5649
return useMemo(() => {
57-
if (!conf?.AI_MODEL) {
58-
return null;
50+
if (!modules || !conf?.AI_MODEL) {
51+
return;
5952
}
6053

54+
const { llmFormats, createAIExtension, createBlockNoteAIClient } = modules;
55+
56+
const clientAI = createBlockNoteAIClient({
57+
baseURL: ``,
58+
apiKey: '',
59+
});
60+
6161
const openai = createOpenAI({
62-
...client.getProviderSettings('openai'),
62+
...clientAI.getProviderSettings('openai'),
6363
fetch: (input, init) => {
6464
// Create a new headers object without the Authorization header
6565
const headers = new Headers(init?.headers);
@@ -76,7 +76,7 @@ export const useAI = (docId: Doc['id']) => {
7676
const extension = createAIExtension({
7777
stream: false,
7878
model,
79-
agentCursor: conf?.AI_BOT,
79+
agentCursor: conf.AI_BOT,
8080
// Create a custom promptBuilder that extends the default one
8181
promptBuilder: async (editor, opts): Promise<Array<CoreMessage>> => {
8282
const defaultPromptBuilder = llmFormats.html.defaultPromptBuilder;
@@ -155,5 +155,5 @@ export const useAI = (docId: Doc['id']) => {
155155
});
156156

157157
return extension;
158-
}, [conf?.AI_BOT, conf?.AI_MODEL, docId]);
158+
}, [conf?.AI_BOT, conf?.AI_MODEL, docId, modules]);
159159
};
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { useEffect, useState } from 'react';
2+
import { useTranslation } from 'react-i18next';
3+
4+
const modulesAGPL =
5+
process.env.NEXT_PUBLIC_PUBLISH_AS_MIT === 'false'
6+
? import('./libAGPL')
7+
: Promise.resolve(null);
8+
9+
export const useModuleAI = () => {
10+
const [modules, setModules] = useState<Awaited<typeof modulesAGPL>>();
11+
12+
useEffect(() => {
13+
const resolveModule = async () => {
14+
const resolvedModules = await modulesAGPL;
15+
if (!resolvedModules) {
16+
return;
17+
}
18+
setModules(resolvedModules);
19+
};
20+
void resolveModule();
21+
}, []);
22+
23+
return modules;
24+
};
25+
26+
export const useModuleDictionnaryAI = () => {
27+
const { i18n } = useTranslation();
28+
const lang = i18n.resolvedLanguage;
29+
30+
const [dictionary, setDictionary] = useState<{
31+
ai?: unknown;
32+
}>();
33+
34+
useEffect(() => {
35+
const resolveModule = async () => {
36+
const resolvedModules = await modulesAGPL;
37+
if (!resolvedModules) {
38+
return;
39+
}
40+
41+
const { localesAI } = resolvedModules;
42+
43+
setDictionary({
44+
ai: localesAI[lang as keyof typeof localesAI],
45+
});
46+
};
47+
48+
void resolveModule();
49+
}, [lang]);
50+
51+
return dictionary;
52+
};

src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,9 @@ import {
55
withPageBreak,
66
} from '@blocknote/core';
77
import '@blocknote/core/fonts/inter.css';
8-
import * as locales from '@blocknote/core/locales';
98
import { BlockNoteView } from '@blocknote/mantine';
109
import '@blocknote/mantine/style.css';
1110
import { useCreateBlockNote } from '@blocknote/react';
12-
import { AIMenuController } from '@blocknote/xl-ai';
13-
import { en as aiEn } from '@blocknote/xl-ai/locales';
14-
import '@blocknote/xl-ai/style.css';
1511
import { HocuspocusProvider } from '@hocuspocus/provider';
1612
import { useEffect } from 'react';
1713
import { useTranslation } from 'react-i18next';
@@ -22,13 +18,14 @@ import { Doc, useIsCollaborativeEditable } from '@/docs/doc-management';
2218
import { useAuth } from '@/features/auth';
2319

2420
import { useHeadings, useUploadFile, useUploadStatus } from '../hook/';
21+
import { useDictionary } from '../hook/useDictionary';
2522
import useSaveDoc from '../hook/useSaveDoc';
2623
import { useEditorStore } from '../stores';
2724
import { cssEditor } from '../styles';
2825
import { DocsBlockNoteEditor } from '../types';
2926
import { randomColor } from '../utils';
3027

31-
import { AIMenu, useAI } from './AI';
28+
import { AIMenu, AIMenuController, useAI } from './AI';
3229
import { BlockNoteSuggestionMenu } from './BlockNoteSuggestionMenu';
3330
import { BlockNoteToolbar } from './BlockNoteToolBar/BlockNoteToolbar';
3431
import { CalloutBlock, DividerBlock } from './custom-blocks';
@@ -57,8 +54,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
5754
const readOnly = !doc.abilities.partial_update || !isEditable || isLoading;
5855

5956
useSaveDoc(doc.id, provider.document, !readOnly);
60-
const { i18n } = useTranslation();
61-
const lang = i18n.resolvedLanguage;
57+
const dictionary = useDictionary();
6258

6359
const { uploadFile, errorAttachment } = useUploadFile(doc.id);
6460
const aiExtension = useAI(doc.id);
@@ -120,7 +116,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
120116
},
121117
showCursorLabels: showCursorLabels as 'always' | 'activity',
122118
},
123-
dictionary: { ...locales[lang as keyof typeof locales], ai: aiEn },
119+
dictionary,
124120
extensions: aiExtension ? [aiExtension] : [],
125121
tables: {
126122
splitCells: true,
@@ -131,7 +127,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
131127
uploadFile,
132128
schema: blockNoteSchema,
133129
},
134-
[collabName, lang, provider, uploadFile],
130+
[aiExtension, collabName, dictionary, provider, uploadFile],
135131
);
136132

137133
useHeadings(editor);

src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import {
66
useBlockNoteEditor,
77
useDictionary,
88
} from '@blocknote/react';
9-
import { getAISlashMenuItems } from '@blocknote/xl-ai';
109
import React, { useMemo } from 'react';
1110
import { useTranslation } from 'react-i18next';
1211

1312
import { useConfig } from '@/core';
1413

1514
import { DocsBlockSchema } from '../types';
1615

16+
import { modGetAISlashMenuItems } from './AI';
1717
import {
1818
getCalloutReactSlashMenuItems,
1919
getDividerReactSlashMenuItems,
@@ -26,19 +26,24 @@ export const BlockNoteSuggestionMenu = () => {
2626
const { data: conf } = useConfig();
2727

2828
const getSlashMenuItems = useMemo(() => {
29-
return async (query: string) =>
30-
Promise.resolve(
29+
return async (query: string) => {
30+
const getAISlashMenuItems = await modGetAISlashMenuItems;
31+
32+
return Promise.resolve(
3133
filterSuggestionItems(
3234
combineByGroup(
3335
getDefaultReactSlashMenuItems(editor),
3436
getPageBreakReactSlashMenuItems(editor),
3537
getCalloutReactSlashMenuItems(editor, t, basicBlocksName),
3638
getDividerReactSlashMenuItems(editor, t, basicBlocksName),
37-
conf?.AI_FEATURE_ENABLED ? getAISlashMenuItems(editor) : [],
39+
conf?.AI_FEATURE_ENABLED && getAISlashMenuItems
40+
? getAISlashMenuItems(editor)
41+
: [],
3842
),
3943
query,
4044
),
4145
);
46+
};
4247
}, [basicBlocksName, editor, t, conf?.AI_FEATURE_ENABLED]);
4348

4449
return (
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import * as locales from '@blocknote/core/locales';
2+
import { useEffect, useState } from 'react';
3+
import { useTranslation } from 'react-i18next';
4+
5+
import { useModuleDictionnaryAI } from '../components/AI';
6+
7+
export const useDictionary = () => {
8+
const { i18n } = useTranslation();
9+
const lang = i18n.resolvedLanguage;
10+
const aiDictionary = useModuleDictionnaryAI();
11+
const [dictionary, setDictionary] = useState(() => ({
12+
...locales[lang as keyof typeof locales],
13+
}));
14+
15+
useEffect(() => {
16+
const dictionary = locales[lang as keyof typeof locales];
17+
18+
if (!aiDictionary) {
19+
setDictionary(dictionary);
20+
return;
21+
}
22+
23+
setDictionary({
24+
...dictionary,
25+
...aiDictionary,
26+
});
27+
}, [aiDictionary, lang]);
28+
29+
return dictionary;
30+
};

0 commit comments

Comments
 (0)