diff --git a/frontend/src/components/feature/chat/ChatInput/tiptap.styles.css b/frontend/src/components/feature/chat/ChatInput/tiptap.styles.css index fe76aac3f..fc3fade34 100644 --- a/frontend/src/components/feature/chat/ChatInput/tiptap.styles.css +++ b/frontend/src/components/feature/chat/ChatInput/tiptap.styles.css @@ -127,7 +127,7 @@ color: #fbbc88; } -.tiptap pre .tiptap pre .hljs-string, +.tiptap pre .hljs-string, .tiptap pre .hljs-symbol, .tiptap pre .hljs-bullet { color: #b9f18d; diff --git a/frontend/src/components/feature/settings/ai/bots/BotDocs.tsx b/frontend/src/components/feature/settings/ai/bots/BotDocs.tsx new file mode 100644 index 000000000..ec04f9586 --- /dev/null +++ b/frontend/src/components/feature/settings/ai/bots/BotDocs.tsx @@ -0,0 +1,111 @@ +import CodeBlock from '@/components/layout/CodeBlock' +import { Stack } from '@/components/layout/Stack' +import { RavenBot } from '@/types/RavenBot/RavenBot' +import { Code, Heading, Text } from '@radix-ui/themes' +import { useFormContext } from 'react-hook-form' + +const BotDocs = () => { + + const { getValues } = useFormContext() + + const bot_id = getValues('name') + + const botVarName = bot_id.replace(/-/g, '_') + + const SectionHeading = ({ children }: { children: React.ReactNode }) => { + return {children} + } + + const Paragraph = ({ children }: { children: React.ReactNode }) => { + return {children} + } + + const codeSamples = { + sendMessage: `${botVarName} = frappe.get_doc("Raven Bot", "${bot_id}") + +# Send a message to a channel. Text can be in HTML format. +${botVarName}.send_message(channel_id="channel-name", text="This is a test message.")`, + + sendMessageInMarkdown: `${botVarName}.send_message( + channel_id="channel-name", + text="This is a test message.", + markdown=True + )`, + + sendMessageWithDocumentLink: `${botVarName}.send_message( + channel_id="channel-name", + text="This is a test message.", + link_doctype="DocType", + link_document="Document Name" + )`, + + sendDirectMessage: `${botVarName}.send_direct_message( + user_id="john.doe@example.com", + text="This is a test message." + )` + } + + return ( + + + The following code samples show how to use the bot in a Frappe app or Server Script. + + + + + Sending a message to a channel + + + Bots can be used to send messages to channels with html formatted content. + + + + + + + + Sending a message to a channel in markdown format + + + You can send markdown formatted text to a channel by setting the markdown parameter to True. + + + + + + + + + Sending a message with a document link + + + You can send a message with a link to any document in the system by setting the link_doctype and link_document parameters. + + + + + + + + Sending a direct message to a user + + + You can send a direct message to a user by calling the send_direct_message method and setting the user_id parameter. + This method also accepts markdown and document link parameters. + + + + + + ) +} + +export default BotDocs \ No newline at end of file diff --git a/frontend/src/components/feature/settings/ai/bots/BotForm.tsx b/frontend/src/components/feature/settings/ai/bots/BotForm.tsx index 723b7fa01..a227891e8 100644 --- a/frontend/src/components/feature/settings/ai/bots/BotForm.tsx +++ b/frontend/src/components/feature/settings/ai/bots/BotForm.tsx @@ -1,12 +1,13 @@ import { Box, Tabs } from '@radix-ui/themes' import { LuFunctionSquare, LuSparkles } from 'react-icons/lu' import InstructionField from '../InstructionField' -import { BiBot, BiFile } from 'react-icons/bi' +import { BiBot, BiCode, BiFile } from 'react-icons/bi' import GeneralBotForm from './GeneralBotForm' import AIFeaturesBotForm from './AIFeaturesBotForm' import BotFunctionsForm from './BotFunctionsForm' import { useFormContext } from 'react-hook-form' import { RavenBot } from '@/types/RavenBot/RavenBot' +import BotDocs from './BotDocs' type Props = {} @@ -26,6 +27,7 @@ const BotForm = ({ isEdit }: { isEdit: boolean }) => { {isAiBot ? AI : null} {isAiBot ? Instructions : null} {isAiBot ? Functions : null} + {isEdit ? API Docs : null} @@ -40,6 +42,10 @@ const BotForm = ({ isEdit }: { isEdit: boolean }) => { + + + + ) diff --git a/frontend/src/components/layout/CodeBlock.tsx b/frontend/src/components/layout/CodeBlock.tsx new file mode 100644 index 000000000..bea242e39 --- /dev/null +++ b/frontend/src/components/layout/CodeBlock.tsx @@ -0,0 +1,77 @@ +import { EditorContent, useEditor } from '@tiptap/react' +import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight' +import { common, createLowlight } from 'lowlight' +import python from 'highlight.js/lib/languages/python' +import css from 'highlight.js/lib/languages/css' +import js from 'highlight.js/lib/languages/javascript' +import ts from 'highlight.js/lib/languages/typescript' +import html from 'highlight.js/lib/languages/xml' +import json from 'highlight.js/lib/languages/json' +import StarterKit from '@tiptap/starter-kit' +import '@/components/feature/chat/ChatInput/tiptap.styles.css' +import { IconButton, Tooltip } from '@radix-ui/themes' +import { BiClipboard, BiCopy } from 'react-icons/bi' +import { toast } from 'sonner' + +const lowlight = createLowlight(common) +lowlight.register('python', python) +lowlight.register('css', css) +lowlight.register('js', js) +lowlight.register('ts', ts) +lowlight.register('html', html) +lowlight.register('json', json) + + +type Props = { + code: string, +} + +const CodeBlock = ({ code }: Props) => { + + const editor = useEditor({ + editorProps: { + attributes: { + class: 'tiptap' + } + }, + editable: false, + extensions: [ + StarterKit, + CodeBlockLowlight.configure({ + lowlight + }) + ], + content: `
${code}
` + }) + + const onCopy = () => { + navigator.clipboard.writeText(code) + + toast.success('Copied to clipboard', { + duration: 800 + }) + } + + if (!editor) return null + + return ( +
+ + + + + + +
+ + ) +} + +export default CodeBlock \ No newline at end of file diff --git a/raven/raven_bot/doctype/raven_bot/raven_bot.py b/raven/raven_bot/doctype/raven_bot/raven_bot.py index 0bf65fb27..b481f894e 100644 --- a/raven/raven_bot/doctype/raven_bot/raven_bot.py +++ b/raven/raven_bot/doctype/raven_bot/raven_bot.py @@ -249,11 +249,12 @@ def send_message( channel_id: The channel_id of the channel to send the message to You need to provide either text or link_doctype and link_document - text: The text of the message in HTML format (markdown is not supported) + text: The text of the message in HTML format. If markdown is True, the text will be converted to HTML. Optional: link_doctype: The doctype of the document to link the message to link_document: The name of the document to link the message to + markdown: If True, the text will be converted to HTML. Returns the message ID of the message sent """ @@ -306,7 +307,12 @@ def create_direct_message_channel(self, user_id: str) -> str: return channel.name def send_direct_message( - self, user_id: str, text: str = None, link_doctype: str = None, link_document: str = None + self, + user_id: str, + text: str = None, + link_doctype: str = None, + link_document: str = None, + markdown: bool = False, ) -> str: """ Send a text message to a user in a Direct Message channel @@ -314,11 +320,12 @@ def send_direct_message( user_id: The User's 'name' field to send the message to You need to provide either text or link_doctype and link_document - text: The text of the message in HTML format (markdown is not supported) + text: The text of the message in HTML format. If markdown is True, the text will be converted to HTML. Optional: link_doctype: The doctype of the document to link the message to link_document: The name of the document to link the message to + markdown: If True, the text will be converted to HTML. Returns the message ID of the message sent """ @@ -326,7 +333,7 @@ def send_direct_message( channel_id = self.create_direct_message_channel(user_id) if channel_id: - return self.send_message(channel_id, text, link_doctype, link_document) + return self.send_message(channel_id, text, link_doctype, link_document, markdown) def get_last_message(self, channel_id: str = None, message_type: str = None) -> Document | None: """