Flask + MySQL + Ollama(DeepSeek) 漏洞资产库 的网络安全资产分析平台的templates中(chat.html)渲染文件
这是一个后端模板渲染的聊天前端页面模板语法为{% %}属于 Jinja2常见于 Flask实现深色风格 AI 对话界面页面包含头部导航、聊天消息容器、输入提交表单JS 实现表单提交、fetch 接口请求、简单 Markdown 转 HTML 渲染、自动插入报告日期功能。关键点chat_history后端传入的对话历史列表循环渲染用户消息、机器人回复两个超链接新窗口打开对接后端另外两个功能页面资产核查、FOFA HASH 工具form 表单阻止默认提交全部走fetch异步请求无页面刷新。CSS 样式分析页面基础全屏居中布局height:100vh背景深色渐变10s 循环渐变动画整体深色主题主色调#00bcd4青蓝色作为强调色。核心容器.chat-container聊天主容器最大宽度 750px高度90vhflex 纵向布局实现头部‑消息区‑输入框固定布局.chat-box消息滚动容器flex‑grow:1自动占满剩余高度overflow‑y:auto消息滚动.user-message用户消息靠右对齐深灰色背景.bot-responseAI 回复靠左左侧青色边框支持内部 h1/h2/h3/strong/code/ul 列表渲染.input-box底部输入区flex 布局输入框圆角发送按钮使用主题色。动画backgroundAnimation背景渐变切换fadeIn消息淡入动画。JavaScript 逻辑分析formatReport(text)格式化函数作用后端返回纯文本简单模拟 Markdown 转 HTML自动追加报告日期!DOCTYPE html html langzh-CN head meta charsetUTF-8 / meta nameviewport contentwidthdevice-width, initial-scale1 / titleAI智能体/title style body { font-family: Segoe UI, Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #121212, #2a2a2a); color: #fff; margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; animation: backgroundAnimation 10s infinite alternate; } keyframes backgroundAnimation { 0% { background: linear-gradient(135deg, #121212, #2a2a2a); } 50% { background: linear-gradient(135deg, #2a2a2a, #121212); } 100% { background: linear-gradient(135deg, #121212, #2a2a2a); } } .chat-container { width: 100%; max-width: 750px; background-color: #1a1a1a; border-radius: 15px; box-shadow: 0 8px 15px rgba(255, 255, 255, 0.2); display: flex; flex-direction: column; height: 90vh; border: 1px solid #fff; } .header { background-color: #2b2b2b; padding: 15px 20px; font-size: 28px; font-weight: bold; border-bottom: 2px solid #00bcd4; display: flex; justify-content: space-between; align-items: center; } .header .buttons { display: flex; gap: 12px; } .header a { text-decoration: none; background-color: #00bcd4; color: white; padding: 8px 14px; border-radius: 20px; font-size: 14px; } .chat-box { padding: 20px; overflow-y: auto; flex-grow: 1; background-color: #111; display: flex; flex-direction: column; } .user-message, .bot-response { margin-bottom: 18px; max-width: 85%; border-radius: 12px; padding: 14px; animation: fadeIn 0.4s ease forwards; } .user-message { background-color: #3a3a3a; align-self: flex-end; text-align: right; } .bot-response { background-color: #1e1e1e; align-self: flex-start; border-left: 5px solid #00bcd4; box-shadow: 0 2px 10px rgba(0, 188, 212, 0.2); line-height: 1.75; } .bot-response h1, .bot-response h2, .bot-response h3 { margin: 16px 0 10px; color: #00e5ff; } .bot-response h2 { border-left: 4px solid #00bcd4; padding-left: 10px; } .bot-response strong { color: #ffd54f; } .bot-response ul { padding-left: 20px; margin: 10px 0; } .bot-response li { margin-bottom: 6px; } .bot-response code { background: #000; padding: 3px 6px; border-radius: 4px; color: #ffab70; } .input-box { display: flex; padding: 15px; background-color: #000; } .input-box input { flex-grow: 1; padding: 12px 18px; font-size: 16px; border-radius: 25px; border: 2px solid #fff; background-color: #333; color: #fff; } .input-box button { margin-left: 15px; padding: 12px 18px; border-radius: 25px; border: none; background-color: #00bcd4; color: #fff; cursor: pointer; } /style /head body div classchat-container div classheader spanAI智能体/span div classbuttons a href/asset-check target_blank资产未报备/a a href/hash target_blankFOFA-HASH/a /div /div div classchat-box idchat-box div classbot-response你好请问需要什么帮助/div {% for chat in chat_history %} div classuser-message{{ chat.user_message }}/div div classbot-response{{ chat.bot_response }}/div {% endfor %} /div div classinput-box form idchat-form styledisplay:flex;width:100%; input typetext idmessage namemessage placeholder请输入问题或IP地址... required / button typesubmit发送/button /form /div /div script function formatReport(text) { if (!text) return ; // HTML 转义 text text.replace(//g, lt;).replace(//g, gt;); // 自动补报告日期插入到“报告结束”之前 if (!/报告日期[:]/.test(text)) { const now new Date(); const dateStr now.getFullYear() - String(now.getMonth() 1).padStart(2, 0) - String(now.getDate()).padStart(2, 0); if (/报告结束/.test(text)) { text text.replace( /(\n*报告结束)/, \n\n报告日期 ${dateStr}\n$1 ); } else { text \n\n报告日期 ${dateStr}; } } // Markdown → HTML text text.replace(/^### (.*)$/gm, h3$yd/h3); text text.replace(/^## (.*)$/gm, h2$yd/h2); text text.replace(/^# (.*)$/gm, h1$yd/h1); text text.replace(/\*\*(.*?)\*\*/g, strong$yd/strong); text text.replace(/^- (.*)$/gm, li$yd/li); text text.replace(/(li.*\/li)/gs, ul$yd/ul); text text.replace(/\n/g, br); return text; } document.getElementById(chat-form).addEventListener(submit, function(e) { e.preventDefault(); const msg document.getElementById(message).value; const chatBox document.getElementById(chat-box); chatBox.innerHTML div classuser-message${msg}/div; document.getElementById(message).value ; const loading document.createElement(div); loading.className bot-response; loading.innerText 正在分析请稍候...; chatBox.appendChild(loading); chatBox.scrollTop chatBox.scrollHeight; fetch(/chat, { method: POST, headers: { Content-Type: application/x-www-form-urlencoded }, body: new URLSearchParams({ message: msg }) }) .then(res res.json()) .then(data { loading.innerHTML formatReport(data.bot_response); chatBox.scrollTop chatBox.scrollHeight; }); }); /script /body /html