Flask + MySQL + Ollama(DeepSeek) 漏洞资产库 的网络安全资产分析平台的templates中(chat.html)渲染文件

这是一个后端模板渲染的聊天前端页面(模板语法为{% %},属于 Jinja2,常见于 Flask),实现深色风格 AI 对话界面;页面包含头部导航、聊天消息容器、输入提交表单,JS 实现表单提交、fetch 接口请求、简单 Markdown 转 HTML 渲染、自动插入报告日期功能。

关键点

  1. chat_history:后端传入的对话历史列表,循环渲染用户消息、机器人回复;
  2. 两个超链接新窗口打开,对接后端另外两个功能页面:资产核查、FOFA HASH 工具;
  3. form 表单阻止默认提交,全部走fetch异步请求,无页面刷新。

CSS 样式分析

页面基础

  • 全屏居中布局,height:100vh,背景深色渐变,10s 循环渐变动画;
  • 整体深色主题,主色调#00bcd4青蓝色作为强调色。

核心容器

  1. .chat-container:聊天主容器,最大宽度 750px,高度90vh,flex 纵向布局,实现头部‑消息区‑输入框固定布局;
  2. .chat-box:消息滚动容器,flex‑grow:1自动占满剩余高度,overflow‑y:auto消息滚动;
  3. .user-message:用户消息靠右对齐,深灰色背景;
  4. .bot-response:AI 回复靠左,左侧青色边框,支持内部 h1/h2/h3/strong/code/ul 列表渲染;
  5. .input-box底部输入区,flex 布局,输入框圆角,发送按钮使用主题色。

动画

  • backgroundAnimation:背景渐变切换;
  • fadeIn:消息淡入动画。

JavaScript 逻辑分析

formatReport(text) 格式化函数

作用:后端返回纯文本,简单模拟 Markdown 转 HTML,自动追加报告日期

复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>AI智能体</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 class="chat-container">
    <div class="header">
        <span>AI智能体</span>
        <div class="buttons">
            <a href="/asset-check" target="_blank">资产未报备</a>
            <a href="/hash" target="_blank">FOFA-HASH</a>
        </div>
    </div>

    <div class="chat-box" id="chat-box">
        <div class="bot-response">你好,请问需要什么帮助?</div>
        {% for chat in chat_history %}
            <div class="user-message">{{ chat.user_message }}</div>
            <div class="bot-response">{{ chat.bot_response }}</div>
        {% endfor %}
    </div>

    <div class="input-box">
        <form id="chat-form" style="display:flex;width:100%;">
            <input type="text" id="message" name="message" placeholder="请输入问题或IP地址..." required />
            <button type="submit">发送</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 class="user-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>
相关推荐
词却1 小时前
数据库基础:MySQL 安装与基础操作
数据库·mysql
xieliyu.1 小时前
MySQL 进阶笔记:用户 / 会话 / 全局 / 局部变量 + CASE 分支语法
开发语言·数据库·笔记·mysql
川石课堂软件测试2 小时前
自动化测试常见的异常处理
python·jmeter·mysql·docker·容器·单元测试·grafana
骇客野人2 小时前
MySQL / PostgreSQL 单表及表数据备份恢复实施方案
数据库·mysql·postgresql
动力 continue2 小时前
MySQL 与网络基础 · 外键约束及 TCP/UDP 协议
网络·tcp/ip·mysql
不过普通话一乙不改名2 小时前
补充:权限与角色
mysql
海兰3 小时前
【应用】UUID v7 生成器 HTML 代码
css·html·css3
蒲锘3 小时前
DevOps 实验阶段四:Infra 节点 + MySQL + Spring Boot 容器化
spring boot·mysql·docker
叫我:松哥3 小时前
基于flask图书管理系统,技术栈flask+layui+sqlite+Echarts
后端·python·数据分析·flask·echarts·layui