1 Star 0 Fork 15

谷先生/chatgpt聊天前端源代码

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
index.html 134.42 KB
一键复制 编辑 原始数据 按行查看 历史
hoppinzq 提交于 2023-04-17 12:35 . update index.html.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="HOPPINZQ的ChatGPT">
<title>聊天</title>
<link rel="shortcut icon" type="image/x-icon" href="https://hoppinzq.com/zui/static/favicon/favicon.ico">
<link rel="stylesheet" href="https://hoppinzq.com/chat/static/css/material-design-iconic-font.min.css">
<link rel="stylesheet" href="https://hoppinzq.com/chat/static/css/style.min.css">
<link rel="stylesheet" href="https://hoppinzq.com/static/css/plugins/editormd.min.css"/>
<link rel="stylesheet" href="https://hoppinzq.com/zq/preloader/zq_preloader.css">
<link rel="stylesheet" href="https://hoppinzq.com/zui/static/css/sweetalert.css">
<link rel="stylesheet" href="https://hoppinzq.com/spider/css/simple-bar.css">
<link rel="stylesheet" href="https://hoppinzq.com/chat/static/css/jBox.all.min.css">
<link rel="stylesheet" type="text/css" href="https://hoppinzq.com/chat/static/css/built-editor.css"/>
</head>
<style>
a{
color: var(--primary-color);
}
a:hover{
color: var(--dark-color);
}
.modal-right.show .modal-dialog {
transform: translate(0, 0) !important;
}
.modal.show .modal-dialog {
transform: none;
}
.modal.fade .modal-dialog {
transition: transform 0.3s ease-out;
transform: translate(0, -50px);
}
.modal-right .modal-dialog {
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 360px;
max-width: 100%;
margin: 0;
transform: translate(100%, 0) !important;
transition: .5s;
}
.modal-right .modal-content {
height: 100%;
display: -webkit-box;
display: flex;
flex-direction: column;
border-radius: 0;
}
.text-chat {
white-space: pre-wrap;
/*white-space: normal;*/
}
.code-box {
margin-top: 5px;
margin-bottom: 5px;
padding: 5px;
background: #fff;
border-radius: 6px;
color: #444;
line-height: 1.5;
max-height: 350px;
position: relative;
height: auto;
background-color: #fff;
border: solid 1px #f5f5f5;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.075);
}
.code-box code {
color: #555;
}
.code-box textarea {
padding: 0;
resize: none;
width: 100%;
}
.copy-btn {
position: absolute;
top: 22px;
right: 12px;
border: 1px solid #eee;
background: rgba(154, 154, 255, 0.1);
border-radius: 5px;
font-size: 12px;
padding: 7px 16px;
transition: all 0.4s ease;
font-family: 'Inter', sans-serif;
}
.copy-btn:focus-within,
.copy-btn:hover {
background: #61b864;
border-color: transparent;
color: #fff;
}
.center-modal {
transform: scale(0);
transition: .4s
}
.center-modal.show {
transform: scale(1)
}
.center-modal .modal-dialog {
margin: 0;
width: 100%;
position: absolute;
bottom: 50%;
left: 50%;
transform: translate(-50%, 50%) !important
}
.modal-fill {
background: rgba(255, 255, 255, 0.97);
transform: scale(0, 0);
transition: .4s
}
.modal.modal-fill {
background: var(--card-color);
}
.modal-fill.show {
display: flex!important;
justify-content: center;
flex-flow: column nowrap;
transform: scale(1,1);
transition: .4s;
}
/*增补样式,代码样式,夜间模式样式*/
.modal-body{
background: var(--card-color);
}
.modal-header{
background: var(--card-color);
/*border-bottom: var(--border-color);*/
}
.qaq{
background: var(--card-color);
}
.hljs {
display: block;
overflow-x: auto;
padding: .5em;
background: #1e1e1e !important;
color: #dcdcdc;
}
.editormd-html-preview pre.prettyprint, .editormd-preview-container pre.prettyprint {
border: 1px solid var(--border-color);
}
.editormd-html-preview pre, .editormd-preview-container pre {
border: 1px solid #ddd;
background: var(--card-color);
}
li.L1, li.L3, li.L5, li.L7, li.L9 {
background: var(--card-color);
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
.kwd{
color: #569cd6;
}
.tag{
color: #9b9b9b;
}
.typ,.atn{
color: #569cd6;
}
.clo, .opn, .pun{
color: var(--dark-color);
}
.str{
color: #d69d85;
}
.pln{
color: #666666;
}
.com{
color: #57a64a;
font-style: italic;
}
.hljs li.L1,.hljs li.L3,.hljs li.L5,.hljs li.L7,.hljs li.L9 {
background: #212121;
}
.hljs .kwd{
color: #569cd6;
}
.hljs .tag{
color: #9b9b9b;
}
.hljs .typ,.hljs .atn{
color: #569cd6;
}
.hljs .clo, .hljs .opn, .hljs .pun{
color: #dcdcdc;
}
.hljs .str{
color: #d69d85;
}
.hljs .pln{
color: #dcdcdc;
}
.hljs .com{
color: #57a64a;
font-style: italic;
}
.code_change {
left: 5px;
top: 5px;
display: block;
width: 90px;
height: 28px;
color: var(--font-555);
border: 1px solid var(--dark-color);;
background: rgba(154, 154, 255, 0.1);
padding: 2px 8px;
border-radius: 4px;
cursor: pointer;
transition: all 0.4s ease;
font-family: 'Inter', sans-serif;
}
.copy-code-btn {
float: right;
right: 5px;
top: 5px;
display: block;
width: 90px;
height: 28px;
border: 1px solid var(--dark-color);;
color: var(--font-555);
background: rgba(154, 154, 255, 0.1);
padding: 2px 8px;
border-radius: 4px;
cursor: pointer;
transition: all 0.4s ease;
font-family: 'Inter', sans-serif;
}
.hljs .code_change{
color: #eee;
}
.hljs .copy-code-btn{
color: #eee;
}
</style>
<body>
<div class="zq_preloader zq_preloader_center">
<span>H</span><span>O</span><span>P</span><span>P</span><span>I</span><span>N</span><span>Z</span><span>Q</span>
</div>
<div id="layout" class="theme-cyan">
<div class="navigation navbar justify-content-center py-xl-4 py-md-3 py-0 px-3">
<div class="nav flex-md-column nav-pills flex-grow-1" role="tablist" aria-orientation="vertical">
<a class="mb-xl-3 mb-md-2 nav-link" data-toggle="pill" href="#nav-tab-user" role="tab">
<img src="https://hoppinzq.com/zui/static/picture/0.jpg" class="avatar sm rounded-circle"
alt="user avatar"></a>
<a class="mb-xl-3 mb-md-2 nav-link active" data-toggle="pill" href="#nav-tab-chat" role="tab"><i
class="zmdi zmdi-comment-alt"></i></a>
<a class="mb-xl-3 mb-md-2 nav-link d-sm-block image-nav" data-toggle="modal" href="#modal-image">
<i class="zmdi zmdi-image-o"></i>
</a>
<a class="mb-xl-3 mb-md-2 nav-link d-none d-sm-block flex-grow-1" data-toggle="modal" href="#modal-code"
role="tab"> <i class="zmdi zmdi-code"></i>
</a>
<a class="mt-xl-3 mt-md-2 nav-link text-center "
data-toggle="modal" href="#modal-log" ><i class="zmdi zmdi-blogger"></i></a>
<a class="mt-xl-3 mt-md-2 nav-link text-center " target="_blank"
href="https://gitee.com/hoppin/chatgpt-front"><i
class="zmdi zmdi-github"></i></a>
<a class="mt-xl-3 mt-md-2 nav-link light-dark-toggle" href="javascript:void(0);">
<i class="zmdi zmdi-brightness-2"></i>
<input class="light-dark-btn" type="checkbox"></a>
<a class="mt-xl-3 mt-md-2 nav-link rightbar-link" id="settings" href="#modal-settings" data-toggle="modal"
data-target="#modal-settings">
<i class="zmdi zmdi-settings"></i>
</a>
</div>
<button type="submit" class="btn sidebar-toggle-btn shadow-sm"><i class="zmdi zmdi-menu"></i></button>
</div>
<div class="sidebar border-end py-xl-4 py-3 px-xl-4 px-3">
<div class="tab-content">
<div class="tab-pane fade" id="nav-tab-user" role="tabpanel">
<div class="d-flex justify-content-between align-items-center mb-4"><h3 class="mb-0 text-primary">
个人信息</h3>
<div><a href="http://150.158.28.40:8804/login.html" title="" class="btn btn-dark">登入</a></div>
</div>
<div class="card border-0 text-center pt-3 mb-4">
<div class="card-body">
<div class="card-user-avatar">
<img src="http://hoppinzq.com/zui/static/picture/0.jpg" alt="avatar">
</div>
<div class="card-user-detail mt-4"><h6 id="user_id"></h6><span class="text-muted"></span>
<p>微信:HOPPIN_HAZZ</p>
</div>
<div class="text-center border-top">
<button type="button" class="btn btn-success" data-toggle="modal"
data-target="#modal-settings">更新token
</button>
<button class="btn btn-success" type="button" data-toggle="modal"
data-target="#modal-chatContent">
上下文设置
</button>
</div>
</div>
</div>
<div class="d-flex justify-content-between align-items-center mb-4"><h3 class="mb-0 text-primary">
全局设置</h3>
<div><a href="#" title="" class="btn btn-dark default-settings">使用默认设置</a></div>
</div>
<div class="card border-0">
<ul class="list-group custom list-group-flush">
<li class="list-group-item d-flex justify-content-between align-items-center">
<span>始终使用本地缓存</span><label
class="c_checkbox"><input id="iall-cache" class="cache-m" data-cache="locache"
type="checkbox" checked=""><span
class="checkmark"></span></label></li>
<li class="list-group-item d-flex justify-content-between align-items-center"
data-toggle="tooltip"
data-original-title="在bot对话期间,始终选择对话滚动会始终将滚动条拉到最底下,期间不能向上滚动。若影响体验,请禁止。">
<span>始终跟随对话滚动</span><label
class="c_checkbox"><input id="iall-scoll" class="cache-m" data-cache="isscoll"
type="checkbox" checked=""><span
class="checkmark"></span></label></li>
<li class="list-group-item d-flex justify-content-between align-items-center"
data-toggle="tooltip" data-original-title="chatBot会预先生成两条带有提示性的对话">
<span>新建聊天时始终给出提示对话</span><label
class="c_checkbox"><input type="checkbox" id="iall-help" class="cache-m"
data-cache="ishelp" checked=""><span class="checkmark"></span></label>
</li>
<li class="list-group-item border-0 mt-2"><a class="link" href="#"><i
class="zmdi zmdi-chevron-right me-2"></i>日间/夜间模式在右下角开启</a>
</li>
</ul>
</div>
</div>
<div class="tab-pane fade show active" id="nav-tab-chat" role="tabpanel">
<div class="d-flex justify-content-between align-items-center mb-4">
<h3 class="mb-0 text-primary">ChatGPT对话</h3>
<div>
<button class="btn btn-dark create-new-chat" type="button">新建对话</button>
</div>
</div>
<div class="form-group input-group-lg search mb-3">
<i class="zmdi zmdi-search"></i>
<i class="zmdi zmdi-dialpad"></i>
<input type="text" class="form-control chat-search" placeholder="搜索...">
</div>
<ul class="chat-list">
<li class="header chat-all-header d-flex justify-content-between ps-3 pe-3 mb-1">
<span>最近聊天记录</span>
<div class="dropdown">
<a class="btn btn-link px-1 py-0 border-0 text-muted dropdown-toggle" href="#" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i
class="zmdi zmdi-filter-list"></i></a>
<div class="dropdown-menu dropdown-menu-right">
<a class="dropdown-item" href="#">导入</a>
<a class="dropdown-item" href="#">全部清理</a>
</div>
</div>
</li>
</ul>
</div>
<div class="tab-pane fade" id="nav-tab-pages" role="tabpanel">
<div class="d-flex justify-content-between align-items-center mb-4">
<h3 class="mb-0 text-primary">聊天</h3>
</div>
<div class="d-flex justify-content-between align-items-center mb-4">
<div class="text-truncate">这是别人公开或者分享的聊天。</div>
</div>
<div class="card border-0">
<ul class="list-group list-group-flush chat-public">
<!-- <li class="list-group-item border-0">-->
<!-- <a class="link" href="#"><i class="zmdi zmdi-label-alt me-2"></i> 你好啊</a>-->
<!-- </li>-->
</ul>
</div>
</div>
</div>
</div>
<div class="main px-xl-5 px-lg-4 px-3">
<div class="chat-body">
<div class="chat-header border-bottom py-xl-4 py-md-3 py-2">
<div class="container-xxl">
<div class="row align-items-center">
<div class="col-6 col-xl-4">
<div class="media">
<div class="avatar me-3 show-user-detail" data-toggle="tooltip" title=""
data-original-title="ChatGPT Bot">
<div class="avatar rounded-circle no-image bg-primary text-light">
<span><i class="zmdi zmdi-comment-text"></i></span>
</div>
</div>
<div class="media-body overflow-hidden">
<div class="d-flex align-items-center mb-1">
<h6 class="text-truncate mb-0 me-auto">ChatGPT Bot</h6>
</div>
<div class="text-truncate">基于gpt-3.5-turbo模型</div>
</div>
</div>
</div>
<div class="col-6 col-xl-8 text-end">
<ul class="nav justify-content-end">
<li class="nav-item list-inline-item d-none d-md-block me-3">
<a href="#" class="nav-link text-muted px-3" data-toggle="collapse"
data-target="#chat-search-div" aria-expanded="true" title="Search this chat">
<i class="zmdi zmdi-search zmdi-hc-lg"></i>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="collapse" id="chat-search-div">
<div class="container-xxl py-2">
<div class="input-group">
<input type="text" class="form-control chat-message-search" placeholder="搜索当前聊天内容">
<div class="input-group-append">
<span class="input-group-text text-muted">0 / 0</span>
</div>
<div class="input-group-append">
<button type="button" class="btn btn-success chat-message-search-btn">搜索</button>
</div>
</div>
</div>
</div>
<div class="chat-content" id="chat-content">
<div class="container-xxl">
<ul class="list-unstyled py-4 chat-message">
</ul>
</div>
</div>
<div class="chat-footer border-top py-xl-4 py-lg-2 py-2">
<div class="container-xxl">
<div class="row">
<div class="col-12">
<div class="input-group align-items-center"><input type="text"
class="form-control border-0 pl-0"
id="sendText"
placeholder="输入内容...">
<div class="input-group-append d-none d-sm-block"><span
class="input-group-text border-0"><button class="btn btn-sm btn-link text-muted"
data-toggle="tooltip" title="重新提问"
type="button"><i
class="zmdi zmdi-refresh font-22"></i></button></span></div>
<div class="input-group-append">
<span class="input-group-text border-0 pr-0">
<button type="btn" id="sendChat" class="btn btn-primary"><span
class="d-none d-md-inline-block me-2">发送</span><i
class="zmdi zmdi-mail-send"></i></button>
<button type="btn" id="stopChat" style="display: none"
class="btn btn-primary"><span
class="d-none d-md-inline-block me-2">结束</span><i
class="zmdi zmdi-stop"></i></button>
</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal center-modal fade" id="modal-chatContent" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"><h5 class="modal-title">上下文设置</h5>
</div>
<div class="modal-body">
<div class="form-group">演示期间总是允许携带上下文</div>
<small class="form-text text-muted">由于gpt-3.5-turbo有token的限制,所以我将只携带3个上下文。</small>
<div class="mt-5">
<button type="button" class="btn btn-link" data-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal modal-right fade" id="modal-settings" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body modal-settings-body">
<div class="main-body">
<div class="body-header border-bottom py-xl-3 py-2">
<div class="container px-0">
<div class="row align-items-center">
<div class="col-12">
<div class="media">
<div class="avatar sm"><a href="#" data-dismiss="modal" title=""
class="link"><i
class="zmdi zmdi-arrow-left zmdi-hc-lg"></i></a></div>
<div class="media-body overflow-hidden">
<div class="d-flex align-items-center mb-1"><h6
class="fw-bold text-truncate mb-0 me-auto">设置</h6></div>
<div class="text-truncate">仅供专业人士使用</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="body-page d-flex py-xl-3 py-2">
<div class="container px-0">
<div class="row">
<div class="col-12">
<ul class="nav nav-tabs nav-overflow page-header-tabs mb-4 mt-md-5 mt-3">
<li class="nav-item"><a class="nav-link active" data-toggle="tab"
href="#setting-general" role="tab">账号相关</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="tab"
href="#setting-billing" role="tab">费用</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="tab"
href="#setting-apiKeys" role="tab">ApiKeys</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="tab"
href="#setting-org" role="tab">组织</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="tab" id="faqs"
href="#setting-faqs" role="tab">FAQs</a></li>
</ul>
</div>
</div>
<div class="tab-content">
<div class="tab-pane fade show active" id="setting-general" role="tabpanel">
<div class="row">
<div class="col-12">
<div class="card mb-4">
<div class="card-header"><h6 class="card-title mb-0">Auth Access
Token</h6>
<span class="text-muted small" style="cursor: help">由于几个月前Openai更新了他们的校验机制,这使得我无法通过用户名密码来登录到openai官网,因此
需要你在<a href="https://chat.openai.com/" target="_blank">openai官网登录</a>然后获取localStorage中的Auth AccessToken和refreshToken,该AccessToken和的有效期为14天</span>
<br>
<span class="text-muted small">该AccessToken是标志用户登录的一串字符串,为JWT格式,用户名在载荷部分。因为我无法获知签名的内容,所以无法伪造和篡改用户登录,需要你去获取,然后我使用该token登录。
来获取重要的sessionToken,使用该Token可以管理您的ApiKey和查询计费
</span>
</div>
<div class="card-body token-card">
<div class="row g-3">
<div class="col-12">
<pre data-simplebar="" class="code-box">
<button class="copy-btn">复制</button><code
id="access-token"
style="margin-left: -450px;"></code>
</pre>
</div>
<div class="col-auto">
<button class="btn btn-success"
onclick="checkToken(true)">解析
</button>
<button class="btn btn-danger" onclick="deleteToken()">
删除
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row justify-content-between mt-4">
<div class="col-12 col-md-6"><h5>管理您的AccessToken</h5>
<p class="text-muted mb-md-0">
删除AccessToken不影响聊天的使用,会影响某些查询计费和ApiKey的管理</p></div>
<div class="col-12">
<div class="form-group">
<div class="input-group">
<textarea rows="4" class="form-control access-token"
placeholder="输入openai登录后的accessToken"></textarea>
</div>
</div>
</div>
<div class="col-12" style="margin-top: 8px">
<button type="button" class="btn btn-primary"
onclick="updateAccessToken()">新增/更新accessToken
</button>
<button type="button" class="btn btn-link"
onclick="$('.access-token').val('')">清空
</button>
</div>
</div>
</div>
<div class="tab-pane fade" id="setting-billing" role="tabpanel">
<div class="row">
<div class="col-12">
<div class="alert alert-danger"><i class="zmdi zmdi-info me-1"></i>你的AccessToken已过期或者失效,将展示上一次数据。请及时更新token,请求的api请查看后台代码。
</div>
</div>
<div class="col-12 col-md-6">
<div class="card mb-4">
<div class="card-body">
<div class="row align-items-center">
<div class="col"><h6
class="text-uppercase text-muted mb-1 small">
总额度/剩余额度</h6><span class="h3 mb-0" id="billing"></span>
</div>
<div class="col-auto"><a class="btn btn-sm btn-dark"
href="javascript:;">刷新数据</a>
</div>
</div>
</div>
</div>
</div>
<div class="col-12">
<div class="card">
<div class="card-body"><h6 class="card-title mb-0">所有额度分别的计费</h6>
</div>
<div class="table-responsive">
<table class="table table-border table-hover table-nowrap card-table mb-0">
<thead>
<tr>
<th>id</th>
<th>额度</th>
<th>已使用</th>
<th>生效日期</th>
<th>失效日期</th>
</tr>
</thead>
<tbody class="font-size-base account-billing">
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="setting-apiKeys" role="tabpanel">
<div class="row">
<div class="col-12">
<div class="alert alert-danger"><i class="zmdi zmdi-info me-1"></i>你的AccessToken已过期或者失效,将展示上一次数据。请及时更新token,请求的api请查看后台代码。
</div>
</div>
<div class="col-12 col-md-6">
<div class="card mb-4">
<div class="card-body">
<div class="row align-items-center">
<div class="col"><p
class="text-uppercase text-muted small mb-1">
可申请key的上限/已申请的key</p><span class="h4 mb-0">5 / 5</span>
</div>
<div class="col-auto"><a
class="btn btn-sm btn-outline-primary"
href="https://platform.openai.com/account/api-keys"
target="_blank">申请</a>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header d-flex justify-content-between"><h6
class="card-title">
ApiKeys</h6>
</div>
<div class="card-body">
<div class="my-md-3">
<div class="table-responsive">
<table class="table table-border table-hover table-nowrap card-table mb-0">
<thead>
<tr>
<th>name</th>
<th>key</th>
<th>创建时间</th>
<th>上次使用时间</th>
</tr>
</thead>
<tbody class="font-size-base api-key-list">
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="setting-org" role="tabpanel">
<div class="row justify-content-between mb-4">
<div class="col-12">
<div class="alert alert-danger"><i class="zmdi zmdi-info me-1"></i>你的AccessToken已过期或者失效,将展示上一次数据。请及时更新token,请求的api请查看后台代码。
</div>
</div>
<div class="col-12 col-md-6">
<div class="card mb-4">
<div class="card-body">
<div class="row align-items-center">
<div class="col"><p
class="text-uppercase text-muted small mb-1">组织</p>
<span class="h4 mb-0">Southworth Aleigha</span>
<p class="small text-muted mb-0"><a
class="d-block text-reset text-truncate"
href="javascript:;"><span>wytarudae4@outlook.com</span></a>
</p></div>
<div class="col-auto"><a class="btn btn-sm btn-dark"
href="https://platform.openai.com/account/members"
target="_blank">管理</a></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="setting-faqs" role="tabpanel">
<div class="row">
<div class="col-lg-3 col-md-12">
<div class="mb-4"><h6>提示</h6>
<p class="text-muted">尽量不要停止对话,保证对话的完整。对话有三种状态的等待提示信号</p>
<div class="list-group custom">
<a class="list-group-item" href="#"><i
class="zmdi zmdi-circle small me-2 text-danger"></i>出现错误,这是后台的锅</a>
<a class="list-group-item" href="#"><i
class="zmdi zmdi-circle small me-2 text-info"></i>命中缓存</a>
<a class="list-group-item" href="#"><i
class="zmdi zmdi-circle small me-2 text-primary"></i>正常等待中</a>
</div>
</div>
<div class="mb-3"><h6>如何提出疑问或者反馈bug </h6>
<p class="text-muted">QQ:937040147</p>
<p class="text-muted">微信:HOPPIN_HAZZ</p>
<a href="https://gitee.com/hoppin" target="_blank"
class="btn btn-primary">gitee发起issue</a></div>
</div>
<div class="col-lg-9 col-md-12">
<div class="card">
<div class="card-body"><h6>聊天</h6>
<div id="demo-gen-faq" class="accordion border-bottom mb-4">
<div class="mb-1">
<div class="py-2 px-3 qaq">
<a aria-expanded="true" data-toggle="collapse"
href="#answer-1">为什么新建聊天没有保存成功?</a>
<div class="panel-collapse collapse in py3"
id="answer-1" role="tabpanel">
这是因为新建聊天实际是在有一条有效对话(chagpt必须已结束或者手动停止的对话)的时候新增的,你可能已经新建了聊天或者编辑了聊天,但是还没有开始对话,
如果你觉得不合理,请自行手动修改前端源代码。很不幸,我无意对任何前端代码做改动
</div>
</div>
</div>
<div class="mb-1">
<div class="py-2 px-3 qaq">
<a aria-expanded="true" data-toggle="collapse"
href="#answer-2">为什么我切换聊天的时候丢失了前面的两条提示信息?</a>
<div class="panel-collapse collapse in py3"
id="answer-2" role="tabpanel">
前面的两条信息仅在新增聊天的时候会被添加上,无论做任何其他操作,这些提示信息都应该被清理。如果你觉得不合理,请自行手动修改前端源代码。
</div>
</div>
</div>
<div class="mb-1">
<div class="py-2 px-3 qaq">
<a aria-expanded="true" data-toggle="collapse"
href="#answer-3">
为什么我的聊天列表没有被正确加载?</a>
<div class="panel-collapse collapse in py3"
id="answer-3" role="tabpanel">
这跟后台有关,这是因为前端初始化聊天列表设置的超时时长为10s(webMetaData.timeout),若该请求时间超过10s,则该请求会被阻塞。
一旦被阻塞,就会默认添加一个新的聊天。你可以修改源代码延长超时时长参数或者刷新页面。
</div>
</div>
</div>
<div class="mb-1">
<div class="py-2 px-3 qaq">
<a aria-controls="answer-4"
aria-expanded="true" data-toggle="collapse"
href="#answer-4">
为什么我的聊天不能被公开?</a>
<div class="panel-collapse collapse in py3"
id="answer-4" role="tabpanel">
因为我懒。
</div>
</div>
</div>
</div>
<h6>聊天信息</h6>
<div id="demo-acc-faq" class="accordion mb-4">
<div class="mb-1">
<div class="py-2 px-3 qaq">
<a aria-expanded="true" data-toggle="collapse"
href="#answer-5">
在我的聊天中,bot的回复一直处于等待状态,这正常吗?</a>
<div class="panel-collapse collapse in py3"
id="answer-5" role="tabpanel">
没错,这很正常,这是网的问题。
</div>
</div>
</div>
<div class="mb-1">
<div class="py-2 px-3 qaq">
<a aria-expanded="true" data-toggle="collapse"
href="#answer-6">
bot的回复的样式不是很美观</a>
<div class="panel-collapse collapse in py3"
id="answer-6" role="tabpanel">
bot返回的格式是markdown的格式,如果你有能力自行将其处理的美观,请自行修改前端源代码。考虑到性能问题,我是在bot完成整个聊天才渲染的,你可以修改代码使得边打印边渲染。
</div>
</div>
</div>
<div class="mb-1">
<div class="py-2 px-3 qaq">
<a aria-expanded="true" data-toggle="collapse"
href="#answer-7">
我能使用其他聊天模型吗?</a>
<div class="panel-collapse collapse in py3"
id="answer-7" role="tabpanel">
模型暂时是写死在源代码里的,你可以修改前端源代码改变模型,推荐使用gpt-3.5-turbo模型,因为相比于text模型或者gpt-4等语言模型,
3.5的计费是其10%。
</div>
</div>
</div>
<div class="mb-1">
<div class="py-2 px-3 qaq">
<a aria-expanded="true" data-toggle="collapse"
href="#answer-8">
有时候聊天内容没保存好,或者干脆无法显示?</a>
<div class="panel-collapse collapse in py3"
id="answer-8" role="tabpanel">
是的,出现这种原因是你在gpt生成聊天的时候,点击了停止,或者意外终止了聊天对话。这种情况下会依然保存终止前的信息,但由于聊天没有全部完成,导致解析数据不完整。
你可以修改前端的渲染方法markdownToHtml()
</div>
</div>
</div>
<div class="mb-1">
<div class="py-2 px-3 qaq">
<a aria-expanded="true" data-toggle="collapse"
href="#answer-9">
聊着聊着,突然不打印了!</a>
<div class="panel-collapse collapse in py3"
id="answer-9" role="tabpanel">
这是因为gpt-3.5-turbo模型最大的token是4096,大约2000个汉字左右,在每次聊天我都会使用上下文总共3次的对话内容,所以token可能会超过,
最近的gpt-4.0模型支持32000个token,但是计费是3.5的10倍。目前我无意更换模型,并把模型写死在后台了,你得自己拉后台代码部署,并将
模型修改为gpt-4.0,传参也有一点点改变。
</div>
</div>
</div>
<div class="mb-1">
<div class="py-2 px-3 qaq">
<a aria-expanded="true" data-toggle="collapse"
href="#answer-10">
bot回复什么也不显示!!!</a>
<div class="panel-collapse collapse in py3"
id="answer-10" role="tabpanel">
我也注意到这个现象了,第一个原因是这个报错org.eclipse.jetty.io.EofException,
也就是sse或者websocket服务返回数据,但客户端提前关闭了。这表示是我搞砸了,你可以刷新页面简单的解决这个问题。
第二个原因是你输入的默写特殊字符被拼接到请求的url里了,这直接导致404,现在这个问题已得到解决
</div>
</div>
</div>
</div>
<h6>图片生成</h6>
<div id="demo-image-faq" class="accordion mb-4">
<div class="mb-1">
<div class="py-2 px-3 qaq">
<a aria-expanded="true" data-toggle="collapse"
href="#answer-11">
图片生成不显示,报错!!!</a>
<div class="panel-collapse collapse in py3"
id="answer-11" role="tabpanel">
第一个原因是因为限制,该模型限制每分钟只能生成5张图片(官网写的是50张,但是亲测超过5张就是Rate limit exceeded for images per minute . Limit: 5/1min. Current: 6/1min.)
第二个原因是这个报错com.hoppinzq.api.OpenAiHttpException: Your request was rejected as a result of our safety system. Your prompt may contain text that is not allowed by our safety system.
这可能跟你的描述有关,你可能要生成一些不可描述的图片。
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal center-modal fade" id="chatSettings" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"><h5 class="modal-title">更改聊天内容</h5></div>
<div class="modal-body">
<form>
<form class="row g-3">
<div class="col-12 mt-2 mb-2">
<div class="form-group">
<div class="input-group"><input type="text" id="edit-chat-title"
class="form-control form-control-lg"
placeholder="聊天标题">
</div>
</div>
</div>
<div class="col-12 mt-2 mb-2">
<div class="form-group">
<div class="input-group">
<textarea rows="4" class="form-control" id="edit-chat-answer"
placeholder="聊天描述"></textarea>
</div>
</div>
</div>
</form>
</form>
<div class="mt-5">
<button type="button" class="btn btn-primary" id="edit-modal-chat-ok">确定</button>
<button type="button" class="btn btn-link" data-dismiss="modal">取消</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal modal-right fade" id="modal-image" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body modal-image-body">
<div class="main-body">
<div class="body-header border-bottom py-xl-3 py-2">
<div class="container px-0">
<div class="row align-items-center">
<div class="col-12">
<div class="media">
<div class="avatar sm"><a href="#" data-dismiss="modal" title=""
class="link"><i
class="zmdi zmdi-arrow-left zmdi-hc-lg"></i></a></div>
<div class="media-body overflow-hidden">
<h6 class="mb-0 font-weight-bold">图片智能生成</h6>
<span class="text-muted">基于DALL·E(达尔文)模型</span>
</div>
<div class="avatar sm"><button class="btn btn-link close-sidebar text-muted" data-dismiss="modal" type="button"><i
class="zmdi zmdi-close"></i></button></div>
</div>
</div>
</div>
</div>
</div>
<div class="body-page d-flex py-xl-3 py-2">
<div class="card mb-4">
<div class="card-body">
<div class="row g-3">
<p class="mb-1">图像 API 提供了三种与图像交互的方法: </p>
<ol class="activity-feed text-muted mb-0" onclick="resetImageH()">
<li class="d-flex">
<div class="card">
<div class="card-body">
<input type="checkbox" id="expand_1"
name="expand_1">
<label for="expand_1" class="mb-0">
根据文本提示从头开始创建图像。案例具体点我
</label>
<div class="feed-content">
<div class="message-content">
<div class="col-auto">
<span class="mb-1 text-muted">一只雪白优雅且趴在床上的猫,看起来很好奇的样子</span>
<button class="btn btn-sm btn-white" onclick="createImage('一只雪白优雅且趴在床上的猫,看起来很好奇的样子',1,'256x256')">
<a href="#image-sc">试一试</a>
</button>
</div>
<div class="attachment right-file">
<img class="rounded mt-1" src="https://hoppinzq.com/chat/static/image/img-Q1eVaWXQ0dGDeUWiuCwPUW7O.png" alt="">
</div>
</div>
</div>
</div>
</div>
</li>
<li class="d-flex">
<div class="card">
<div class="card-body">
<input type="checkbox" id="expand_2"
name="expand_2">
<label for="expand_2" class="mb-0">
根据新的文本提示创建现有图像的编辑。这个需要传两张图片,案例具体点我
</label>
<div class="feed-content">
<div class="message-content">
<div class="col-auto">
<span class="mb-1">阳光明媚的室内休息区,游泳池内有一个火烈鸟游泳圈</span>
</div>
<div class="attachment right-file">
<img class="rounded mt-1" width="256" src="https://hoppinzq.com/chat/static/image/image_edit_original.png" alt="">
<img class="rounded mt-1" width="256" src="https://hoppinzq.com/chat/static/image/image_edit_mask.png" alt="">
<img class="rounded mt-1" width="256" src="https://hoppinzq.com/chat/static/image/image_edit_output.png" alt="">
</div>
</div>
</div>
</div>
</div>
</li>
<li class="d-flex">
<div class="card">
<div class="card-body">
<input type="checkbox" id="expand_3"
name="expand_3">
<label for="expand_3" class="mb-0">
创建现有图像的变体
</label>
<div class="feed-content">
<div class="message-content">
<div class="attachment right-file">
<img class="rounded mt-1" width="256" src="https://hoppinzq.com/chat/static/image/image_variation_original.png" alt="">
<img class="rounded mt-1" width="256" src="https://hoppinzq.com/chat/static/image/image_variation_output.png" alt="">
</div>
</div>
</div>
</div>
</div>
</li>
</ol>
</div>
<div class="row align-items-center mt-5">
<div class="col-6 col-xl-4">
<div class="media">
<div class="avatar me-3 show-user-detail" data-toggle="tooltip" title="" data-original-title="ChatGPT Bot">
<div class="avatar rounded-circle no-image bg-primary text-light">
<span><i class="zmdi zmdi-comment-text"></i></span>
</div>
</div>
<div class="media-body overflow-hidden">
<div class="d-flex align-items-center mb-1">
<h6 class="text-truncate mb-0 me-auto">ChatGPT Bot</h6>
</div>
<div class="text-truncate">基于DALL·E模型</div>
</div>
</div>
</div>
<div class="col-12 mt-1 mb-1">
<div class="alert alert-warning"><i class="zmdi zmdi-info me-1"></i>注意:由于模型限制,每分钟只能生成5张图片(无论成功与否)。所以本次演示每次限制生成1张256x256的图片,并适当延长了响应时间。每张图片有效期为1小时,喜欢请手动保存到本地。
</div>
</div>
</div>
<div class="form-group mt-3 mb-3">
<textarea rows="3" class="form-control no-resize" id="image-prompt"
placeholder="输入图片描述"></textarea>
</div>
<div class="align-right">
<button class="btn btn-primary image-cr-btn">生成</button>
</div>
<div class="row g-3">
<div class="message-content">
<div class="col-auto">
<span class="mb-1">生成的图片如下</span>
</div>
<div class="attachment right-file image-sc" id="image-sc">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal center-modal fade" id="modal-log" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"><h5 class="modal-title">更新日志</h5>
</div>
<div class="modal-body">
<ol class="activity-feed p-0 ms-3 mb-0 pt-5">
<li class="feed-item d-flex mb-3 pl-lg-4 ps-3" data-content="" data-time="2023-04-17" data-color="yellow">
<div class="card mb-3">
<div class="card-body">
<input type="checkbox" id="log_11" name="log_1">
<label for="log_11" class="mb-0">
<b>代码补全</b> 正在开发
</label>
</div>
</div>
</li>
<li class="feed-item d-flex mb-3 pl-lg-4 ps-3" data-content="" data-time="2023-04-17" data-color="green">
<div class="card mb-3">
<div class="card-body">
<input type="checkbox" id="log_41" name="log_41">
<label for="log_2" class="mb-0">
修复了<b>bot回复为空的重大bug</b>,这个bug很有意思,我不确定你是否感兴趣。
</label>
</div>
</div>
</li>
<li class="feed-item d-flex mb-3 pl-lg-4 ps-3" data-content="" data-time="2023-04-17" data-color="green">
<div class="card mb-3">
<div class="card-body">
<input type="checkbox" id="log_31" name="log_31">
<label for="log_2" class="mb-0">
重写代码段渲染的样式,为代码段添加主题和复制功能
</label>
</div>
</div>
</li>
<li class="feed-item d-flex mb-3 pl-lg-4 ps-3" data-content="" data-time="2023-04-16" data-color="green">
<div class="card mb-3">
<div class="card-body">
<input type="checkbox" id="log_2" name="log_2">
<label for="log_2" class="mb-0">
修复了<b>xml格式被解析成html标签而无法正确渲染的重大bug</b>
</label>
</div>
</div>
</li>
<li class="feed-item d-flex mb-3 pl-lg-4 ps-3" data-content="" data-time="2023-04-16" data-color="green">
<div class="card mb-3">
<div class="card-body">
<input type="checkbox" id="log_3" name="log_3">
<label for="log_3" class="mb-0">
添加了图片生成的功能<a href="#" onclick="openImage()" data-dismiss="modal">点我查看</a>
</label>
</div>
</div>
</li>
<li class="feed-item d-flex mb-3 pl-lg-4 ps-3" data-content="" data-time="2023-04-15" data-color="dark">
<div class="card mb-3">
<div class="card-body">
<input type="checkbox" id="log_4" name="log_4">
<label for="log_4" class="mb-0">
<b>聊天demo</b> 开源了!<a href="https://gitee.com/hoppin/chatgpt-front" target="_blank">点我访问</a>
</label>
</div>
</div>
</li>
</ol>
<div class="mt-5">
<button type="button" class="btn btn-link" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-link no-show-log" data-dismiss="modal">不再显示</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal modal-fill fade" data-backdrop="false" id="modal-code" tabindex="-1">
<div class="modal-dialog" style="max-width: 1366px">
<div class="modal-content" style="width: 1000px">
<div class="modal-header">
<div class="media">
<div class="avatar me-3 show-user-detail" data-toggle="tooltip" title="" data-original-title="ChatGPT Bot">
<div class="avatar rounded-circle no-image bg-primary text-light">
<span><i class="zmdi zmdi-comment-text"></i></span>
</div>
</div>
<div class="media-body overflow-hidden">
<div class="d-flex align-items-center mb-1">
<h6 class="text-truncate mb-0 me-auto">ChatGPT Bot</h6>
</div>
<div class="text-truncate">基于code-davinci-edit模型</div>
</div>
</div>
</div>
<div class="modal-body">
<div style="height: 600px;" id="code_edit">
<pre class="code-editor" style="height: 600px;" data-editor-lang="js" data-editor-show-annotation-ruler="false" data-editor-show-overview-ruler="false" data-editor-show-folding-ruler="false"> //使用Java编写一个快速排序</pre>
</div>
<div class="mt-5">
<button type="button" class="btn btn-link" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-link" id="code-check">增补/修改</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://hoppinzq.com/video/assets/js/jquery-3.3.1.min.js"></script>
<script src="https://hoppinzq.com/chat/static/js/bootstrap.bundle.min.js"></script>
<script src="https://hoppinzq.com/chat/static/js/template.js"></script>
<script src="https://hoppinzq.com/chat/static/js/marked.min.js"></script>
<script src="https://hoppinzq.com/chat/static/js/prettify.min.js"></script>
<script src="https://hoppinzq.com/chat/static/js/raphael.min.js"></script>
<script src="https://hoppinzq.com/chat/static/js/underscore.min.js"></script>
<script src="https://hoppinzq.com/chat/static/js/sequence-diagram.min.js"></script>
<script src="https://hoppinzq.com/chat/static/js/flowchart.min.js"></script>
<script src="https://hoppinzq.com/chat/static/js/jquery.flowchart.min.js"></script>
<script src="https://hoppinzq.com/chat/static/js/editormd.js"></script>
<script src="https://hoppinzq.com/chat/static/js/zq.js"></script>
<script src="https://hoppinzq.com/zui/static/js/sweetalert.min.js"></script>
<script src="https://hoppinzq.com/zui/static/js/jquery.sweet-alert.custom.js"></script>
<script src="https://hoppinzq.com/spider/js/simple-bar.js"></script>
<script src="https://hoppinzq.com/chat/static/js/jBox.all.min.js"></script>
<script src="https://hoppinzq.com/chat/static/js/built-editor.min.js"></script>
<script>
console.log("\n %c 前端代码 %c https://gitee.com/hoppin/chatgpt-front \n\n", "background: #35495e; padding: 1px; border-radius: 3px 0 0 3px; color: #fff", "background: #fadfa3; padding: 1px; border-radius: 0 3px 3px 0; color: #fff");
var ip = "http://103.143.11.157:8094"
var webMetaData = {
zq: __zqChat,//zq元数据,提供公用方法和浏览器环境信息(如:是否移动端,是否在联网环境等)
userId: null,//浏览器独一无二的标识,模拟用户登录后的id,永久存放于缓存中
modal: "gpt-3.5-turbo",//全局模型,其他模型在帮助中查看
timeout: 7500,
ws: null,//websocket对象,项目启动后会马上连接,注意:每次重连的时候ws会有2s被置为null,请妥善处理
sse: null,//sse对象,仅在使用时连接,error事件和complete事件都放在error中处理了,请知悉
chatState: 0,//0表示关闭,即没有在聊天,处于空闲状态。1表示等待中,这时候后台已经接收到请求,但还没有返回数据。2表示正在聊天中,后台通过sse实时返回聊天对话。
index: 1,//当前聊天索引
userno: null,//不同于userId,userno为websocket标志的当前浏览器的标识,每次重启都会改变
isContent: true,//是否携带上下文
cache: {},//缓存
accessToken: null,//openai登录需要的凭证,通过该token,无需用户名密码即可伪造登录openai,并获取账号元数据
chat: [],//聊天内容
chatCurrentId: null,//当前聊天id
accessTokenJWT: {//解析后的token
header: null,
payload: null,
signature: null
}
}
$(function () {
webMetaData.userno = __zqChat.uuid(32, 64);
webMetaData.userId = localStorage.getItem("userId");
if (webMetaData.userId == null) {
webMetaData.userId = __zqChat.uuid(32, 64);
localStorage.setItem("userId", webMetaData.userId);
}
$("#user_id").text("欢迎您,游客:" + webMetaData.userId);
init();
bind();
connect("sse");
setTimeout(function () {
$("#modal-settings .modal-dialog").width($(".main").width());
$("#modal-image .modal-dialog").width($(".main").width());
}, 1000);
setInterval(function () {
//$("#modal-image .modal-dialog").height(0).height($(".modal-image-body").height()+60);
$("#modal-image .modal-dialog").height(0).height($(".modal-image-body").height()+60);
$("#modal-settings .modal-dialog").height(0).height($(".modal-settings-body").height()+30);
}, 20);
// if(localStorage.getItem("log1")==null){
// $("#modal-log").modal();
// }
console.log(webMetaData)
account();
require(["orion/editor/edit"], function (edit) {
edit({className: "code-editor"});
});
})
function createChat() {
$(".chat-message").html("");
let chatId = __zqChat.uuid(32, 62);
let nowTime = __zqChat.getRealDate(new Date());
$(".chat-title").removeClass("active")
$(".chat-all-header").after2(`<li class="online chat-title active new" data-id="${chatId}">
<div class="hover_action">
<button type="button" data-toggle="tooltip" onclick="openChat('${chatId}')" data-original-title="标记为公开" class="btn btn-link text-info"><i class="zmdi zmdi-eye"></i></button>
<button type="button" class="btn btn-link text-warning" data-title="新建聊天" data-answer="点击我来跟chatgpt聊天吧" onclick="editChat('${chatId}')" data-original-title="修改聊天"><i class="zmdi zmdi-edit"></i>
</button>
<button type="button" data-toggle="tooltip" onclick="removeChat('${chatId}')" data-original-title="移除聊天" class="btn btn-link text-danger"><i class="zmdi zmdi-delete"></i>
</button>
</div>
<a href="#" class="card">
<div class="card-body">
<div class="media">
<div class="avatar me-3">
<div class="avatar rounded-circle no-image bg-primary text-light">
<span><i class="zmdi zmdi-comment-text"></i></span>
</div>
</div>
<div class="media-body overflow-hidden">
<div class="d-flex align-items-center mb-1">
<h6 class="text-truncate mb-0 me-auto chat-question-header" >新建聊天</h6>
<p class="small text-muted text-nowrap ms-4 mb-0">${nowTime}</p>
</div>
<div class="text-truncate chat-answer-header">
点击我来跟chatgpt聊天吧
</div>
</div>
</div>
</div>
</a>
</li>`, function () {
setHelp();
$(".chat-title").off("click").on("click", function () {
webMetaData.index = 1;
if (webMetaData.chatState > 0) {
stopChat();
}
$(".chat-message").html("");
$(this).addClass("active").siblings().removeClass("active");
let chatId = $(this).data("id");
webMetaData.chatCurrentId = chatId;
$.each(webMetaData.chat, function (i, cc) {
if (cc.chat_id == chatId) {
webMetaData.index += cc.chatMessageList.length / 2;
$.each(cc.chatMessageList, function (index, chatMsg) {
let chatIndex = index + 1;
if (chatMsg.message_role == "user") {
buildMessage(false, "user-chat-question-" + chatMsg.message_index, chatMsg.message_createDate, chatMsg.message_user_name, chatMsg.message_user_image, chatMsg.message, chatIndex,false);
}
if (chatMsg.message_role == "assistant") {
buildMessage(true, "user-chat-answer-" + chatMsg.message_index, chatMsg.message_createDate, chatMsg.message_user_name, chatMsg.message_user_image, chatMsg.message, chatIndex,false);
}
markdownToHtml("message-user-chat-answer-" + chatMsg.message_index);
})
}
})
let scrollableDiv = document.getElementById("chat-content");
scrollableDiv.scrollTop = 0;
})
});
webMetaData.chatCurrentId = chatId;
webMetaData.chat.push({
chat_id: chatId,
chat_user_id: webMetaData.userId,
chat_createDate: nowTime,
chat_title: "新建聊天",
chat_answer: "点击我来跟chatgpt聊天吧",
chat_state: 0,//0表示不公开,1表示公开
chatMessageList: [],
chat_modal: webMetaData.modal
})
}
/**
* 根据chatID查找chat
* */
function findChatByChatid(chatId) {
let temp = null;
$.each(webMetaData.chat, function (i, chat) {
if (chat.chat_id == chatId) {
temp = chat;
return;
}
})
return temp;
}
/**
* 移除聊天
* */
function removeChat(chatId) {
swal({
title: "确定?",
text: "该操作将移除该聊天!",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "移除!",
cancelButtonText: "不移除!",
closeOnConfirm: false,
closeOnCancel: false
},
function (isConfirm) {
if (isConfirm) {
$.get(`${ip}/hoppinzq?method=deleteChatByChatId&params={"chatId":"${chatId}"}`, function (data) {
let _data = JSON.parse(data);
if (_data.code == 200) {
swal("成功!", "删除成功", "success");
$.each(webMetaData.chat, function (index, chat) {
if (chat.chat_id == chatId) {
webMetaData.chat.splice(1, index - 1);
}
})
let temp = 0;
$(".chat-title").each(function (index, element) {
if (chatId == $(element).data("id")) {
$(element).remove();
temp = index;
}
if (temp = index + 1) {
$(element).click();
}
})
//若全部都被移除,新建一个
if ($(".chat-title").length == 0) {
createChat()
}
} else {
swal("错误!", "删除失败", "error");
}
})
} else {
swal("取消!", "移除操作已取消", "success");
}
});
}
/**
* 公开聊天
* */
function openChat(chatId) {
swal("错误!", "目前不可公开/分享:该功能已移除,API:getPublicChats", "error");
}
/**
* 编辑聊天
* */
function editChat(chatId) {
$("#chatSettings").modal();
let chat = {};
chat.chat_id = chatId;
chat.chat_user_id = webMetaData.userId;
chat.chat_modal = webMetaData.modal;
$.get(`${ip}/hoppinzq?method=getChatByChatId&params={"chatId":"${chatId}"}`, function (data) {
let _data = JSON.parse(data);
if (_data.code == 200) {
if (_data.data) {
chat = _data.data;
$("#edit-chat-title").val(_data.data.chat_title)
$("#edit-chat-answer").val(_data.data.chat_answer)
} else {
}
}
});
$("#edit-modal-chat-ok").off("click").on("click", function () {
chat.chat_createDate = __zqChat.getRealDate(new Date());
if ($("#edit-chat-title").val().trim().length == 0) {
alert("无标题");
$("#edit-chat-title").focus();
return;
}
if ($("#edit-chat-answer").val().trim().length == 0) {
alert("内容");
$("#edit-chat-answer").focus();
return;
}
chat.chat_title = $("#edit-chat-title").val();
chat.chat_answer = $("#edit-chat-answer").val();
$.ajax({
url: `${ip}/hoppinzq?method=insertOrUpdateChat`,
type: "post",
contentType: "application/json",
data: JSON.stringify({
"chat": chat
}),
success: function (data) {
swal("成功!", "修改成功", "success");
$(".chat-title").each(function (i, element) {
if ($(element).data("id") == chatId) {
$(element).find(".chat-question-header").text(chat.chat_title);
$(element).find(".chat-answer-header").text(chat.chat_answer);
}
})
$("#chatSettings").modal("hide");
},
error: function (data) {
swal("失败!", "修改失败", "success");
}
})
})
}
function loadChatMessage() {
}
function loadChat() {
if (webMetaData.chat.length == 0) {
createChat();
} else {
$.each(webMetaData.chat, function (index, chat) {
$(".chat-all-header").after(`<li class="online chat-title" data-id="${chat.chat_id}">
<div class="hover_action">
<button type="button" data-toggle="tooltip" onclick="openChat('${chat.chat_id}')" data-original-title="标记为公开" class="btn btn-link text-info"><i class="zmdi zmdi-eye"></i></button>
<button type="button" class="btn btn-link text-warning" onclick="editChat('${chat.chat_id}')" data-original-title="修改聊天"><i class="zmdi zmdi-edit"></i>
</button>
<button type="button" data-toggle="tooltip" onclick="removeChat('${chat.chat_id}')" data-original-title="移除聊天" class="btn btn-link text-danger"><i class="zmdi zmdi-delete"></i>
</button>
</div>
<a href="#" class="card">
<div class="card-body">
<div class="media">
<div class="avatar me-3">
<div class="avatar rounded-circle no-image bg-primary text-light">
<span><i class="zmdi zmdi-comment-text"></i></span>
</div>
</div>
<div class="media-body overflow-hidden">
<div class="d-flex align-items-center mb-1">
<h6 class="text-truncate mb-0 me-auto chat-question-header" >${chat.chat_title}</h6>
<p class="small text-muted text-nowrap ms-4 mb-0">${chat.chat_createDate}</p>
</div>
<div class="text-truncate chat-answer-header">
${chat.chat_answer}
</div>
</div>
</div>
</div>
</a>
</li>`);
});
createChat();
}
}
function init() {
webMetaData.cache.theme = localStorage.getItem("theme");
webMetaData.cache.locache = localStorage.getItem("locache") == null ? "1" : localStorage.getItem("locache");
webMetaData.cache.isscoll = localStorage.getItem("isscoll") == null ? "1" : localStorage.getItem("isscoll");
webMetaData.cache.ishelp = localStorage.getItem("ishelp") == null ? "1" : localStorage.getItem("ishelp");
if (webMetaData.cache.locache == "0") {
$("#iall-cache").attr("checked", false);
}
if (webMetaData.cache.isscoll == "0") {
$("#iall-scoll").attr("checked", false);
}
if (webMetaData.cache.ishelp == "0") {
$("#iall-help").attr("checked", false);
}
initAccessToken();
initChat();
}
function initChat() {
if (webMetaData.userId != null) {
$.ajax({
url: `${ip}/hoppinzq?method=getChatByUserId&params={"userId":"${webMetaData.userId}"}`,
timeout: webMetaData.timeout,
success: function (data) {
let _data = JSON.parse(data);
if (_data.code == 200) {
let chat = _data.data;
webMetaData.chat = chat;
}
},
complete: function () {
loadChat();
__zqChat.stopLoading(0, 0);
}
})
}
}
/**
* 初始化accesstoken
**/
function initAccessToken() {
webMetaData.accessToken = localStorage.getItem("accessToken");
if (webMetaData.accessToken == null || !checkToken(false)) {
$(".token-card").hide();
$("#access-token").html("");
} else {
$(".token-card").show();
$("#access-token").html(webMetaData.accessToken.trim());
let header = webMetaData.accessToken.split(".")[0];
webMetaData.accessTokenJWT.header = header;
let payload = webMetaData.accessToken.split(".")[1];
webMetaData.accessTokenJWT.payload = payload;
let signature = webMetaData.accessToken.split(".")[2];
webMetaData.accessTokenJWT.signature = signature;
}
}
/**
* 删除accesstoken
**/
function deleteToken() {
swal({
title: "确定删除?",
text: "该操作将删除现有token!",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "删除!",
cancelButtonText: "不删除!",
closeOnConfirm: false,
closeOnCancel: false
},
function (isConfirm) {
if (isConfirm) {
localStorage.removeItem("accessToken");
initAccessToken();
swal("成功!", "删除成功", "success");
} else {
swal("取消!", "删除操作已取消", "success");
}
});
}
/**
* 检查accesstoken
**/
function checkToken(isSweet) {
let token = webMetaData.accessToken;
if (isSweet) {
if (token == null || token.split(".").length != 3) {
swal("失败!", "格式有错误,解析失败", "error");
} else {
let header = token.split(".")[0];
webMetaData.accessTokenJWT.header = header;
let payload = token.split(".")[1];
webMetaData.accessTokenJWT.payload = payload;
let signature = token.split(".")[2];
webMetaData.accessTokenJWT.signature = signature;
swal({
html: true, title: "解析成功!", text: `<div class="card bg-light border">
<div class="card-body"><p class="mb-2">头部</p>
<p class="small text-muted mb-2">${atob(header)}</p><p class="mb-2">载荷</p>
<p class="small text-muted mb-2">${atob(payload)}</p><p class="mb-2">签名</p>
<p class="small text-muted mb-2">${signature}</p>
</div>
</div>`
});
}
} else {
if (token == null || token.split(".").length != 3) {
return false;
} else {
return true;
}
}
}
/**
* 更新accesstoken
**/
function updateAccessToken() {
swal({
title: "确定?",
text: "该操作将更新token!",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "更新!",
cancelButtonText: "不更新!",
closeOnConfirm: false,
closeOnCancel: false
},
function (isConfirm) {
if (isConfirm) {
let token = $(".access-token").val();
if (token.length == 0) {
swal("失败!", "token为空", "error");
$(".access-token").focus();
return;
}
if (token.split(".").length != 3) {
swal("失败!", "token格式不正确,token必须为JWT格式,请检查格式", "error");
$(".access-token").focus();
return;
}
localStorage.setItem("accessToken", token);
webMetaData.accessToken = token;
webMetaData.accessTokenJWT = {};
swal("成功", "token已修改", "success")
initAccessToken();
} else {
swal("取消!", "操作已取消", "success");
}
});
}
function bind() {
$(".no-show-log").click(function () {
localStorage.setItem("log1","0")
})
$(".cache-m").click(function () {
let cacheKey = $(this).data("cache")
$(this).is(":checked") == 1 ? localStorage.setItem(cacheKey, "1") : localStorage.setItem(cacheKey, "0");
webMetaData.cache[cacheKey] = localStorage.getItem(cacheKey);
})
$(".default-settings").click(function () {
$(".cache-m").each(function (index, element) {
if ($(element).is(":checked") == 0) {
$(element).click();
}
})
})
let copyButton = document.querySelectorAll('.copy-btn');
copyButton.forEach(element => {
element.addEventListener('click', (e) => {
$(copyButton).each(function (index, elem) {
$(elem).text("复制");
});
const elem = e.target.parentElement.children[1].innerText;
let save = function (e) {
e.clipboardData.setData('text/plain', elem);
e.preventDefault();//阻止默认行为
}
document.addEventListener('copy', save);
document.execCommand("copy");
$(element).text("复制成功!");
// const el = document.createElement('textarea');
// el.value = elem;
// document.body.appendChild(el);
// el.select();
// document.execCommand("copy");
// $(element).text("复制成功!");
// document.body.removeChild(el)
})
});
/**
* 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常
*/
window.onbeforeunload = function () {
if (webMetaData.ws != null && webMetaData.ws.readyState === 1) {
$.post(ip+"/v1/chat/completions/stopstream/" + webMetaData.userno)
webMetaData.ws.close();
}
if (webMetaData.sse != null) {
webMetaData.sse.close();
}
}
//监听回车
$("#sendText").keydown(function (e) {
if (e.keyCode == 13) {
question();
e.preventDefault();
}
})
$(".chat-message-search").keydown(function (e) {
if (e.keyCode == 13) {
let search = $(this).val();
if (search.trim().length == 0) {
swal("错误!", "请输入搜索内容", "error");
} else {
swal("", "这个功能没什么用,自己去实现", "success");
}
e.preventDefault();
}
})
$(".chat-message-search-btn").click(function () {
let search = $(".chat-message-search").val();
if (search.trim().length == 0) {
swal("错误!", "请输入搜索内容", "error");
} else {
swal("", "这个功能没什么用,自己去实现", "success");
}
})
$(".chat-search").keydown(function (e) {
if (e.keyCode == 13) {
let search = $(this).val();
if (search.trim().length == 0) {
swal("错误!", "请输入搜索内容", "error");
} else {
swal("", "这个功能没什么用,自己去实现", "success");
}
e.preventDefault();
}
})
$("#sendChat").click(function () {
question();
})
/**
* 停止对话
* */
$("#stopChat").click(function () {
stopChat();
})
$(".create-new-chat").click(function () {
createChat();
})
$(".image-cr-btn").click(function () {
let prompt=$("#image-prompt").val();
if(prompt.trim().length==0){
alert("请输入图片描述");
return;
}
createImage(prompt,1,"256x256");
});
$("#code-check").click(function () {
$(this).off("click").text("请稍等...");
fixCode();
})
}
function fixCode(){
$.ajax({
url: "http://103.143.11.157:8094/v1/edits/code",
type: "post",
data: JSON.stringify({
"input": $(".code-editor").text(),
"instruction": "Complete the code based on comments"
}),
contentType: "application/json",
success: function (data) {
console.log(data)
$(".code-editor").text(data.choices[0].text);
require(["orion/editor/edit"], function (edit) {
edit({className: "code-editor"});
});
},
complete:function () {
$("#code-check").off("click").on("click",function () {
$(this).off("click").text("增补/修改");
fixCode();
})
}
})
}
function stopChat() {
if (webMetaData.ws != null) {
$.post(ip+"/v1/chat/completions/stopstream/" + webMetaData.userno)
} else {
webMetaData.sse.close();
}
if (webMetaData.chatState == 1) {
$("#user-chat-answer-" + webMetaData.index).remove();
} else if (webMetaData.chatState == 2) {
webMetaData.chatState = 0;
webMetaData.index++;
$("#stopChat").hide();
$("#sendChat").show();
saveChat();
}
}
/**
* 连接,sse为sse服务,ws为websocket服务,其中两个服务对话都可以用,但是后续功能(如终止对话等)全部只支持sse
* websocket可以当作demo学习或者使用,本项目使用了sse,官网也是。
* */
function connect(type) {
if (type == "sse") {
} else {
webMetaData.ws = new WebSocket("ws://103.143.11.157:8094/chatgpt/" + webMetaData.userno);
webMetaData.ws.onopen = function () {
};
webMetaData.ws.onmessage = function (event) {
$("#message-user-chat-answer-" + webMetaData.index).find(".wave").remove();
let msg = event.data;
let _msg = JSON.parse(msg);
let chat = JSON.parse(_msg.msg);
if (chat.choices[0].message.content != undefined) {
webMetaData.chatState = 2;
$("#message-user-chat-answer-" + webMetaData.index).text($("#message-user-chat-answer-" + webMetaData.index).text() + chat.choices[0].message.content);
}
if (webMetaData.cache.isscoll == "1") {
let scrollableDiv = document.getElementById("chat-content");
scrollableDiv.scrollTop = scrollableDiv.scrollHeight;
}
if (chat.choices[0].finishReason != undefined && chat.choices[0].finishReason == "stop") {
markdownToHtml("message-user-chat-answer-" + webMetaData.index);
webMetaData.index++;
//结束
webMetaData.chatState = 0;
}
};
webMetaData.ws.onclose = function () {
$.post(ip+"/v1/chat/completions/stopstream/" + webMetaData.userno)
setTimeout(function () {
connect(); // 重新连接
}, 2000);
};
webMetaData.ws.onerror = function () {
};
}
}
/**
* 提问
* */
function question() {
if (webMetaData.chatState > 0) {
new jBox('Notice', {
attributes: {
y: 'bottom'
},
position: {
x: 'center',
y: 'center'
},
animation: 'flip',
color: "red",
autoClose: 5000,
content: '请等待聊天完成',
delayOnHover: true,
showCountdown: true,
});
return;
}
let question = $("#sendText").val();
if (question.length == 0) {
new jBox('Notice', {
attributes: {
y: 'bottom'
},
position: {
x: 'center',
y: 'center'
},
animation: 'flip',
color: "blue",
autoClose: 5000,
content: '请输入内容',
delayOnHover: true,
showCountdown: true,
});
$("#sendText").focus();
return;
}
$("#sendText").val("");
buildMessage(false, "user-chat-question-" + webMetaData.index, __zqChat.getRealDate(new Date()), "HOPPIN", "http://hoppinzq.com/zui/static/picture/0.jpg", question, webMetaData.index,false);
answer("user-chat-answer-" + webMetaData.index, question, "sse");
};
/**
* 不渲染md,还原原来的聊天格式
* */
function notUserMd(id) {
if (webMetaData.chatState > 0) {
new jBox('Notice', {
attributes: {
y: 'bottom'
},
position: {
x: 'center',
y: 'center'
},
animation: 'flip',
color: "blue",
autoClose: 5000,
content: '正在生成聊天中,生成完毕可操作',
delayOnHover: true,
showCountdown: true,
});
return;
}
$("#" + id).removeClass("markdown-body").removeClass("editormd-html-preview").html("")
.text($("#" + id).data("predate"));
}
/**
* 渲染md
* */
function userMd(id) {
if (webMetaData.chatState > 0) {
new jBox('Notice', {
attributes: {
y: 'bottom'
},
position: {
x: 'center',
y: 'center'
},
animation: 'flip',
color: "blue",
autoClose: 5000,
content: '正在生成聊天中,生成完毕可操作',
delayOnHover: true,
showCountdown: true,
});
return;
}
markdownToHtml(id)
}
/**
* md转html
* */
function markdownToHtml(id) {
let markdown = $("#" + id).text();
$("#" + id).text("").data("predate", markdown);
let testEditormdView = editormd.markdownToHTML(id, {
markdown: markdown,//+ "\r\n" + $("#append-test").text(),
htmlDecode : true, // 开启 HTML 标签解析,为了安全性,默认不开启
//htmlDecode: "style,script,iframe", // you can filter tags decode
//toc : false,
tocm: true, // Using [TOCM]
//tocContainer : "#custom-toc-container", // 自定义 ToC 容器层
//gfm : false,
//tocDropdown : true,
// markdownSourceCode : true, // 是否保留 Markdown 源码,即是否删除保存源码的 Textarea 标签
emoji: true,
taskList: true,
tex: true, // 默认不解析
flowChart: true, // 默认不解析
sequenceDiagram: true, // 默认不解析
});
$(".message-content pre").each(function (index_code,element_code){
let $element_code=$(element_code);
$(element_code).find(".code_change").remove();
$(element_code).find(".copy-code-btn").remove();
let code=$element_code.text();
$element_code.addClass("pre_"+index_code);
let $code=$element_code.on({
mouseover : function(e1){
e1.stopPropagation();
} ,
mouseout : function(e2){
e2.stopPropagation();
}
});
$element_code.prepend($(`<button class="code_change cursor-pointer">切换主题</button>`).off("click").on("click",function () {
$code.toggleClass("hljs");
})).prepend($(`<button class="copy-code-btn">复制</button>`).off("click").on("click",function () {
$(".copy-code-btn").each(function (index, elem) {
$(elem).text("复制");
});
let save = function (e) {
e.clipboardData.setData('text/plain', code);
e.preventDefault();//阻止默认行为
}
document.addEventListener('copy', save);
document.execCommand("copy");
$(this).text("复制成功!");
}))
})
}
/**
*
**/
function buildMessage(isBot, id, date, user, userImg, message, index,isHtml) {
message = message.trim();
let messageId = __zqChat.uuid(32, 64);
if (isBot) {
$(".chat-message").append2(`<li class="d-flex message message-bot" id="${id}">
<div class="message-body">
<div class="d-flex align-items-center">
<div class="avatar sm rounded-circle bg-primary d-flex align-items-center justify-content-center">
<span><i class="zmdi zmdi-comment-text text-light"></i></span>
</div>
<div class="mx-10 p-2">
<a href="#" class="text-dark hover-primary font-weight-bold">${user}</a>
</div>
</div>
<span class="date-time text-muted">${date} <i
class="zmdi zmdi-check-all text-primary"></i></span>
<div class="message-row d-flex align-items-center">
<div class="message-content p-3 text-chat" id="message-${id}" data-img="${userImg}" data-user="${user}" data-date="${date}" data-role="assistant" data-id="${messageId}"></div>
<div class="dropdown">
<a class="text-muted me-1 p-2 text-muted" href="#" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="zmdi zmdi-more-vert"></i>
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" onclick="notUserMd('message-${id}')" title="将会还原ChatBot原来的文本">不使用样式</a>
<a class="dropdown-item" href="#" onclick="userMd('message-${id}')" title="渲染ChatBot代码,表格等数据">渲染</a>
<a class="dropdown-item" href="#" onclick="needhelp('message-${id}')" title="将会还原ChatBot原来的文本">有疑问?</a>
</div>
</div>
</div>
</div>
</li>`, function () {
if(isHtml){
$("#message-"+id).html(message);
}else{
$("#message-"+id).text(message);
markdownToHtml("message-"+id);
}
})
} else {
$(".chat-message").append2(`<li class="d-flex message message-user right" id="${id}">
<div class="message-body">
<div class="d-flex align-items-center justify-content-end">
<div class="mx-10 p-2">
<a href="#" class="text-dark hover-primary font-weight-bold">${user}</a>
</div>
<span class="msg-avatar">
<img src="${userImg}" class="avatar avatar-lg rounded-circle">
</span>
</div>
<span class="date-time text-muted">${date}<i
class="zmdi zmdi-check-all text-primary"></i></span>
<div class="message-row d-flex align-items-center justify-content-end">
<div class="dropdown">
<a class="text-muted me-1 p-2 text-muted" href="#" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="zmdi zmdi-more-vert"></i>
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" onclick="needhelp()" title="将会还原ChatBot原来的文本">有疑问?</a>
<a class="dropdown-item" href="#" title="这是预留的位置,待拓展功能">预留位置2</a>
</div>
</div>
<div class="message-content p-3 text-chat" id="message-${id}" data-img="${userImg}" data-user="${user}" data-role="user" data-date="${date}" data-id="${messageId}">${message}</div>
</div>
</div>
</li>`, function () {
})
}
let scrollableDiv = document.getElementById("chat-content");
scrollableDiv.scrollTop = scrollableDiv.scrollHeight;
}
/**
* 保存对话
* */
function saveChat() {
let chat = findChatByChatid(webMetaData.chatCurrentId);
if (chat != undefined) {
let lastIndex = webMetaData.index - 1;
let lastChatUserDom = $("#message-user-chat-question-" + lastIndex);
let tempChatMessage = [];
chat.chatMessageList.push({
"chatId": webMetaData.chatCurrentId,
"messageId": lastChatUserDom.data("id"),
"role": lastChatUserDom.data("role"),
"message": lastChatUserDom.text(),
"date": lastChatUserDom.data("date"),
"user": lastChatUserDom.data("user"),
"index": lastIndex,
"image": lastChatUserDom.data("img")
});
tempChatMessage.push({
"chatId": webMetaData.chatCurrentId,
"messageId": lastChatUserDom.data("id"),
"role": lastChatUserDom.data("role"),
"message": lastChatUserDom.text(),
"date": lastChatUserDom.data("date"),
"user": lastChatUserDom.data("user"),
"index": lastIndex,
"image": lastChatUserDom.data("img")
})
let lastChatAssistantDom = $("#message-user-chat-answer-" + lastIndex);
chat.chatMessageList.push({
"chatId": webMetaData.chatCurrentId,
"messageId": lastChatAssistantDom.data("id"),
"role": lastChatAssistantDom.data("role"),
"message": lastChatAssistantDom.data("predate") == undefined ? lastChatAssistantDom.text() : lastChatAssistantDom.data("predate"),
"date": lastChatAssistantDom.data("date"),
"user": lastChatAssistantDom.data("user"),
"index": lastIndex,
"image": lastChatAssistantDom.data("img")
});
tempChatMessage.push({
"chatId": webMetaData.chatCurrentId,
"messageId": lastChatAssistantDom.data("id"),
"role": lastChatAssistantDom.data("role"),
"message": lastChatAssistantDom.data("predate") == undefined ? lastChatAssistantDom.text() : lastChatAssistantDom.data("predate"),
"date": lastChatAssistantDom.data("date"),
"user": lastChatAssistantDom.data("user"),
"index": lastIndex,
"image": lastChatAssistantDom.data("img")
})
$.ajax({
url: `${ip}/hoppinzq?method=createChatMessages`,
type: "post",
data: JSON.stringify({
"chatMessages": tempChatMessage
}),
contentType: "application/json",
success: function (data) {
},
error: function (data) {
}
})
}
}
/**
* 需要帮助?
* */
function needhelp() {
$("#settings").click();
$("#faqs").click();
}
/**
* 回复,支持ws跟sse,推荐使用sse
* */
function answer(chatid, question, type) {
if (type == "sse") {
let questionEncode=encodeURI(question);
let eventSource = new EventSource('http://103.143.11.157:8094/stream-sse3?message=' + questionEncode + "&chatId=" + webMetaData.chatCurrentId + "&isContent=" + webMetaData.isContent);
webMetaData.chatState = 1;
buildMessage(true, "user-chat-answer-" + webMetaData.index, __zqChat.getRealDate(new Date()), "ChatGPT Bot", "botimg", `
<div class="wave">
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>`, webMetaData.index,true);
$("#sendChat").hide();
$("#stopChat").show();
webMetaData.sse = eventSource;
eventSource.onopen = function (event) {
};
eventSource.addEventListener("message", function (event) {
$("#message-user-chat-answer-" + webMetaData.index).find(".wave").remove();
let msg = event.data;
let chat = JSON.parse(msg);
if (chat.choices[0].message.content != undefined && chat.choices[0].message.content != null) {
webMetaData.chatState = 2;
$("#message-user-chat-answer-" + webMetaData.index).text($("#message-user-chat-answer-" + webMetaData.index).text() + chat.choices[0].message.content);
}
if (webMetaData.cache.isscoll == "1") {
let scrollableDiv = document.getElementById("chat-content");
scrollableDiv.scrollTop = scrollableDiv.scrollHeight;
}
if (chat.choices[0].finishReason != undefined && chat.choices[0].finishReason == "length") {
swal("啊呀呀!", "token超出限制", "error");
}
});
eventSource.addEventListener("error", function (event) {
if (webMetaData.index == 1) {
updateChat();
}
markdownToHtml("message-user-chat-answer-" + webMetaData.index);
webMetaData.index++;
//结束
webMetaData.chatState = 0;
eventSource.close();
$("#sendChat").show();
$("#stopChat").hide();
saveChat();
//聊天错误
});
} else {
$.ajax({
type: "post",
url: ip+"/v1/chat/completions/poststream/" + webMetaData.userno,
data: JSON.stringify({
"model": "gpt-3.5-turbo",
"stream": true,
"messages": [
{"role": "user", "content": question}
]
}),
contentType: "application/json",
beforeSend: function () {
webMetaData.chatState = 1;
buildMessage(true, "user-chat-answer-" + webMetaData.index, __zqChat.getRealDate(new Date()), "ChatGPT Bot", "botimg", `<div class="wave"><span class="dot"></span><span class="dot"></span><span class="dot"></span></div>`, webMetaData.index,true);
},
success: function (response) {
},
error: function (xhr, status, error) {
alert("出错了!");
}
});
}
}
/**
* 更新&新增聊天
* */
function updateChat() {
let chatId = webMetaData.chatCurrentId;
let index = webMetaData.index;
let chat_title = $("#message-user-chat-question-" + index).text().substr(0, 10);
let chat_answer = $("#message-user-chat-answer-" + index).text().substr(0, 20);
let nowTime = __zqChat.getRealDate(new Date());
$(".chat-title").each(function (i, element) {
if ($(element).data("id") == chatId) {
$(element).find(".chat-question-header").text(chat_title);
$(element).find(".chat-answer-header").text(chat_answer);
}
})
let chat = {};
chat.chat_id = chatId;
chat.chat_user_id = webMetaData.userId;
chat.chat_createDate = nowTime;
chat.chat_title = chat_title;
chat.chat_answer = chat_answer;
chat.chat_state = "0";
chat.chat_modal = webMetaData.modal;
$.ajax({
url: `${ip}/hoppinzq?method=insertOrUpdateChat`,
type: "post",
contentType: "application/json",
data: JSON.stringify({
"chat": chat
}),
success: function (data) {
},
error: function (data) {
}
})
}
/**
* 删除回答对话
* */
function removeAnswer(id) {
$("#" + id).remove();
}
/**
* 设置帮助
*/
function setHelp() {
if (webMetaData.cache.ishelp == "1") {
$(".chat-message").append2(`<li class="d-flex message chat-help" id="chat-help1">
<div class="message-body">
<div class="d-flex align-items-center">
<div class="avatar sm rounded-circle bg-primary d-flex align-items-center justify-content-center">
<span><i class="zmdi zmdi-comment-text text-light"></i></span>
</div>
<div class="mx-10 p-2">
<a href="#" class="text-dark hover-primary font-weight-bold">ChatGPT Bot</a>
</div>
</div>
<span class="date-time text-muted">这是提示对话 不想要?<a data-toggle="pill" href="#nav-tab-user">设置关闭</a></span>
<div class="message-row d-flex align-items-center">
<div class="message-content p-3 text-chat">🙌 欢迎你!
我是ChatGPT Bot🤖
<a href="#" onclick="openImage()">(现已支持生成图片👈)</a>
在对话的时候,你可以给我一个前提条件,比如:"你是一名程序员","假如今年是2018年","假如你在日本"等。当然对于gpt-3.5-turbo模型来说没有这个必要。建议你直接问我问题,包括但不限于</div>
<div class="dropdown">
<a class="text-muted me-1 p-2 text-muted" href="#" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="zmdi zmdi-more-vert"></i>
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" onclick="removeAnswer('chat-help1')">删除对话</a>
</div>
</div>
</div>
<div class="message-row d-flex align-items-center">
<button type="button" class="btn btn-outline-primary btn-rounded mb-1 me-1" onclick="openAndImage('生成1张忧郁的猫的图片')">
生成1张忧郁的猫的图片
</button>
<button type="button" class="btn btn-outline-warning btn-rounded mb-1 me-1 demochat" data-message="请编写一个基于java的二叉树的代码">
请编写一个基于java的二叉树的代码
</button>
<button type="button" class="btn btn-outline-dark btn-rounded mb-1 me-1 demochat" data-message="给小黑狗起个名字">
给小黑狗起个名字
</button>
<button type="button" class="btn btn-outline-success btn-rounded mb-1 me-1 demochat" data-message="写一篇关于搜索引擎的论文">
写一篇关于搜索引擎的论文
</button>
</div>
</div>
</li>
<li class="d-flex message chat-help" id="chat-help2">
<div class="message-body">
<div class="d-flex align-items-center">
<div class="avatar sm rounded-circle bg-primary d-flex align-items-center justify-content-center">
<span><i class="zmdi zmdi-comment-text text-light"></i></span>
</div>
<div class="mx-10 p-2">
<a href="#" class="text-dark hover-primary font-weight-bold">ChatGPT Bot</a>
</div>
</div>
<span class="date-time text-muted">这是提示对话 不想要?<a data-toggle="pill" href="#nav-tab-user">设置关闭</a></span>
<div class="message-row d-flex align-items-center">
<div class="card rounded-3">
<div class="card-body"><h5 class="card-title">开始尝试吧!</h5>
<p class="card-text">你有任何疑问可以查看我的帮助文档,如果你不会使用我,你可以在下面获取帮助。</p>
<p class="card-text text-danger fw-bold">最后,请不要清理缓存,因为没有引入用户登录机制,我无法知道你是谁。
您的所有聊天会被缓存到本地和数据库,误清缓存请联系我恢复聊天数据。微信:HOPPIN_HAZZ</p>
<p class="card-text">您的临时用户id是:${webMetaData.userId}。临时id只跟您的设备有关,如要同步其他端的聊天,请手动修改缓存的用户id。</p></div>
<div class="card-body"><a href="https://hoppinzq.com/manager/chatgptAPI.html" target="_blank" class="card-link">✨ 查看文档</a>
<a href="#" onclick="needhelp()" class="card-link">👈 我需要帮助</a></div>
</div>
<div class="dropdown">
<a class="text-muted me-1 p-2 text-muted" href="#" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="zmdi zmdi-more-vert"></i>
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" onclick="removeAnswer('chat-help2')">删除对话</a>
</div>
</div>
</div>
</div>
</li>
<li class="d-flex message divider mt-xl-5 mt-md-3 mb-xl-5 mb-md-3">
<small class="text-muted">今天</small>
</li>`, function () {
$(".demochat").off("click").on("click", function () {
$("#sendText").val($(this).data("message"));
question();
})
})
}
}
function account() {
let token = webMetaData.accessToken;
if (token == null) {
__zqChat.getResource("https://hoppinzq.com/chat/static/json/apiKeys.json", function (data) {
let keys = data.data;
$.each(keys, function (index, key) {
$(".api-key-list").append(`<tr>
<td>${key.publishable == "ture" ? "Publish key" : "Secret key"}</td>
<td>${key.sensitive_id}</td>
<td>${__zqChat.getRealDate(parseInt(key.created) * 1000)}</td>
<td>${key.last_use == null ? "未使用" : __zqChat.getRealDate(parseInt(key.last_use) * 1000)}</td>
</tr>`)
})
})
__zqChat.getResource("https://hoppinzq.com/chat/static/json/billing.json", function (data) {
$("#billing").append("$" + data.total_granted + "/$" + data.total_available);
let grants = data.grants.data;
$.each(grants, function (index, grant) {
$(".account-billing").append(`<tr>
<td><a href="javascript:;">${grant.id}</a></td>
<td>$${grant.grant_amount}</td>
<td>$${grant.used_amount}</td>
<td>${__zqChat.getRealDate(parseInt(grant.effective_at) * 1000)}</td>
<td>${__zqChat.getRealDate(parseInt(grant.expires_at) * 1000)}</td>
</tr>`)
})
})
} else {
//请求api请看后台代码
}
}
function createImage(prompt,n,size){
$(".image-sc").html("");
$.ajax({
url:`${ip}/v1/images/generations`,
type:"post",
data: JSON.stringify({
"prompt": prompt,
"n": n,
"size": size
}),
beforeSend:function () {
$(".image-sc").append(`<div class="wave">
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>`);
},
contentType: "application/json",
success:function (data) {
if(data.code!=undefined&&data.code==500){
swal("出错了!", data.msg, "error");
$(".image-sc").html("");
}else{
$(".image-sc").html("");
let images=data.data;
$.each(images,function (index,image) {
$(".image-sc").append(`<img class="rounded mt-1" width="256" src="${image.url}" alt="">`);
})
}
},
complete:function () {
resetImageH();
}
})
}
function openAndImage(prompt) {
$(".image-nav").click();
$("#image-prompt").val(prompt);
createImage(prompt,1,"256x256");
}
function openImage(){
$(".image-nav").click();
}
function resetImageH(){
}
</script>
</body>
</html>
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/guzhibin1989/chatgpt-front.git
git@gitee.com:guzhibin1989/chatgpt-front.git
guzhibin1989
chatgpt-front
chatgpt聊天前端源代码
master

搜索帮助