无需搭建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