当前位置: 首页 > article >正文

基于shadcn/ui与Tailwind CSS构建可定制AI应用组件库

1. 项目概述与核心价值如果你正在用 Next.js 和 React 构建 AI 应用并且对市面上那些要么功能简陋、要么风格死板的 UI 组件感到头疼那么prompt-kit这个项目很可能就是你一直在找的“瑞士军刀”。简单来说它是一套基于shadcn/ui和Tailwind CSS构建的、高度可定制化的高质量 AI 应用组件库。它的目标不是提供一个“大而全”的框架而是精准地解决 AI 应用开发中那些高频、核心且对交互体验要求极高的 UI 场景比如智能聊天输入框、消息流展示、AI 状态指示器等等。我自己在开发一个 AI 写作助手时就曾深陷 UI 细节的泥潭。原生的textarea处理多行提示词和自动扩展很别扭自己从头写一个支持 Markdown 高亮、代码块渲染的聊天气泡组件又得折腾半天。prompt-kit的出现相当于把一群资深前端工程师在多个 AI 项目中沉淀下来的最佳实践打包成了开箱即用的组件。它最大的魅力在于“可定制性”因为底层是shadcn/ui的哲学——你不是在安装一个无法修改的黑盒 NPM 包而是将一份高质量的、属于你自己的源代码添加到项目中可以随心所欲地调整每一个像素和交互逻辑。这对于追求产品独特性和品牌一致性的团队来说价值巨大。2. 核心设计哲学与技术栈解析2.1 为什么选择 shadcn/ui 作为基石prompt-kit没有选择自己造一个完整的 UI 系统而是坚定地站在shadcn/ui的肩膀上这是一个非常聪明且务实的选择。理解这一点是高效使用它的关键。shadcn/ui本身不是一个传统的组件库比如 Material-UI 或 Ant Design。它更像一个“组件源代码生成器”。当你运行npx shadcn add button时它并不是在你的node_modules里安装一个包而是将Button组件的完整源代码TSX CSS复制到你的项目目录中通常是/components/ui。这意味着完全的所有权和控制权组件代码是你的项目资产。你可以直接修改它无需担心版本升级导致样式覆盖或行为改变也无需通过繁琐的className覆盖或ThemeProvider来定制。零运行时开销组件在编译时就已经是你的代码的一部分没有额外的运行时 JavaScript 捆绑包。这对于追求极致性能的 Next.js 应用至关重要。与 Tailwind CSS 深度集成组件的样式完全由 Tailwind CSS 工具类定义与你项目的设计系统tailwind.config.js无缝融合。修改主题、间距、颜色等只需要调整 Tailwind 配置或直接修改组件内的类名。prompt-kit继承了所有这些优点。它提供的每一个组件本质上都是基于shadcn/ui的设计语言和工程模式专门为 AI 交互场景优化过的“增强版”源代码。你得到的不是node_modules/prompt-kit里的一个抽象组件而是可以直接上手编辑的、位于你项目/components/ui/prompt-input这样的具体文件。2.2 Tailwind CSS样式定制的灵魂由于依赖shadcn/uiprompt-kit组件的样式完全由 Tailwind CSS 驱动。这带来了无与伦比的定制灵活性。假设你不喜欢默认的输入框边框颜色你不需要去研究组件的 Props API 是否支持borderColor也不需要写复杂的 CSS 选择器去覆盖。你只需要打开对应的组件源文件例如prompt-input.tsx找到相关的className将border-gray-300改成border-blue-500即可。这种“样式即代码”的方式让 UI 定制变得极其直观和高效。同时它也意味着你的团队需要熟悉 Tailwind CSS。好消息是prompt-kit和shadcn/ui的文档通常都会清晰地标注出用于不同部分的 Tailwind 类名降低了学习成本。2.3 面向 AI 场景的组件设计考量prompt-kit的组件不是通用组件的简单堆砌其设计深入考虑了 AI 应用的特有交互模式状态复杂性AI 交互往往涉及“空闲-思考-流式输出-错误”等多种状态。组件需要优雅地展示加载指示器、流式文本的逐字打印效果、错误状态的重试机制等。内容复杂性AI 生成的内容可能包含 Markdown、代码、列表、表格等。消息展示组件需要内置强大的渲染能力而不仅仅是显示纯文本。输入复杂性Prompt 输入框可能需要支持多模态文本文件、历史记录、快捷指令/命令触发、自动高度调整等高级功能。交互实时性流式响应要求 UI 能够平滑、不间断地更新内容这对组件的渲染性能提出了要求。prompt-kit的组件在设计时已经内置了对这些场景的初步支持提供了一个高起点开发者可以在此基础上进行更精细的打磨。3. 环境准备与项目初始化实战在引入prompt-kit之前你需要一个已经配置好shadcn/ui的 Next.js 项目。以下是详细的步骤和避坑指南。3.1 创建 Next.js 项目如果你是从零开始建议使用官方的create-next-app并选择 TypeScript 和 Tailwind CSS 模板这是与shadcn/ui及prompt-kit最兼容的起点。npx create-next-applatest my-ai-app --typescript --tailwind --app cd my-ai-app注意在初始化时如果询问是否使用src/目录你可以根据习惯选择。shadcn/ui默认会将组件添加到/components/ui这个路径通常在项目根目录。如果使用src/结构路径会变成/src/components/ui后续命令可能需要调整--path参数。3.2 安装并配置 shadcn/ui这是最关键的一步。prompt-kit的安装完全依赖于一个正确配置的shadcn/ui环境。运行初始化命令npx shadcnlatest init这个命令会启动一个交互式配置向导。关键配置项解析Style: 选择Default。这会将shadcn/ui的默认 CSS 变量主题导入你的app/globals.css。Base Color: 选择你喜欢的基色如slate,gray,zinc。这决定了组件的基础色调。CSS Variables:务必选择Yes。这是shadcn/ui实现动态主题和深色模式的核心prompt-kit组件也依赖于此。Tailwind CSS Config: 通常选择tailwind.config.ts。Components Directory: 默认是/components/ui。确保这个路径与你的项目结构匹配。/别名通常已在 Next.js 中配置为指向项目根目录或src/目录。初始化后的检查 命令执行成功后请检查以下文件components.json这是shadcn/ui的配置文件记录了组件路径、样式引擎等信息。prompt-kit的 CLI 会读取这个文件。app/globals.css文件顶部应该被添加了tailwind base; tailwind components; tailwind utilities;以及一行import “tailwindcss”;。更重要的是下面会有一大段:root和.dark的 CSS 变量定义这就是你的设计系统。tailwind.config.tscontent字段应该包含了你的组件路径。实操心得我建议在初始化shadcn/ui后先手动添加一个基础组件如Button测试一下环境是否正常。npx shadcnlatest add button然后去app/page.tsx中导入并使用它运行npm run dev查看页面是否正常渲染了一个样式优美的按钮。这一步能提前排除掉 90% 的路径或配置问题。4. 安装与使用 prompt-kit 组件详解4.1 组件安装流程假设你的shadcn/ui环境已经测试通过。现在我们来安装prompt-kit的核心组件之一PromptInput。根据文档使用以下命令npx shadcnlatest add prompt-kit/prompt-input这个命令背后发生了什么读取配置CLI 首先读取你项目根目录的components.json文件。解析源地址它发现你要添加的组件来自prompt-kit这个“源”而非常规的shadcn/ui官方源。获取源代码CLI 会从prompt-kit的 GitHub 仓库或注册的源中找到prompt-input组件的源代码。复制并适配它将组件的tsx文件、可能伴随的css文件复制到你components.json中定义的ui目录下例如/components/ui。在这个过程中它会自动将组件内部引用其他shadcn/ui组件如Button的路径调整为你项目的别名路径如/components/ui/button。更新依赖它可能会向你的package.json中添加prompt-kit作为依赖。但请注意这个依赖主要是为了类型定义和未来的 CLI 更新核心的组件代码已经在你本地了。4.2 基础使用与属性探索安装完成后你可以在项目中引入并使用PromptInput。// app/page.tsx import { PromptInput } from /components/ui/prompt-input; export default function Home() { const handleSubmit (value: string) { console.log(用户输入的 Prompt:, value); // 在这里调用你的 AI API例如 OpenAI、Anthropic 等 }; return ( div classNamecontainer mx-auto p-8 h1 classNametext-3xl font-bold mb-6我的 AI 助手/h1 PromptInput placeholder请输入你的问题... onSubmit{handleSubmit} // 其他可选属性... / /div ); }一个设计良好的PromptInput组件通常会提供丰富的属性来控制其行为属性名类型说明典型用例onSubmit(value: string) void提交回调函数通常绑定回车键。用户输入完成后触发 AI 请求。placeholderstring输入框占位文本。引导用户输入如“描述你想要生成的图片...”。disabledboolean是否禁用输入框。在 AI 正在生成内容时防止用户发送新消息。isLoadingboolean是否显示加载状态。与disabled配合使用在输入框旁显示一个加载旋转图标。autoFocusboolean是否自动获取焦点。页面加载后让用户可以直接开始输入。onClear() void清除按钮点击回调。提供一键清空输入的功能。classNamestring自定义容器样式类。调整输入框的整体宽度、边距等。4.3 高级功能与自定义渲染prompt-kit的威力在于其扩展性。一个成熟的PromptInput可能不仅仅是一个文本框加一个按钮。多模态支持组件可能提供一个onFileUpload属性或内置的文件选择按钮允许用户上传图片、文档作为输入的一部分。PromptInput onSubmit{handleSubmit} onFileUpload{(files) { /* 处理上传的文件如转换为 base64 */ }} acceptimage/*,.pdf /快捷命令Slash Commands像 Notion AI 或许多聊天工具一样输入/可以弹出一个命令菜单如/image生成图片/translate翻译。PromptInput onSubmit{handleSubmit} commands{[ { label: 生成图片, value: /image, description: 根据描述生成图像 }, { label: 总结文章, value: /summarize, description: 总结长文本内容 }, ]} onCommandSelect{(command) { /* 处理命令选择可能自动填充输入框 */ }} /实现这个功能需要组件内部处理键盘事件、渲染下拉菜单并与shadcn/ui的Command或Dropdown组件结合。自定义操作按钮除了提交按钮你可能想在输入框旁添加“语音输入”、“历史记录”、“提示词库”等按钮。PromptInput onSubmit{handleSubmit} actions{ Button variantghost sizeicon onClick{startSpeechRecognition} MicIcon / /Button Button variantghost sizeicon onClick{openPromptLibrary} BookOpenIcon / /Button / } /这通常通过组件暴露一个actions插槽React children 或 render prop来实现。5. 核心组件生态与场景化应用prompt-kit不可能只有一个PromptInput。一个完整的 AI 应用 UI 套件应该包含一系列互补的组件。虽然项目文档可能只示例了一个但我们可以根据其定位推演并构建一个完整的组件生态。以下是几个我认为必然会包含或应该包含的核心组件及其应用场景。5.1 ChatMessage ChatFeed构建对话流这是聊天界面的核心。ChatMessage负责渲染单条消息需要区分“用户”和“助手”角色并精美地渲染 Markdown 内容。// 假想的 ChatMessage 组件使用 import { ChatMessage } from /components/ui/chat-message; import { Avatar, AvatarFallback, AvatarImage } from /components/ui/avatar; const message { id: 1, role: assistant as const, // user | assistant | system content: 你好我是 AI 助手。**这是加粗文本**这是代码。, timestamp: new Date(), }; export function MessageItem({ message }) { return ( ChatMessage role{message.role} avatar{ Avatar AvatarImage src{message.role user ? /user-avatar.jpg : /bot-avatar.jpg} / AvatarFallback{message.role user ? U : AI}/AvatarFallback /Avatar } content{message.content} timestamp{message.timestamp} isStreaming{message.id currentStreamingId} // 流式输出时的特殊状态 / ); }ChatFeed则是一个容器组件管理消息列表、自动滚动到底部当新消息或流式输出到来时并集成ChatMessage。实现难点与技巧Markdown 渲染组件内部可能会使用react-markdown或marked库并搭配tailwindcss/typography插件来获得漂亮的排版。需要特别注意代码高亮集成prism.js或highlight.js和数学公式渲染rehype-katex。流式输出当isStreaming为true时content可能会不断变化。组件需要能平滑地追加文本而不是整个重新渲染导致跳动。这可能涉及使用useDeferredValue或手动管理一个内部状态来累积流式数据。引用与操作消息可能支持点击复制、重新生成、点赞/点踩等操作。这些可以通过在ChatMessage上暴露onCopy,onRegenerate等回调属性并在组件内部渲染一个悬停时才显示的操作栏来实现。5.2 AgentStatus ThinkingIndicator展示 AI 状态当 AI 在执行复杂任务如联网搜索、执行代码时需要一个比简单的“加载中”更丰富的状态指示器。// 假想的 AgentStatus 组件 import { AgentStatus } from /components/ui/agent-status; export function TaskPanel() { const [agentState, setAgentState] useStateidle | thinking | searching | writing | error(thinking); return ( div classNameborder rounded-lg p-4 h3任务执行状态/h3 AgentStatus state{agentState} // 不同状态可以配置不同的标签和图标 states{{ thinking: { label: 思考中, icon: BrainIcon, color: text-blue-500 }, searching: { label: 联网搜索中, icon: SearchIcon, color: text-amber-500 }, writing: { label: 撰写回答, icon: PenIcon, color: text-green-500 }, error: { label: 遇到错误, icon: AlertCircleIcon, color: text-red-500 }, }} // 可以显示当前步骤或进度 currentStep正在分析您的问题... / /div ); }ThinkingIndicator可能是一个更简单的、带有动画的视觉元素比如三个跳动的圆点常用于消息输入后的等待状态。5.3 PromptTemplateSelector管理提示词模板对于专业用户快速选择预设的提示词模板如“充当代码审查专家”、“以小红书风格写作”能极大提升效率。// 假想的 PromptTemplateSelector 组件 import { PromptTemplateSelector } from /components/ui/prompt-template-selector; const templates [ { id: 1, name: 代码解释器, description: 详细解释代码的功能和逻辑, preview: 请解释以下代码... }, { id: 2, name: 周报生成器, description: 根据工作内容生成周报, preview: 请根据以下要点生成周报... }, ]; export function PromptPanel() { const [selectedTemplate, setSelectedTemplate] useState(templates[0]); const handleTemplateSelect (template) { setSelectedTemplate(template); // 通常这里还会自动将模板内容填充到 PromptInput }; return ( PromptTemplateSelector templates{templates} onSelect{handleTemplateSelect} selectedId{selectedTemplate.id} // 可以分组显示 groups{[ { name: 开发, templates: templates.filter(t t.category dev) }, { name: 写作, templates: templates.filter(t t.category write) }, ]} // 支持搜索 searchable // 支持自定义渲染模板项 renderItem{(template) ( div strong{template.name}/strong p classNametext-sm text-gray-500{template.description}/p /div )} / ); }这个组件可能需要结合shadcn/ui的Command用于搜索和选择和Card组件来构建一个美观的弹出式选择器。6. 深度定制与主题适配实战拿到组件源代码只是第一步让它们完美融入你的产品才是最终目的。prompt-kit的可定制性就体现在这里。6.1 修改组件视觉样式假设你觉得默认的PromptInput边框太细提交按钮颜色不符合品牌色。找到组件文件/components/ui/prompt-input.tsx。在代码中你会看到类似这样的结构return ( div className{cn(flex rounded-lg border border-input bg-background px-3 py-2, className)} textarea classNamemin-h-[60px] w-full resize-none bg-transparent outline-none placeholder:text-muted-foreground ... / Button typesubmit sizeicon classNameml-2 disabled{disabled || isLoading} {isLoading ? Loader2Icon classNameanimate-spin / : SendIcon /} /Button /div );直接修改 Tailwind 类名将外层容器的border从默认的border-input一个 CSS 变量改为border-2 border-primary让边框更粗并使用主题主色。将Button的className添加bg-primary hover:bg-primary/90明确其背景色。// 修改后 div className{cn(flex rounded-lg border-2 border-primary bg-background px-3 py-2, className)} ... Button typesubmit sizeicon classNameml-2 bg-primary hover:bg-primary/90 disabled{disabled || isLoading} ... /Button /div保存文件更改会立即在你的应用中生效。无需重启开发服务器。6.2 扩展组件行为逻辑也许你需要PromptInput支持Ctrl Enter换行而单按Enter直接提交类似于微信。在prompt-input.tsx中找到textarea的onKeyDown事件处理函数如果没有就添加一个。修改逻辑const handleKeyDown (event: React.KeyboardEventHTMLTextAreaElement) { // 原有的自动高度调整逻辑... // ... // 新增Ctrl/Cmd Enter 换行Enter 提交 if (event.key Enter) { if (event.ctrlKey || event.metaKey) { // 插入换行符这是默认行为我们允许它发生 return; } else { event.preventDefault(); // 阻止默认的换行行为 handleSubmit(); // 调用你的提交逻辑 } } }; // 在 textarea 上绑定事件 textarea ... onKeyDown{handleKeyDown} /为了更好的用户体验可以在输入框的右下角添加一个提示文本div classNamerelative textarea ... / div classNameabsolute bottom-2 right-2 text-xs text-muted-foreground Enter 发送CtrlEnter 换行 /div /div6.3 实现深色模式无缝切换得益于shadcn/ui基于 CSS 变量的设计prompt-kit组件天生支持深色模式。你只需要确保你的应用正确实现了主题切换。检查 CSS 变量打开app/globals.css你会看到:root浅色模式和.dark深色模式下分别定义了一套颜色变量如--background,--foreground,--primary。使用 next-themes推荐这是 Next.js 生态最流行的主题管理库。npm install next-themes在app/providers.tsx中配置use client; import { ThemeProvider } from next-themes; export function Providers({ children }: { children: React.ReactNode }) { return ( ThemeProvider attributeclass defaultThemesystem enableSystem disableTransitionOnChange {children} /ThemeProvider ); }在app/layout.tsx中包裹import { Providers } from ./providers; export default function RootLayout({ children }) { return ( html langen suppressHydrationWarning body Providers{children}/Providers /body /html ); }添加切换按钮使用useTheme钩子。use client; import { useTheme } from next-themes; import { Button } from /components/ui/button; import { MoonIcon, SunIcon } from lucide-react; export function ThemeToggle() { const { theme, setTheme } useTheme(); return ( Button variantghost sizeicon onClick{() setTheme(theme dark ? light : dark)} SunIcon classNameh-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0 / MoonIcon classNameabsolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100 / /Button ); }完成以上步骤后你的prompt-kit组件就会自动跟随系统的深色模式设置或用户的手动切换在浅色和深色主题间流畅变换因为组件内部使用的都是bg-background、text-foreground、border-border这类 CSS 变量。7. 常见问题与排查技巧实录在实际集成和使用过程中你可能会遇到一些典型问题。以下是我根据经验总结的排查清单。7.1 安装与编译问题问题现象可能原因解决方案运行npx shadcn add prompt-kit/xxx报错Cannot find source1. 组件名拼写错误。2.prompt-kit源未正确配置或项目不存在。1. 检查组件名是否完全匹配文档。2. 确认prompt-kit是一个公开的、可访问的shadcn/ui兼容源。可以尝试直接查看其 GitHub 仓库的components目录确认组件是否存在。安装后导入组件时 TypeScript 报错Cannot find module1. 组件安装路径与导入路径不一致。2. TypeScript 路径别名/*未配置。1. 检查components.json中的componentPath设置确认组件实际安装到了哪里然后调整导入语句。2. 检查tsconfig.json确保paths下配置了/*: [./*]或/*: [./src/*]。组件样式丢失看起来像无样式的原生 HTML1.shadcn/ui的 CSS 变量未正确导入。2. Tailwind CSS 未扫描到新组件。1. 确认app/globals.css文件顶部包含了import tailwindcss;以及tailwind指令。2. 检查tailwind.config.ts的content数组确保包含了你的组件路径如./components/**/*.{ts,tsx}。修改后重启开发服务器。7.2 运行时与交互问题问题现象可能原因解决方案PromptInput的onSubmit不触发1. 表单提交事件被阻止。2. 组件被包裹在另一个表单中事件冲突。1. 检查组件内部或外层是否有form标签并阻止了默认提交行为。确保onSubmit回调被正确绑定到组件内部的提交事件上。2. 尝试将组件放在form标签外或使用event.stopPropagation()。流式输出时ChatMessage内容闪烁或跳动1. 组件在每次content变化时完全重新渲染。2. React 键key设置不当。1. 确保流式更新时只更新content字符串本身而不是替换整个消息对象。使用useState或useDeferredValue来管理流式累积的数据。2. 为每条消息设置稳定且唯一的key避免列表重排。深色模式切换后组件部分样式未更新1. 组件内硬编码了颜色类名未使用 CSS 变量。2.next-themes的attribute设置与组件不匹配。1. 检查自定义修改过的组件代码将类似text-gray-800的硬编码类名改为text-foreground等变量类名。2. 确认ThemeProvider的attributeclass并且组件根元素能正确接收到darkclass。7.3 性能优化建议虚拟化长列表如果你的聊天记录或提示词模板列表非常长超过数百条直接渲染所有ChatMessage或PromptTemplateSelector项会导致严重的性能问题。考虑集成tanstack/react-virtual实现虚拟滚动只渲染可视区域内的元素。避免不必要的重渲染使用React.memo包裹纯展示型的子组件如ChatMessage并确保其 Props 是稳定的使用useMemo或useCallback。代码分割如果prompt-kit组件库很大可以考虑使用 Next.js 的动态导入dynamic import来按需加载不那么常用的组件减少初始包体积。const DynamicPromptTemplateSelector dynamic(() import(/components/ui/prompt-template-selector), { ssr: false, // 如果组件依赖浏览器 API可以禁用 SSR loading: () Skeleton classNameh-[200px] w-full /, // 加载时的占位符 });8. 从组件到完整应用架构思路prompt-kit提供了优秀的“砖块”但要建成一座“大厦”还需要良好的应用架构。这里分享一个基于 Next.js App Router 的简单 AI 聊天应用状态管理思路。核心状态管理可以使用 Zustand、Jotai 或 Context useReducer// stores/chat-store.ts import { create } from zustand; interface Message { id: string; role: user | assistant; content: string; timestamp: Date; } interface ChatStore { messages: Message[]; input: string; isLoading: boolean; // Actions setInput: (input: string) void; appendMessage: (message: OmitMessage, id | timestamp) void; updateLastMessage: (content: string) void; // 用于流式更新 setIsLoading: (loading: boolean) void; submitMessage: () Promisevoid; } export const useChatStore createChatStore((set, get) ({ messages: [], input: , isLoading: false, setInput: (input) set({ input }), appendMessage: (message) set((state) ({ messages: [...state.messages, { ...message, id: Date.now().toString(), timestamp: new Date() }] })), updateLastMessage: (content) set((state) { const lastMsg state.messages[state.messages.length - 1]; if (lastMsg lastMsg.role assistant) { const updatedMessages [...state.messages]; updatedMessages[updatedMessages.length - 1] { ...lastMsg, content }; return { messages: updatedMessages }; } return state; }), setIsLoading: (isLoading) set({ isLoading }), submitMessage: async () { const { input, appendMessage, updateLastMessage, setIsLoading } get(); if (!input.trim() || get().isLoading) return; const userMessage input; // 1. 清空输入设置加载状态 set({ input: , isLoading: true }); // 2. 添加用户消息 appendMessage({ role: user, content: userMessage }); // 3. 添加一个空的助手消息用于流式填充 appendMessage({ role: assistant, content: }); try { // 4. 调用 AI API例如 OpenAI const response await fetch(/api/chat, { method: POST, body: JSON.stringify({ message: userMessage }), }); const reader response.body?.getReader(); const decoder new TextDecoder(); if (reader) { while (true) { const { done, value } await reader.read(); if (done) break; const chunk decoder.decode(value); // 5. 流式更新最后一条助手消息的内容 updateLastMessage((prev) prev chunk); } } } catch (error) { updateLastMessage(抱歉出错了: error.message); } finally { setIsLoading(false); } }, }));页面组件集成// app/page.tsx use client; import { PromptInput } from /components/ui/prompt-input; import { ChatFeed } from /components/ui/chat-feed; // 假设有该组件 import { useChatStore } from /stores/chat-store; export default function HomePage() { const { messages, input, isLoading, setInput, submitMessage } useChatStore(); const handleSubmit (value: string) { setInput(value); submitMessage(); // 触发状态管理中的异步流程 }; return ( div classNameflex flex-col h-screen max-w-4xl mx-auto p-4 header classNamepy-4 border-b.../header main classNameflex-1 overflow-y-auto py-4 ChatFeed messages{messages} / /main footer classNameborder-t p-4 PromptInput value{input} onChange{(e) setInput(e.target.value)} onSubmit{handleSubmit} isLoading{isLoading} placeholder与 AI 对话... / /footer /div ); }这个架构将 UI 组件prompt-kit与业务逻辑和状态管理清晰地分离。prompt-kit组件只负责渲染和触发事件所有的数据流和副作用都由 Zustand Store 管理使得代码更易于测试和维护。你可以在此基础上轻松集成历史记录保存、多会话管理、模型切换等更复杂的功能。

相关文章:

基于shadcn/ui与Tailwind CSS构建可定制AI应用组件库

1. 项目概述与核心价值如果你正在用 Next.js 和 React 构建 AI 应用,并且对市面上那些要么功能简陋、要么风格死板的 UI 组件感到头疼,那么prompt-kit这个项目很可能就是你一直在找的“瑞士军刀”。简单来说,它是一套基于shadcn/ui和Tailwind…...

Transformer模型工程化实战:从微调到部署的完整指南

1. 项目概述:当Transformers模型走出实验室如果你在过去几年里关注过人工智能,尤其是自然语言处理领域,那么“Transformer”这个词对你来说一定不陌生。从ChatGPT的惊艳亮相,到各类文本生成、代码补全工具的遍地开花,其…...

Loki介绍(Grafana Labs轻量级日志聚合系统,不索引日志内容,只索引元数据labels)LogQL查询语言、日志监控、日志系统、ELK、Promtail、Query Frontend

文章目录Loki 入门与架构解析:云原生日志系统的最佳实践一、什么是 Loki?二、Loki 的核心特点1. 低成本存储2. 与 Prometheus 生态无缝集成3. 原生支持云原生4. 高扩展性三、Loki 架构详解1. Distributor(分发器)2. Ingester&…...

阿里云2026年萌新手册:搭建Hermes Agent/OpenClaw配置Token Plan指南

阿里云2026年萌新手册:搭建Hermes Agent/OpenClaw配置Token Plan指南 。OpenClaw作为阿里云生态下新一代的开源AI自动化代理平台,曾用名Moltbot/Clawdbot,凭借“自然语言交互自动化任务执行大模型智能决策”的核心能力,正在重构个…...

Claude Code多项目管理实战:AI代理分层架构与自动化工作流配置

1. 项目概述:一个为多项目开发者设计的Claude Code实战配置如果你和我一样,手里同时维护着十几个不同技术栈、不同用途的个人项目,从家庭预算工具到个人知识库,再到各种小游戏,那你一定理解那种在多个代码仓库间反复横…...

终极Unity游戏视觉恢复:专业级去马赛克插件完整指南

终极Unity游戏视觉恢复:专业级去马赛克插件完整指南 【免费下载链接】UniversalUnityDemosaics A collection of universal demosaic BepInEx plugins for games made in Unity3D engine 项目地址: https://gitcode.com/gh_mirrors/un/UniversalUnityDemosaics …...

Python爬虫从入门到实战:用logger.info(msg)构建企业级日志系统与反反爬虫技术详解

目录 1. 为什么你的爬虫总是被封IP? 2. 日志系统——爬虫的灵魂:logger.info(msg)深度解析 2.1 Python logging模块基础 2.2 结构化日志(JSON格式)- 适合ELK/日志中心 2.3 为爬虫定制的日志装饰器 2.4 日志级别的最佳实践 3. 环境搭建与依赖管理(2026最新版) 3.1…...

2026年阿里云OpenClaw/Hermes Agent安装教程,百炼token Plan配置解析

2026年阿里云OpenClaw/Hermes Agent安装教程,百炼token Plan配置解析。OpenClaw作为阿里云生态下新一代的开源AI自动化代理平台,曾用名Moltbot/Clawdbot,凭借“自然语言交互自动化任务执行大模型智能决策”的核心能力,正在重构个人…...

5分钟掌握Windows风扇控制:Fan Control终极免费散热优化指南

5分钟掌握Windows风扇控制:Fan Control终极免费散热优化指南 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trend…...

终极英雄联盟回放分析工具:5步掌握ROFL播放器的完整使用指南

终极英雄联盟回放分析工具:5步掌握ROFL播放器的完整使用指南 【免费下载链接】ROFL-Player (No longer supported) One stop shop utility for viewing League of Legends replays! 项目地址: https://gitcode.com/gh_mirrors/ro/ROFL-Player 还在为英雄联盟…...

MySQL如何解决版本迁移中的触发器冲突_先备份后手动重建

mysqldump 导出时默认禁用触发器,需显式加--triggers参数;导入时需处理DEFINER不存在、同名冲突、函数弃用、依赖顺序等问题,跨版本迁移尤需验证触发逻辑实效性。mysqldump 导出时触发器被自动禁用MySQL 5.7 默认在 mysqldump 中加上 --skip-…...

Ruby 运算符

Ruby 运算符 Ruby 作为一种强大的编程语言,提供了丰富的运算符来帮助开发者实现复杂的逻辑运算。本文将详细介绍 Ruby 的运算符类型、使用方法和注意事项。 运算符类型 Ruby 中的运算符主要分为以下几类: 算术运算符 关系运算符 逻辑运算符 赋值运算符 位运算符 算术运算符…...

内容生产,正在进入“工业化时代”

01|一个被忽视的变化:内容正在被重新定义过去,内容是“创意产物”。现在,内容更像“生产结果”。从一篇文案、一张海报,到一条视频,企业越来越依赖持续稳定的内容输出能力,而不是偶发灵感。这意…...

MIMIGenRec:基于GAN与VAE的数据生成与识别重建框架实战

1. 项目概述与核心价值 最近在搞一个挺有意思的项目,叫 MIMIGenRec。这名字乍一看有点唬人,拆开来看其实就是“MIMI”(一个特定领域或工具的代号,这里我们理解为一种数据或模型格式)的“Gen”(生成&#x…...

基于Matplotlib的学术论文图表标准化绘制与自动化工作流实践

1. 项目概述:一个为学术论文量身打造的图表生成利器 如果你和我一样,常年泡在实验室或者对着代码编辑器,为了一篇论文的图表格式、配色、字体而反复折腾,那么你一定会对 ChenLiu-1996/figures4papers 这个项目产生强烈的共鸣。这…...

SQL Developer 连接类型 (Connection Type) :SID 和 Service Name的区别

SQL Developer连接Oracle数据库时,Basic连接类型最常用,需区分SID和服务名。SID是数据库实例的唯一标识(1对1),适合单机数据库;服务名是逻辑入口(1对多),适合RAC集群和云…...

Browser Ops:为OpenClaw构建智能、可恢复的浏览器工作流内核

1. 项目概述:一个为OpenClaw而生的浏览器工作流内核如果你也像我一样,在自动化领域摸爬滚打多年,肯定经历过这样的场景:写了一大堆浏览器脚本,今天跑得好好的,明天网站改个布局或者加个验证码,整…...

TwinCAT C++项目避坑指南:封装一个稳定可靠的CoE(SDO)读写工具类

TwinCAT C项目实战:构建高可靠CoE读写工具类的工程实践 在工业自动化领域,稳定可靠的设备通信是系统正常运转的基石。作为TwinCAT开发者,我们经常需要与各种伺服驱动器、I/O模块进行CoE(CANopen over EtherCAT)通信&am…...

Me-LLaMA医学大模型实战:从部署到微调,打造专业AI医疗助手

1. 项目概述:当医学遇上大语言模型,我们如何打造一个“懂行”的AI助手?在医疗健康这个信息密度极高、容错率极低的领域,通用的大语言模型(LLM)常常显得“力不从心”。它们或许能写出优美的诗句,…...

【零基础部署】Ubuntu 部署 Hermes Agent 保姆级教程

Hermes Agent 是一个开源的 AI Agent 框架,支持连接飞书、Telegram、Discord 等多种平台,可以帮你自动化处理各种任务。本文手把手带你从零开始在 Ubuntu 上部署 Hermes Agent,全程保姆级,跟着走就行。 1. 环境准备 1.1 系统要求…...

告别单线程等待:用xtdata的download_history_data2回调函数实现进度监控与日志

告别单线程等待:用xtdata的download_history_data2回调函数实现进度监控与日志 在量化交易领域,高效获取历史行情数据是策略研发的基础环节。当面对全市场数千只股票的数据下载任务时,传统的同步等待模式往往让开发者陷入"黑箱操作"…...

SkillSwitch:基于Tauri 2的AI编程助手Skill管理工具开发全解析

1. 项目概述与核心价值 如果你和我一样,日常重度依赖 Claude Code、Cursor 这类 AI 编程助手,那你一定遇到过这个痛点:Skill(或者说 Agent、指令集)越来越多,管理起来却一团糟。它们散落在各个应用的配置目…...

保姆级教程:用ADB给海信电视LED55N3000U‘瘦身’,一键卸载预装软件清单

海信电视LED55N3000U系统深度优化指南:ADB卸载预装应用与自定义桌面实战 海信LED55N3000U作为一款性价比突出的智能电视,其VIDAA系统在长期使用后常因预装应用占用存储空间而影响性能表现。不同于简单的缓存清理,本指南将系统性地讲解如何通过…...

STM32F103ZET6固件库工程搭建避坑大全:从“Manage Run-Time Environment”弹窗到HEX文件生成

STM32F103ZET6固件库工程搭建实战:从零到点灯的完整避坑指南 第一次接触STM32开发的朋友,往往会在工程搭建阶段就遇到各种"拦路虎"。明明按照教程一步步操作,却总在某个环节卡住,弹出的错误提示让人一头雾水。本文将带你…...

别再傻傻定义结构体了!用Qt的QPair轻松搞定函数多返回值(附排序实战)

告别繁琐结构体:用QPair解锁Qt函数多返回值的高效玩法 在C开发中,我们经常遇到需要从函数返回多个值的场景。传统做法是定义一个临时结构体或类,但这往往带来不必要的代码膨胀。今天我要分享的是Qt框架中一个被严重低估的工具——QPair&#…...

MacBook外接显示器必看:2K屏开启HiDPI的底层原理与手动配置指南

MacBook外接2K显示器HiDPI配置全解析:从原理到实战 为什么你的2K显示器在Mac上总是不清晰? 每次把2K显示器接到MacBook上,总有种说不出的别扭感——要么文字小得需要眯眼,要么放大后模糊得像隔了层毛玻璃。这背后的原因&#xff0…...

用游戏化思维学编程:从ICode训练场代码反推关卡设计逻辑

用游戏化思维学编程:从ICode训练场代码反推关卡设计逻辑 在编程教育领域,游戏化学习正成为一种革命性的教学方法。ICode国际青少年编程竞赛通过精心设计的训练场关卡,将抽象的编程概念转化为直观的游戏挑战。本文将从游戏设计师的视角&#x…...

别急着买显卡!手把手教你用旧电脑(GTX 1060 6G)低成本玩转DeepFaceLab换脸

别急着买显卡!手把手教你用旧电脑(GTX 1060 6G)低成本玩转DeepFaceLab换脸 在AI技术快速发展的今天,深度学习应用如DeepFaceLab(DFL)换脸技术吸引了大量爱好者。然而,许多人被高端显卡的价格门槛…...

从零到自动化:用Python+PyNX快速上手UG二次开发,告别C语言恐惧

从零到自动化:用PythonPyNX快速上手UG二次开发,告别C语言恐惧 UG NX作为工业设计领域的标杆软件,其二次开发能力一直是工程师提升效率的利器。但传统基于C/C的开发方式让许多设计师望而却步——复杂的语法、繁琐的内存管理、漫长的编译过程&a…...

谁说 WinForm 不能高颜值?看这个 Ant Design 无边框收银系统

前言零售门店里,收银系统是每天被使用上百次的工具。但很多系统界面老旧、操作卡顿,甚至在高分屏或触控设备上显示错乱,严重影响效率和体验。有没有可能在 Windows 平台上做出一款既好看又好用、还能真正适配现代硬件的收银软件?本…...