采用流式输出搭建chatgpt网站,无需搭建js服务,逐字输出,加快响应速度

无需搭建js服务,方便把已有的非流式代码改为流式代码,提高响应速度
反向代理访问接口,据说这样被openai屏蔽的可能性更小
浏览器指纹统计用户
页面可以自定义设置tokens长度,gpt创造力指数
具有代码高亮显示
Python flask提供接口
Python 文件app.py代码如下:


from flask import Flask,request, abort,Response
import os
import openai
import json

app = Flask(__name__)



# 设置JSONIFY_TIMEOUT为5秒
app.config['JSONIFY_TIMEOUT'] = 60000

    
@app.route('/chat', methods=['POST'])
def chat():

    openai.api_key = "你的api key"
    
    
    json_data = request.get_json()
    
    
    
    conversation = []  # 创建空列表
    conversation.append({"role": "system", "content": "You are a helpful assistant."})
    questions = json_data['myArray']
    answers = json_data['assistant']
    temperatures = 0.7
    if 'temperatures' in json_data:
       if json_data['temperatures']=='适中':    
          temperatures = 0.7
       if json_data['temperatures']=='更有创造力':    
          temperatures = 1.4
       if json_data['temperatures']=='更精准':    
          temperatures = 0.2
    tokens = 1000
    if 'tokens' in json_data:
        tokens = int(json_data['tokens'])
        if tokens>4000:
            tokens =4000

    
    if len(questions) > 2:
        questions = questions[-2:]
        answers = answers[-2:]
    
    if len(questions): 
        # 遍历数组并添加到对话列表中
        for i in range(len(questions)):
            conversation.append({"role": "user", "content": questions[i]})
            conversation.append({"role": "assistant", "content": answers[i]})
        conversation.append({"role": "user", "content": json_data['text']})
            
    else:
        conversation.append({"role": "user", "content": json_data['text']})
        
    
    inp_text = json_data['text']
    
    try:
        
        
        response = openai.ChatCompletion.create(
          model="gpt-3.5-turbo",
          messages = conversation,
          temperature=temperatures,
          max_tokens=tokens,
          stream=True,#指明为流式输出
        #   frequency_penalty=0.5,
        #   presence_penalty=0.5,
        #   top_p=0.9
        )
    except Exception as e:
        response = False
        if 's maximum context length is' in str(e):
              pattern = r'\d+' 
              matches = re.findall(pattern, str(e)) 
              if len(matches) >= 2: 
                 number = int(matches[1]) -4000
                 return ["maximum",number]
              return ["maximum"]         
        if 'a deactivated account' in str(e):
              
              return {'error': '当前api key已经用完额度或者失效,可以通知管理员更新'}, 401
        
        return {'error': '出错了稍后重试'}, 401
    if response:
        //采用流式输出
        return Response(generate(response), mimetype='json')
def generate(response):
            for text in response:
                yield json.dumps(text['choices'][0])+'\n##'  




if __name__ == "__main__":
    app.run(port=端口, host="ip", debug=True)

写好这个代码后可以在linux系统中app.py文件所在目录下,命令行输入 python app.py运行这个文件,成功运行就可以接着部署下面方前端代码了。如果是正式的环境推荐用Gunicorn服务器来管理,用supervisor来自动重启。

接下来是前端代码:



@extends('layouts.capp')

@section('title')
    首页
@endsection
@section('sidebar')
    @parent
    
@endsection

@section('content')
    <body class="antialiased1">
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js">script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js">script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js">script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fingerprintjs2/2.1.0/fingerprint2.min.js">script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js">script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/2.1.3/marked.min.js">script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/highlight.min.js">script>
    <script>hljs.initHighlightingOnLoad();script>

    <div id="existing-element">div>

    
    <div id="app">
        <div class="b-i-c1">
            <div class="b-i-c">
		   <textarea type="text" v-model="message1" class="input-box" id="input-box" oninput="autoResize()" rows="1" placeholder="输入信息">
		   textarea>
                
                <button class="button-c" v-on:click="greet" id="button-c">
                    <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round"
                         stroke-linejoin="round" class="h-4 w-4 mr-1" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
                        <line x1="22" y1="2" x2="11" y2="13">line><polygon points="22 2 15 22 11 13 2 9 22 2">polygon>
                    svg>
                    <div class="h-4 w-4 mr-1 fa">发送div>
                    <div class="text-2xl" id="text-box">
                        <span class="dot">.span>
                        <span class="dot">.span>
                        <span class="dot">.span>
                    div>
                button>
            div>
        div>
        <ul ref="myList" id="myList">ul>
        <h1 class="text-4xl font-semibold text-center mt-6 sm:mt-[20vh] ml-auto mr-auto mb-10 sm:mb-16 flex gap-2 items-center justify-center">
                欢迎使用智能助手
            h1>
        <div class="dio-m">选择对话模式div>
        <div class="container2">

            <div class="item" onclick="toggleActive(this)">更有创造力div>
            <div class="item active" onclick="toggleActive(this)">适中div>
            <div class="item" onclick="toggleActive(this)">更精准div>
        div>

        <div class="container3">
          <label for="rangeInput">单次聊天回复的最大 Token 数,如果预计输出的内容比较多,把它调大一些。如果你输入内容过多,可能会超过Token数限制则要调小一点。label>
          <div class="v_my input-range_input-range__QBkD1 ">
            <span id="rangeValueFormatted">1000span>
            
            <input type="range" min="1" max="3500" step="1" v-model="rangeValue" id="rangeInput">
            <span class="t-t">tokensspan>
          div>
        div>
        <div class="text-gray-800 w-full md:max-w-2xl lg:max-w-3xl md:h-full md:flex md:flex-col px-6 dark:text-gray-100" id="text-gray-800">


            
             <br>
            <div class="md:flex items-start text-center gap-3.5">
                <div class="flex flex-col mb-8 md:mb-auto gap-3.5 flex-1">
                    <h2 class="flex gap-3 items-center m-auto text-lg font-normal md:flex-col md:gap-2" >
                        <svg
                            stroke="currentColor"
                            fill="none"
                            stroke-width="1.5"
                            viewBox="0 0 24 24"
                            stroke-linecap="round"
                            stroke-linejoin="round"
                            class="h-6 w-6"
                            height="1em"
                            width="1em"
                            xmlns="http://www.w3.org/2000/svg"
                        >
                            <circle cx="12" cy="12" r="5">circle>
                            <line x1="12" y1="1" x2="12" y2="3">line>
                            <line x1="12" y1="21" x2="12" y2="23">line>
                            <line x1="4.22" y1="4.22" x2="5.64" y2="5.64">line>
                            <line x1="18.36" y1="18.36" x2="19.78" y2="19.78">line>
                            <line x1="1" y1="12" x2="3" y2="12">line>
                            <line x1="21" y1="12" x2="23" y2="12">line>
                            <line x1="4.22" y1="19.78" x2="5.64" y2="18.36">line>
                            <line x1="18.36" y1="5.64" x2="19.78" y2="4.22">line>
                        svg>
                        例子
                    h2>
                    <ul class="flex flex-col gap-3.5 w-full sm:max-w-md m-auto" id="container" v-on:click="getText($event)">
                        <button class="w-full bg-gray-50 dark:bg-white/5 p-3 rounded-md hover:bg-gray-200 dark:hover:bg-gray-900">
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">
                                    我今天见了3个客户帮我写一个工作日报,需要包含今日工作内容,明日工作计划,心得。

                                font>font><font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                        button>
                        <button class="w-full bg-gray-50 dark:bg-white/5 p-3 rounded-md hover:bg-gray-200 dark:hover:bg-gray-900">
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">
                                    js 实现点击并列元素中的一个获取里面的text赋值到input中
                                font>font><font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                        button>
                        <button class="w-full bg-gray-50 dark:bg-white/5 p-3 rounded-md hover:bg-gray-200 dark:hover:bg-gray-900">
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">

                                    我要你扮演诗人。你将创作出能唤起情感并具有触动人心的力量的诗歌。确保文字优美而有意义。我的第一个请求是:我需要一首关于爱情的诗。

                                font>font><font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                        button>

                        <button class="w-full bg-gray-50 dark:bg-white/5 p-3 rounded-md hover:bg-gray-200 dark:hover:bg-gray-900">
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">如何在 Javascript 中发出 HTTP 请求?font
                                >font
                            ><font style="vertical-align: inherit"
                            ><font style="vertical-align: inherit">font>font
                            >
                        button>
                    ul>
                div>
                <div class="flex flex-col mb-8 md:mb-auto gap-3.5 flex-1">
                    <h2 class="flex gap-3 items-center m-auto text-lg font-normal md:flex-col md:gap-2" >
                        <svg
                            stroke="currentColor"
                            fill="none"
                            stroke-width="1.5"
                            viewBox="0 0 24 24"
                            stroke-linecap="round"
                            stroke-linejoin="round"
                            class="h-6 w-6"
                            height="1em"
                            width="1em"
                            xmlns="http://www.w3.org/2000/svg"
                        >
                            <circle cx="12" cy="12" r="5">circle>
                            <line x1="12" y1="1" x2="12" y2="3">line>
                            <line x1="12" y1="21" x2="12" y2="23">line>
                            <line x1="4.22" y1="4.22" x2="5.64" y2="5.64">line>
                            <line x1="18.36" y1="18.36" x2="19.78" y2="19.78">line>
                            <line x1="1" y1="12" x2="3" y2="12">line>
                            <line x1="21" y1="12" x2="23" y2="12">line>
                            <line x1="4.22" y1="19.78" x2="5.64" y2="18.36">line>
                            <line x1="18.36" y1="5.64" x2="19.78" y2="4.22">line>
                        svg>
                        例子
                    h2>
                    <ul class="flex flex-col gap-3.5 w-full sm:max-w-md m-auto" id="container" v-on:click="getText($event)">
                        <button class="w-full bg-gray-50 dark:bg-white/5 p-3 rounded-md hover:bg-gray-200 dark:hover:bg-gray-900">
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">
                                    帮我写一个云南7日游计划
                                font>font><font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                        button>
                        <button class="w-full bg-gray-50 dark:bg-white/5 p-3 rounded-md hover:bg-gray-200 dark:hover:bg-gray-900">
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">
                                    用简单的术语解释量子计算

                                font>font><font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                        button>
                        <button class="w-full bg-gray-50 dark:bg-white/5 p-3 rounded-md hover:bg-gray-200 dark:hover:bg-gray-900">
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">
                                    我想让你担任职业顾问。您的任务是帮助根据技能、兴趣和经验确定最适合的职业。您还应该对可用的各种选项进行研究,解释不同行业的就业市场趋势,并就哪些资格证书对特定领域有益提出建议。我的第一个请求是“给一份在软件工程领域的职业建议。”
                                font>font><font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                        button>
                        <button class="w-full bg-gray-50 dark:bg-white/5 p-3 rounded-md hover:bg-gray-200 dark:hover:bg-gray-900">
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">Laravel如何引入Illuminate\Http\Requestfont>font>
                            <font style="vertical-align: inherit"><font style="vertical-align: inherit">font>font>
                        button>
                    ul>
                div>
                <div class="flex flex-col mb-8 md:mb-auto gap-3.5 flex-1">
                    <h2 class="flex gap-3 items-center m-auto text-lg font-normal md:flex-col md:gap-2" >
                        <svg
                            stroke="currentColor"
                            fill="none"
                            stroke-width="1.5"
                            viewBox="0 0 24 24"
                            stroke-linecap="round"
                            stroke-linejoin="round"
                            class="h-6 w-6"
                            height="1em"
                            width="1em"
                            xmlns="http://www.w3.org/2000/svg"
                        >
                            <circle cx="12" cy="12" r="5">circle>
                            <line x1="12" y1="1" x2="12" y2="3">line>
                            <line x1="12" y1="21" x2="12" y2="23">line>
                            <line x1="4.22" y1="4.22" x2="5.64" y2="5.64">line>
                            <line x1="18.36" y1="18.36" x2="19.78" y2="19.78">line>
                            <line x1="1" y1="12" x2="3" y2="12">line>
                            <line x1="21" y1="12" x2="23" y2="12">line>
                            <line x1="4.22" y1="19.78" x2="5.64" y2="18.36">line>
                            <line x1="18.36" y1="5.64" x2="19.78" y2="4.22">line>
                        svg>
                        限制
                    h2>
                    <ul class="flex flex-col gap-3.5 w-full sm:max-w-md m-auto" id="container" >
                        <button class="w-full bg-gray-50 dark:bg-white/5 p-3 rounded-md hover:bg-gray-200 dark:hover:bg-gray-900">
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">
                                    可能偶尔会产生不正确的信息。
                                font>font><font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                        button>
                        <button class="w-full bg-gray-50 dark:bg-white/5 p-3 rounded-md hover:bg-gray-200 dark:hover:bg-gray-900">
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">
                                    可能偶尔会产生有害的指令或有偏见的内容。
                                font>font><font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                        button>
                        <button class="w-full bg-gray-50 dark:bg-white/5 p-3 rounded-md hover:bg-gray-200 dark:hover:bg-gray-900">
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">font>font>
                            <font style="vertical-align: inherit">
                                <font style="vertical-align: inherit">对 2021 年后的世界和事件的了解有限。font>font>
                            <font style="vertical-align: inherit"><font style="vertical-align: inherit">font>font>
                        button>
                    ul>
                div>
            div>
        div>

       <div id="randomNum" style="display:none;">div>
       <button class="button-cancel" v-on:click="cancel" id="button-cancel">取消button>


    div>
<style>


        .dot {
            animation: dot-animation 1s infinite;
            opacity: 0;
            animation-delay: 0s, 0.2s, 0.4s;
            animation-fill-mode: both;
            display: inline-block;
        }
        .dot:nth-child(1) {
            animation-delay: 0s;
        }
        .dot:nth-child(2) {
            animation-delay: 0.2s;
        }
        .dot:nth-child(3) {
            animation-delay: 0.4s;
        }

        @keyframes dot-animation {
            0% {
                opacity: 0;
            }
            50% {
                opacity: 1;
            }
            100% {
                opacity: 0;
            }
        }
        .text-2xl{
            display:none;
        }
        .text-2xl.processing{
            display:block;
            margin-bottom: 9px;
        }
        .input-box{
            width: 99%;
            height: 42px;
            font-size: 18px;
            padding: 11px;
            overflow: hidden;
            border-radius: 0.375rem;
            border: 1px solid;
            box-shadow: var(--tw-ring-offset-shadow,0 0 transparent),var(--tw-ring-shadow,0 0 transparent),0 0 10px rgba(0,0,0,.1);
        }
        /*.input-box:focus{
            width: 99%;
            height: 45px;
            font-size: 18px;
            padding: 10px;
        }*/
        .button-c{
            height: 40px;
            border: none;
            position: absolute;
            right: 30px;
            bottom: 0px;
        }

        .b-i-c{

            display: flex;
        }
        .b-i-c1{
            position: relative;
            /*bottom: 0;*/
            width: 100%;
            max-width: 50rem;
            padding-left: 1.5rem;
            padding-right: 1.5rem;
            background-color: #fff;
            top: 0px;
            padding-top: 14px;
        }
        #app{
            max-width: 50rem;
            margin: 0 auto;

        }
        body{
            position: relative;
        }
        .buttonc svg{
            display:none;
        }

        .textgray h1{
            /*display:none !important;*/
            font-size: 25px;
        }

        .container-j {
            /* display: flex;*/

            padding: 10px 15px;
        }

        .container-j img {
            margin-right: 10px;
        }
        .container-j p{
            margin-left: 10px;
        }
        .container-jc{
            background-color: #f1f3f4;
        }

        /*@media screen and (min-width: 789px) and (max-width: 1200px) {*/

        .container-jc{
            /*white-space: pre!important;*/
            overflow: auto;
        }
        .container-jc .rounded-sm{
            float: left;
            width: 34px;
            margin-top: 10px;
            border-radius: 0.125rem;
        }

        .container-jc .texts{
            float: right;
            width: calc(100% - 50px);
        }
        .highlight pre,.aq-text pre{
            white-space: pre-wrap;
            word-wrap: break-word;
        }

        .container-jc svg{
            --tw-text-opacity: 1;
            color: rgba(255,255,255,var(--tw-text-opacity));
        }
    style>
    <style>
        :after,:before{--tw-content:"";}
        h1,h2{font-size:inherit;font-weight:inherit;}
        button{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0;}
        button{text-transform:none;}
        button{-webkit-appearance:button;background-color:transparent;background-image:none;}
        h1,h2{margin:0;}
        ul{list-style:none;margin:0;padding:0;margin-bottom: 65px;    padding-left: 0.1rem;}
        button{cursor:pointer;}
        :disabled{cursor:default;}
        svg{display:block;vertical-align:middle;}
        h1{font-size:1.875rem;line-height:2.25rem;}
        h1,h2{font-weight:600;}
        h2{font-size:1.5rem;line-height:2rem;}
        *,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scroll-snap-strictness:proximity;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 transparent;--tw-ring-shadow:0 0 transparent;--tw-shadow:0 0 transparent;--tw-shadow-colored:0 0 transparent;}
        ::-webkit-scrollbar{height:1rem;width:.5rem;}
        ::-webkit-scrollbar-track{background-color:transparent;border-radius:9999px;}
        ::-webkit-scrollbar-thumb{--tw-border-opacity:1;background-color:rgba(217,217,227,.8);border-color:rgba(255,255,255,var(--tw-border-opacity));border-radius:9999px;border-width:1px;}
        ::-webkit-scrollbar-thumb:hover{--tw-bg-opacity:1;background-color:rgba(236,236,241,var(--tw-bg-opacity));}
        .m-auto{margin:auto;}
        .ml-auto{margin-left:auto;}
        .mr-auto{margin-right:auto;}
        .mb-10{margin-bottom:2.5rem;}
        .mt-6{margin-top:1.5rem;}
        .mb-8{margin-bottom:2rem;}
        .flex{display:flex;}
        .h-6{height:1.5rem;}
        .w-full{width:100%;}
        .w-6{
            width: 30px;
            margin-top: 5px;
            margin-bottom: 5px;
        }
        .flex-1{flex:1 1 0%;}
        .flex-col{flex-direction:column;}
        .items-start{align-items:flex-start;}
        .items-center{align-items:center;}
        .justify-center{justify-content:center;}
        .gap-3{gap:.75rem;}
        .gap-2{gap:.5rem;}
        .gap-3\.5{gap:.875rem;}
        .rounded-md{border-radius:.375rem;}
        .bg-gray-50{--tw-bg-opacity:1;background-color:rgba(247,247,248,var(--tw-bg-opacity));}
        .p-3{padding:.75rem;}
        .px-6{padding-left:1.5rem;padding-right:1.5rem;}
        .text-center{text-align:center;}
        .text-lg{font-size:1.125rem;}
        .text-lg{line-height:1.75rem;}
        .text-4xl{font-size:2.25rem;line-height:2.5rem;}
        .font-semibold{font-weight:600;}
        .font-normal{font-weight:400;}
        .text-gray-800{--tw-text-opacity:1;color:rgba(52,53,65,var(--tw-text-opacity));}
        .hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgba(217,217,227,var(--tw-bg-opacity));}
        @media (min-width:640px){
            .sm\:mb-16{margin-bottom:2rem;}
            .sm\:mt-\[20vh\]{margin-top:10vh;}
            .sm\:max-w-md{max-width:28rem;}
        }
        @media (min-width:768px){
            .md\:mb-auto{margin-bottom:auto;}
            .md\:flex{display:flex;}
            /*.md\:h-full{height:100%;}*/
            .md\:max-w-2xl{max-width:42rem;}
            .md\:flex-col{flex-direction:column;}
            .md\:gap-2{gap:.5rem;}
        }
        @media (min-width:1024px){
            .lg\:max-w-3xl{max-width:48rem;}
        }
        @media (max-width: 767px){
            .custom .des {
                font-size: 16px;
            }

            .container-j {
            padding: 10px 8px;
        }

        .container-jc .texts {
            float: right;
            width: calc(100% - 45px) !important;
            padding: 4px 0px;
        }

        .input-text {
            width: calc(100% - 45px) !important;

        }

        .input-text p{
            /*margin-top: 5px;*/
        }
        .container-j p {
            margin-left: 4px;
        }
        .container-jc .rounded-sm {
            width: 33px;

        }
        .aq-text,.input-text{
            font-size: 16px;
            line-height: 22px;
        }

            .b-i-c1 {
                position: relative;
                /*bottom: 0;*/
                background-color: #fff;
                top: 0px;
                padding-top: 14px;
                width: 100%;
                max-width: 50rem;
                padding-left: 5px;
                padding-right: 5px;
            }
            .w-full {
                width: unset !important;
            }
            .px-6 {
                padding-left: 0.5rem !important;
                padding-right: 0.5rem !important;
            }
            ul {
                list-style: none;
                margin: 0;
                padding: 0;
                margin-bottom: 65px;
                padding-left: 0rem;
            }
            .input-box {
                width: 96%;
            }
            .button-c {
                right: calc(33px + 0%);
            }
            .w-6 {
                width: 3.5rem;
                margin-top: 3px;
            }
            .button-c {
                right: calc(19px + 0%);
                bottom: 3px;
            }
            .input-box {

                padding-right: 22px;
            }
            .button-c svg{
                display: none;
            }
            .button-c {
                right: calc(9px + 0%);
                bottom: 3px;
            }
        }
        @media (min-width: 767px){
            .button-c .fa{
                display: none;
            }
        }
        @media screen and (min-width: 750px) and (max-width: 1199px){

            /* 添加样式 */
            /* 例如: */
            .b-i-c1{
                width: 95%;
                padding-left: 0.5rem;
                padding-right: 0.5rem;
            }
            .px-6 {
                padding-left: 0.3rem;
                padding-right: 1.5rem;
            }

            .button-c {
                right: 30px;
            }

            .px-6 {
                padding-left: 0rem;
                padding-right: 0rem;
            }
            ul {

                padding-left: 0.5rem;
            }

        }

        @media screen and (min-width: 624px) and (max-width: 770px){
            .input-box {
                width: 98%;
            }

        }
        .container-jy .icon {
            display: block;
            vertical-align: middle;
            color: #fff !important;
            border-color: #fff;
            width: 30px !important;
            height: 30px !important;
            padding: 2.5px;
        }
        .b-i-c1.fixed {
            position: fixed;
            top: 0;
            z-index: 1000;
        }

        .button-c .fa{
            background-color: #198de3;
            padding: 3px;
            border-radius: 5px;
            color: #fff;
            font-size: 14px;
        }
        .buttonc .fa{
            display:none;
        }
        #copyid{
            margin-bottom: 10px;
            margin-top: 20px;
        }
        .icopy{
            border: 0.5px solid #a69d9d;
            width: 30px;
            padding: 1px;
            border-radius: 5px;
            color: #8c8585;
            font-size: 13px;
            background-color: #f7f7f8;
            box-shadow: 1px 1px 1px 1px #a3a3af;
        }
    style>
    <style>
:root {
    --white: #fff;
    --black: #303030;
    --gray: #fafafa;
    --primary: #1d93ab;
    --second: #e7f8ff;
    --hover-color: #f3f3f3;
    --bar-color: rgba(0,0,0,.1);
    --theme-color: var(--gray);
    --shadow: 50px 50px 100px 10px rgba(0,0,0,.1);
    --card-shadow: 0px 2px 4px 0px rgba(0,0,0,.05);
    --border-in-light: 1px solid #dedede;
    --window-width: 90vw;
    --window-height: 90vh;
    --sidebar-width: 300px;
    --window-content-width: calc(100% - var(--sidebar-width));
    --message-max-width: 80%;
    --full-height: 100%;
}
input[type="range" i] {
  color: red;
}
input[type="range" i] {
  background-color: red;
}
.input-range_input-range__QBkD1 {
    border: 1px solid #dedede;
    border-radius: 10px;
    padding: 5px 15px 5px 10px;
    font-size: 12px;
    display: flex;
	width: max-content;
	margin: 0 auto;
    margin-top: 6px;
}
.container3{
        text-align: center;
    margin: 0 auto;
    margin-top: 1px;
    /* margin-bottom: 6px; */
    max-width: 460px;
    padding: 10px;
}
input[type="range" i] {
    appearance: auto;
    cursor: default;
    color: -internal-light-dark(rgb(16, 16, 16), rgb(255, 255, 255));
    padding: initial;
    border: initial;
    margin: 2px;
}
#rangeValueFormatted{
    width: 30px;
}
input[type=range] {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: auto;
    background-color: #fff;
    color: #303030;
}
/* 自定义进度条样式 */
.v_my input[type=range] {
  -webkit-appearance: none;/*清除系统默认样式*/

  background: -webkit-linear-gradient(#ddd, #dfe2e3) no-repeat, #ddd;/*设置左边颜色为#61bd12,右边颜色为#ddd*/
  margin-top: 5px;
  height: 5px;/*横条的高度*/
  outline: none;
}
/*拖动块的样式*/
.v_my input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;/*清除系统默认样式*/
  height: 15px;/*拖动块高度*/
  width: 10px;/*拖动块宽度*/
  background: #80b3d8;/*拖动块背景*/
  border-radius: 5px; /*外观设置为圆形*/

  }

.container2 .item:hover {
    background-color: #609cc8 !important;
}

.button-c .fa:hover {
    background-color: #0d6aad;
}
.t-t{
    margin-left: 5px;
    line-height: 14px;
}
.code-example,.aq-text pre{
    background-color: #282a36;
    color: #eaeaea;
    padding: 10px;
    border-radius: 5px;
    padding-bottom: 20px;
    padding-top: 20px;
    font-size: 14px;
}
style>
<style>



      .VIPTISI span {
        /* //   内联元素(inline)动画不起作用, 因此要设置为‘inline-block’ */
        display: inline-block;
        animation: jump 500ms ease-in-out;
        animation-delay: var(--delay);
      }

      @keyframes jump {
        0%,
        100% {
          transform: translateY(0);
        }
        50% {
          transform: translateY(-10px);
        }
      }
    style>   
   <style>
        .dio-m{

                width: max-content;
                margin: 0 auto;
                margin-bottom: 10px;

        }
        .container2 {
            display: flex;
            flex-direction: row;
            justify-content: space-between;
            align-items: center;
            width: 45%;
            height: 50px;
            background-color: #fff;
            padding: 4px;
            border: 1px solid;
            border-radius: 5px;
            margin: 0 auto;
        }

        .container2 .item {
            flex: 1;
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: #fff;
            /* border: 1px solid #ccc; */
            cursor: pointer;
            border-radius: 5px;
        }

        .container2 .item.active {
            background-color: #80b3d8;
        }
        @media (max-width: 767px){
        .container2 {

            width: 85%;
            max-width: 300px;

        }
        }

        .aq-text{
            padding-top: 6px;

        }
    style>

    <script>

        function toggleActive(item) {
            var lis = document.querySelectorAll(".container2 .item");

            // 遍历所有 li 元素
            for (var i = 0; i < lis.length; i++) {
                if(lis[i].classList.contains("active")){
                    lis[i].classList.remove('active');
                }
            }
            item.classList.add('active');
            // activeItem = item;
        }


    script>
    <script>
    
    const userAgent = navigator.userAgent;
    const plugins = navigator.plugins;
    const screenWidth = window.screen.width;
    const screenHeight = window.screen.height;
    const language = navigator.language;
    const platform = navigator.platform;
    const languages = navigator.languages;
    let pluginString = "";
    for (let i = 0; i < navigator.plugins.length; i++) {
      pluginString += navigator.plugins[i].name + ", ";
    }
    pluginString = pluginString.slice(0, -2); // 移除最后一个逗号和空格
    const fingerprint = `${userAgent}${pluginString}${screenWidth}${screenHeight}${language}${platform}${languages}`;
    //console.log(pluginString);
        // 获取容器元素和输入元素
        const container = document.getElementById("container");
        const input = document.getElementById("input-box");
        input.value = ''
        // 为容器元素中的所有项添加一个点击事件监听器

        var timestamp = new Date().getTime();
        var randomNum = Math.floor(Math.random() * timestamp);
        document.getElementById("randomNum").innerText = randomNum

        var app = new Vue({
            el: '#app',
            data: {
                name: 'Vue.js',
                message1: '',
                myArray: [],
                assistant: [],
                cancelToken: null,
                rangeValue: 1000
            },

            // 在 `methods` 对象中定义方法
            methods: {
                greet: function (event) {
                    const self = this; // 将Vue实例保存到变量self中
                    // 获取输入框元素
                    const inputBox = document.getElementById("text-box");
                    inputBox.classList.add("processing");

                    const buttonc = document.getElementById("button-c");
                    if (buttonc.classList.contains("buttonc")) {
                       // 如果包含
                       console.log("该元素包含'buttonc'类名");
                       return;
                    }



                    const buttoncancel = document.getElementById("button-cancel");
                    buttoncancel.classList.add("sh");
                    buttonc.classList.add("buttonc");

                    //获取提交内容
                    const input = document.getElementById("input-box");
                    if(input.value.trim().length <1){
                        alert('请输入内容');
                        inputBox.classList.remove("processing");
                        buttonc.classList.remove("buttonc");

                        buttoncancel.classList.remove("sh");
                        return;
                    }
                    data1 = {'text':input.value}

                    // 创建 cancelToken
                    this.cancelToken = axios.CancelToken.source();


                    async function fetchData() {
					    //用浏览器指纹验证用户点击次数 
                        const fp = await Fingerprint2.getPromise();
                        const values = fp.map(item => item.value);
                        const result = values.join('');
                        // console.log(fp);
                        const hash = CryptoJS.MD5(result).toString();
                        data1.hash =hash;
						//用浏览器指纹验证用户点击次数
                        //const response = await axios.post('/mingang', data1);
                        //const data = response.data;
                        
                        //return data;
						return data ={HitFlag:0};
                    }

                    fetchData().then((data) => {
                        
                        if(data.HitFlag==1){
                                                        
                            inputBox.classList.remove("processing");
                            buttonc.classList.remove("buttonc");
                            const buttoncancel = document.getElementById("button-cancel");
                            buttoncancel.classList.remove("sh");
                            return;
                            
                        }else{
                            
                            const temperatures = document.querySelector(".container2 .item.active");
                            const tokens = document.querySelector(".container3 #rangeInput");

                            axios.defaults.timeout = 6000;
                            
                            let randomNum1 = document.getElementById("randomNum").innerText
                            data = {'randomNum':randomNum1,'text':input.value,'myArray':this.myArray,'assistant':this.assistant,'temperatures':temperatures.innerText,'tokens':tokens.value}
                            //建议用反向代理将这个请求url指向最终请求
							//比如nginx中在配置文件中加入如下设置
							
							//location /chat {

							//	  proxy_pass 上面Python代码访问的ip:端口/chat;
							  
							//	  proxy_set_header Host $host;
							  
							//	  proxy_set_header X-Real-IP $proxy_add_x_forwarded_for;
								  
							//	  proxy_connect_timeout 600s;
							//	  proxy_send_timeout 600s;
							//	  proxy_read_timeout 600s;
							//	  proxy_buffering off;
							//	  proxy_cache off;
							  
							//	}
							
                            fetch('/chat', {
                                method: 'POST',
                                headers: {
                                    'Content-Type': 'application/json'
                                },
                                body: JSON.stringify(data)
                            }).then(response => {
							    //采用流式输出 可以用gpt解释代码意思
                                const reader = response.body.getReader();

                                return new ReadableStream({
                                    start(controller) {
                                        function push() {
                                            reader.read().then(({ done, value }) => {
                                                if (done) {
                                                    controller.close();
                                                    return;
                                                }

                                                controller.enqueue(value);
                                                push();
                                            });
                                        }

                                        push();
                                    }
                                });
                            }).then(stream => new Response(stream))
                                .then(response => {
                                    const reader = response.body.getReader();
                                    const decoder = new TextDecoder('utf-8');
                                    let buffer = '';
                                    let  text = '';
                                    function push() {

                                        reader.read().then(({ done, value }) => {
                                            if (done) {
                                                let list = document.getElementById('myList');
                                                let lastItems = list.lastChild;
                                                let textDivs = lastItems.querySelector('.aq-text');
                                                Vue.set(self.myArray, self.myArray.length, input.value);
                                                Vue.set(self.assistant, self.assistant.length, textDivs.innerText);
                                                input.value = '';
                                                autoResize();
                                                inputBox.classList.remove("processing");
                                                buttonc.classList.remove("buttonc");
                                                const buttoncancel = document.getElementById("button-cancel");
                                                buttoncancel.classList.remove("sh");

                                                const li_index = Array.from(list.children).indexOf(lastItems);
                                                // var li1 = lastItems;
                                                var liHtml = lastItems.innerHTML;
                                                var randomNum = document.getElementById("randomNum").innerText;
                                                var title = lastItems.getElementsByClassName("input-text")[0].innerText;
                                                //savehtml(liHtml,title,li_index,randomNum);
                                                return;
                                            }

                                            buffer += decoder.decode(value, { stream: true });

                                            const parts = buffer.split('\n##');

                                            parts.forEach(part => {
                                                if (part) {
                                                    const data = JSON.parse(part);
                                                    
                                                    if(data.error){
                                                        alert(data.error);
                                                        inputBox.classList.remove("processing");
                                                        buttonc.classList.remove("buttonc");
                                                        const buttoncancel = document.getElementById("button-cancel");
                                                        buttoncancel.classList.remove("sh");
                                                        return;
                                                    }

                                                    if(data[0]=='maximum'){
                                                        let lun_num = self.myArray.length;

                                                        // Vue.set(this.assistant, this.assistant.length, data['choices'][0]['assistant']);
                                                        if(lun_num){
                                                            if(lun_num>1){
                                                                const lastElement = self.myArray[self.myArray.length - 1];
                                                                const lastElementa = self.assistant[self.assistant.length - 1];
                                                                // 清空数组并添加最后一个元素
                                                                self.myArray.splice(0, self.myArray.length, lastElement);
                                                                self.assistant.splice(0, self.assistant.length, lastElementa);

                                                                alert('对话内容过多,偶尔会有这种情况,这一次回答只考虑上一次会话内')
                                                                // return;
                                                            }else{
                                                                alert('对话内容超过长度限制,这一次回答不再考虑之前的内容');
                                                                Vue.set(self, 'myArray', []);
                                                                Vue.set(self, 'assistant', []);
                                                                // return;
                                                            }

                                                        }else{
                                                            alert('输入内容过多,删除部分再试');
                                                            Vue.set(self, 'myArray', []);
                                                            Vue.set(self, 'assistant', []);
                                                            // return;
                                                        }

                                                        inputBox.classList.remove("processing");
                                                        buttonc.classList.remove("buttonc");
                                                        const buttoncancel = document.getElementById("button-cancel");
                                                        buttoncancel.classList.remove("sh");
                                                        return;


                                                    }

                                                    if(data['delta']['role']){
                                                        const newItem = document.createElement('li');
                                                        const list = self.$refs.myList;
                                                        // let list = document.getElementById('myList');


                                                        newItem.textContent = 'Item ' + (list.children.length + 1);
                                                        newItem.innerHTML = '
'+ '
'+ '
'+ ''+ '
'
+ '
'+escapeHtml(input.value)+'
'
+ '
'
+ '
'+ '
'+ ''+ '
'
+ '
'+ '
'+ '
'+ '
复制
'
+ '
'
+ '
'
; '
'
; if(input.value.length>100){ input.value =''; autoResize(); } // 添加点击事件到动态元素上 newItem.addEventListener('click', function(event) { console.log(event.target) if (event.target.className.toLowerCase() === 'icopy') { console.log('按钮被点击了!'); // 在这里编写按钮被点击时的逻辑 const parentText = event.target.parentNode.previousSibling.innerText; console.log(event.target.parentNode.parentNode.innerText) const tempTextarea = document.createElement("textarea"); tempTextarea.value = parentText; document.body.appendChild(tempTextarea); tempTextarea.select(); document.execCommand("copy"); document.body.removeChild(tempTextarea); } }); list.appendChild(newItem); }else { let list = document.getElementById('myList'); const lastItem = list.lastChild; const textDiv = lastItem.querySelector('.aq-text'); if(textDiv.innerText=='复制'){ // textDiv.innerText=''; } if(data['delta']['content']){ const oldText = textDiv.getAttribute('data-text') || ''; const newText = oldText + data['delta']['content']; textDiv.innerText = newText; var nextSibling = textDiv.nextElementSibling; if (nextSibling) { var elementRect = nextSibling.getBoundingClientRect(); var windowHeight = window.innerHeight; var elementTop = elementRect.top; var elementBottom = elementRect.bottom; // Check if the element is within the visible window height var isVisible = (elementTop < windowHeight-20) && (elementBottom >= 0); // 如果不在视窗内,则滑动到视窗内 var newPosition = nextSibling.getBoundingClientRect().top + window.scrollY - 150; if (!isVisible&&oldText=='') { // 将页面滑动到新元素处 window.scrollTo({ top: newPosition, behavior: 'smooth' }); } } textDiv.setAttribute('data-text', newText); } if(data['finish_reason']=="stop"||data['finish_reason']=="length"){ const oldText = textDiv.getAttribute('data-text') || ''; var finish_reason = textDiv.getAttribute('data-finish') || ''; if (oldText.includes('```')&&finish_reason!='length') { const html = marked(oldText); textDiv.innerText = ''; textDiv.innerHTML = html; } } //中断的处理不好html代码用text显示 if(data['finish_reason']=="stop"){ textDiv.setAttribute('data-finish', "stop"); } if(data['finish_reason']=="length"){ textDiv.setAttribute('data-finish', "length"); } } } }); buffer = parts[parts.length - 1]; push(); }); } push(); }); // `event` 是原生 DOM 事件 if (event) { //alert(event.target.tagName) } } }).catch((error) => { console.log(error); inputBox.classList.remove("processing"); buttonc.classList.remove("buttonc"); const buttoncancel = document.getElementById("button-cancel"); buttoncancel.classList.remove("sh"); alert(error.message+',稍后重试') }); }, // 添加一个 `cancel` 方法 cancel: function() { if (this.cancelToken) { const inputBox = document.getElementById("text-box"); const buttonc = document.getElementById("button-c"); const buttoncancel = document.getElementById("button-cancel"); inputBox.classList.remove("processing"); buttonc.classList.remove("buttonc"); buttoncancel.classList.remove("sh"); this.cancelToken.cancel('请求已取消'); } }, getText(event) { this.text = event.target.textContent //alert(this.text); const input = document.getElementById("input-box"); text =this.text.trim() //text =text.trim('→') text = text.replace(//g, ""); text = text.replace(//g, ""); text = text.replace(//g, ""); text = text.trim() input.value = text; $("#input-box").focus(); autoResize(); } }, computed: { formattedRangeValue() { return this.rangeValue.toString(); } }, watch: { rangeValue() { document.getElementById("rangeValueFormatted").innerText = this.formattedRangeValue; } } }) // 也可以用 JavaScript 直接调用方法 //app.greet() // -> 'Hello Vue.js!' function escapeHtml(html) { return html.replace(/</g, '<').replace(/>/g, '>'); } function autoResize() { const textarea = document.getElementById("input-box"); textarea.style.height = "auto"; textarea.style.height = (textarea.scrollHeight) + "px"; function isElementBelowViewport(el) { var rect = el.getBoundingClientRect(); return rect.bottom > window.innerHeight; } if (isElementBelowViewport(textarea)) { document.querySelector('.b-i-c1').style.position = "fixed"; document.querySelector('.b-i-c1').style.bottom = "0"; document.querySelector('.b-i-c1').style.top = "unset"; console.log('Element is below the viewport!'); } } script> <script> var fixedDiv = document.querySelector('.b-i-c1'); // 获取该div距离文档顶部的距离 var offsetTop = fixedDiv.offsetTop; // 监听窗口的滚动事件 window.addEventListener('scroll', function() { // 获取当前滚动的位置 var scrollTop = window.pageYOffset || document.documentElement.scrollTop; // 判断是否需要固定 if (scrollTop >= offsetTop) { fixedDiv.classList.add('fixed'); } else { fixedDiv.classList.remove('fixed'); } }); script> <style> .b-i-c1{ position: fixed; bottom: 1px; width: 100%; max-width: 50rem; padding-left: 1.5rem; padding-right: 1.5rem; background-color: #fff; top: unset !important; padding-top: 14px; } @media (max-width: 767px) { .b-i-c1 { position: fixed; bottom: 1px; background-color: #fff; /*top: 0px;*/ padding-top: 14px; width: 100%; max-width: 50rem; padding-left: 5px; padding-right: 5px; } } .b-i-c1.fixed { position: fixed; bottom: 1px; top: unset; z-index: 1000; } .nav.fixed{ width: 100%; top: 0; } #footer{ margin-bottom: 50px; } .b-i-c1 { background-color: unset; z-index: 10; } style> <style> #button-cancel{ background-color: #198de3; color: #fff; padding: 2px 2px; border-radius: 5px; margin: 0 auto; position: fixed; bottom: 55px; display: none; width: max-content; /* margin-left: calc(50% - 108px); */ left: 0; right: 0; } #button-cancel.sh{ display: block; } #button-c svg { display: none; } .button-c .fa { display: block; } .button-c.buttonc .fa { display: none; } #app textarea { padding-right: 32px; } style> body> @endsection

你可能感兴趣的:(chatgpt,chatgpt,flask)