Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use @jupyterlab/rendermime for in-chat markdown rendering #564

Merged
merged 48 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
f508d7d
create markdown widget and component
andrii-i Dec 22, 2023
3f01973
add rendermime
andrii-i Jan 4, 2024
2e8477b
add rendermime registry requrement, activation to plugin
andrii-i Jan 4, 2024
b6dd872
update var naming
andrii-i Jan 4, 2024
b0de686
use rendermime directrly in the react component
andrii-i Jan 8, 2024
e467b77
use css to emulate code styling
andrii-i Jan 8, 2024
a6727e5
add @types/react-dom
andrii-i Jan 10, 2024
f5099cc
create CopyButton component based on chat-code-view.tsx by @dlqqq
andrii-i Jan 10, 2024
b2fc459
add CopyButton and styling
andrii-i Jan 10, 2024
27c1ad1
remoev unsused code
andrii-i Jan 10, 2024
805b3a5
add min width to the button
andrii-i Jan 10, 2024
540524c
omit units for 0
andrii-i Jan 10, 2024
635930e
use RendermimeMarkdown for ChatSettings model help
andrii-i Jan 10, 2024
154212d
remove react-markdown dependency
andrii-i Jan 10, 2024
fd51988
revert CopyButton styling
andrii-i Jan 10, 2024
3de2d4a
remove comments
andrii-i Jan 10, 2024
4520796
memoize RendermimeMarkdown (10% faster)
andrii-i Jan 10, 2024
5b1aaaa
Update packages/jupyter-ai/src/components/copy-button.tsx
andrii-i Jan 11, 2024
e50be7f
remove copying status
andrii-i Jan 11, 2024
2538554
update yarn.lock
andrii-i Jan 25, 2024
a394025
detect mimetype, render latex
andrii-i Jan 30, 2024
53644fe
set latexTypesetter
andrii-i Jan 30, 2024
4652053
MathJax typeset redered md
andrii-i Jan 31, 2024
66d6296
use rmRegistry typesetter
andrii-i Jan 31, 2024
88d559e
remove MathJaxTypesetter import
andrii-i Jan 31, 2024
73207fb
Modify CHAT_SYSTEM_PROMPT, use $ and $$ style LaTeX delimiters only
andrii-i Jan 31, 2024
b5b19b7
remove @jupyterlab/mathjax-extension dependency
andrii-i Feb 1, 2024
34311be
remove @jupyterlab/builder dependency
andrii-i Feb 1, 2024
b16c26f
Update packages/jupyter-ai/src/index.ts
andrii-i Feb 1, 2024
b92892c
render content after attaching buttons per @krassowski
andrii-i Feb 1, 2024
4d7ad57
remove duplicate rmRegistry per @krassowski
andrii-i Feb 1, 2024
f5ab373
update snapshots
andrii-i Feb 1, 2024
9aff53b
Remove unused react-syntax-highlighter, rehype-katex, remark-math dep…
andrii-i Feb 3, 2024
4382422
move @types/react-dom dependency from root to packages/jupyter-ai per…
andrii-i Feb 3, 2024
37fe0b7
Update packages/jupyter-ai/package.json
andrii-i Feb 3, 2024
30629d2
update yarn.lock
andrii-i Feb 5, 2024
ae1a0b7
Escale LaTeX delimeters with regex instead of prompt engineering
andrii-i Feb 6, 2024
7bbc099
add .jp-ai-rendermime-markdown mjx-container styling to match jlab
andrii-i Feb 6, 2024
affd353
update escapeLatexDelimiters comment
andrii-i Feb 6, 2024
1d69280
update lockfile
andrii-i Feb 6, 2024
35c6377
update lockfile
andrii-i Feb 6, 2024
ac74941
move escapeLatexDelimiters outside of RendermimeMarkdownBase to avoid…
andrii-i Feb 7, 2024
bfdf488
adjust escapeLatexDelimiters parameter naming
andrii-i Feb 7, 2024
b692679
Rename escapeLatexDelimiters argument from str to text
andrii-i Feb 7, 2024
2a8a680
Update packages/jupyter-ai/src/components/rendermime-markdown.tsx
andrii-i Feb 7, 2024
8578990
Update escapeLatexDelimiters docstring per @dlqqq
andrii-i Feb 7, 2024
b257a9d
bump react-dom version per @dlqqq
andrii-i Feb 7, 2024
748fd38
add @jupyterlab/rendermime as a direct dependenct per @dlqqq to avoid…
andrii-i Feb 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions packages/jupyter-ai/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,25 +72,22 @@
"@jupyterlab/docregistry": "^4",
"@jupyterlab/fileeditor": "^4",
"@jupyterlab/notebook": "^4",
"@jupyterlab/rendermime": "^4",
"@jupyterlab/services": "^7",
"@jupyterlab/settingregistry": "^4",
"@jupyterlab/ui-components": "^4",
"@mui/icons-material": "^5.11.0",
"@mui/material": "^5.11.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-markdown": "^8.0.6",
"react-syntax-highlighter": "^15.5.0",
"rehype-katex": "^6.0.2",
"remark-math": "^5.1.1"
"react-dom": "^18.2.0"
andrii-i marked this conversation as resolved.
Show resolved Hide resolved
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@jupyterlab/builder": "^4",
"@jupyterlab/testutils": "^4",
"@types/jest": "^29",
"@types/react-syntax-highlighter": "^15.5.6",
"@types/react-dom": "^18.2.0",
"@typescript-eslint/eslint-plugin": "^4.8.1",
"@typescript-eslint/parser": "^4.8.1",
"eslint": "^7.14.0",
Expand Down
93 changes: 0 additions & 93 deletions packages/jupyter-ai/src/components/chat-code-view.tsx

This file was deleted.

40 changes: 8 additions & 32 deletions packages/jupyter-ai/src/components/chat-messages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@ import React, { useState, useEffect } from 'react';

import { Avatar, Box, Typography } from '@mui/material';
import type { SxProps, Theme } from '@mui/material';
import ReactMarkdown from 'react-markdown';
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
import 'katex/dist/katex.min.css';

import { ChatCodeView } from './chat-code-view';
import { AiService } from '../handler';
import { useCollaboratorsContext } from '../contexts/collaborators-context';
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
import { Jupyternaut } from '../icons';
import { RendermimeMarkdown } from './rendermime-markdown';
import { useCollaboratorsContext } from '../contexts/collaborators-context';

type ChatMessagesProps = {
rmRegistry: IRenderMimeRegistry;
messages: AiService.ChatMessage[];
};

Expand All @@ -22,11 +20,6 @@ type ChatMessageHeaderProps = {
sx?: SxProps<Theme>;
};

type NewTabLinkProps = {
children: React.ReactNode;
href?: string;
};

export function ChatMessageHeader(props: ChatMessageHeaderProps): JSX.Element {
const collaborators = useCollaboratorsContext();

Expand Down Expand Up @@ -133,14 +126,6 @@ export function ChatMessages(props: ChatMessagesProps): JSX.Element {
}
}, [props.messages]);

function NewTabLink(props: NewTabLinkProps) {
return (
<a href={props.href ?? '#'} target="_blank" rel="noopener noreferrer">
{props.children}
</a>
);
}

return (
<Box
sx={{
Expand All @@ -157,19 +142,10 @@ export function ChatMessages(props: ChatMessagesProps): JSX.Element {
timestamp={timestamps[message.id]}
sx={{ marginBottom: 3 }}
/>
<ReactMarkdown
// We are using the jp-RenderedHTMLCommon class here to get the default Jupyter
// markdown styling and then overriding any CSS to make it more compact.
className="jp-RenderedHTMLCommon jp-ai-react-markdown"
components={{
a: NewTabLink,
code: ChatCodeView
}}
remarkPlugins={[remarkMath]}
rehypePlugins={[rehypeKatex]}
>
{message.body}
</ReactMarkdown>
<RendermimeMarkdown
rmRegistry={props.rmRegistry}
markdownStr={message.body}
/>
</Box>
))}
</Box>
Expand Down
20 changes: 12 additions & 8 deletions packages/jupyter-ai/src/components/chat-settings.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import React, { useEffect, useState, useMemo } from 'react';

import ReactMarkdown from 'react-markdown';

import { Box } from '@mui/system';
import {
Alert,
Expand All @@ -13,22 +11,27 @@ import {
Radio,
RadioGroup,
TextField,
CircularProgress,
Typography
CircularProgress
} from '@mui/material';

import { Select } from './select';
import { AiService } from '../handler';
import { ModelFields } from './settings/model-fields';
import { ServerInfoState, useServerInfo } from './settings/use-server-info';
import { ExistingApiKeys } from './settings/existing-api-keys';
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
import { minifyUpdate } from './settings/minify';
import { useStackingAlert } from './mui-extras/stacking-alert';
import { RendermimeMarkdown } from './rendermime-markdown';

type ChatSettingsProps = {
rmRegistry: IRenderMimeRegistry;
};

/**
* Component that returns the settings view in the chat panel.
*/
export function ChatSettings(): JSX.Element {
export function ChatSettings(props: ChatSettingsProps): JSX.Element {
// state fetched on initial render
const server = useServerInfo();

Expand Down Expand Up @@ -287,9 +290,10 @@ export function ChatSettings(): JSX.Element {
/>
)}
{helpMarkdown && (
<Typography className="jp-ai-ChatSettings-model-help">
<ReactMarkdown linkTarget="_blank">{helpMarkdown}</ReactMarkdown>
</Typography>
<RendermimeMarkdown
rmRegistry={props.rmRegistry}
markdownStr={helpMarkdown}
/>
)}
{lmGlobalId && (
<ModelFields
Expand Down
18 changes: 14 additions & 4 deletions packages/jupyter-ai/src/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@ import {
import { SelectionWatcher } from '../selection-watcher';
import { ChatHandler } from '../chat_handler';
import { CollaboratorsContextProvider } from '../contexts/collaborators-context';
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
import { ScrollContainer } from './scroll-container';

type ChatBodyProps = {
chatHandler: ChatHandler;
setChatView: (view: ChatView) => void;
rmRegistry: IRenderMimeRegistry;
};

function ChatBody({
chatHandler,
setChatView: chatViewHandler
setChatView: chatViewHandler,
rmRegistry: renderMimeRegistry
}: ChatBodyProps): JSX.Element {
const [messages, setMessages] = useState<AiService.ChatMessage[]>([]);
const [showWelcomeMessage, setShowWelcomeMessage] = useState<boolean>(false);
Expand Down Expand Up @@ -147,7 +150,7 @@ function ChatBody({
return (
<>
<ScrollContainer sx={{ flexGrow: 1 }}>
<ChatMessages messages={messages} />
<ChatMessages messages={messages} rmRegistry={renderMimeRegistry} />
</ScrollContainer>
<ChatInput
value={input}
Expand Down Expand Up @@ -180,6 +183,7 @@ export type ChatProps = {
chatHandler: ChatHandler;
globalAwareness: Awareness | null;
themeManager: IThemeManager | null;
rmRegistry: IRenderMimeRegistry;
chatView?: ChatView;
};

Expand Down Expand Up @@ -226,9 +230,15 @@ export function Chat(props: ChatProps): JSX.Element {
</Box>
{/* body */}
{view === ChatView.Chat && (
<ChatBody chatHandler={props.chatHandler} setChatView={setView} />
<ChatBody
chatHandler={props.chatHandler}
setChatView={setView}
rmRegistry={props.rmRegistry}
/>
)}
{view === ChatView.Settings && (
<ChatSettings rmRegistry={props.rmRegistry} />
)}
{view === ChatView.Settings && <ChatSettings />}
</Box>
</CollaboratorsContextProvider>
</SelectionContextProvider>
Expand Down
50 changes: 50 additions & 0 deletions packages/jupyter-ai/src/components/copy-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { useState, useCallback } from 'react';

import { Box, Button } from '@mui/material';

enum CopyStatus {
None,
Copied
}

const COPYBTN_TEXT_BY_STATUS: Record<CopyStatus, string> = {
[CopyStatus.None]: 'Copy to Clipboard',
[CopyStatus.Copied]: 'Copied!'
};

type CopyButtonProps = {
value: string;
};

export function CopyButton(props: CopyButtonProps): JSX.Element {
const [copyStatus, setCopyStatus] = useState<CopyStatus>(CopyStatus.None);

const copy = useCallback(async () => {
try {
await navigator.clipboard.writeText(props.value);
} catch (err) {
console.error('Failed to copy text: ', err);
setCopyStatus(CopyStatus.None);
return;
}

setCopyStatus(CopyStatus.Copied);
setTimeout(() => setCopyStatus(CopyStatus.None), 1000);
}, [props.value]);

return (
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<Button
onClick={copy}
disabled={copyStatus !== CopyStatus.None}
aria-label="Copy To Clipboard"
sx={{
alignSelf: 'flex-end',
textTransform: 'none'
}}
>
{COPYBTN_TEXT_BY_STATUS[copyStatus]}
</Button>
</Box>
);
}
Loading
Loading