实现chatGPT 聊天样式

news2024/12/25 2:30:04

效果图在这里插入图片描述
代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Chat Example</title>

    <link rel="stylesheet" href="./highlight/default.min.css">

    <script src="./highlight/highlight.min.js"></script>


    <script src="./marked/marked.min.js"></script>

</head>

<body>
    <div class="title">
        <span> 软件部测试,后端大模型使用claude2。计划接入gpt4</span>
    </div>
    <div id="chat-container">
        <div id="chat-messages">
        </div>
    </div>
    <div class="message-input-wrapper">
        <textarea type="text" id="message-input" placeholder="请输入您的内容"></textarea>
        <div id="send-button">发送</div>
    </div>

    <script>
        console.log(window)
        // 获取需要的DOM元素
        const chatMessages = document.getElementById("chat-messages");
        const messageInput = document.getElementById("message-input");
        const sendButton = document.getElementById("send-button");

      
      
        // formateMarkdown("# Hello World")
        // 定义发送消息的函数
        function sendMessage() {
            const message = messageInput.value;
            if (message.trim() === "") {
                return;
            }

            // 创建一个新的消息元素,并添加到聊天框
            let messageElement = `<div class="flex-right">
                <div class="time-remark-wrapper mr10">
                    <span class="time">${getNowTime()}</span>
                    <div class="message user-message" style="display: inline-block;">
                        ${message}
                    </div>
                </div>
                <img src="./images/avatar.jpeg" class="avatar"/>
            </div>`
            chatMessages.innerHTML += messageElement;

            messageInput.value = "";

            // 发送消息到服务器
            sendToServer(message);
        }


        function getNowTime() {
            var currentTime = new Date();
            var year = currentTime.getFullYear();
            var month = currentTime.getMonth() + 1; // 月份从 0 开始,所以要加 1
            var day = currentTime.getDate();
            var hours = currentTime.getHours();
            var minutes = currentTime.getMinutes();
            var seconds = currentTime.getSeconds();

            // 格式化为两位数
            if (month < 10) {
                month = '0' + month;
            }
            if (day < 10) {
                day = '0' + day;
            }
            if (hours < 10) {
                hours = '0' + hours;
            }
            if (minutes < 10) {
                minutes = '0' + minutes;
            }
            if (seconds < 10) {
                seconds = '0' + seconds;
            }

            var formattedTime = year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;
            return formattedTime;
        }


        function formateMarkdown(message) {

            var renderer = new marked.Renderer();
            renderer.code = function (code, language) {
                var highlightedCode = hljs.highlightAuto(code).value;
                return '<pre><code class="hljs ' + language + '">' + highlightedCode + '</code></pre>';
            };

            marked.setOptions({
                renderer: renderer,
                gfm: true,
                tables: true,
                breaks: true,
                pedantic: false,
                sanitize: false,
                smartLists: true,
                smartypants: false,
            })

            var parsedHTML = marked.parse(message);
            let messageHTML = ` <div class="flex-left">
                <img src="./images/chatGPT.png" class="avatar mr10"/>
                <div class="time-remark-wrapper">
                    <span class="time">${getNowTime()}</span>
                    <div class="message bot-message" style="display: inline-block;">
                        ${parsedHTML}
                    </div>
                </div>
              
            </div>`
            chatMessages.innerHTML += messageHTML;

        }

        // 定义发送消息到服务器的函数
        function sendToServer(message) {
            // formateMarkdown(
            //     '好的,下面是用javascript实现冒泡排序的代码:\n\n```js\nfunction bubbleSort(arr) {\n  const len = arr.length;\n  for (let i = 0; i &lt; len; i++) {\n    for (let j = 0; j &lt; len - 1 - i; j++) {\n      if (arr[j] &gt; arr[j+1]) {\n        // 相邻元素两两对比\n        [arr[j], arr[j+1]] = [arr[j+1], arr[j]]; // 交换两个元素\n      } \n    }\n  }\n  return arr;\n}\n\n// 测试\nconst arr = [5, 4, 3, 2, 1];\nconsole.log(bubbleSort(arr)); // [1, 2, 3, 4, 5]\n```\n\n主要思路是:\n\n1. 从第一个元素开始,依次与后面的元素进行两两比较\n2. 如果顺序相反,则交换两个元素的位置\n3. 一轮比较下来,可以保证最后一个元素是最大的\n4. 下一轮继续比较到倒数第二个元素,以此类推\n5. 直到数组有序\n\n冒泡排序的时间复杂度为 O(n^2),是一种简单但不是很高效的排序算法。"'
            // )

            // 使用AJAX发送POST请求
            const xhr = new XMLHttpRequest();
            xhr.open("POST", "/chat", true);
            xhr.setRequestHeader("Content-Type", "application/json");
            xhr.onreadystatechange = function () {
                if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
                    try {
                        // 解析服务器响应
                        const response = JSON.parse(xhr.responseText);
                        // 提取服务器回复的消息
                        const botMessage = response.msg;
                        // 创建回复消息的元素,并添加到聊天框
                        formateMarkdown(botMessage);

                    } catch (error) {
                        console.error("Error parsing JSON response:", error);
                    }
                }
            };
            xhr.send(JSON.stringify({
                message
            }));
        }

        // 绑定发送按钮的点击事件
        sendButton.addEventListener("click", sendMessage);
    </script>

    <style>
        body {
            font-size: 14px;
        }

        html,
        body {
            width: 100%;
            height: 100%;
            padding: 0;
            margin: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .time-remark-wrapper {
            display: flex;
            flex-direction: column;
        }

        .mr10 {
            margin-right: 10px;
        }

        .time {
            color: rgba(180, 187, 196);
            font-size: 12px;
            margin-bottom: 5px;
        }

        .title {
            display: flex;
            justify-content: center;
            text-align: center;
            font-size: 16px;
            padding: 15px;

        }

        #chat-messages {
            padding: 30px;
        }

        #chat-container {
            width: 1000px;
            margin: 0 auto;
            border-width: 1px;
            border-style: solid;
            border-color: #e5e7eb;
            border-radius: 8px;
            height: calc(100% - 150px);
            box-sizing: content-box;
            position: relative;
            overflow: auto;
        }

        .message-input-wrapper {
            position: fixed;
            bottom: 20px;
            display: flex;
            align-items: center;
            max-width: 1280px;
            margin: 0 auto;
            width: 1000px;
            /* background-color: #fff; */
        }

        .flex-right .time-remark-wrapper {
            align-items: flex-end;
        }

        .message {
            padding: 8px;
            border-radius: 8px;

        }

        textarea:focus {
            outline: none;
        }

        #message-input {
            border: 1px solid #e5e7eb;
            border-top-left-radius: 4px;
            border-bottom-left-radius: 4px;
            padding: 10px;
            flex: 1;

        }

        #message-input>textarea {
            flex: 1;
        }

        .user-message {
            background-color: rgb(210, 249, 209);
            text-align: right;
            margin-bottom: 20px;
            padding: 10px 15px;
        }

        .avatar {
            width: 32px;
            height: 32px;
            border-radius: 50%;
        }

        .flex-right {
            display: flex;
            justify-content: end;
        }

        .flex-left {
            display: flex;
            justify-content: start;
        }

        #send-button {
            background: #0c7a43;
            color: #fff;
            padding: 16px 15px;
            border-top-right-radius: 4px;
            border-bottom-right-radius: 4px;
            cursor: pointer;

        }

        .bot-message {
            background-color: rgb(244, 246, 248);
            margin-bottom: 20px;
            padding: 10px 15px;
        }

        .hljs {
            background: #fff;
            border-radius: 8px;
        }
    </style>
</body>

</html>

实现思路:
1、因为GPT请求返回来得数据是markdown数据,主要是用marked解析markdown数据格式

marked.parse(message);

2、然后用highlight实现代码的高亮显示

https://www.jsdelivr.com/
在这里插入图片描述
最开始这里不晓得怎么引入, 然后用

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js/styles/default.min.css">
<script src="https://cdn.jsdelivr.net/npm/highlight.js"></script>

提示没有require

然后下载了文档
在这里插入图片描述
在下载的文档中看README.md 文档
在这里插入图片描述
根据此链接,找到了正确的js文件和css样式文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/890666.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

axios使用axiosSource.cancel取消请求后怎么恢复请求,axios取消请求和恢复请求实现

在前端做大文件分片上传&#xff0c;或者其它中断请求时&#xff0c;需要暂停或重新请求&#xff0c;比如这里大文件上传时&#xff0c;可能会需要暂停、继续上传&#xff0c;如下GIF演示&#xff1a; 这里不详细说文件上传的处理和切片细节&#xff0c;后续有时间在出一篇&a…

Viobot ROS主从机配置

本篇介绍如何配置Viobot的ROS主从机&#xff0c;设备已经默认配好了主机的大部分设置&#xff0c;由于涉及到开机自启动&#xff0c;所以主机必须是Viobot。 以虚拟机ubuntu20.04为例。 1.从机配置 虚拟机终端输入命令,输入密码&#xff0c;按下图修改文件&#xff0c;保存…

途乐证券-上证指数有哪些股票组成?

上证指数是我国股市最重要的指数之一&#xff0c;它由上海证券交易所根据必定的计算方法加权均匀得出来的数据&#xff0c;是我国股市中重要的股票指数之一。那么&#xff0c;上证指数有哪些股票组成呢&#xff1f;让我们从多个视点剖析。 首先&#xff0c;从职业散布视点看&am…

数据流中的中位数

解题思路一&#xff1a; import java.util.*;public class Solution {//用栈来存储所有数据Stack<Integer> s new Stack<Integer>();//入栈public void Insert(Integer num) {s.push(num);}//出栈public Double GetMedian() {Double result 0.0;if(s.size() <…

01_langchain

Langchain简介 LLM的诞生推动了自然语言处理领域的变革&#xff0c;让以前无法实现的一些应用成为了可能。然而仅仅利用LLM还无法完成真正强大的应用程序&#xff0c;还需要一些相关的资源和技术知识。 Langchain用于开发这些应用程序&#xff0c;可用于&#xff1a; 基于文…

认识docker+LNMP架构

目录 一、docker 1.安装&#xff0c;启动 2.docker相关命令 3.如何使用&#xff1f; 二、LNMP 1.认识LNMP 2.sql注入漏洞挖掘 3.如何绕过检测进行注入 一、docker 1.安装&#xff0c;启动 2.docker相关命令 docker search nginx 搜索镜像 docker pull docker.io/ngin…

Constanze‘s Machine

一、题目 二、分析 列表找规律&#xff0c;不同长度的u能够带来多少种不同的情况 发现规律&#xff0c;case满足斐波那契数列。 所以可以先预计算斐波那契数列fib。 #include<iostream> #include<cstring> #include<algorithm> #define int long long usi…

设置bootstrap的modal垂直居中

效果&#xff1a; 代码&#xff1a; updateEmpModal 指的是我的模态框id$("#updateEmpModal").modal("show"); // show 方法调用之后立即触发该事件 $(#updateEmpModal).on(shown.bs.modal, function(){let $this $(this);let $modal_dialog $this.fi…

elementui 修改日期选择器el-date-picker样式

1. 案例&#xff1a; 2. css /* 最外层颜色 */ .el-popper.is-pure {background: url("/assets/imgList/memuBG.png") no-repeat;border: none;background-size:100% 100%}/* 日期 1.背景透明 */ .el-date-picker{background: transparent; }/* 日期 2.标题、左右图…

C++碎知识点

二叉树 由 n个节点构成的形态不同的⼆叉树 同余符号 定义设m是大于1的正整数&#xff0c;a,b是整数&#xff0c;如果m|(a-b)&#xff0c;则称a与b关于模m同余,记作abmod(m)&#xff0c;读作a同余于b模m。 符号& 按位与 后赋值 C语言中计算优先级

业务数据“一站式”数据管理平台,从设备实时数据和业务应用数据两个方面要彻底解决“信息孤岛”的问题

1. 产品背景 工业数据大致分为两种数据&#xff1a;设备实时数据和业务应用数据。 设备实时数据的管理是iNeuOS工业互联网操作系统的基础平台重要组成部分&#xff0c;要求数据的实时性、稳定性&#xff0c;通过设备驱动&#xff08;数据交互驱动&#xff09;、服务驱动&…

[oneAPI] 图像分类CIFAR-10

[oneAPI] 图像分类CIFAR-10 图像分类参数与包加载数据模型训练过程结果 oneAPI 比赛&#xff1a;https://marketing.csdn.net/p/f3e44fbfe46c465f4d9d6c23e38e0517 Intel DevCloud for oneAPI&#xff1a;https://devcloud.intel.com/oneapi/get_started/aiAnalyticsToolkitSam…

JVM——JVM 垃圾回收

文章目录 写在前面本节常见面试题本文导火索 1 揭开 JVM 内存分配与回收的神秘面纱1.1 对象优先在 eden 区分配1.2 大对象直接进入老年代1.3 长期存活的对象将进入老年代1.4 动态对象年龄判定1.5 主要进行 gc 的区域 2 对象已经死亡&#xff1f;2.1 引用计数法2.2 可达性分析算…

【C++】set/multiset容器

1.set基本概念 #include <iostream> using namespace std;//set容器构造和赋值 #include<set>//遍历 void printSet(const set<int>& st) {for (set<int>::const_iterator it st.begin(); it ! st.end(); it){cout << *it << " …

网络编程学习

网络编程 软件结构 C/S结构&#xff1a;QQ、迅雷、百度网盘 程序员&#xff1a;开发客户端和服务端程序用户&#xff1a;需要下载升级更新客户端对网络带宽要求相对较低数据安全性相对较高 B/S结构&#xff1a;IE、谷歌、火狐 程序员&#xff1a;只需要开发服务端程序用户&am…

泛微E-Office任意文件上传漏洞复现

0x01 产品简介 泛微E-Office是一款标准化的协同 OA 办公软件&#xff0c;泛微协同办公产品系列成员之一,实行通用化产品设计&#xff0c;充分贴合企业管理需求&#xff0c;本着简洁易用、高效智能的原则&#xff0c;为企业快速打造移动化、无纸化、数字化的办公平台。 0x02 漏…

【云原生,k8s】基于Helm管理Kubernetes应用

第四阶段 时 间&#xff1a;2023年8月18日 参加人&#xff1a;全班人员 内 容&#xff1a; 基于Helm管理Kubernetes应用 目录 一、Kubernetes部署方式 &#xff08;一&#xff09;minikube &#xff08;二&#xff09;二进制包 &#xff08;三&#xff09;Kubeadm …

米尔瑞萨RZ/G2L开发板-02 ffmpeg的使用和RTMP直播

最近不知道是不是熬夜太多&#xff0c;然后记忆力减退了&#xff1f; 因为板子回来以后我就迫不及待的试了一下板子&#xff0c;然后发现板子有SSH&#xff0c;但是并没有ffmpeg&#xff0c;最近总是在玩&#xff0c;然后今天说是把板子还原一下哇&#xff0c;然后把官方的固件…

Linux系统之wget命令的基本使用

Linux系统之wget命令的基本使用 一、wget命令介绍二、本次实践环境三、wget命令的使用帮助3.1 wget命令的基本语法3.2 wget选项解释 四、安装wget工具4.1 检查yum仓库状态4.2 安装wget工具 五、wget命令的基本使用5.1 直接下载文件5.2 下载时指定文件名5.3 后台下载文件5.4 限速…

视频汇聚/视频云存储/视频监控管理平台EasyCVR如何进行CDN转推?

视频汇聚/视频云存储/集中存储/视频监控管理平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、云存储、智能分析等&#xff0c;视频智能分析平台EasyCVR融合性强、开放度…