FEATURED · 精选文章

React 19 集成 DeepSeek API 实现动态图表与公式渲染

发布时间 / 2026/8/21 11:25:42
来源 / 创域科博编辑部
栏目 / 资讯中心
React 19 集成 DeepSeek API 实现动态图表与公式渲染 在实际前端项目中集成 AI 能力尤其是处理复杂的图表生成和数学公式渲染已经从一个“锦上添花”的特性变成了提升产品交互深度和用户体验的关键路径。React 19 带来了并发渲染、Actions 等新特性为构建响应式、高性能的 AI 应用界面提供了更优的底层支持。而 DeepSeek 这类大语言模型其强大的代码生成和逻辑推理能力恰好能弥补前端在动态内容生成上的短板。本文将围绕如何构建一个“DeepSeek-React19-WebAI”系统带你从零开始完成 React 19 与 DeepSeek API 的深度集成并重点攻克图表如 ECharts和数学公式如 KaTeX/MathJax的动态生成与渲染难题。无论你是希望为现有项目添加智能对话与内容生成能力还是想探索下一代 React 与 AI 结合的最佳实践这篇文章都将提供一套可运行、可排查、可扩展的完整方案。1. 理解核心架构React 19、DeepSeek 与动态内容渲染在动手写代码之前我们需要厘清三个核心组件如何协同工作以及为什么选择它们。1.1 为什么是 React 19React 19 并非仅仅是版本号更新它引入的并发特性Concurrent Features和服务器组件Server Components理念对于 AI 交互场景至关重要。传统的 AI 对话界面在模型“思考”生成内容时如果响应较慢整个页面可能会卡顿或无响应。React 19 的并发渲染允许我们将耗时的 AI 响应生成任务标记为可中断的保持用户界面的流畅交互。例如用户可以在模型生成图表描述的同时滚动查看之前的对话历史。此外新的useHook 和 Actions 简化了异步数据获取和表单处理使得集成异步的 DeepSeek API 调用更加符合直觉。1.2 DeepSeek API 的角色与能力边界DeepSeek 作为一个大语言模型其核心能力是理解和生成自然语言与代码。在我们的系统中它扮演着“内容生成引擎”的角色。具体来说图表描述生成用户用自然语言描述需求如“展示公司近半年销售额的折线图”DeepSeek 需要理解需求并生成对应的 ECharts 配置对象JSON 格式。数学公式生成用户提出数学问题如“请写出勾股定理的公式并解释”DeepSeek 需要生成包含 LaTeX 语法的文本。通用对话与代码辅助处理其他编程问题、文本总结等任务。这里有一个关键约束DeepSeek不直接渲染图表或公式。它只输出结构化的配置JSON或标记文本LaTeX。渲染工作必须由前端专门的库ECharts, KaTeX来完成。明确这个边界是设计清晰架构的第一步。1.3 动态内容渲染的技术选型图表渲染ECharts是首选。它是一个基于 Canvas 的强大图表库通过一个 JSON 格式的option对象来定义图表的所有属性。这正是 DeepSeek 可以完美生成的格式。相较于 SVG 基础的库ECharts 在大数据量和动态更新方面性能表现更好且社区活跃文档丰富。数学公式渲染KaTeX是首选。它渲染速度快体积相对较小且输出为纯 HTML/CSS易于样式控制。对于需要复杂特性或兼容性要求极高的场景MathJax是备选但它更重、更慢。我们的系统将优先集成 KaTeX。至此系统的工作流已经清晰React 19 构建界面并管理状态 - 用户输入发送至 DeepSeek API - DeepSeek 返回图表配置JSON或公式文本LaTeX- React 组件调用 ECharts/KaTeX 进行渲染。2. 项目环境搭建与核心依赖配置我们将使用 Vite 作为构建工具它启动快、配置简单对现代前端框架支持极佳。2.1 初始化项目与安装 React 19首先使用 Vite 官方模板创建一个新的 React 项目并确保使用 TypeScript 以获得更好的类型安全。# 使用 npm create 命令初始化项目 npm create vitelatest deepseek-react-ai -- --template react-ts # 进入项目目录 cd deepseek-react-ai # 安装依赖 (Vite 会自动安装 React 18我们需要升级到 19) npm install # 升级 React 到 19 版本 (请检查最新稳定版) npm install reactlatest react-domlatest # 安装 React 19 对应的类型定义 npm install --save-dev types/reactlatest types/react-domlatest升级后检查package.json中react和react-dom的版本号应为^19.0.0或更高。2.2 安装 AI 与渲染相关依赖接下来安装处理 AI 通信、图表和公式的核心库。# 1. HTTP 客户端用于调用 DeepSeek API推荐 axios npm install axios # 2. 图表库ECharts 及其 React 封装 npm install echarts echarts-for-react # 3. 公式渲染库KaTeX 及其 CSS npm install katex # KaTeX 的样式文件需要单独引入 # 4. 代码高亮库可选用于展示 DeepSeek 返回的代码块 npm install react-syntax-highlighter types/react-syntax-highlighter # 5. UI 组件库可选用于快速搭建界面这里以 Ant Design 为例 npm install antd ant-design/icons2.3 配置 DeepSeek API 访问你需要从 DeepSeek 平台获取 API Key。永远不要将 API Key 硬编码在客户端代码中这会导致密钥泄露。对于前端项目标准的做法是创建一个本地的后端代理服务例如用 Node.js Express由后端持有 API Key 并转发请求。或者在开发环境使用环境变量并通过 Vite 的配置注入。这里我们以开发环境变量为例演示如何安全地配置。在生产环境中务必使用上述第一种方法。在项目根目录创建.env.development.local文件# .env.development.local VITE_DEEPSEEK_API_KEYyour_actual_deepseek_api_key_here VITE_DEEPSEEK_API_BASE_URLhttps://api.deepseek.comVITE_前缀是 Vite 的约定这样变量才会被暴露给客户端。然后在你的 API 请求模块中读取// src/utils/api/config.ts const DEEPSEEK_API_KEY import.meta.env.VITE_DEEPSEEK_API_KEY; const DEEPSEEK_BASE_URL import.meta.env.VITE_DEEPSEEK_API_BASE_URL; if (!DEEPSEEK_API_KEY) { console.error(DeepSeek API Key is not configured. Please check your .env file.); // 在实际项目中这里应该抛出错误或使用降级策略 } export const apiConfig { baseURL: DEEPSEEK_BASE_URL, headers: { Authorization: Bearer ${DEEPSEEK_API_KEY}, Content-Type: application/json, }, };3. 构建核心 AI 对话与内容生成模块我们将创建一个可复用的 HookuseDeepSeekChat来管理对话状态、发送请求和处理流式响应如果 API 支持。3.1 定义消息类型与 API 请求函数首先定义 TypeScript 类型来保证数据结构的清晰。// src/types/chat.ts export interface Message { id: string; role: user | assistant | system; content: string; // 用于存储 AI 返回的原始数据如图表配置 rawData?: { chartOption?: any; // ECharts 配置对象 latex?: string; // 纯 LaTeX 字符串 }; timestamp: number; } export interface ChatRequest { model: string; // 例如 deepseek-chat messages: Array{ role: Message[role]; content: string }; stream?: boolean; // 其他可能的参数如 temperature, max_tokens } export interface ChatResponse { id: string; choices: Array{ message: { role: string; content: string; }; finish_reason: string; }; usage: { prompt_tokens: number; completion_tokens: number; total_tokens: number; }; }然后创建 API 请求函数。这里我们假设 DeepSeek API 的聊天端点与 OpenAI 格式兼容。// src/api/deepseek.ts import axios from axios; import { apiConfig } from ../utils/api/config; import { ChatRequest, ChatResponse } from ../types/chat; const client axios.create({ baseURL: apiConfig.baseURL, headers: apiConfig.headers, }); export const createChatCompletion async ( params: ChatRequest ): PromiseChatResponse { try { const response await client.post(/chat/completions, params); return response.data; } catch (error) { console.error(DeepSeek API request failed:, error); // 处理错误例如网络错误、认证失败、额度不足等 if (axios.isAxiosError(error)) { throw new Error(API Error: ${error.response?.status} - ${error.response?.data?.error?.message || error.message}); } throw error; } };3.2 实现 useDeepSeekChat Hook这个 Hook 是应用的状态和逻辑中心。// src/hooks/useDeepSeekChat.ts import { useState, useCallback, useRef } from react; import { Message, ChatRequest } from ../types/chat; import { createChatCompletion } from ../api/deepseek; import { extractChartOption, extractLatex } from ../utils/contentParser; // 稍后实现 export const useDeepSeekChat (initialMessages: Message[] []) { const [messages, setMessages] useStateMessage[](initialMessages); const [inputText, setInputText] useState(); const [isLoading, setIsLoading] useState(false); const [error, setError] useStatestring | null(null); // 用于在组件卸载时取消请求 const abortControllerRef useRefAbortController | null(null); const sendMessage useCallback(async (content: string) { if (!content.trim() || isLoading) return; setIsLoading(true); setError(null); const userMessage: Message { id: Date.now().toString(), role: user, content, timestamp: Date.now(), }; // 更新消息列表显示用户消息 setMessages(prev [...prev, userMessage]); const newMessages [...messages, userMessage]; const requestPayload: ChatRequest { model: deepseek-chat, // 根据实际模型名调整 messages: newMessages.map(m ({ role: m.role, content: m.content })), stream: false, }; abortControllerRef.current new AbortController(); try { const response await createChatCompletion(requestPayload); const assistantContent response.choices[0]?.message?.content || ; // **关键步骤解析 AI 返回的内容** const chartOption extractChartOption(assistantContent); const latex extractLatex(assistantContent); const assistantMessage: Message { id: response.id, role: assistant, content: assistantContent, rawData: { chartOption, latex }, timestamp: Date.now(), }; setMessages(prev [...prev, assistantMessage]); } catch (err: any) { console.error(Failed to send message:, err); setError(err.message || 请求失败请重试); // 可以添加一个错误消息到对话中 const errorMessage: Message { id: err-${Date.now()}, role: assistant, content: 抱歉处理您的请求时出错${err.message}, timestamp: Date.now(), }; setMessages(prev [...prev, errorMessage]); } finally { setIsLoading(false); abortControllerRef.current null; } }, [messages, isLoading]); const clearMessages useCallback(() { setMessages([]); setError(null); }, []); return { messages, inputText, setInputText, isLoading, error, sendMessage, clearMessages, }; };3.3 实现内容解析器 (Content Parser)这是连接 AI 生成文本与前端渲染库的桥梁。我们需要从 AI 返回的文本中智能地提取出 JSON 配置和 LaTeX 代码块。// src/utils/contentParser.ts /** * 从 AI 回复的文本中尝试提取 ECharts 配置对象。 * 假设 AI 会将 JSON 包裹在 json ... 或 javascript ... 代码块中。 */ export const extractChartOption (text: string): any | null { // 正则匹配被 json 或 javascript 包裹的代码块 const jsonBlockRegex /(?:json|javascript)\s*([\s\S]*?)/; const match text.match(jsonBlockRegex); if (!match) return null; const potentialJson match[1].trim(); try { const parsed JSON.parse(potentialJson); // 简单验证是否为 ECharts 配置结构 (包含 series 等) if (parsed typeof parsed object (parsed.series || parsed.xAxis || parsed.yAxis)) { return parsed; } } catch (e) { console.warn(Failed to parse extracted JSON as chart option:, e); } return null; }; /** * 从 AI 回复的文本中提取 LaTeX 表达式。 * 匹配行内公式 $...$ 和块公式 $$...$$ */ export const extractLatex (text: string): string | null { // 优先匹配块公式 $$...$$ const blockLatexRegex /\$\$([\s\S]*?)\$\$/; const blockMatch text.match(blockLatexRegex); if (blockMatch) { return blockMatch[1].trim(); } // 其次匹配行内公式 $...$取第一个 const inlineLatexRegex /\$([^$\n]?)\$/; const inlineMatch text.match(inlineLatexRegex); if (inlineMatch) { return inlineMatch[1].trim(); } return null; };4. 实现动态图表与公式渲染组件有了解析后的数据我们需要专门的 React 组件来渲染它们。4.1 智能消息渲染组件这个组件会根据消息的rawData决定如何渲染内容。// src/components/SmartMessage.tsx import React from react; import { Message } from ../types/chat; import { EChart } from ./EChart; import { LatexRenderer } from ./LatexRenderer; import ReactMarkdown from react-markdown; // 用于渲染 Markdown 文本 import { Prism as SyntaxHighlighter } from react-syntax-highlighter; import { vscDarkPlus } from react-syntax-highlighter/dist/esm/styles/prism; interface SmartMessageProps { message: Message; } export const SmartMessage: React.FCSmartMessageProps ({ message }) { const { role, content, rawData } message; const isUser role user; // 容器样式 const containerClass message ${isUser ? user-message : assistant-message}; return ( div className{containerClass} div classNamemessage-avatar{isUser ? : }/div div classNamemessage-content {/* 如果有图表配置优先渲染图表 */} {rawData?.chartOption ( div classNamechart-container EChart option{rawData.chartOption} / /div )} {/* 如果有 LaTeX渲染公式 */} {rawData?.latex !rawData?.chartOption ( div classNamelatex-container LatexRenderer latex{rawData.latex} / /div )} {/* 渲染剩余的文本内容Markdown 格式 */} {/* 注意需要过滤掉已被提取为图表/公式的原始代码块 */} div classNametext-content ReactMarkdown children{content} components{{ code({ node, inline, className, children, ...props }) { const match /language-(\w)/.exec(className || ); const language match ? match[1] : ; // 如果这个代码块是已经被提取的 JSON可以选择不渲染或简化渲染 const codeString String(children).replace(/\n$/, ); if (language json rawData?.chartOption codeString.includes(series)) { // 这是一个图表配置代码块可以选择折叠或显示一个提示 return ( details summary查看图表配置代码/summary SyntaxHighlighter children{codeString} style{vscDarkPlus} language{language} PreTagdiv {...props} / /details ); } return !inline ? ( SyntaxHighlighter children{codeString} style{vscDarkPlus} language{language} PreTagdiv {...props} / ) : ( code className{className} {...props} {children} /code ); } }} / /div /div /div ); };4.2 ECharts 图表组件使用echarts-for-react封装一个受控组件。// src/components/EChart.tsx import React, { useRef, useEffect } from react; import * as echarts from echarts; import type { EChartsOption, ECharts } from echarts; import ReactEChartsCore from echarts-for-react/lib/core; // 按需引入所需图表组件减小打包体积 import { LineChart, BarChart, PieChart } from echarts/charts; import { TitleComponent, TooltipComponent, GridComponent, LegendComponent, } from echarts/components; import { CanvasRenderer } from echarts/renderers; // 注册组件 echarts.use([ TitleComponent, TooltipComponent, GridComponent, LegendComponent, LineChart, BarChart, PieChart, CanvasRenderer, ]); interface EChartProps { option: EChartsOption; style?: React.CSSProperties; onChartReady?: (instance: ECharts) void; } export const EChart: React.FCEChartProps ({ option, style, onChartReady }) { const chartRef useRefReactEChartsCore(null); useEffect(() { // 当 option 变化时可以在这里执行一些副作用比如合并配置 if (chartRef.current) { const instance chartRef.current.getEchartsInstance(); instance.setOption(option, true); // true 表示不合并旧配置 onChartReady?.(instance); } }, [option, onChartReady]); // 默认样式 const defaultStyle: React.CSSProperties { width: 100%, height: 400px, ...style, }; return ( ReactEChartsCore ref{chartRef} echarts{echarts} option{option} style{defaultStyle} notMerge{true} lazyUpdate{true} themelight / ); };4.3 KaTeX 公式渲染组件// src/components/LatexRenderer.tsx import React from react; import katex from katex; import katex/dist/katex.min.css; // 引入 KaTeX 样式 interface LatexRendererProps { latex: string; displayMode?: boolean; // true 为块公式false 为行内公式 } export const LatexRenderer: React.FCLatexRendererProps ({ latex, displayMode true }) { const containerRef React.useRefHTMLDivElement(null); React.useEffect(() { if (containerRef.current) { try { katex.render(latex, containerRef.current, { displayMode, throwOnError: false, // 渲染出错时不抛出异常而是显示错误文本 errorColor: #cc0000, }); } catch (error) { console.error(KaTeX rendering error:, error); if (containerRef.current) { containerRef.current.innerHTML span stylecolor: red;公式渲染错误: ${latex}/span; } } } }, [latex, displayMode]); return div ref{containerRef} /; };5. 组装主应用界面与交互逻辑现在我们将所有部分组合到主应用组件App.tsx中。// src/App.tsx import React from react; import { useDeepSeekChat } from ./hooks/useDeepSeekChat; import { SmartMessage } from ./components/SmartMessage; import { Input, Button, Spin, Alert, Card } from antd; import { SendOutlined, ClearOutlined } from ant-design/icons; import ./App.css; // 基础样式 const { TextArea } Input; function App() { const { messages, inputText, setInputText, isLoading, error, sendMessage, clearMessages, } useDeepSeekChat([ // 可设置初始系统消息或欢迎语 { id: welcome, role: assistant, content: 你好我是你的 AI 助手。你可以让我生成图表例如“画一个展示过去一周气温的折线图”或解答数学问题例如“写出勾股定理公式”。, timestamp: Date.now(), }, ]); const handleSubmit (e: React.FormEvent) { e.preventDefault(); if (inputText.trim()) { sendMessage(inputText); setInputText(); // 清空输入框 } }; const handleKeyDown (e: React.KeyboardEvent) { if (e.key Enter !e.shiftKey) { e.preventDefault(); handleSubmit(e); } }; return ( div classNameapp-container header classNameapp-header h1DeepSeek React 19 AI 助手/h1 p集成动态图表与公式渲染/p /header main classNameapp-main {/* 消息列表区域 */} Card classNamemessage-list-card div classNamemessage-list {messages.map((msg) ( SmartMessage key{msg.id} message{msg} / ))} {isLoading ( div classNameloading-indicator Spin sizesmall / spanAI 正在思考.../span /div )} /div {error ( Alert message请求出错 description{error} typeerror showIcon closable classNameerror-alert / )} /Card {/* 输入区域 */} Card classNameinput-card form onSubmit{handleSubmit} TextArea value{inputText} onChange{(e) setInputText(e.target.value)} onKeyDown{handleKeyDown} placeholder输入您的问题或指令...例如生成一个饼图显示浏览器市场份额 autoSize{{ minRows: 3, maxRows: 6 }} disabled{isLoading} / div classNameinput-actions Button typeprimary icon{SendOutlined /} htmlTypesubmit loading{isLoading} disabled{!inputText.trim() || isLoading} 发送 /Button Button icon{ClearOutlined /} onClick{clearMessages} disabled{messages.length 1 || isLoading} // 保留欢迎消息 清空对话 /Button /div /form /Card /main footer classNameapp-footer p基于 React 19, DeepSeek API, ECharts KaTeX 构建/p /footer /div ); } export default App;5.1 基础样式文件创建src/App.css来定义基本的布局和样式。/* src/App.css */ .app-container { display: flex; flex-direction: column; min-height: 100vh; max-width: 1200px; margin: 0 auto; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif; } .app-header { text-align: center; margin-bottom: 30px; padding-bottom: 20px; border-bottom: 1px solid #f0f0f0; } .app-main { flex: 1; display: flex; flex-direction: column; gap: 20px; } .message-list-card { flex: 1; overflow-y: auto; min-height: 500px; } .message-list { display: flex; flex-direction: column; gap: 16px; } .message { display: flex; gap: 12px; padding: 12px; border-radius: 8px; } .user-message { background-color: #f0f7ff; align-self: flex-end; flex-direction: row-reverse; } .assistant-message { background-color: #fafafa; align-self: flex-start; } .message-avatar { font-size: 24px; flex-shrink: 0; } .message-content { flex: 1; display: flex; flex-direction: column; gap: 10px; } .chart-container, .latex-container { border: 1px solid #e8e8e8; border-radius: 4px; padding: 16px; background-color: white; margin-bottom: 10px; } .text-content { line-height: 1.6; } .loading-indicator { display: flex; align-items: center; gap: 8px; padding: 12px; color: #888; justify-content: center; } .error-alert { margin-top: 16px; } .input-card { flex-shrink: 0; } .input-actions { display: flex; justify-content: flex-end; gap: 12px; margin-top: 16px; } .app-footer { text-align: center; margin-top: 30px; padding-top: 20px; border-top: 1px solid #f0f0f0; color: #666; font-size: 0.9em; }6. 运行验证与效果测试完成所有代码编写后启动开发服务器进行测试。npm run devVite 通常会启动在http://localhost:5173。打开浏览器按以下步骤验证基础对话在输入框输入“你好”查看是否能收到 AI 的回复并且消息列表正常显示。图表生成测试输入一个明确的图表生成指令例如“生成一个展示 2023 年各季度销售额的柱状图数据为Q1: 120, Q2: 200, Q3: 180, Q4: 250”。观察AI 回复的文本中是否包含 JSON 代码块。页面是否在文本上方渲染出了一个柱状图。检查图表是否可交互悬停显示数值。公式生成测试输入一个数学问题例如“请写出牛顿第二定律的公式”。观察AI 回复的文本中是否包含用$$或$包裹的 LaTeX 代码。页面是否将 LaTeX 代码渲染成了美观的数学公式。混合内容测试输入一个复杂请求例如“解释一下勾股定理并画一个直角三角形示意图标注边长 a, b, c”。观察回复是否同时包含文本解释、LaTeX 公式a^2 b^2 c^2和一个简单的示意图可能是基于 ECharts 的散点图连线。错误处理尝试断开网络或输入一个无意义的字符查看错误提示是否正常显示在界面中。7. 常见问题排查与优化建议在实际开发中你可能会遇到以下问题。这里提供排查路径和解决方案。7.1 图表或公式未渲染问题现象可能原因检查方式处理建议AI 回复了正确描述但页面只显示文本没有图表/公式。1.解析器未匹配到内容AI 返回的 JSON/LaTeX 格式与正则表达式不匹配。2.rawData未正确设置Hook 中的extractChartOption或extractLatex返回null。3.组件条件渲染逻辑错误SmartMessage组件中rawData的判断条件有误。1. 打开浏览器开发者工具F12在“网络”标签页查看 AI 返回的完整响应体检查 JSON/LaTeX 代码块的具体格式。2. 在useDeepSeekChat的sendMessage函数中打印chartOption和latex的提取结果。3. 检查SmartMessage组件的渲染逻辑。1. 调整contentParser.ts中的正则表达式使其能兼容 AI 可能返回的多种代码块格式如,json,javascript。2. 确保 Hook 中将解析结果正确赋值给assistantMessage.rawData。3. 简化SmartMessage的渲染逻辑先确保rawData能打印出来。图表区域空白或报错。1.ECharts 配置无效AI 生成的 JSON 不是合法的 EChartsoption。2.ECharts 组件未正确注册在EChart.tsx中未注册需要的图表类型或组件。3.KaTeX 公式语法错误AI 返回的 LaTeX 包含不支持的命令。1. 将 AI 生成的option对象复制到 ECharts 官方示例编辑器 中验证。2. 检查浏览器控制台是否有 ECharts 或 KaTeX 的错误信息。3. 对于 KaTeX查看katex.render是否抛出了异常。1. 在 Prompt 中更明确地要求 AI 输出标准、简洁的 ECharts 配置。可以提供一个示例。2. 在EChart.tsx中确保注册了所有用到的图表类型LineChart, BarChart, PieChart 等。3. 设置throwOnError: false让 KaTeX 在错误时回退到文本显示。7.2 API 请求失败问题现象可能原因检查方式处理建议网络错误或 401/403 状态码。1.API Key 未配置或错误环境变量未加载或 Key 无效。2.跨域问题 (CORS)如果直接从前端调用浏览器会阻止跨域请求。3.网络问题或 API 服务不可用。1. 检查.env.development.local文件是否存在变量名是否正确是否已重启开发服务器。2. 在浏览器“网络”标签页查看请求详情查看请求头中的Authorization字段和响应状态码。3. 使用 curl 或 Postman 直接测试 API 端点。1.绝对不要将真实 API Key 提交到 Git。确保.env*.local文件已在.gitignore中。2.为生产环境搭建后端代理。这是解决 CORS 和隐藏密钥的唯一安全方法。3. 在前端代码中添加更详细的错误处理提示用户检查网络或联系管理员。7.3 性能与体验优化流式响应上述示例使用的是非流式响应。如果 DeepSeek API 支持流式Server-Sent Events可以实现打字机效果提升用户体验。这需要修改useDeepSeekChatHook 和 API 调用逻辑使用fetch并处理data:事件。图表按需引入示例中一次性引入了多个 ECharts 组件。对于生产环境应该根据 AI 可能生成的图表类型实现更细粒度的动态引入以减小打包体积。消息持久化使用localStorage或IndexedDB在本地保存对话记录避免页面刷新后丢失。Prompt 工程优化AI 生成内容的准确度高度依赖 Prompt。可以设计一个“系统提示词”System Prompt明确告诉 AI 需要以何种格式返回图表和公式。例如你是一个前端开发助手擅长生成 ECharts 图表配置和 LaTeX 公式。 当用户请求图表时你必须将完整的 ECharts 配置对象包裹在 json ... 代码块中输出。 当用户请求数学公式时你必须使用 $$...$$ 或 $...$ 包裹 LaTeX 代码。 配置和公式之外你可以提供必要的文字解释。在createChatCompletion的请求中可以将此提示词作为role: system的消息放在消息数组开头。8. 生产环境部署与安全最佳实践将本系统部署到生产环境需要额外考虑以下方面后端代理服务必须使用 Node.js (Express/Fastify)、Python (FastAPI) 或 Go 编写一个简单的后端服务。该服务持有 DeepSeek API Key并提供一个/api/chat端点供前端调用。后端负责转发请求、添加认证头、处理流式响应如果需要以及实施速率限制。示例Node.js Express// server/index.js const express require(express); const axios require(axios); require(dotenv).config(); const app express(); app.use(express.json()); const DEEPSEEK_API_KEY process.env.DEEPSEEK_API_KEY; app.post(/api/chat, async (req, res) { try { const response await axios.post(https://api.deepseek.com/chat/completions, req.body, { headers: { Authorization: Bearer ${DEEPSEEK_API_KEY} } }); res.json(response.data); } catch (error) { res.status(500).json({ error: error.message }); } }); app.listen(3001, () console.log(Proxy server running on port 3001));前端 API 配置中的baseURL改为这个代理服务器的地址如http://your-domain.com/api。环境变量管理在构建时如使用 Docker通过构建参数注入环境变量。使用云服务商提供的密钥管理服务如 AWS Secrets Manager, GCP Secret Manager。前端构建与部署npm run build生成的dist目录可以部署到任何静态文件托管服务如 Nginx、Vercel、Netlify、GitHub Pages 等。确保代理服务器的地址在构建后被正确配置通常通过环境变量。监控与日志在后端代理服务中添加请求日志和错误日志。监控 API 调用次数和费用。前端可以集成 Sentry 等工具监控运行时错误。用户体验增强添加“重新生成”按钮让用户可以要求 AI 重新回答。为图表添加下载为图片的功能利用 ECharts 的getDataURL方法。实现对话历史管理保存、加载、删除会话。通过以上步骤你不仅拥有了一个可运行的 DeepSeek-React19-WebAI 系统更掌握了一套将大语言模型与前端可视化深度集成的工程方法。关键在于理解数据流从用户自然语言到 AI 的结构化输出再到前端专用库的渲染指令。这套模式可以扩展到更多场景如生成地图、流程图、音乐谱等只需替换对应的解析器和渲染器即可。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻