From 032722e21b68f910a97fede8bc870bc83bbb9a29 Mon Sep 17 00:00:00 2001 From: Evandro Fonseca Junior Date: Wed, 19 Nov 2025 00:34:57 -0300 Subject: [PATCH] feat: enhance chat functionality with markdown support and default prompts - Added support for rendering markdown in chat messages using ReactMarkdown with custom renderers. - Integrated a default format prompt for the chat system, improving user experience by initializing with a predefined prompt. - Updated the prompt generator to handle model selection more robustly, including loading states and fallback options for model selection. - Enhanced UI components for better accessibility and user feedback during prompt generation. --- app/chat/page.tsx | 5 +- components/chat/chat-message.tsx | 19 +- components/chat/code-block.tsx | 45 ++ components/chat/markdown-renderers.tsx | 138 ++++++ components/chat/message-actions.tsx | 81 ++++ components/chat/prompt-generator.tsx | 85 +++- components/ui/dropdown-menu.tsx | 199 +++++++++ data/prompts/default-format.md | 29 ++ next.config.ts | 10 + package.json | 4 +- pnpm-lock.yaml | 576 +++++++++++++++++++++++++ 11 files changed, 1167 insertions(+), 24 deletions(-) create mode 100644 components/chat/code-block.tsx create mode 100644 components/chat/markdown-renderers.tsx create mode 100644 components/chat/message-actions.tsx create mode 100644 components/ui/dropdown-menu.tsx create mode 100644 data/prompts/default-format.md diff --git a/app/chat/page.tsx b/app/chat/page.tsx index 345b630..50cbfe3 100644 --- a/app/chat/page.tsx +++ b/app/chat/page.tsx @@ -15,6 +15,8 @@ import { useLocalModels } from "@/hooks/use-local-models"; import { useState, useEffect, useRef } from "react"; import { useTheme } from "next-themes"; import { ImperativePanelHandle } from "react-resizable-panels"; +// @ts-ignore +import defaultFormatPrompt from "@/data/prompts/default-format.md"; export default function ChatPage() { const { messages, sendMessage, isLoading, stop } = useChat(); @@ -22,7 +24,8 @@ export default function ChatPage() { const { theme, setTheme } = useTheme(); const [selectedModel, setSelectedModel] = useState(""); - const [systemPrompt, setSystemPrompt] = useState("Você é um assistente útil e prestativo."); + // Initialize with default format prompt + const [systemPrompt, setSystemPrompt] = useState(defaultFormatPrompt || "Você é um assistente útil e prestativo."); const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false); const sidebarRef = useRef(null); diff --git a/components/chat/chat-message.tsx b/components/chat/chat-message.tsx index 2eff8b3..82b085f 100644 --- a/components/chat/chat-message.tsx +++ b/components/chat/chat-message.tsx @@ -3,13 +3,15 @@ import remarkGfm from 'remark-gfm'; import { cn } from "@/lib/utils"; import { Message } from "@/hooks/use-chat"; import { Bot, User } from "lucide-react"; +import { markdownRenderers } from "./markdown-renderers"; +import { MessageActions } from "./message-actions"; export function ChatMessage({ message }: { message: Message }) { const isUser = message.role === 'user'; return (
@@ -20,14 +22,23 @@ export function ChatMessage({ message }: { message: Message }) { {isUser ? : }
-
+
- + {message.content}
+ + {/* Actions Toolbar - Absolute positioned or flex end */} + {!isUser && ( +
+ +
+ )}
); } - diff --git a/components/chat/code-block.tsx b/components/chat/code-block.tsx new file mode 100644 index 0000000..8456cb7 --- /dev/null +++ b/components/chat/code-block.tsx @@ -0,0 +1,45 @@ +import { Check, Copy } from "lucide-react"; +import { useState } from "react"; +import { Button } from "@/components/ui/button"; + +interface CodeBlockProps { + language: string; + children: string; +} + +export function CodeBlock({ language, children }: CodeBlockProps) { + const [copied, setCopied] = useState(false); + + const handleCopy = () => { + navigator.clipboard.writeText(children); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + return ( +
+
+ + {language || "text"} + + +
+
+ {children} +
+
+ ); +} + diff --git a/components/chat/markdown-renderers.tsx b/components/chat/markdown-renderers.tsx new file mode 100644 index 0000000..622f2f1 --- /dev/null +++ b/components/chat/markdown-renderers.tsx @@ -0,0 +1,138 @@ +import { Components } from "react-markdown"; +import { CodeBlock } from "./code-block"; +import { cn } from "@/lib/utils"; + +export const markdownRenderers: Components = { + h1: ({ className, ...props }) => ( +

+ ), + h2: ({ className, ...props }) => ( +

+ ), + h3: ({ className, ...props }) => ( +

+ ), + h4: ({ className, ...props }) => ( +

+ ), + p: ({ className, ...props }) => ( +

+ ), + ul: ({ className, ...props }) => ( +