js调用gpt3.5

时间:2022-03-28 01:09:32

参考链接:直接在前端调用 GPT-3 API

效果图:
js调用gpt3.5

小技巧:
1. shift+enter是发送消息的快捷键
2. 有本地聊天记录功能
3. 按delete按钮可以删除包括这条之后的记录


<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>ChatGPT Web Example</title>
  <style>
    body {
      font-family: "Helvetica Neue", Arial, sans-serif;
    }

    h1 {
      margin-bottom: 20px;
      text-align: center;
    }

    #chatbox {
      border: 1px solid gray;
      height: calc(100vh - 180px);
      margin-bottom: 20px;
      overflow-y: scroll;
      padding: 10px;
    }

    .message {
      margin-bottom: 10px;
      font-size: 18px;
    }

    pre {
      white-space: pre-wrap;
      word-wrap: break-word;
    }

    .user-message {
      color: forestgreen;
      text-align: right;
    }

    .assistant-message {
      color: darkolivegreen;
    }

    .warning-message {
      color: red;
    }

    .chatgpt-message {
      text-align: left;
    }

    #input-container {
      display: flex;
      align-items: center;
      justify-content: center;
      padding-right: 5%;
    }

    #inputbox {
      font-size: 1rem;
      margin-right: 10px;
      padding: 10px;
      width: 100%;
    }

    #submit {
      background-color: cornflowerblue;
      border: none;
      border-radius: 5px;
      box-sizing: border-box;
      color: white;
      cursor: pointer;
      float: right;
      padding: 10px 20px;
      width: 80px;
    }
  </style>
</head>

<body>
  <div id="chatbox">
    <!-- 消息列表 -->
  </div>
  <div id="input-container">
    <textarea id="inputbox" type="text" placeholder="请输入您的问题" rows="5"></textarea>
    <button id="submit" loading="true">提交</button>
  </div>
</body>
<script>
  /* 官方文档[https://platform.openai.com/docs/guides/chat] */
  const chatboxEl = document.getElementById("chatbox");
  const inputEl = document.getElementById("inputbox");
  const submitEl = document.getElementById("submit");

  const endpoint = "https://api.openai.com/v1/chat/completions"; //如api过时,请查询官网
  const apiKey = "sk-"; //换成自己的API Key
  const delayTime = 60000; // 超时时间为60秒
  const model = "gpt-3.5-turbo";
  const temperature = 1; // 回答随机度
  const max_tokens = 1000;
  const historyMessageNum = 10;
  let historyMessage = [];
  let messageIdx = 0;

  function addMessage(text, sender) {
    historyMessage.push({ role: sender, content: text });
    localStorage.setItem("localMessage", JSON.stringify(historyMessage));
    const messageEl = document.createElement("div");
    const preEl = document.createElement("pre");
    messageEl.classList.add("message");
    messageEl.classList.add(`${sender}-message`);
    preEl.textContent = text;
    messageEl.appendChild(preEl);
    if (sender == 'user') {
      const delEl = document.createElement("button");
      delEl.classList.add("delete");
      delEl.innerText = "delete";
      const nowIdx = (historyMessage.length - 1);
      delEl.onclick = function () {
        deleteMessage(nowIdx);
      };
      messageEl.appendChild(delEl);
    }
    chatboxEl.appendChild(messageEl);
    chatboxEl.scrollTop = chatboxEl.scrollHeight;
  }

  deleteMessage = (idx) => {
    const msgEls = document.querySelectorAll('.message');
    msgEls.forEach((el, i) => {
      if (i >= idx) {
        el.parentNode.removeChild(el);
      }
    })
    historyMessage = historyMessage.slice(0, idx);
    localStorage.setItem("localMessage", JSON.stringify(historyMessage));
  }

  async function getResponseFromAPI() {
    const controller = new AbortController();
    const signal = controller.signal;
    const timeout = setTimeout(() => {
      controller.abort();
    }, delayTime);
    const messages = historyMessage
      .filter((v) => ["system", "user", "assistant"].includes(v.role))
      .slice(-historyMessageNum); // 最近消息
    const response = await fetch(endpoint, {
      signal,
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${apiKey}`,
      },
      body: JSON.stringify({
        model,
        messages,
        max_tokens,
        n: 1,
        stop: null,
        temperature,
      }),
    });
    clearTimeout(timeout);
    const result = await response.json();
    return result.choices[0].message;
  }

  function init() {
    submitEl.addEventListener("click", async () => {
      const input = inputEl.value;
      addMessage(input, "user");
      inputEl.value = "";

      // 显示加载动画
      submitEl.innerHTML = "等待中...";
      submitEl.setAttribute("disabled", true);
      // 使用 OpenAI API 获取 ChatGPT 的回答
      getResponseFromAPI(input)
        .then((response) => {
          addMessage(response.content, response.role);
        })
        .catch((error) => {
          addMessage(
            error.name === "AbortError" ? "Network Error" : error.message,
            "warning"
          );
        })
        .finally(() => {
          // 隐藏加载动画
          submitEl.innerHTML = "提交";
          submitEl.removeAttribute("disabled");
        });
    });
    document.addEventListener("keydown", function (event) {
      if (event.shiftKey && event.keyCode === 13) {
        submitEl.click();
        event.preventDefault();
      }
    });
    const localMessage = localStorage.getItem("localMessage") ? JSON.parse(localStorage.getItem("localMessage")) : []
    chatboxEl.innerHTML = '';
    localMessage.forEach(v => addMessage(v.content, v.role));
  }

  init();
</script>

</html>