页面调用deepseek接口,需要自己去deepseek官网,注册获取apiKey;

并且保证deepseek账号有钱,才能调用;

支持上下文对话;支持v2和r1模型调用。

使用方法:

1、在左面创建一个.html格式文件

2、将下面带啊复制到新建的文件中

3、可以直降将新建文件拖拽到浏览器中,或者左键文件,使用浏览器打开;

4、页面如下,输入apiKey,就可以发起提问。

代码如下:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <!-- 新增官网同款字体 -->
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
  <!-- 在<head>中添加语法高亮库 -->
  <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/themes/prism-tomorrow.min.css" rel="stylesheet" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/prism.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/components/prism-javascript.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/components/prism-python.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.24.1/components/prism-java.min.js"></script>  <meta charset="UTF-8">
  <title>DeepSeek Chat</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      max-width: 800px;
      margin: 0 auto;
      padding: 20px;
      background: #f0f2f5;
    }
    #chat-container {
      background: white;
      border-radius: 10px;
      box-shadow: 0 2px 10px rgba(0,0,0,0.1);
      padding: 20px;
    }
    /* 标题样式 */
    .content-heading {
      color: #1a1a1a;
      margin: 1.2em 0 0.8em;
      font-weight: 600;
      position: relative;
      padding-left: 24px;
    }
    h1.content-heading { font-size: 1.8em; }
    h2.content-heading { font-size: 1.6em; }
    h3.content-heading { font-size: 1.4em; }

    .content-heading::before {
      content: '';
      position: absolute;
      left: 0;
      color: #0878FF;
      font-weight: 700;
    }

    /* 强调样式 */
    strong {
      color: #d32f2f;
      font-weight: 600;
      padding: 2px 4px;
      background: #ffebee;
      border-radius: 4px;
    }

    em {
      color: #0878FF;
      font-style: normal;
      border-bottom: 2px dashed rgba(8,120,255,0.3);
    }

    /* 列表样式 */
    .custom-list {
      margin: 12px 0;
      padding-left: 28px;
      list-style: none;
    }

    .star-list::before {
      content: "✦"; /* 使用星形符号替代默认圆点 */
      color: #0878FF;
      margin-right: 8px;
      font-size: 0.9em;
    }

    #chat-history {
      height: 500px;
      overflow-y: auto;
      margin-bottom: 20px;
      padding: 10px;
      border: 1px solid #e0e0e0;
      border-radius: 8px;
    }
    /* 官网风格消息气泡 */
    .message {
      margin: 12px 24px;
      padding: 16px 20px;
      border-radius: 12px;
      line-height: 1.6;
      font-size: 15px;
      max-width: 85%;
      position: relative;
      transition: transform 0.2s ease;
    }
    .user-message {
      background: #e3f2fd;
      margin-left: auto;
      border-bottom-right-radius: 4px;
    }

    .bot-message {
      background: #f5f5f5;
      margin-right: auto;
    }

    /* 添加角色图标 */
    .user-message::before,
    .bot-message::before {
      content: '';
      width: 24px;
      height: 24px;
      position: absolute;
      background-size: contain;
      top: 10px;
    }

    .user-message::before {
      background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23007bff"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/></svg>');
      right: -32px;
    }

    .bot-message::before {
      background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%235a5a5a"><path d="M19 2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h4l3 3 3-3h4c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-6 16h-2v-2h2v2zm2.07-7.75-.9.92C13.45 11.9 13 12.5 13 14h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"/></svg>');
      left: -32px;
    }
    @keyframes messageAppear {
      0% { opacity: 0; transform: translateY(20px); }
      100% { opacity: 1; transform: translateY(0); }
    }
    /* 代码块样式 */
    pre {
      background: #1e1e1e;
      color: #d4d4d4;
      padding: 15px;
      border-radius: 8px;
      overflow-x: auto;
      tab-size: 4;
      font-family: 'Consolas', monospace;
      margin: 10px 0;
    }

    /* XML标签高亮 */
    .xml-tag { color: #569cd6; }
    .xml-attr { color: #9cdcfe; }
    .xml-value { color: #ce9178; }

    /* 链接样式 */
    a {
      color: #007bff;
      text-decoration: none;
      border-bottom: 1px solid rgba(0,123,255,0.3);
    }

    a:hover {
      color: #0056b3;
      border-bottom-color: currentColor;
    }
    /* 表格样式 */
    table {
      border-collapse: collapse;
      margin: 16px 0;
    }
    td {
      padding: 8px 12px;
      border: 1px solid #e0e0e0;
    }
    /* 列表样式 */
    ul, ol {
      margin: 10px 0;
      padding-left: 25px;
    }

    li {
      margin: 5px 0;
    }
    #input-area {
      display: flex;
      gap: 10px;
    }
    #user-input {
      flex: 1;
      padding: 12px;
      border: 1px solid #e0e0e0;
      border-radius: 25px;
      outline: none;
    }
    button {
      padding: 12px 24px;
      background: #007bff;
      color: white;
      border: none;
      border-radius: 25px;
      cursor: pointer;
      transition: background 0.3s;
    }
    button:hover {
      background: #0056b3;
    }
    button:disabled {
      background: #cccccc;
      cursor: not-allowed;
    }
    .loading {
      color: #666;
      font-style: italic;
    }
    /* 新增模型选择样式 */
    #model-selector {
      margin-bottom: 15px;
      display: flex;
      gap: 10px;
      align-items: center;
    }
    #model-list {
      padding: 8px 12px;
      border-radius: 20px;
      border: 1px solid #e0e0e0;
      background: white;
    }
    #custom-model-input {
      display: none;
      padding: 8px 12px;
      border-radius: 20px;
      border: 1px solid #e0e0e0;
      width: 200px;
    }
    .custom-model-visible {
      display: inline-block !important;
    }
    /* 增强代码块样式 */
    pre[class*="language-"] {
      border-radius: 12px;
      margin: 1em 0;
      padding: 1.5em 2em;
      overflow: auto;
      position: relative;
      background: #2d2d2d;
      font-family: 'Fira Code', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
      font-size: 0.95em;
      line-height: 1.5;
    }

    /* 行号样式 */
    pre[class*="language-"].line-numbers {
      padding-left: 3.8em;
      counter-reset: linenumber;
    }

    pre[class*="language-"].line-numbers > code {
      position: relative;
      white-space: pre-wrap;
    }

    .line-numbers .line-numbers-rows {
      position: absolute;
      pointer-events: none;
      top: 1em;
      left: -3.8em;
      width: 3em; /* 行号宽度 */
      letter-spacing: -1px;
      border-right: 1px solid #999;
      user-select: none;
    }

    .line-numbers-rows > span {
      display: block;
      counter-increment: linenumber;
    }

    .line-numbers-rows > span:before {
      content: counter(linenumber);
      color: #666;
      display: block;
      padding-right: 0.8em;
      text-align: right;
    }
    /* 代码抬头框 */
    .md-code-block-banner-wrap{
      background-color: #fff;
      position: -webkit-sticky;
      position: sticky;
      top: 0;
    }
    .code-block {
      max-height: 600px;
      overflow: auto;
      position: relative;
    }
    /* 代码类型提示标签 */
    .code-language-tag {
      position: absolute;
      top: 0;
      right: 0;
      background: rgba(255,255,255,0.1);
      color: #999;
      padding: 0.2em 1em;
      font-size: 0.8em;
      border-bottom-left-radius: 8px;
    }
    /* 复制按钮样式 */
    .copy-code-btn {
      opacity: 1; /* 始终显示 */
      top: 8px;
      right: 8px;
      padding: 6px 10px;
      background: rgba(40, 167, 69, 0.9);
      border: none;
      transition: all 0.2s ease;
    }

    .copy-code-btn:hover {
      background: #28a745;
      transform: scale(1.05);
    }
    .copy-code-btn svg {
      width: 14px;
      height: 14px;
    }

    /* 新增成功提示样式 */
    .copy-success-tag {
      position: absolute;
      background: #28a745;
      color: white;
      padding: 6px 12px;
      border-radius: 4px;
      font-size: 0.9em;
      animation: fadeOut 1.5s ease forwards;
      z-index: 1000;
    }

    @keyframes fadeOut {
      0% { opacity: 1; }
      100% { opacity: 0; }
    }
    /* 代码标题栏样式 */
    .code-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 8px 12px;
      background: rgba(0,0,0,0.1);
      background-color: #fff;
      border-radius: 8px 8px 0 0;
    }

    .code-header {
      background: white;
      border-bottom: 1px solid var(--ds-border);
      padding: 8px 12px;
    }

    .code-language {
      color: #999;
      font-size: 0.85em;
      text-transform: uppercase;
    }
    pre[class*="language-"]:hover .copy-code-btn {
      opacity: 1;
    }

    /* 复制成功提示 */
    .copy-success {
      position: fixed;
      top: 20px;
      right: 20px;
      background: #4CAF50;
      color: white;
      padding: 12px 24px;
      border-radius: 8px;
      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
      animation: slideIn 0.3s ease-out;
      z-index: 1000;
    }

    @keyframes slideIn {
      from { transform: translateX(100%); }
      to { transform: translateX(0); }
    }


    .md-code-block-banner {
      padding: 8px 16px;
      color: #fff;
      font-size: var(--ds-md-code-block-font-size);
      line-height: var(--ds-md-code-block-font-size);
      border-top-left-radius: 8px;
      border-top-right-radius: 8px;
      background: #50505a;
      justify-content: space-between;
      display: flex;
    }

    .md-code-block-banner-wrap {
      background-color: #fff;
      position: -webkit-sticky;
      position: sticky;
      top: 0;
    }

    Style Attribute {
      --ds-md-zoom: 1.143;
    }
    body, page, .ds-theme {
      --ds-font-size-m: 14px;
    }

    .md-code-block {
      --ds-md-code-block-font-size: calc(var(--ds-md-zoom)*var(--ds-font-size-xsp));
      border-radius: calc(var(--ds-md-zoom)*10px);
      font-size: var(--ds-md-code-block-font-size);
      line-height: calc(var(--ds-md-code-block-font-size)*1.6);
      color: #fff;
      background: #181d28;
    }
    /*.md-code-block-infostring {*/
    /*  position: absolute;*/
    /*  top: -12px;*/
    /*  right: 10px;*/
    /*  z-index: 1;                 !* 确保悬浮于代码块上方 *!*/
    /*}*/

    .md-code-block-infostring {
      font-size: 0.85em;              /* 字号小于主代码内容 */
      color: #f0f0f0;                    /* 中性灰文字色 */
      display: inline-block;          /* 行内块布局 */
      /*margin: 0 0 8px 0;             !* 下边距隔离代码块 *!*/
      margin-right: auto;
    }
    .md-code-block-infostring-right {
      position: absolute;
      top: -12px;
      right: 10px;
      z-index: 1;                 /* 确保悬浮于代码块上方 */
    }

    /*.md-code-block-action {*/
    /*  align-items: center;*/
    /*  display: flex;*/
    /*}*/
    .ds-markdown-code-copy-button {
      background-color: rgba(var(--ds-rgba-transparent));
      color: inherit;
      cursor: pointer;
      border: none;
      margin: 0;
      padding: 0;
    }


    body, page {
      --ds-rgba-transparent: 255 255 255/0;
      font-family: Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,Oxygen,Open Sans,sans-serif;
    }

    /* 容器样式‌:ml-citation{ref="1,2" data="citationList"} */
    .md-code-block-action {
      position: relative;
      background: #F8F9FA;
      border-radius: 6px;
      margin: 16px 0;
      border: 1px solid #EAECEF;
    }

    /* 代码块样式‌:ml-citation{ref="3,6" data="citationList"} */
    pre code {
      display: block;
      padding: 20px;
      font-family: 'JetBrains Mono', monospace;
      font-size: 14px;
      color: #24292E;
      overflow-x: auto;
    }

    /* 复制按钮样式‌:ml-citation{ref="2,4" data="citationList"} */
    .ds-markdown-code-copy-button {
      position: absolute;
      top: 12px;
      right: 12px;
      padding: 6px 12px;
      background: rgba(255, 255, 255, 0.1);
      border: 1px solid rgba(255, 255, 255, 0.2);
      border-radius: 6px;
      color: #e0e0e0;
      cursor: pointer;
      transition: all 0.2s ease;
      backdrop-filter: blur(4px);
      display: flex;
      align-items: center;
      gap: 6px;
      font-size: 0.85em;
    }

    /* 悬停交互‌:ml-citation{ref="4,5" data="citationList"} */

    /* ========= 复制按钮核心样式 ========= */
    .ds-markdown-code-copy-button {
      position: absolute;
      top: 12px;
      right: 12px;
      padding: 5px 10px;
      background: rgba(255, 255, 255, 0.9);
      border: 1px solid #EBEDF0;
      border-radius: 4px;
      cursor: pointer;
      transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
      display: flex;
      align-items: center;
      gap: 6px;
      font-family: -apple-system, system-ui, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;
      font-size: 12px;
      color: #606266;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
      opacity: 0;
      transform: translateY(2px);
    }

    /* 悬停状态 */
    .ds-markdown-code-copy-button:hover {
      background: #FFFFFF;
      border-color: #C0C4CC;
      color: #0878FF;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
      transform: translateY(0);
    }

    /* 显示规则 */
    .md-code-block:hover .ds-markdown-code-copy-button {
      opacity: 1;
    }

    /* 图标动画 */
    .ds-markdown-code-copy-button svg {
      width: 14px;
      height: 14px;
      transition: fill 0.2s;
    }

    .ds-markdown-code-copy-button:hover svg {
      fill: #0878FF;
    }

    /* ========= 成功提示样式 ========= */
    .copy-success-tag {
      position: fixed;
      top: 24px;
      right: 24px;
      background: rgba(0, 0, 0, 0.8);
      color: #FFFFFF;
      padding: 8px 16px;
      border-radius: 4px;
      font-size: 12px;
      display: flex;
      align-items: center;
      gap: 8px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
      animation: dsSlideIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);
      z-index: 9999;
    }

    @keyframes dsSlideIn {
      from {
        opacity: 0;
        transform: translateY(-10px);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

    /* ========= 深色模式适配 ========= */
    .dark .ds-markdown-code-copy-button {
      background: rgba(255, 255, 255, 0.1);
      border-color: rgba(255, 255, 255, 0.12);
      color: rgba(255, 255, 255, 0.8);
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
    }

    .dark .ds-markdown-code-copy-button:hover {
      background: rgba(255, 255, 255, 0.15);
      color: #4D8EFF;
    }

    .dark .copy-success-tag {
      background: rgba(255, 255, 255, 0.9);
      color: #1A1A1A;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
    }

  </style>
</head>
<body>
<div id="chat-container">
  <h1>DeepSeek Chat</h1>

  <!-- 模型选择区域 -->
  <div id="model-selector">
    <select id="model-list">
      <option value="deepseek-chat">基础推理-v3</option>
      <option value="deepseek-reasoner">深度思考-r1</option>
      <option value="custom">自定义模型</option>
    </select>
    <input type="text" id="custom-model-input" placeholder="输入模型名称">

    <div id="api-key-container" >
      <label for="api-key-input">API Key:</label>
      <input type="password" id="api-key-input" placeholder="输入你的API Key">
    </div>

    <div id="api-key-error" style="color: red; display: none;">API Key不能为空</div>

  </div>

  <div id="chat-history"></div>
  <div id="input-area">
    <input type="text" id="user-input" placeholder="输入消息...">
    <button onclick="sendMessage()" id="send-btn">发送</button>
  </div>
  <script>
     const API_URL = 'https://api.deepseek.com/v1/chat/completions';
    let apiKey = localStorage.getItem('apiKey') || '';

    // 初始化模型设置
    let currentModel = localStorage.getItem('selectedModel') || 'deepseek-chat';
    let conversationHistory = [];
    let isGenerating = false;

    // 初始化页面时恢复模型设置
    document.addEventListener('DOMContentLoaded', () => {
      const modelSelector = document.getElementById('model-list');
      const customInput = document.getElementById('custom-model-input');

      // 恢复保存的模型设置
      if (currentModel.startsWith('custom:')) {
        modelSelector.value = 'custom';
        customInput.value = currentModel.replace('custom:', '');
        customInput.classList.add('custom-model-visible');
      } else {
        modelSelector.value = currentModel;
      }

      // 模型选择事件监听
      modelSelector.addEventListener('change', (e) => {
        if (e.target.value === 'custom') {
          customInput.classList.add('custom-model-visible');
          customInput.focus();
        } else {
          customInput.classList.remove('custom-model-visible');
          currentModel = e.target.value;
          localStorage.setItem('selectedModel', currentModel);
        }
      });

      // 自定义模型输入监听
      customInput.addEventListener('input', (e) => {
        currentModel = `custom:${e.target.value}`;
        localStorage.setItem('selectedModel', currentModel);
      });

      // 恢复保存的API Key设置
      const apiKeyInput = document.getElementById('api-key-input');
      apiKeyInput.value = apiKey;

      // API Key输入监听
      apiKeyInput.addEventListener('input', (e) => {
        const value = e.target.value.trim();
        const errorElement = document.getElementById('api-key-error');
        if (!value) {
          errorElement.style.display = 'block';
        } else {
          errorElement.style.display = 'none';
        }
        apiKey = value;
        localStorage.setItem('apiKey', apiKey);
      });
      apiKeyInput.addEventListener('blur', () => {
        if (!apiKey.trim()) {
          document.getElementById('api-key-error').style.display = 'block';
        }
      });
    });

    // 消息处理函数保持不变,修改sendMessage函数:
    async function sendMessage() {
      if (isGenerating) return;
      const trimmedKey = apiKey.trim();
      if (!trimmedKey) {
        alert('API Key为必填项,请先配置');  // 或调用错误提示元素显示
        return;
      }

      const userInput = document.getElementById('user-input');
      const message = userInput.value.trim();
      if (!message) return;

      // 获取当前选择的模型
      const activeModel = currentModel.startsWith('custom:')
              ? currentModel.split(':')[1]
              : currentModel;

      // 禁用输入和按钮
      userInput.value = '';
      const sendBtn = document.getElementById('send-btn');
      sendBtn.disabled = true;
      isGenerating = true;

      try {
        // 添加用户消息
        addMessage('user', message);
        conversationHistory.push({ role: 'user', content: message });

        // 添加加载状态
        const loadingDiv = document.createElement('div');
        loadingDiv.className = 'message bot-message loading';
        loadingDiv.textContent = '思考中...';
        document.getElementById('chat-history').appendChild(loadingDiv);

        // 调用API
        const response = await fetch(API_URL, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${apiKey}`
          },
          body: JSON.stringify({
            model: activeModel,
            messages: conversationHistory,
            temperature: 0.7
          })
        });

        if (!response.ok) throw new Error(`HTTP错误 ${response.status}`);

        const data = await response.json();
        const reply = data.choices[0].message.content;

        // 移除加载状态
        document.getElementById('chat-history').removeChild(loadingDiv);

        // 添加助理消息
        addMessage('assistant', reply);
        conversationHistory.push({ role: 'assistant', content: reply });
      } catch (error) {
        console.error('请求失败:', error);
        addMessage('assistant', `请求失败: ${error.message}`);
      } finally {
        sendBtn.disabled = false;
        isGenerating = false;
      }
    }
    // 添加格式化处理函数
    function formatContent(content) {
      // XML格式化
      content = formatXML(content);
      // 处理井号标题
      content = content.replace(/^#+\s+(.*$)/gm, (match, text) => {
        const level = match.match(/^#+/)[0].length;
        return `<h${level} class="content-heading">${text}</h${level}>`;
      });

      // 处理星号强调
      content = content.replace(/\*{2}(.*?)\*{2}/g, '<strong>$1</strong>'); // 双星号转粗体
      content = content.replace(/\*{1}(.*?)\*{1}/g, '<em>$1</em>');         // 单星号转斜体

      // 处理无序列表
      content = content.replace(/^\*\s+(.*$)/gm, '<li class="star-list">$1</li>');
      content = content.replace(/(<li.*?<\/li>)/gs, '<ul class="custom-list">$1</ul>');

      // 处理代码块中的符号(避免转换)
      content = content.replace(/<pre>.*?<\/pre>/gs, (code) => {
        return code.replace(/\*/g, '※').replace(/#/g, '#'); // 使用全角符号替代
      });
      // 处理嵌套强调
      content = content.replace(/\*{3}(.*?)\*{3}/g, '<strong><em>$1</em></strong>');

// 处理表格符号
      content = content.replace(/^\|(.+)\|$/gm, (match, cells) => {
        const cols = cells.split('|').map(c => `<td>${c.trim()}</td>`).join('');
        return `<tr>${cols}</tr>`;
      });

      // 代码块处理
      content = content.replace(/<code>([\s\S]*?)<\/code>/g, (match, code) => {
        return `<pre>${code.trim()}</pre>`;
      });

      // 链接自动识别
      content = content.replace(/(https?:\/\/[^\s]+)/g, '<a href="$1" target="_blank">$1</a>');

      // 列表自动识别
      content = content.replace(/^(\s*-\s+.*)$/gm, '<ul><li>$1</li></ul>')
              .replace(/<\/ul>\n<ul>/g, '');
// 自动检测代码块(支持多种格式)
      content = content.replace(/(```[\s\S]*?```)/g, (match) => {
        const langMatch = match.match(/```(\w+)?/);
        const language = langMatch && langMatch[1] ? langMatch[1] : 'text';
        const codeContent = match.replace(/```[\s\S]*?\n/, '').replace(/```$/, '');

        return `
            <div class="md-code-block">
                <div class="md-code-block-banner-wrap">
                    <div class="md-code-block-banner">
                        <span class="md-code-block-infostring">${language}</span>
                       <button class="ds-markdown-code-copy-button" onclick="copyCode(this)">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                          <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
                          <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
                        </svg>
                        <span>复制</span>
                      </button>
                    </div>
                 </div>
                <pre ><code class="language-${language}">${escapeHtml(codeContent)}</code></pre>
            </div>
        `;
      });
      return content;
    }

    // 复制功能实现
    function copyCode(button) {
      const codeBlock = button.closest('.md-code-block');
      const codeElement = codeBlock.querySelector('code');
      const language = codeBlock.querySelector('.md-code-block-infostring').textContent;

      // 获取原始代码内容(自动处理转义字符)
      const rawCode = codeElement.textContent;

      // 添加语言标识(可选)
      const codeWithLang = language !== 'text' ? `// ${language}\n${rawCode}` : rawCode;

      navigator.clipboard.writeText(codeWithLang).then(() => {
        showAdvancedCopySuccess(codeBlock);
      }).catch(err => {
        console.error('复制失败:', err);
        fallbackCopy(codeWithLang);
      });
    }

    // 显示成功提示
    function showCopySuccess() {
      const existing = document.querySelector('.copy-success');
      if (existing) existing.remove();

      const div = document.createElement('div');
      div.className = 'copy-success';
      div.textContent = '✓ 已复制到剪贴板';

      document.body.appendChild(div);
      setTimeout(() => div.remove(), 2000);
    }

    // 兼容性备用方案
    function fallbackCopy(text) {
      const textarea = document.createElement('textarea');
      textarea.value = text;
      textarea.style.position = 'fixed';
      document.body.appendChild(textarea);
      textarea.select();
      textarea.style.top = `${rect.top + window.scrollY + 10}px`;
      textarea.style.left = `${rect.left + window.scrollX + 10}%`;

      try {
        document.execCommand('copy');
        showCopySuccess();
      } catch (err) {
        alert('复制失败,请手动选择内容复制');
      } finally {
        document.body.removeChild(textarea);
      }
    }
    // HTML转义函数
    function escapeHtml(unsafe) {
      return unsafe
              .replace(/&/g, "&amp;")
              .replace(/</g, "&lt;")
              .replace(/>/g, "&gt;")
              .replace(/"/g, "&quot;")
              .replace(/'/g, "&#039;");
    }
    // 增强的XML格式化函数
    function formatXML(xml) {
      // 添加语法高亮
      return xml
              .replace(/</g, '&lt;')
              .replace(/>/g, '&gt;')
              .replace(/(&lt;\/([\w-]+)&gt;)/g, '<span class="xml-tag">$1</span>')
              .replace(/(&lt;([\w-]+))/g, '<span class="xml-tag">$1</span>')
              .replace(/([\w-]+)=/g, '<span class="xml-attr">$1</span>=')
              .replace(/("([^"]*)")/g, '<span class="xml-value">$1</span>');
    }

    function addMessage(role, content) {
      const historyDiv = document.getElementById('chat-history');
      const messageDiv = document.createElement('div');
      messageDiv.className = `message ${role}-message`;
      messageDiv.innerHTML = formatContent(content);
      // 恢复代码块中的符号
      messageDiv.querySelectorAll('pre').forEach(pre => {
        pre.innerHTML = restoreSymbols(pre.innerHTML);
      });
      // 初始化Prism高亮
      const preElements = messageDiv.querySelectorAll('pre[class*="language-"]');
      preElements.forEach(pre => {
        Prism.highlightElement(pre.querySelector('code'));
      });
      historyDiv.appendChild(messageDiv);
      historyDiv.scrollTop = historyDiv.scrollHeight;

    }
    // 在代码块中恢复原始符号
    function restoreSymbols(codeBlock) {
      return codeBlock.replace(/※/g, '*').replace(/#/g, '#');
    }

    // 切换模型时清空历史
    document.getElementById('model-list').addEventListener('change', () => {
      if (confirm('切换模型将清空对话历史,是否继续?')) {
        conversationHistory = [];
        document.getElementById('chat-history').innerHTML = '';
      }
    });

    // 优化成功提示
    function showAdvancedCopySuccess(codeBlock) {
      const successTag = document.createElement('div');
      successTag.className = 'copy-success-tag';
      successTag.textContent = '✓ 已复制';

      const rect = codeBlock.getBoundingClientRect();
      // successTag.style.top = `${rect.top + window.scrollY + 10}px`;
      // successTag.style.left = `${rect.right + window.scrollX }%`;
      // 定位到可视区域顶部居中
      successTag.style.position = 'fixed';
      successTag.style.top = '20px';
      successTag.style.left = '50%';
      successTag.style.transform = 'translateX(-50%)';

      console.info("scoll"+(rect.top + window.scrollY + 10));
      console.info("scoll ${rect.top + window.scrollY + 10}"+(rect.right + window.scrollX ));
      document.body.appendChild(successTag);
      setTimeout(() => successTag.remove(), 1000);
    }

    // 支持回车发送
    document.getElementById('user-input').addEventListener('keypress', (e) => {
      if (e.key === 'Enter' && !isGenerating) {
        sendMessage();
      }
    });

    // 增强版复制功能
    function copyCode(button) {
      const codeBlock = button.closest('.md-code-block');
      const codeContent = codeBlock.querySelector('code').innerText;
      const language = codeBlock.querySelector('.md-code-block-infostring').innerText;

      // 生成带语言标识的代码
      const formattedCode = language ? `// ${language}\n${codeContent}` : codeContent;

      navigator.clipboard.writeText(formattedCode).then(() => {
        showOfficialStyleSuccess();
      }).catch(err => {
        console.error('复制失败:', err);
        fallbackCopy(formattedCode);
      });
    }

    // 官方风格成功提示
    function showOfficialStyleSuccess() {
      const existing = document.querySelector('.copy-success-tag');
      if (existing) existing.remove();

      const div = document.createElement('div');
      div.className = 'copy-success-tag';
      div.innerHTML = `
    <svg viewBox="0 0 24 24" width="16" height="16" fill="#52c41a">
      <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"></path>
    </svg>
    已复制到剪贴板
  `;

      document.body.appendChild(div);
      setTimeout(() => div.remove(), 2000);
    }

    // 备用复制方案
    function fallbackCopy(text) {
      const textarea = document.createElement('textarea');
      textarea.value = text;
      textarea.style.position = 'fixed';
      document.body.appendChild(textarea);
      textarea.select();

      try {
        document.execCommand('copy');
        showOfficialStyleSuccess();
      } catch (err) {
        alert('复制失败,请手动选择内容复制');
      } finally {
        document.body.removeChild(textarea);
      }
    }
  </script>
</div>
</body>
</html>

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐