Skip to content

Commit

Permalink
ai
Browse files Browse the repository at this point in the history
  • Loading branch information
felixfeng33 committed Oct 1, 2024
1 parent a0b6e25 commit 0ae094e
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 48 deletions.
19 changes: 19 additions & 0 deletions apps/www/src/app/api/stream/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export function POST() {
const streams = [
{ delay: 100, texts: 'Hello' },
{ delay: 200, texts: 'World' },
];

const stream = new ReadableStream({
async start(controller) {
for (const stream of streams) {
await new Promise((resolve) => setTimeout(resolve, stream.delay)); // Increasing delay
controller.enqueue(stream.texts);
}

controller.close();
},
});

return new Response(stream);
}
19 changes: 19 additions & 0 deletions apps/www/src/registry/default/example/playground-demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,25 @@ export const usePlaygroundEditor = (id: any = '', scrollSelector?: string) => {
AIPlugin.configure({
options: {
createAIEditor: createAIEditor,
// eslint-disable-next-line @typescript-eslint/require-await, @typescript-eslint/no-unused-vars
fetchSuggestion: async ({ abortSignal, prompt, system }) => {
const response = await fetch('/api/stream', {
body: JSON.stringify({ prompt, system }),
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
signal: abortSignal.signal,
}).catch((error) => {
console.error(error);
});

if (!response || !response.body) {
throw new Error('Response or response body is null or abort');
}

return response.body;
},
scrollContainerSelector: `#${scrollSelector}`,
},
render: { aboveEditable: AIMenu },
Expand Down
7 changes: 7 additions & 0 deletions apps/www/src/registry/default/plate-ui/ai-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,10 @@ export const SelectionSuggestionActions = {
value: ACTION_SELECTION_SUGGESTION_TRY_AGAIN,
},
};

export const aiActions = {
CursorCommandsActions,
CursorSuggestionActions,
SelectionCommandsActions,
SelectionSuggestionActions,
};
7 changes: 7 additions & 0 deletions apps/www/src/registry/default/plate-ui/ai-menu-items.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,10 @@ export const SelectionSuggestions = () => {
</>
);
};

export const aiCommands = {
CursorCommands,
CursorSuggestions,
SelectionCommands,
SelectionSuggestions,
};
31 changes: 4 additions & 27 deletions apps/www/src/registry/default/plate-ui/ai-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,8 @@ import { useAI } from '@udecode/plate-ai/react';
import { Icons } from '@/components/icons';

import { useActionHandler } from './action-handler';
import {
CursorCommandsActions,
CursorSuggestionActions,
SelectionCommandsActions,
SelectionSuggestionActions,
defaultValues,
} from './ai-actions';
import {
CursorCommands,
CursorSuggestions,
SelectionCommands,
SelectionSuggestions,
} from './ai-menu-items';
import { aiActions, defaultValues } from './ai-actions';
import { aiCommands } from './ai-menu-items';
import { AIPreviewEditor } from './ai-previdew-editor';
import { Button } from './button';
import { Menu, comboboxVariants, renderSearchMenuItems } from './menu';
Expand All @@ -40,25 +29,13 @@ export const AIMenu = memo(({ children }: React.PropsWithChildren) => {
submitButtonProps,
onCloseMenu,
} = useAI({
aiActions: {
CursorCommandsActions,
CursorSuggestionActions,
SelectionCommandsActions,
SelectionSuggestionActions,
},
aiCommands: {
CursorCommands,
CursorSuggestions,
SelectionCommands,
SelectionSuggestions,
},
aiActions: aiActions,
aiCommands: aiCommands,
defaultValues,
});

useActionHandler(action, aiEditor!);

/** IME */

return (
<>
<Menu
Expand Down
7 changes: 7 additions & 0 deletions packages/ai/src/react/ai/AIPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,16 @@ import { useAIHooks } from './useAIHook';

export const KEY_AI = 'ai';

export interface FetchAISuggestionProps {
abortSignal: AbortController;
prompt: string;
system?: string;
}

interface ExposeOptions {
createAIEditor: () => PlateEditor;
scrollContainerSelector: string;
fetchSuggestion?: (props: FetchAISuggestionProps) => Promise<ReadableStream>;
trigger?: RegExp | string[] | string;

triggerPreviousCharPattern?: RegExp;
Expand Down
1 change: 0 additions & 1 deletion packages/ai/src/react/ai/hook/useAI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ export const useAI = ({
if (isHotkey('enter')(e)) await streamInsert();
};

// TODO: move to API
const onCloseMenu = useCallback(() => {
// close menu if ai is not generating
if (aiState === 'idle' || aiState === 'done') {
Expand Down
27 changes: 7 additions & 20 deletions packages/ai/src/react/ai/stream/streamTraversal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,15 @@ export const streamTraversal = async (
const abortController = new AbortController();
editor.setOptions(AIPlugin, { abortController });

const response = await fetch('/api/ai/command', {
body: JSON.stringify({ prompt, system }),
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
signal: abortController.signal,
}).catch((error) => {
console.error(error);
});
const fetchSuggestion = editor.getOptions(AIPlugin).fetchSuggestion!;

if (response?.status === 429) {
return fn(
'Rate limit exceeded. You have made too many requests. Please try again later.',
true
);
}
if (!response || !response.body) {
throw new Error('Response or response body is null or abort');
}
const response = await fetchSuggestion({
abortSignal: abortController,
prompt,
system,
});

const reader = response.body.getReader();
const reader = response.getReader();
const decoder = new TextDecoder();

// eslint-disable-next-line no-constant-condition
Expand Down

0 comments on commit 0ae094e

Please sign in to comment.