无需搭建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'+ ''+ ''+ ''; ''+ ''+ ''+ ''+ '复制' + '