Difference between revisions of "ZhiweiTalk"

From MobiNetS
Jump to: navigation, search
(Created page with "<html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>赵老师的数字分身</title>...")
 
(Replaced content with "<html> <iframe src="https://mns.uestc.cn/resource/talk2zhiwei.html" width="100%" frameborder="0"></iframe> </html>")
Tag: Replaced
 
Line 1: Line 1:
<html lang="zh-CN">
<html>
<head>
<iframe src="https://mns.uestc.cn/resource/talk2zhiwei.html" width="100%" frameborder="0"></iframe>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>赵老师的数字分身</title>
    <style>
        /* 仅保留核心样式,移除背景色 */
        .dt-container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            border-radius: 15px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.2);
            overflow: hidden;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
 
        .dt-header {
            background: linear-gradient(135deg, #4a90e2 0%, #667eea 100%);
            color: white;
            padding: 20px;
            text-align: center;
        }
 
        .dt-header h1 {
            font-size: 24px;
            margin-bottom: 5px;
        }
 
        .dt-header p {
            font-size: 14px;
            opacity: 0.9;
        }
 
        .dt-chat-area {
            height: 400px;
            overflow-y: auto;
            padding: 20px;
            background: #f8f9fa;
        }
 
        .dt-message {
            margin-bottom: 15px;
            padding: 12px 16px;
            border-radius: 12px;
            max-width: 80%;
            word-wrap: break-word;
            line-height: 1.5;
        }
 
        .dt-user-message {
            background: linear-gradient(135deg, #4a90e2 0%, #667eea 100%);
            color: white;
            margin-left: auto;
            text-align: right;
        }
 
        .dt-bot-message {
            background: #e9ecef;
            color: #333;
            margin-right: auto;
        }
 
        .dt-input-area {
            padding: 20px;
            background: white;
            border-top: 1px solid #eee;
            display: flex;
            gap: 10px;
        }
 
        .dt-message-input {
            flex: 1;
            padding: 12px 15px;
            border: 2px solid #e1e5e9;
            border-radius: 25px;
            resize: none;
            height: 50px;
            font-size: 14px;
            transition: border-color 0.3s;
        }
 
        .dt-message-input:focus {
            outline: none;
            border-color: #4a90e2;
            box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
        }
 
        .dt-button-group {
            display: flex;
            gap: 10px;
        }
 
        .dt-send-button, .dt-save-button {
            padding: 12px 20px;
            border: none;
            border-radius: 25px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 500;
            transition: transform 0.2s, box-shadow 0.2s;
        }
 
        .dt-send-button {
            background: linear-gradient(135deg, #4a90e2 0%, #667eea 100%);
            color: white;
        }
 
        .dt-save-button {
            background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
            color: white;
        }
 
        .dt-send-button:hover, .dt-save-button:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
        }
 
        .dt-send-button:active, .dt-save-button:active {
            transform: translateY(0);
        }
 
        .dt-typing-indicator {
            display: inline-block;
            padding: 12px 16px;
            background: #e9ecef;
            border-radius: 12px;
            font-style: italic;
            color: #666;
        }
 
        .dt-status-bar {
            background: #f8f9fa;
            padding: 10px 20px;
            border-top: 1px solid #eee;
            font-size: 12px;
            color: #666;
            text-align: center;
        }
 
        .dt-welcome-message {
            text-align: center;
            color: #666;
            font-style: italic;
            padding: 20px;
        }
 
        /* Markdown 样式 */
        .markdown-content {
            line-height: 1.6;
        }
 
        .markdown-content h1,
        .markdown-content h2,
        .markdown-content h3 {
            margin: 10px 0 5px 0;
            font-weight: bold;
            color: #333;
        }
 
        .markdown-content h1 {
            font-size: 1.5em;
            border-bottom: 1px solid #eee;
            padding-bottom: 5px;
        }
 
        .markdown-content h2 {
            font-size: 1.3em;
        }
 
        .markdown-content h3 {
            font-size: 1.1em;
        }
 
        .markdown-content p {
            margin: 8px 0;
        }
 
        .markdown-content ul,
        .markdown-content ol {
            margin: 8px 0;
            padding-left: 20px;
        }
 
        .markdown-content li {
            margin: 4px 0;
        }
 
        .markdown-content strong {
            font-weight: bold;
        }
 
        .markdown-content em {
            font-style: italic;
        }
 
        .markdown-content code {
            background: #f1f1f1;
            padding: 2px 4px;
            border-radius: 3px;
            font-family: monospace;
            font-size: 0.9em;
        }
 
        .markdown-content pre {
            background: #f8f8f8;
            padding: 10px;
            border-radius: 5px;
            overflow-x: auto;
            margin: 10px 0;
        }
 
        .markdown-content pre code {
            background: none;
            padding: 0;
        }
 
        .markdown-content blockquote {
            border-left: 3px solid #ccc;
            padding-left: 10px;
            margin: 10px 0;
            color: #666;
            font-style: italic;
        }
 
        .markdown-content a {
            color: #4a90e2;
            text-decoration: none;
        }
 
        .markdown-content a:hover {
            text-decoration: underline;
        }
 
        @media (max-width: 600px) {
            .dt-container {
                margin: 10px;
                border-radius: 10px;
            }
           
            .dt-chat-area {
                height: 300px;
            }
           
            .dt-message {
                max-width: 90%;
            }
           
            .dt-input-area {
                flex-direction: column;
            }
           
            .dt-button-group {
                flex-direction: row;
            }
        }
    </style>
</head>
<body>
    <!-- 这个容器可以嵌入到其他网页中 -->
    <div class="dt-container">
        <div class="dt-header">
            <h1>🤖 赵老师的数字分身</h1>
            <p>由于学校网络管理,偶遇重大节日或特殊日期时可能无法回答,请谅解~</p>
        </div>
       
        <div class="dt-chat-area" id="dt-chat-messages">
            <div class="dt-welcome-message">
                正在连接服务器...
            </div>
        </div>
       
        <div class="dt-input-area">
            <textarea class="dt-message-input" id="dt-message-input" placeholder="请输入您的问题..."></textarea>
            <div class="dt-button-group">
                <button class="dt-send-button" id="dt-send-button">发送</button>
                <button class="dt-save-button" id="dt-save-button">保存对话</button>
            </div>
        </div>
       
        <div class="dt-status-bar" id="dt-status-bar">
            <span id="dt-connection-status">正在初始化...</span>
        </div>
    </div>
 
    <script>
        // 获取配置信息,允许通过属性传入
        const container = document.querySelector('.dt-container');
        const backendUrl = container.dataset.backendUrl || 'https://mns.uestc.cn/vs';
        const knowledgeBase = container.dataset.knowledgeBase || 'default'; // 可指定知识库
 
        document.addEventListener('DOMContentLoaded', function() {
            const chatMessages = document.getElementById('dt-chat-messages');
            const messageInput = document.getElementById('dt-message-input');
            const sendButton = document.getElementById('dt-send-button');
            const saveButton = document.getElementById('dt-save-button');
            const connectionStatus = document.getElementById('dt-connection-status');
           
            // 生成唯一的会话ID
            const sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
           
            // 简单的Markdown解析函数
            function renderMarkdown(text) {
                // 替换标题
                text = text.replace(/^### (.*$)/gim, '<h3>$1</h3>');
                text = text.replace(/^## (.*$)/gim, '<h2>$1</h2>');
                text = text.replace(/^# (.*$)/gim, '<h1>$1</h1>');
               
                // 替换粗体和斜体
                text = text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
                text = text.replace(/\*(.*?)\*/g, '<em>$1</em>');
               
                // 替换行内代码
                text = text.replace(/`(.*?)`/g, '<code>$1</code>');
               
                // 替换链接
                text = text.replace(/\[(.*?)\]\((.*?)\)/g, '<a href="$2" target="_blank">$1</a>');
               
                // 替换引用
                text = text.replace(/^> (.*$)/gim, '<blockquote>$1</blockquote>');
               
                // 替换列表
                text = text.replace(/^\- (.*$)/gim, '<li>$1</li>');
                text = text.replace(/^\* (.*$)/gim, '<li>$1</li>');
               
                // 将连续的<li>包装到<ul>中
                text = text.replace(/(<li>.*<\/li>)/gs, '<ul>$1</ul>');
               
                // 替换换行符为<p>标签
                text = text.replace(/\n\s*\n/g, '</p><p>');
               
                // 包装剩余文本到<p>标签中
                text = '<p>' + text + '</p>';
               
                // 清理多余的<p>标签
                text = text.replace(/<p>\s*<\/p>/g, '');
               
                return text;
            }
           
            // 首次连接:发送"欢迎接入"获取欢迎信息
            async function initializeConnection() {
                try {
                    connectionStatus.textContent = '正在初始化...';
                    connectionStatus.style.color = '#ffc107';
                   
                    const response = await fetch(`${backendUrl}/query`, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify({
                            query: "欢迎接入",
                            session_id: sessionId,
                            knowledge_base: knowledgeBase
                        })
                    });
                   
                    if (response.ok) {
                        const data = await response.json();
                        if (data.response) {
                            // 成功连接,显示欢迎信息
                            connectionStatus.textContent = '连接正常';
                            connectionStatus.style.color = '#28a745';
                           
                            // 清空欢迎消息并显示欢迎信息
                            chatMessages.innerHTML = '';
                            addMessage(data.response, 'bot');
                            return true;
                        }
                    }
                   
                    connectionStatus.textContent = '连接异常';
                    connectionStatus.style.color = '#dc3545';
                    return false;
                } catch (error) {
                    console.error('初始化连接失败:', error);
                    connectionStatus.textContent = '连接失败';
                    connectionStatus.style.color = '#dc3545';
                    return false;
                }
            }
           
            // 定期连接测试(不返回消息,只检查连接状态)
            async function testConnection() {
                try {
                    const response = await fetch(`${backendUrl}/query`, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify({
                            query: "连接测试",
                            session_id: sessionId,
                            knowledge_base: knowledgeBase
                        })
                    });
                   
                    if (response.ok) {
                        const data = await response.json();
                        // 连接测试只检查状态,不显示消息
                        if (data.response === "pong") {
                            connectionStatus.textContent = '连接正常';
                            connectionStatus.style.color = '#28a745';
                            return true;
                        }
                    }
                   
                    connectionStatus.textContent = '连接异常';
                    connectionStatus.style.color = '#dc3545';
                    return false;
                } catch (error) {
                    console.error('连接测试失败:', error);
                    connectionStatus.textContent = '连接失败';
                    connectionStatus.style.color = '#dc3545';
                    return false;
                }
            }
           
            // 添加消息到聊天记录
            function addMessage(text, sender) {
                const messageDiv = document.createElement('div');
                messageDiv.className = `dt-message dt-${sender}-message`;
               
                // 如果是机器人消息,应用Markdown渲染
                if (sender === 'bot') {
                    messageDiv.innerHTML = `<div class="markdown-content">${renderMarkdown(text)}</div>`;
                } else {
                    // 用户消息直接显示
                    messageDiv.textContent = text;
                }
               
                chatMessages.appendChild(messageDiv);
               
                // 自动滚动到底部
                chatMessages.scrollTop = chatMessages.scrollHeight;
            }
           
            // 发送消息
            async function sendMessage() {
                const message = messageInput.value.trim();
                if (!message) return;
               
                // 添加用户消息
                addMessage(message, 'user');
                messageInput.value = '';
               
                // 显示打字指示器
                const typingIndicator = document.createElement('div');
                typingIndicator.className = 'dt-message dt-bot-message';
                typingIndicator.innerHTML = '<div class="dt-typing-indicator">正在思考...</div>';
                chatMessages.appendChild(typingIndicator);
                chatMessages.scrollTop = chatMessages.scrollHeight;
               
                try {
                    const response = await fetch(`${backendUrl}/query`, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify({
                            query: message,
                            session_id: sessionId,
                            knowledge_base: knowledgeBase
                        })
                    });
                   
                    const data = await response.json();
                   
                    // 移除打字指示器
                    chatMessages.removeChild(typingIndicator);
                   
                    if (data.response) {
                        addMessage(data.response, 'bot');
                    } else {
                        addMessage('抱歉,服务器返回了错误信息。', 'bot');
                    }
                } catch (error) {
                    console.error('Error:', error);
                    chatMessages.removeChild(typingIndicator);
                    addMessage('抱歉,连接服务器失败: ' + error.message, 'bot');
                }
            }
           
            // 保存对话历史
            function saveChatHistory() {
                const messages = chatMessages.querySelectorAll('.dt-message');
                let historyText = `数字分身对话历史\n${new Date().toLocaleString()}\n知识库: ${knowledgeBase}\n会话ID: ${sessionId}\n\n`;
               
                messages.forEach(msg => {
                    if (msg.classList.contains('dt-user-message')) {
                        historyText += `用户: ${msg.textContent}\n`;
                    } else if (msg.classList.contains('dt-bot-message') && !msg.querySelector('.dt-typing-indicator')) {
                        historyText += `数字分身: ${msg.textContent}\n`;
                    }
                });
               
                // 创建下载链接
                const blob = new Blob([historyText], { type: 'text/plain;charset=utf-8' });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = `数字分身对话_${knowledgeBase}_${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.txt`;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
            }
           
            // 事件监听器
            sendButton.addEventListener('click', sendMessage);
            saveButton.addEventListener('click', saveChatHistory);
           
            messageInput.addEventListener('keypress', function(e) {
                if (e.key === 'Enter' && !e.shiftKey) {
                    e.preventDefault();
                    sendMessage();
                }
            });
           
            // 页面加载时初始化连接并获取欢迎信息
            initializeConnection();
           
            // 每30秒自动测试连接状态(不显示消息)
            const connectionInterval = setInterval(async () => {
                await testConnection();
            }, 30000);
        });
    </script>
</body>
</html>
</html>

Latest revision as of 19:32, 23 January 2026