1662 lines
52 KiB
HTML
Executable File
1662 lines
52 KiB
HTML
Executable File
<!DOCTYPE html>
|
||
<html lang="zh">
|
||
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate">
|
||
<meta http-equiv="Pragma" content="no-cache">
|
||
<meta http-equiv="Expires" content="Thu, 01 Jan 1970 00:00:00 GMT">
|
||
<title>新能源智能体</title>
|
||
<link rel="icon" href="./img/logo.png" type="image/x-icon">
|
||
<!-- <script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script> -->
|
||
|
||
<style>
|
||
body {
|
||
margin: 0;
|
||
font-family: "Segoe UI", "PingFang SC", Arial, sans-serif;
|
||
height: 100vh;
|
||
display: flex;
|
||
background: #f0f6fb;
|
||
color: #333;
|
||
width: 100%;
|
||
|
||
}
|
||
|
||
.toast {
|
||
position: fixed;
|
||
top: 20%;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
background: rgba(0, 0, 0, 0.8);
|
||
color: #fff;
|
||
padding: 10px 18px;
|
||
border-radius: 8px;
|
||
font-size: 15px;
|
||
opacity: 0;
|
||
transition: opacity 0.3s ease;
|
||
z-index: 9999;
|
||
}
|
||
|
||
.toast.show {
|
||
opacity: 1;
|
||
}
|
||
|
||
/* 侧边栏 */
|
||
.sidebar {
|
||
width: 240px;
|
||
background: #ffffff;
|
||
border-right: 1px solid #e3eaf2;
|
||
display: flex;
|
||
flex-direction: column;
|
||
transition: all 0.3s ease;
|
||
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.04);
|
||
z-index: 10;
|
||
}
|
||
|
||
.sidebar.collapsed {
|
||
width: 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.sidebar-header {
|
||
padding: 16px;
|
||
padding-left: 20px;
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
color: #0057ff;
|
||
border-bottom: 1px solid #f0f4f8;
|
||
display: flex;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.sidebar-header img {
|
||
width: 24px;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.sidebar-actions {
|
||
padding: 12px;
|
||
border-bottom: 1px solid #f0f4f8;
|
||
}
|
||
|
||
.sidebar-actions button {
|
||
width: 100%;
|
||
padding: 10px;
|
||
border: none;
|
||
border-radius: 8px;
|
||
background: #0057ff;
|
||
color: #fff;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
transition: background 0.2s;
|
||
}
|
||
|
||
.sidebar-actions button:hover {
|
||
background: #0046cc;
|
||
}
|
||
|
||
.chat-list {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.chat-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 12px 16px;
|
||
border-bottom: 1px solid #f7f9fb;
|
||
cursor: pointer;
|
||
transition: background 0.2s;
|
||
text-align: center;
|
||
}
|
||
|
||
.chat-item:hover {
|
||
background: #f2f8fd;
|
||
}
|
||
|
||
.chat-item.active {
|
||
background: #e6f0ff;
|
||
font-weight: bold;
|
||
color: #0057ff;
|
||
}
|
||
|
||
.chat-title {
|
||
flex: 1;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.delete-btn {
|
||
margin-left: 8px;
|
||
color: #aaa;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.delete-btn:hover {
|
||
color: #e74c3c;
|
||
}
|
||
|
||
/* 收起按钮(独立漂浮在左边) */
|
||
.toggle-btn {
|
||
position: absolute;
|
||
top: 10px;
|
||
left: 190px;
|
||
background: #0057ff;
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: 50%;
|
||
width: 40px;
|
||
height: 40px;
|
||
font-size: 18px;
|
||
cursor: pointer;
|
||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||
z-index: 20;
|
||
transition: background 0.2s;
|
||
}
|
||
|
||
.toggle-btn:hover {
|
||
background: #0046cc;
|
||
}
|
||
|
||
/* 右侧聊天区域 */
|
||
.chat-container {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: #f9fcff;
|
||
justify-content: space-between;
|
||
width: calc(100% - 240px)
|
||
}
|
||
|
||
.chat-container .content {
|
||
height: 70%;
|
||
overflow-y: auto;
|
||
scrollbar-width: none;
|
||
/* overflow-y: auto; */
|
||
}
|
||
|
||
.chat-header {
|
||
height: 50px;
|
||
padding: 1px 20px;
|
||
padding-left: 56px;
|
||
background: #fff;
|
||
border-bottom: 1px solid #e3eaf2;
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
color: #0057ff;
|
||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
|
||
display: flex;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.chat-header .userinfo {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: 5px;
|
||
color: #666;
|
||
font-weight: 400;
|
||
font-family: fangsong;
|
||
|
||
}
|
||
|
||
.chat-header .userinfo .logout {
|
||
color: #666;
|
||
font-weight: 400;
|
||
font-family: fangsong;
|
||
/* text-decoration: underline; */
|
||
cursor: pointer
|
||
}
|
||
|
||
.price {
|
||
text-decoration: none;
|
||
}
|
||
|
||
.price:hover,
|
||
.logout:hover {
|
||
color: #999 !important;
|
||
}
|
||
|
||
.chat-header .back {
|
||
display: none;
|
||
}
|
||
|
||
.chat-messages {
|
||
flex: 1;
|
||
padding: 20px;
|
||
overflow-y: auto;
|
||
position: relative;
|
||
height: 400px
|
||
}
|
||
|
||
.message {
|
||
|
||
|
||
max-width: 70%;
|
||
margin-bottom: 16px;
|
||
padding: 12px 16px;
|
||
border-radius: 14px;
|
||
font-size: 16px;
|
||
line-height: 1.5;
|
||
/* white-space: pre-wrap;*/
|
||
white-space: normal;
|
||
word-wrap: break-word;
|
||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||
animation: fadeIn 0.3s ease;
|
||
}
|
||
|
||
.message.user {
|
||
display: block;
|
||
background: #d4e5ff;
|
||
color: #000;
|
||
align-self: flex-end;
|
||
border-bottom-right-radius: 4px;
|
||
|
||
display: block;
|
||
width: fit-content;
|
||
}
|
||
|
||
.message.assistant {
|
||
max-width: 100%;
|
||
background: #fff;
|
||
color: #333;
|
||
align-self: flex-start;
|
||
border: 1px solid #e6eaf0;
|
||
border-bottom-left-radius: 4px;
|
||
}
|
||
|
||
.message img {
|
||
max-width: 200px;
|
||
border-radius: 8px;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.chat-input {
|
||
padding: 12px;
|
||
background: #fff;
|
||
border-top: 1px solid #e3eaf2;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.04);
|
||
}
|
||
|
||
.message.thinking {
|
||
width: auto;
|
||
/* 宽度自适应内容 */
|
||
max-width: 40%;
|
||
/* 限制最大宽度 */
|
||
}
|
||
|
||
.input-row {
|
||
display: flex;
|
||
align-items: center;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
}
|
||
|
||
.none {
|
||
display: none;
|
||
}
|
||
|
||
.input-row .img-row {
|
||
width: 100%;
|
||
min-width: 0px;
|
||
min-height: 0px;
|
||
box-sizing: border-box;
|
||
padding: 10px;
|
||
|
||
}
|
||
|
||
.input-row .img-box .delete-btn {
|
||
position: absolute;
|
||
right: -5px;
|
||
top: -5px;
|
||
|
||
}
|
||
|
||
.input-row .img-box {
|
||
width: 40px;
|
||
position: relative
|
||
}
|
||
|
||
|
||
|
||
.input-row img {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 5px;
|
||
|
||
}
|
||
|
||
|
||
.chat-input textarea {
|
||
flex: 1;
|
||
resize: none;
|
||
padding: 10px;
|
||
border-radius: 8px;
|
||
border: 1px solid #d9e4f0;
|
||
font-size: 14px;
|
||
outline: none;
|
||
background: #f9fcff;
|
||
transition: border 0.2s;
|
||
width: 100%;
|
||
}
|
||
|
||
.chat-input textarea:focus {
|
||
/* border-color: #0057ff; */
|
||
}
|
||
|
||
.chat-input button {
|
||
padding: 10px 16px;
|
||
border: none;
|
||
border-radius: 8px;
|
||
background: #0057ff;
|
||
color: #fff;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
transition: background 0.2s;
|
||
}
|
||
|
||
.chat-input button:hover {
|
||
background: #0046cc;
|
||
}
|
||
|
||
.options-row {
|
||
display: flex;
|
||
gap: 10px;
|
||
align-items: center;
|
||
font-size: 13px;
|
||
}
|
||
|
||
select,
|
||
input[type="file"] {
|
||
font-size: 13px;
|
||
padding: 4px 6px;
|
||
border: 1px solid #d9e4f0;
|
||
border-radius: 6px;
|
||
background: #fff;
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(5px);
|
||
}
|
||
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
|
||
/* 修改后的输入框样式 - 豆包/腾讯元宝风格 */
|
||
.chat-input {
|
||
padding: 16px;
|
||
background: #fff;
|
||
border-top: 1px solid #e8e8e8;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
}
|
||
|
||
.input-row {
|
||
display: flex;
|
||
align-items: flex-end;
|
||
justify-content: flex-end;
|
||
/* 底部对齐 */
|
||
gap: 8px;
|
||
border: 1px solid #e5e5e5;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.input-row .button-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: flex-end;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
width: 100%;
|
||
margin-right: 10px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.input-row .button-row>div {
|
||
cursor: pointer;
|
||
width: 40px;
|
||
height: 40px;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
margin-left: 12px;
|
||
}
|
||
|
||
.chat-input textarea {
|
||
flex: 1;
|
||
resize: none;
|
||
padding: 12px 16px;
|
||
|
||
|
||
font-size: 14px;
|
||
outline: none;
|
||
background: #fff;
|
||
transition: all 0.2s;
|
||
min-height: 44px;
|
||
max-height: 200px;
|
||
box-shadow: none;
|
||
border: none !important;
|
||
box-sizing: border-box
|
||
}
|
||
|
||
.chat-input textarea:focus {
|
||
/* border-color: #0057ff; */
|
||
/* box-shadow: 0 0 0 2px rgba(0, 87, 255, 0.1); */
|
||
}
|
||
|
||
.chat-input button {
|
||
padding: 10px 16px;
|
||
height: 44px;
|
||
border: none;
|
||
border-radius: 8px;
|
||
background: #0057ff;
|
||
color: #fff;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.chat-input button:hover {
|
||
background: #0046cc;
|
||
}
|
||
|
||
/* 文件选择和模型选择样式调整 */
|
||
.options-row {
|
||
display: flex;
|
||
gap: 8px;
|
||
align-items: center;
|
||
font-size: 13px;
|
||
}
|
||
|
||
select,
|
||
input[type="file"] {
|
||
font-size: 13px;
|
||
padding: 6px 8px;
|
||
border: 1px solid #e5e5e5;
|
||
border-radius: 6px;
|
||
background: #fff;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
select:focus,
|
||
input[type="file"]:focus {
|
||
border-color: #0057ff;
|
||
outline: none;
|
||
}
|
||
|
||
#fileInput {
|
||
display: none;
|
||
}
|
||
|
||
.mobilelogo {
|
||
display: none;
|
||
}
|
||
|
||
.userinfo-wrapper {
|
||
display: none;
|
||
}
|
||
|
||
|
||
/* 手机端适配 */
|
||
@media (max-width: 768px) {
|
||
.mobilelogo {
|
||
|
||
display: flex;
|
||
width: 28px;
|
||
height: 28px;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.sidebar {
|
||
/* position: absolute;
|
||
top: 10px; */
|
||
/* display: none; */
|
||
width: 240px;
|
||
background: #ffffff;
|
||
border-right: 1px solid #e3eaf2;
|
||
display: flex;
|
||
flex-direction: column;
|
||
transition: all 0.3s ease;
|
||
box-shadow: 8px 0 60px rgba(0, 0, 0, 0.04);
|
||
z-index: 1000;
|
||
position: absolute;
|
||
top: 10px;
|
||
height: 100%;
|
||
}
|
||
|
||
.sidebar.sidebar.collapsed>.toggle-btn {
|
||
position: fixed;
|
||
right: 10px !important;
|
||
}
|
||
|
||
.chat-container {
|
||
width: 100%;
|
||
height: 100vh;
|
||
}
|
||
|
||
|
||
.chat-input {
|
||
/* position: fixed; */
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 100;
|
||
}
|
||
|
||
.chat-messages {
|
||
padding-bottom: 125px;
|
||
/* height: 200px */
|
||
/* 留出输入框空间 */
|
||
}
|
||
|
||
.chat-header .back {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
margin-right: 20px;
|
||
|
||
}
|
||
|
||
.userinfo-wrapper {
|
||
position: relative;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.chat-container .content {
|
||
overflow-y: auto;
|
||
scrollbar-width: none;
|
||
}
|
||
|
||
/* 按钮样式 */
|
||
.userinfo-toggle {
|
||
padding: 7px 2px;
|
||
border-radius: 9px;
|
||
border: none;
|
||
background: #0057ff;
|
||
color: #fff;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
|
||
transition: background 0.3s;
|
||
max-width: 38px;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
.userinfo-toggle:hover {
|
||
background: #0057ff;
|
||
}
|
||
|
||
/* 折叠面板 */
|
||
.userinfo-panel {
|
||
position: absolute;
|
||
top: 50px;
|
||
right: 0;
|
||
width: 100px;
|
||
background: #fff;
|
||
border-radius: 12px;
|
||
padding: 15px 20px;
|
||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
opacity: 0;
|
||
transform: translateY(-10px);
|
||
pointer-events: none;
|
||
transition: all 0.3s ease;
|
||
z-index: 1000;
|
||
}
|
||
|
||
/* 展开状态 */
|
||
.userinfo-panel.show {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
pointer-events: auto;
|
||
}
|
||
|
||
/* 面板内部元素 */
|
||
.userinfo-panel span,
|
||
.userinfo-panel a {
|
||
padding: 8px 12px;
|
||
border-radius: 8px;
|
||
text-decoration: none;
|
||
color: #333;
|
||
background: #f1f1f1;
|
||
text-align: center;
|
||
transition: background 0.2s;
|
||
}
|
||
|
||
.userinfo-panel span:hover,
|
||
.userinfo-panel a:hover {
|
||
background: #e0e0e0;
|
||
}
|
||
|
||
.userinfo {
|
||
display: none !important;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
.fourquestion {
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: 10px;
|
||
margin-bottom: 20px;
|
||
|
||
}
|
||
|
||
.fourquestion>div {
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: 10px;
|
||
|
||
}
|
||
|
||
.fourquestion .question {
|
||
box-sizing: border-box;
|
||
width: 300px;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
font-size: 21px;
|
||
color: #999;
|
||
border: 1px solid #e5e5e5;
|
||
border-radius: 10px;
|
||
padding: 24px 10px;
|
||
cursor: pointer;
|
||
|
||
|
||
|
||
}
|
||
|
||
.fourquestion .question:hover {
|
||
background-color: #e5e5e5;
|
||
color: #0057ff;
|
||
|
||
|
||
|
||
}
|
||
|
||
.fourquestion .question img {
|
||
width: 35px;
|
||
height: 35px;
|
||
margin-right: 5px;
|
||
|
||
|
||
}
|
||
|
||
.sidequestion {
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex-wrap: wrap;
|
||
width: 100%;
|
||
display: none;
|
||
|
||
}
|
||
|
||
.sidequestion>div {
|
||
width: 100%;
|
||
|
||
}
|
||
|
||
.sidequestion>div .question {
|
||
width: 80%;
|
||
height: 2px;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
font-size: 16px;
|
||
color: #999;
|
||
border: 1px solid #e5e5e5;
|
||
border-radius: 10px;
|
||
padding: 15px -16px !important;
|
||
cursor: pointer;
|
||
|
||
}
|
||
|
||
.stopBtn {
|
||
width: 36px;
|
||
height: 36px;
|
||
}
|
||
|
||
.none {
|
||
display: none;
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
|
||
<!-- 左侧侧边栏 -->
|
||
<div class="sidebar" id="sidebar">
|
||
<button class="toggle-btn" id="toggleBtn" onclick="toggleSidebar()">☰</button>
|
||
<div class="sidebar-header"><img src="./img/logo.png">会话列表</div>
|
||
<div class="sidebar-actions">
|
||
<button onclick="newChat()">+ 新建会话</button>
|
||
</div>
|
||
<div class="chat-list" id="chatList"></div>
|
||
<div class="fourquestion sidequestion">
|
||
<div>
|
||
<div class='question' data-value='分析这个场站' data-pre-value="详细分析这个光伏场站,根据图片给出详细的运维方案"><img src="./img/1.png"
|
||
alt="">分析这个场站</div>
|
||
<div class='question' data-value='详细的清洗计划' data-pre-value="如果这个光伏场站需要用无人机清洗怎么做,给出一份详细的计划"><img
|
||
src="./img/4.png" alt="">详细的清洗计划</div>
|
||
</div>
|
||
<div>
|
||
<div class='question' data-value='详细的巡检计划' data-pre-value="如果这个光伏场站需要巡检怎么做,给出一份详细的计划"><img src="./img/2.png"
|
||
alt="">详细的巡检计划</div>
|
||
<div class='question' data-value='详细的割草计划' data-pre-value="如果这个光伏场站需要割草怎么做,给出一份详细的计划"><img src="./img/3.png"
|
||
alt="">详细的割草计划</div>
|
||
</div>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
<!-- 收起按钮 -->
|
||
|
||
|
||
<!-- 右侧聊天区 -->
|
||
<div class="chat-container">
|
||
<div class="chat-header">
|
||
<!-- <div class='back' onclick="handleBack()">
|
||
<svg t="1748925372585" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||
p-id="4688" width="16" height="16">
|
||
<path
|
||
d="M395.21518 513.604544l323.135538-312.373427c19.052938-18.416442 19.052938-48.273447 0-66.660212-19.053961-18.416442-49.910737-18.416442-68.964698 0L291.75176 480.290811c-19.052938 18.416442-19.052938 48.273447 0 66.660212l357.633237 345.688183c9.525957 9.207709 22.01234 13.796214 34.497699 13.796214 12.485359 0 24.971741-4.588505 34.466999-13.82896 19.052938-18.416442 19.052938-48.242747 0-66.660212L395.21518 513.604544z"
|
||
fill="#999" p-id="4689"></path>
|
||
</svg>
|
||
</div> -->
|
||
<div style="
|
||
display: flex;
|
||
justify-content: flex-start;
|
||
align-items: center;
|
||
">
|
||
<img src="./img/logo.png" class="mobilelogo" alt="">
|
||
新能源智能体<span style="font-size:14px">(sataBotAgent)</span>
|
||
</div>
|
||
<div class="userinfo">
|
||
<span class="username"></span>
|
||
<span class="logout" onClick="logout()">退出</span>
|
||
<a class="logout price" href="./modal.html">服务价格</a>
|
||
</div>
|
||
<div class="userinfo-wrapper">
|
||
<!-- 初始按钮 -->
|
||
<button class="userinfo-toggle username" onclick="toggleUserInfo()">用户</button>
|
||
|
||
<!-- 折叠面板 -->
|
||
<div class="userinfo-panel">
|
||
<!-- <span class="username">用户名</span> -->
|
||
<span class="logout" onclick="logout()">退出</span>
|
||
<a class="logout price" href="./modal.html">服务价格</a>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="content">
|
||
<div id="chatMessages" class="chat-messages"></div>
|
||
<div class="fourquestion fourquestionmain">
|
||
<div>
|
||
<div class='question mainauestion' data-value='分析这个场站' data-pre-value="详细分析这个光伏场站,根据图片给出详细的运维方案"><img
|
||
src="./img/1.png" alt="">分析这个场站</div>
|
||
<div class='question mainauestion' data-value='详细的清洗计划' data-pre-value="如果这个光伏场站需要用无人机清洗怎么做,给出一份详细的计划"><img
|
||
src="./img/4.png" alt="">详细的清洗计划</div>
|
||
</div>
|
||
<div>
|
||
<div class='question mainauestion' data-value='详细的巡检计划' data-pre-value="如果这个光伏场站需要巡检怎么做,给出一份详细的计划"><img
|
||
src="./img/2.png" alt="">详细的巡检计划</div>
|
||
<div class='question mainauestion' data-value='详细的割草计划' data-pre-value="如果这个光伏场站需要割草怎么做,给出一份详细的计划"><img
|
||
src="./img/3.png" alt="">详细的割草计划</div>
|
||
</div>
|
||
|
||
|
||
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="chat-input">
|
||
<!-- <div class="options-row">
|
||
|
||
<select id="mmModel">
|
||
<option value="hunyuan-vision">hunyuan-vision</option>
|
||
</select>
|
||
<select id="llModel">
|
||
<option value="hunyuan-api">hunyuan-api</option>
|
||
</select>
|
||
</div> -->
|
||
<div class="input-row">
|
||
<div class="img-row none">
|
||
<div class="img-box">
|
||
<img src="" alt="">
|
||
<span class="delete-btn" onclick="deleteImg()"><svg t="1757836617046" class="icon" viewBox="0 0 1024 1024"
|
||
version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16945" width="16" height="16">
|
||
<path d="M512 512m-512 0a512 512 0 1 0 1024 0 512 512 0 1 0-1024 0Z" fill="#EF4631" p-id="16946">
|
||
</path>
|
||
<path
|
||
d="M733.6 733.6c-16.7 16.7-43.7 16.6-60.2 0.1l-151-151-151 151c-16.6 16.6-43.4 16.6-60.2-0.1-16.7-16.7-16.6-43.7-0.1-60.2l151-151-151-151c-16.6-16.6-16.6-43.4 0.1-60.2 16.7-16.7 43.7-16.6 60.2-0.1l151 151 151-151c16.6-16.6 43.4-16.6 60.2 0.1 16.7 16.7 16.6 43.7 0.1 60.2l-151 151 151 151c16.6 16.6 16.7 43.4-0.1 60.2z"
|
||
fill="#FFFFFF" p-id="16947"></path>
|
||
</svg></span>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
<textarea id="chatInput" rows="1" placeholder="询问任何问题..."></textarea>
|
||
<div class="button-row">
|
||
<!-- <div id="sendFileBtn">
|
||
<input type="file" id="fileInput" /><svg t="1757833755414" class="icon" viewBox="0 0 1024 1024"
|
||
version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14318" width="24" height="24">
|
||
<path
|
||
d="M576 928H192c-52.992 0-96-43.093333-96-96V192c0-52.992 43.093333-96 96-96h640c52.992 0 96 43.093333 96 96v384.064c0 17.706667-14.293333 32-32 32s-32-14.293333-32-32V192.021333c0-17.706667-14.4-32-32-32H192c-17.706667 0-32 14.378667-32 32v639.957334c0 17.706667 14.4 32 32 32h384c17.706667 0 32 14.314667 32 32 0 17.706667-14.293333 32.021333-32 32.021333zM128 693.312a32.064 32.064 0 0 1-22.613333-54.698667l159.402666-159.338666a95.786667 95.786667 0 0 1 110.72-17.984l173.589334 86.805333c12.309333 6.186667 27.093333 3.797333 36.8-5.994667l287.402666-287.445333a32.042667 32.042667 0 0 1 45.290667 45.312L631.210667 587.392a95.786667 95.786667 0 0 1-110.72 18.005333l-173.589334-86.826666a31.616 31.616 0 0 0-36.8 6.016l-159.509333 159.317333c-6.186667 6.314667-14.4 9.386667-22.592 9.386667z m320-277.376c-52.906667 0-96-43.093333-96-96s43.093333-96.021333 96-96.021333 96 43.093333 96 96-43.093333 96.021333-96 96.021333z m0-128c-17.6 0-32 14.378667-32 32 0 17.6 14.4 32 32 32s32-14.4 32-32c0-17.621333-14.4-32-32-32zM768 928c-17.706667 0-32-14.293333-32-32v-192.021333c0-17.706667 14.293333-32 32-32s32 14.293333 32 32v192c0 17.706667-14.293333 32.021333-32 32.021333z m128-128c-7.893333 0-15.701333-2.922667-21.909333-8.725333L768 691.669333l-106.090667 99.712a31.936 31.936 0 0 1-45.226666-1.408 31.957333 31.957333 0 0 1 1.408-45.205333l112.213333-105.386667A48.554667 48.554667 0 0 1 768 621.44c14.72 0 28.501333 6.613333 37.696 17.92l112.213333 105.386667A31.957333 31.957333 0 0 1 896 800z"
|
||
fill="#666666" p-id="14319"></path>
|
||
</svg>
|
||
</div> -->
|
||
<div id="sendFileBtn" style="position: relative; width: 40px; height: 40px; cursor: pointer;">
|
||
<input type="file" id="fileInput" style="position: absolute;
|
||
left: 0; top: 0; width: 100%; height: 100%;
|
||
opacity: 0; cursor: pointer;" capture="camera" />
|
||
<img src="./img/link.jpg" alt="" style="width:24px;height:24px">
|
||
<path
|
||
d="M576 928H192c-52.992 0-96-43.093333-96-96V192c0-52.992 43.093333-96 96-96h640c52.992 0 96 43.093333 96 96v384.064c0 17.706667-14.293333 32-32 32s-32-14.293333-32-32V192.021333c0-17.706667-14.4-32-32-32H192c-17.706667 0-32 14.378667-32 32v639.957334c0 17.706667 14.4 32 32 32h384c17.706667 0 32 14.314667 32 32 0 17.706667-14.293333 32.021333-32 32.021333zM128 693.312a32.064 32.064 0 0 1-22.613333-54.698667l159.402666-159.338666a95.786667 95.786667 0 0 1 110.72-17.984l173.589334 86.805333c12.309333 6.186667 27.093333 3.797333 36.8-5.994667l287.402666-287.445333a32.042667 32.042667 0 0 1 45.290667 45.312L631.210667 587.392a95.786667 95.786667 0 0 1-110.72 18.005333l-173.589334-86.826666a31.616 31.616 0 0 0-36.8 6.016l-159.509333 159.317333c-6.186667 6.314667-14.4 9.386667-22.592 9.386667z m320-277.376c-52.906667 0-96-43.093333-96-96s43.093333-96.021333 96-96.021333 96 43.093333 96 96-43.093333 96.021333-96 96.021333z m0-128c-17.6 0-32 14.378667-32 32 0 17.6 14.4 32 32 32s32-14.4 32-32c0-17.621333-14.4-32-32-32zM768 928c-17.706667 0-32-14.293333-32-32v-192.021333c0-17.706667 14.293333-32 32-32s32 14.293333 32 32v192c0 17.706667-14.293333 32.021333-32 32.021333z m128-128c-7.893333 0-15.701333-2.922667-21.909333-8.725333L768 691.669333l-106.090667 99.712a31.936 31.936 0 0 1-45.226666-1.408 31.957333 31.957333 0 0 1 1.408-45.205333l112.213333-105.386667A48.554667 48.554667 0 0 1 768 621.44c14.72 0 28.501333 6.613333 37.696 17.92l112.213333 105.386667A31.957333 31.957333 0 0 1 896 800z"
|
||
fill="#666666" p-id="14319"></path>
|
||
</svg>
|
||
</div>
|
||
<div id="sendBtn">
|
||
<img src="./img/upload.png" alt="" style="width:36px;height:36px">
|
||
<div class="stopBtn none" id="stopBtn">
|
||
<svg t="1762735469119" class="icon" viewBox="0 0 1024 1024" version="1.1"
|
||
xmlns="http://www.w3.org/2000/svg" p-id="4603" width="36" height="36">
|
||
<path
|
||
d="M512 947.456A435.456 435.456 0 1 1 947.456 512 435.456 435.456 0 0 1 512 947.456z m0.4096-81.3056A353.8432 353.8432 0 1 0 158.72 512.3072a353.8944 353.8944 0 0 0 353.6896 353.8432zM407.7568 386.8672h208.4864a20.8384 20.8384 0 0 1 20.8384 20.7872v208.5888a20.8384 20.8384 0 0 1-20.8384 20.7872H407.7568a20.8384 20.8384 0 0 1-20.8384-20.7872V407.7568a20.8896 20.8896 0 0 1 20.8384-20.8896z"
|
||
p-id="4604"></path>
|
||
</svg>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
<script src="./marked.min.js"></script>
|
||
<!-- <script>
|
||
// 开启 vConsole 调试面板
|
||
var vConsole = new VConsole();
|
||
|
||
console.log("✅ vConsole 已经启动");
|
||
</script> -->
|
||
|
||
|
||
|
||
|
||
|
||
<script>
|
||
const sidebar = document.getElementById("sidebar");
|
||
const chatMessages = document.getElementById("chatMessages");
|
||
const chatInput = document.getElementById("chatInput");
|
||
const fileInput = document.getElementById("fileInput");
|
||
const chatList = document.getElementById("chatList");
|
||
let controller = null;
|
||
let sessIdList = [];
|
||
let isUpload = {};
|
||
let hasImage = false;
|
||
let isPre = false;//是否点击了预设问题
|
||
// let sessIdList = JSON.parse(localStorage.getItem("sessId")) || [];
|
||
let sessId;
|
||
let activeChatId = '';
|
||
const params = new URLSearchParams(window.location.search);
|
||
console.log(params.get("userId"), 644);
|
||
const encodedUserId = params.get("userId");
|
||
const from = params.get("from");
|
||
const code = params.get("code");
|
||
const appid = "wx364b8ebf17fe45fe";
|
||
// 回调地址(必须和公众号后台配置的网页授权域名一致)
|
||
const redirect_uri = encodeURIComponent("http://ai.satabot.com");
|
||
// 授权方式:snsapi_base(静默) 或 snsapi_userinfo(需要用户确认)
|
||
const scope = "snsapi_userinfo";
|
||
// 自定义参数,授权后会原样返回
|
||
const state = "12399";
|
||
|
||
|
||
|
||
// ✅ 先 URL 解码,再 Base64 解码,再 UTF-8 解码
|
||
const userId = decodeURIComponent(Number(escape(atob(encodedUserId))));
|
||
setCookie("userId", userId);
|
||
getUserName(userId);
|
||
// const userId = encodedUserId;
|
||
let sendParam = {
|
||
imageBase64: '',
|
||
userId: userId,
|
||
sessionId: '',
|
||
userPrompt: ''
|
||
}
|
||
if (isMobile()) {
|
||
toggleSidebar();
|
||
}
|
||
console.log(isWeChat(), 999, code)
|
||
// if (isWeChat()) {
|
||
// if (code) {
|
||
// // gotoWeiXin();
|
||
// // 用 code 换取 openid 和 access_token
|
||
// fetch(`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${appid}&secret=SECRET&code=CODE&grant_type=authorization_code?code=${code}`)
|
||
// .then(res => res.json())
|
||
// .then(data => {
|
||
// // data 里返回 userId / openid
|
||
|
||
// setCookie("userId", data.userId);
|
||
// window.location.href = "/"; // 回到首页
|
||
// });
|
||
// } else {
|
||
// // 没拿到 code,再次走 gotoWeiXin()
|
||
// gotoWeiXin();
|
||
// }
|
||
|
||
// } else {
|
||
if (getCookie("userId")) {
|
||
getSessionList();
|
||
} else {
|
||
deleteCookie('userId');
|
||
window.location.href = 'http://ri.satabot.com/#/login?goRemote=1&clear=1';
|
||
}
|
||
// }
|
||
|
||
|
||
const questions = document.querySelectorAll(".question");
|
||
// 获取到用户名称
|
||
function getUserName(userId) {
|
||
try {
|
||
fetch("http://1.95.137.212:30009/user", {
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "application/json"
|
||
},
|
||
body: JSON.stringify({
|
||
userId,
|
||
|
||
})
|
||
}).then(res => res.json()).then(data => {
|
||
if (data.code === 0) {
|
||
document.querySelectorAll('.username').forEach((e) => {
|
||
e.textContent = data.userName;
|
||
})
|
||
|
||
console.log("成功找到该用户:", data.userName, data.userId);
|
||
|
||
} else {
|
||
console.error("未找到该用户:",);
|
||
}
|
||
})
|
||
|
||
|
||
|
||
} catch (err) {
|
||
console.error("请求异常:", err);
|
||
}
|
||
}
|
||
|
||
questions.forEach(q => {
|
||
|
||
q.addEventListener("click", () => {
|
||
if (q.classList.contains("mainauestion")) {
|
||
// q.style.display = 'none';
|
||
// if (!isMobile()) {
|
||
document.querySelector('.fourquestionmain').style.display = 'none';
|
||
document.querySelector('.sidequestion').style.display = 'flex';
|
||
document.querySelector('.chat-messages').style.height = '100%';
|
||
// }
|
||
|
||
}
|
||
isPre = true;
|
||
console.log(isUpload, 88)
|
||
if (!sendParam.imageBase64 && !fileInput.files.length) {
|
||
// if (!isUpload[activeChatId]) {
|
||
if (!hasImage) {
|
||
showToast("请先上传图片");
|
||
// alert("请先上传图片");
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
}
|
||
const value = q.getAttribute("data-value");
|
||
const preValue = q.getAttribute("data-pre-value");
|
||
sendParam.userPrompt = preValue;
|
||
chatInput.value = value; // ✅ 把预设问题填入输入框
|
||
chatInput.focus(); // 可选:让光标聚焦输入框
|
||
sendMessage(true);
|
||
});
|
||
});
|
||
function isMobile() {
|
||
return /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||
}
|
||
|
||
// getHistory();
|
||
function setCookie(name, value, days = 7) {
|
||
const d = new Date();
|
||
d.setTime(d.getTime() + days * 24 * 60 * 60 * 1000);
|
||
const expires = "expires=" + d.toUTCString();
|
||
document.cookie = `${name}=${encodeURIComponent(value)}; ${expires}; path=/`;
|
||
}
|
||
function getCookie(name) {
|
||
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
|
||
if (match) return decodeURIComponent(match[2]);
|
||
return null;
|
||
}
|
||
function deleteCookie(name) {
|
||
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
|
||
}
|
||
function handleBack() {
|
||
RPJavaFragmentInterface.navigateTo("StatusFragment");
|
||
|
||
}
|
||
|
||
function generateUniqueId16() {
|
||
// 当前时间戳(毫秒,取后几位)
|
||
const timestamp = Date.now().toString().slice(-10);
|
||
// 生成 6 位随机数
|
||
const random = Math.floor(Math.random() * 1e6).toString().padStart(6, "0");
|
||
return timestamp + random; // 一共 16 位
|
||
}
|
||
function logout() {
|
||
deleteCookie('userId');
|
||
window.location.href = 'http://ri.satabot.com/#/login?goRemote=1&clear=1';
|
||
}
|
||
|
||
function createSession(userId, sessionId) {
|
||
try {
|
||
fetch("http://1.95.137.212:30009/session", {
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "application/json"
|
||
},
|
||
body: JSON.stringify({
|
||
userId,
|
||
sessionId,
|
||
|
||
})
|
||
}).then(res => res.json()).then(data => {
|
||
if (data.code === 0) {
|
||
hasImage = false;
|
||
console.log("会话创建成功:", data.message);
|
||
} else {
|
||
console.error("创建失败:", data.error);
|
||
}
|
||
})
|
||
|
||
|
||
|
||
} catch (err) {
|
||
console.error("请求异常:", err);
|
||
}
|
||
}
|
||
function showToast(message) {
|
||
// 创建元素
|
||
const toast = document.createElement("div");
|
||
toast.className = "toast";
|
||
toast.innerText = message;
|
||
document.body.appendChild(toast);
|
||
|
||
// 显示
|
||
setTimeout(() => {
|
||
toast.classList.add("show");
|
||
}, 10);
|
||
|
||
// 2 秒后自动消失
|
||
setTimeout(() => {
|
||
toast.classList.remove("show");
|
||
setTimeout(() => toast.remove(), 300); // 动画结束后移除
|
||
}, 2000);
|
||
}
|
||
function scrollToBottom() {
|
||
const chatMessages = document.getElementById("chatMessages");
|
||
if (!chatMessages) return;
|
||
|
||
requestAnimationFrame(() => {
|
||
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||
});
|
||
}
|
||
|
||
|
||
// function scrollToBottom() {
|
||
// const chatMessages = document.getElementById("chatMessages");
|
||
// setTimeout(() => {
|
||
// chatMessages.scrollTop = chatMessages.scrollHeight;
|
||
// chatMessages.bottom = '0px';
|
||
// }, 0);
|
||
// }
|
||
const panel = document.querySelector('.userinfo-panel');
|
||
const toggleButton = document.querySelector('.userinfo-toggle');
|
||
function toggleUserInfo() {
|
||
|
||
panel.classList.toggle('show');
|
||
}
|
||
|
||
document.addEventListener('click', (e) => {
|
||
if (!toggleButton.contains(e.target) && !panel.contains(e.target)) {
|
||
panel.classList.remove('show');
|
||
}
|
||
});
|
||
|
||
// 阻止点击面板本身关闭
|
||
panel.addEventListener('click', (e) => {
|
||
e.stopPropagation();
|
||
});
|
||
|
||
|
||
|
||
function renderChatList(isNew) {
|
||
chatList.innerHTML = '';
|
||
|
||
if (!sessIdList || sessIdList.length == 0) {
|
||
chatMessages.innerHTML = "";
|
||
return;
|
||
}
|
||
// if (isNew == "new") {
|
||
activeChatId = sessIdList[sessIdList.length - 1].sessId;
|
||
// } else {
|
||
// activeChatId = sessIdList[0];
|
||
// }
|
||
sendParam.sessionId = activeChatId;
|
||
getHistory();
|
||
sessIdList.forEach((item, index) => {
|
||
console.log(item, activeChatId);
|
||
|
||
const item1 = document.createElement("div");
|
||
item1.setAttribute("data-sessionid", item.sessId);
|
||
item1.className = "chat-item" + (activeChatId == item.sessId ? " active" : "");
|
||
const title = document.createElement("div");
|
||
title.className = "chat-title";
|
||
if (item.title) {
|
||
title.textContent = item.title;
|
||
} else {
|
||
title.textContent = `新对话${index + 1}`;
|
||
}
|
||
|
||
item1.onclick = () => switchChat(item.sessId);
|
||
|
||
const del = document.createElement("span");
|
||
del.className = "delete-btn";
|
||
del.textContent = "✕";
|
||
del.onclick = (e) => {
|
||
e.stopPropagation();
|
||
deleteChat(item.sessId);
|
||
};
|
||
item1.appendChild(title);
|
||
item1.appendChild(del);
|
||
chatList.appendChild(item1);
|
||
})
|
||
|
||
}
|
||
// bool 是否新创建的
|
||
function renderMessages(data, bool) {
|
||
|
||
|
||
chatMessages.innerHTML = "";
|
||
if (bool || !data || !data.length) {
|
||
|
||
return;
|
||
}
|
||
data.forEach(msg => {
|
||
if (msg.image_base64) {
|
||
hasImage = true; // 只要有一个不为空,就置为 true
|
||
}
|
||
addMessage(msg.content, msg.role, msg.image_base64);
|
||
});
|
||
setTimeout(scrollToBottom, 0);
|
||
}
|
||
// 内容 角色 图片 创造时间
|
||
function addMessage(content = '', role = "assistant", imgUrl = null, time = null) {
|
||
const msg = document.createElement("div");
|
||
msg.className = `message ${role}`;
|
||
if (time) {
|
||
const timeNode = document.createElement("div");
|
||
timeNode.textContent = time;
|
||
timeNode.style.fontSize = "12px";
|
||
timeNode.style.color = "#999";
|
||
timeNode.style.marginTop = "4px";
|
||
// msg.appendChild(timeNode);
|
||
}
|
||
// 如果有文字内容,先创建文字节点
|
||
if (content) {
|
||
const textNode = document.createElement("div");
|
||
textNode.innerHTML = marked.parse(content);
|
||
msg.appendChild(textNode);
|
||
}
|
||
|
||
// 如果有图片,创建图片节点
|
||
if (imgUrl) {
|
||
const img = document.createElement("img");
|
||
img.src = imgUrl;
|
||
img.style.marginTop = content ? "8px" : "0"; // 如果有文字,图片加一点间距
|
||
msg.appendChild(img);
|
||
}
|
||
|
||
// 如果有时间,可以显示
|
||
|
||
chatMessages.appendChild(msg);
|
||
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||
}
|
||
|
||
|
||
function sendMessage(isPre) {
|
||
console.log("发送消息1122");
|
||
const sendBtnImg = document.querySelector('#sendBtn img');
|
||
const stopBtn = document.querySelector('#stopBtn');
|
||
|
||
// 2. 先判断 stopBtn 的状态,再控制 sendBtn img(逻辑更清晰)
|
||
|
||
if (!activeChatId) {
|
||
newChat();
|
||
}
|
||
// if (sessIdList.length == 0) {
|
||
// return;
|
||
// }
|
||
|
||
ifSessionId = true;
|
||
const text = chatInput.value.trim();
|
||
if (!text && !fileInput.files.length && !sendParam.imageBase64) return;
|
||
|
||
if (text) addMessage(text, "user");
|
||
let imgUrl = '';
|
||
if (sendParam.imageBase64) {
|
||
imgUrl = sendParam.imageBase64;
|
||
hasImage = true;
|
||
if (fileInput.files[0]) {
|
||
const file = fileInput.files[0];
|
||
const url = URL.createObjectURL(file);
|
||
addMessage('', "user", url);
|
||
} else {
|
||
addMessage('', "user", sendParam.imageBase64);
|
||
sendParam.imageBase64 = '';
|
||
}
|
||
|
||
fileInput.value = "";
|
||
}
|
||
if (!isPre) {
|
||
sendParam.userPrompt = text;
|
||
} else {
|
||
|
||
}
|
||
|
||
chatInput.value = "";
|
||
if (controller) {
|
||
controller.abort();
|
||
controller = null;
|
||
|
||
}
|
||
if (!sendBtnImg.classList.contains('none')) {
|
||
sendBtnImg.classList.add('none');
|
||
stopBtn.classList.remove('none')
|
||
}
|
||
getAiResponse(imgUrl);
|
||
}
|
||
|
||
const getAiResponse = async (img) => {
|
||
deleteImg();
|
||
const aiMsg = { role: "assistant", content: "", isImage: false };
|
||
const msgDiv = document.createElement("div");
|
||
msgDiv.className = "message assistant";
|
||
msgDiv.textContent = '思考中';
|
||
let dots = 0;
|
||
const interval = setInterval(() => {
|
||
dots = (dots + 1) % 4; // 0,1,2,3
|
||
msgDiv.textContent = '思考中' + '.'.repeat(dots);
|
||
}, 500);
|
||
|
||
msgDiv.className = "message assistant thinking ";
|
||
chatMessages.appendChild(msgDiv);
|
||
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||
sessId = sendParam.sessionId;
|
||
sendParam.imageBase64 = img;
|
||
// sendParam.userId= encodedUserId;
|
||
sendParam.userId = decodeURIComponent(Number(escape(atob(encodedUserId))));
|
||
// ✅ 创建 AbortController
|
||
controller = new AbortController();
|
||
const res = await fetch("http://1.95.137.212:30009/analyze", {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(sendParam),
|
||
signal: controller.signal, // ✅ 加上 signal
|
||
}).catch(err => {
|
||
console.log("✅ 流被中断:", err.name);
|
||
return null;
|
||
});
|
||
if (!res) return; // 流已中断则直接退出
|
||
|
||
|
||
sendParam.imageBase64 = '';
|
||
|
||
const reader = res.body.getReader();
|
||
const decoder = new TextDecoder("utf-8");
|
||
let buffer = "";
|
||
msgDiv.classList.remove("thinking");
|
||
clearInterval(interval);
|
||
|
||
while (true) {
|
||
const { done, value } = await reader.read();
|
||
console.log(done, value, 'done')
|
||
if (done) {
|
||
const sendBtnImg = document.querySelector('#sendBtn img');
|
||
const stopBtn = document.querySelector('#stopBtn');
|
||
sendBtnImg.classList.add('none');
|
||
stopBtn.classList.remove('none');
|
||
break;
|
||
};
|
||
buffer += decoder.decode(value, { stream: true });
|
||
|
||
let lines = buffer.split("\n");
|
||
buffer = lines.pop();
|
||
|
||
for (let line of lines) {
|
||
line = line.trim();
|
||
if (!line.startsWith("data:")) continue;
|
||
|
||
const data = line.slice(5).trim();
|
||
console.log("完成回答", data)
|
||
if (data == "[DONE]") {
|
||
console.log("完成回答")
|
||
// 更新聊天滚动条
|
||
const sendBtnImg = document.querySelector('#sendBtn img');
|
||
const stopBtn = document.querySelector('#stopBtn');
|
||
sendBtnImg.classList.remove('none');
|
||
stopBtn.classList.add('none');
|
||
setTimeout(scrollToBottom, 0); // chatMessages.scrollTop = chatMessages.scrollHeight;
|
||
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const obj = JSON.parse(data);
|
||
// if (obj.content && obj.type != 'title') {
|
||
// // 每次追加内容到 AI 消息
|
||
// aiMsg.content += obj.content;
|
||
// msgDiv.innerHTML = marked.parse(aiMsg.content);
|
||
// // msgDiv.textContent = aiMsg.content;
|
||
// chatMessages.scrollTop = chatMessages.scrollHeight;
|
||
// }
|
||
if (obj.content && obj.type !== "title") {
|
||
for (const char of obj.content) {
|
||
await new Promise(r => setTimeout(r, 5)); // 控制字速
|
||
aiMsg.content += char;
|
||
msgDiv.innerHTML = marked.parse(aiMsg.content);
|
||
|
||
// chatMessages.scrollTop = chatMessages.scrollHeight;
|
||
setTimeout(scrollToBottom, 0);
|
||
}
|
||
}
|
||
if (obj.content && obj.type == 'title') {
|
||
const chatItem = document.querySelector(`.chat-item[data-sessionid="${sessId}"]`);
|
||
if (chatItem) {
|
||
const chatTitle = chatItem.querySelector('.chat-title');
|
||
if (chatTitle) {
|
||
chatTitle.textContent = obj.content; // 设置标题
|
||
}
|
||
}
|
||
}
|
||
|
||
} catch (err) {
|
||
console.error("JSON parse error", data);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
function newChat() {
|
||
const id = generateUniqueId16();
|
||
sessIdList.push({ sessId: id, title: "新对话" });
|
||
createSession(userId, id)
|
||
const chat = [{
|
||
id,
|
||
title: "新对话 " + (sessIdList.length),
|
||
messages: { role: "assistant", content: "👋 新会话已创建,请输入问题。", image_base64: '' }
|
||
}];
|
||
activeChatId = id;
|
||
ifSessionId = true;
|
||
sessId = id;
|
||
sendParam.sessionId = sessId;
|
||
renderMessages([chat[0].messages], true);
|
||
renderChatList('new');
|
||
}
|
||
|
||
function switchChat(id) {
|
||
activeChatId = id;
|
||
sendParam.sessionId = id;
|
||
const items = document.querySelectorAll(".chat-item");
|
||
items.forEach(item => {
|
||
if (item.dataset.sessionid === id) {
|
||
item.classList.add("active");
|
||
} else {
|
||
item.classList.remove("active");
|
||
}
|
||
});
|
||
|
||
getHistory();
|
||
// renderChatList();
|
||
|
||
}
|
||
const deleteSession = (sessionId, userId) => {
|
||
try {
|
||
fetch(`http://1.95.137.212:30009/session?sessionId=${sessionId}&userId=${userId}`, {
|
||
method: "DELETE"
|
||
}).then(res => res.json()).then(data => {
|
||
if (data.code === 0) {
|
||
getSessionList();
|
||
renderChatList();
|
||
|
||
console.log("删除成功:", data.message);
|
||
} else {
|
||
console.error("删除失败:", data.error);
|
||
}
|
||
})
|
||
|
||
|
||
} catch (err) {
|
||
console.error("请求异常:", err);
|
||
}
|
||
}
|
||
|
||
|
||
function deleteChat(id) {
|
||
// sessIdList = sessIdList.filter(item => item !== id);
|
||
// localStorage.setItem("sessId", JSON.stringify(sessIdList));
|
||
deleteSession(id, sendParam.userId)
|
||
|
||
}
|
||
|
||
|
||
function handleSendFile() {
|
||
console.log("选择文件");
|
||
// 触发隐藏的 input 点击
|
||
document.getElementById("fileInput").click();
|
||
}
|
||
|
||
// 监听文件选择
|
||
document.getElementById("fileInput").addEventListener("change", function (e) {
|
||
const file = e.target.files[0];
|
||
if (file) {
|
||
console.log("选择的文件:", file.name);
|
||
// 这里可以直接上传
|
||
uploadFile(file);
|
||
}
|
||
});
|
||
|
||
// 示例上传函数(fetch 到后端接口)
|
||
function uploadFile(file) {
|
||
|
||
if (file) {
|
||
console.log("上传文件:", file.name, URL.createObjectURL(file));
|
||
const reader = new FileReader();
|
||
reader.readAsDataURL(file);
|
||
|
||
reader.onload = async function () {
|
||
console.log(reader.result)
|
||
sendParam.imageBase64 = reader.result;
|
||
document.querySelector(".img-row").classList.remove("none");
|
||
document.querySelector(".img-row img").src = sendParam.imageBase64;
|
||
isUpload[activeChatId] = true;
|
||
}
|
||
// document.getElementById("rawImg").src = URL.createObjectURL(file);
|
||
}
|
||
}
|
||
function deleteImg() {
|
||
document.querySelector(".img-row").classList.add("none");
|
||
sendParam.imageBase64 = '';
|
||
document.querySelector(".img-row img").src = '';
|
||
}
|
||
|
||
chatInput.addEventListener("keydown", function (e) {
|
||
if (e.key === "Enter" && !e.shiftKey) { // 按下回车且未按Shift
|
||
e.preventDefault(); // 阻止换行
|
||
sendMessage(); // 调用发送函数
|
||
}
|
||
});
|
||
document.querySelector("#sendBtn img").addEventListener("click", function () {
|
||
console.log("发送信息11")
|
||
sendMessage();
|
||
|
||
});
|
||
document.getElementById("sendFileBtn").addEventListener("click", function () {
|
||
handleSendFile()
|
||
});
|
||
// getHistory();
|
||
// renderChatList("new");
|
||
|
||
// sendParam.sessionId = "7906661519458367";
|
||
// 调用获取历史记录的接口
|
||
function getHistory() {
|
||
// sendParam.userId = encodedUserId;
|
||
fetch(`http://1.95.137.212:30009/history?sessionId=${sendParam.sessionId}`, {
|
||
// fetch(`http://1.95.137.212:30008/history?sessionId=${sendParam.sessionId}`, {
|
||
method: "GET",
|
||
// headers: { "Content-Type": "application/json" },
|
||
// credentials: 'include', // 发送 cookie
|
||
// body: JSON.stringify(sendParam),
|
||
}).then(res => res.json()).then(data => {
|
||
// chats = data.messages;
|
||
// renderChatList();
|
||
renderMessages(data.messages)
|
||
|
||
})
|
||
}
|
||
// sessIdList
|
||
|
||
|
||
function isWeChat() {
|
||
return /MicroMessenger/i.test(navigator.userAgent);
|
||
}
|
||
// function getCookie(name) {
|
||
// const value = `; ${document.cookie}`;
|
||
// const parts = value.split(`; ${name}=`);
|
||
// if (parts.length === 2) return parts.pop().split(';').shift();
|
||
// return null;
|
||
// }
|
||
// gotoWeiXin();
|
||
function gotoWeiXin() {
|
||
console.log(isWeChat(), 8888, navigator.userAgent);
|
||
|
||
const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`;
|
||
// 拼接完整的授权链接
|
||
// const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`;
|
||
// 跳转到微信授权
|
||
console.log("跳转链接:", authUrl);
|
||
window.location.href = authUrl;
|
||
|
||
}
|
||
|
||
// if(from=="weixin"){
|
||
// gotoWeiXin();
|
||
// }else{
|
||
|
||
// }
|
||
// if (!isWeChat()) {
|
||
|
||
|
||
// } else {
|
||
// gotoWeiXin();
|
||
// }
|
||
|
||
|
||
function getSessionList() {
|
||
|
||
sendParam.userId = userId;
|
||
fetch(`http://1.95.137.212:30009/sessions?userId=${sendParam.userId}`, {
|
||
// fetch(`http://1.95.137.212:30008/history?sessionId=${sendParam.sessionId}`, {
|
||
method: "GET",
|
||
// headers: { "Content-Type": "application/json" },
|
||
// credentials: 'include', // 发送 cookie
|
||
// body: JSON.stringify(sendParam),
|
||
}).then(res => res.json()).then(data => {
|
||
console.log(data, 8777)
|
||
if (data.code == 300) {
|
||
// window.location.href='http://localhost/#/login?goRemote=1 '
|
||
window.location.href = data.error;
|
||
return;
|
||
}
|
||
sessIdList = data.sessions;
|
||
renderChatList();
|
||
console.log(data, 8777)
|
||
// chats = data.messages;
|
||
// renderChatList();
|
||
// renderMessages(data.messages)
|
||
|
||
})
|
||
}
|
||
function toggleSidebar() {
|
||
sidebar.classList.toggle("collapsed");
|
||
const toggleBtn = document.getElementById("toggleBtn");
|
||
if (sidebar.classList.contains("collapsed")) {
|
||
toggleBtn.style.left = "10px"; // 收起后
|
||
} else {
|
||
toggleBtn.style.left = "190px"; // 展开后
|
||
}
|
||
}
|
||
document.getElementById("stopBtn").addEventListener("click", () => {
|
||
const sendBtnImg = document.querySelector('#sendBtn img');
|
||
const stopBtn = document.querySelector('#stopBtn');
|
||
if (controller) {
|
||
controller.abort();
|
||
controller = null;
|
||
if (sendBtnImg.classList.contains('none')) {
|
||
sendBtnImg.classList.remove('none');
|
||
stopBtn.classList.add('none')
|
||
}
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
|
||
</html> |