mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-03-03 00:40:45 +08:00
Merge pull request #2593 from zhayujie/feat-web-ui
feat: web ui channel optimization
This commit is contained in:
@@ -197,27 +197,54 @@
|
||||
}
|
||||
|
||||
.user-container {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin: 10px 0;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.user-container .message-container {
|
||||
flex-direction: row-reverse;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.user-container .avatar {
|
||||
margin-left: 15px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.user-container .message-content {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.user-container .message {
|
||||
background-color: var(--bot-msg-bg);
|
||||
border-radius: 10px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.bot-container .message {
|
||||
background-color: var(--bot-msg-bg);
|
||||
border-radius: 10px 10px 10px 0;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 2px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
background-color: #e0e0e0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 15px;
|
||||
flex-shrink: 0;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.bot-avatar {
|
||||
background-color: #10a37f;
|
||||
color: white;
|
||||
margin-top: 4px; /* 微调头像位置,使其与文本更好地对齐 */
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
@@ -226,17 +253,24 @@
|
||||
}
|
||||
|
||||
.message-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
line-height: 1.6;
|
||||
padding-top: 2px;
|
||||
text-align: left;
|
||||
padding-top: 0; /* 移除顶部内边距 */
|
||||
}
|
||||
|
||||
.bot-container .message-content {
|
||||
align-items: flex-start;
|
||||
margin-top: 0; /* 确保没有顶部外边距 */
|
||||
}
|
||||
|
||||
.message {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
border-radius: 10px;
|
||||
margin-top: 0; /* 移除顶部外边距 */
|
||||
margin-bottom: 8px;
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
line-height: 1.3;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.message p {
|
||||
@@ -300,7 +334,20 @@
|
||||
.timestamp {
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-light);
|
||||
margin-top: 5px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
/* 为机器人消息的时间戳添加左对齐 */
|
||||
.bot-container .timestamp {
|
||||
align-self: flex-start;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
/* 为用户消息的时间戳添加右对齐 */
|
||||
.user-container .timestamp {
|
||||
align-self: flex-end;
|
||||
padding-right: 2px;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
#input-container {
|
||||
@@ -519,6 +566,8 @@
|
||||
position: relative;
|
||||
top: -5px;
|
||||
left: -10px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.typing-indicator span {
|
||||
@@ -571,6 +620,30 @@
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 基础消息样式 */
|
||||
.message {
|
||||
border-radius: 10px;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
/* 用户消息样式 */
|
||||
.user-container .message {
|
||||
background-color: var(--bot-msg-bg);
|
||||
border-radius: 10px;
|
||||
margin-bottom: 8px;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
/* 机器人消息样式 */
|
||||
.bot-container .message {
|
||||
background-color: var(--bot-msg-bg);
|
||||
border-radius: 10px 10px 10px 0;
|
||||
margin-bottom: 8px;
|
||||
padding: 0px 16px 12px 16px;
|
||||
margin-top: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -689,121 +762,10 @@
|
||||
clearChat();
|
||||
});
|
||||
|
||||
// 清空聊天记录并显示欢迎屏幕
|
||||
function clearChat() {
|
||||
// 清空消息区域
|
||||
messagesDiv.innerHTML = '';
|
||||
|
||||
// 创建欢迎屏幕
|
||||
const newWelcomeScreen = document.createElement('div');
|
||||
newWelcomeScreen.id = 'welcome-screen';
|
||||
newWelcomeScreen.innerHTML = `
|
||||
<h1 id="welcome-title">AI 助手</h1>
|
||||
<p id="welcome-subtitle">我可以回答问题、提供信息或者帮助您完成各种任务</p>
|
||||
|
||||
<div class="examples-container">
|
||||
<div class="example-card">
|
||||
<div class="example-title">解释复杂概念</div>
|
||||
<div class="example-text">用简单的语言解释量子计算</div>
|
||||
</div>
|
||||
<div class="example-card">
|
||||
<div class="example-title">创意写作</div>
|
||||
<div class="example-text">写一个关于未来城市的短篇故事</div>
|
||||
</div>
|
||||
<div class="example-card">
|
||||
<div class="example-title">编程帮助</div>
|
||||
<div class="example-text">如何用Python写一个简单的网络爬虫</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 设置样式
|
||||
newWelcomeScreen.style.display = 'flex';
|
||||
newWelcomeScreen.style.flexDirection = 'column';
|
||||
newWelcomeScreen.style.alignItems = 'center';
|
||||
newWelcomeScreen.style.justifyContent = 'center';
|
||||
newWelcomeScreen.style.height = '100%';
|
||||
newWelcomeScreen.style.textAlign = 'center';
|
||||
newWelcomeScreen.style.padding = '20px';
|
||||
|
||||
// 添加到DOM
|
||||
messagesDiv.appendChild(newWelcomeScreen);
|
||||
|
||||
// 绑定示例卡片事件
|
||||
newWelcomeScreen.querySelectorAll('.example-card').forEach(card => {
|
||||
card.addEventListener('click', function() {
|
||||
const exampleText = this.querySelector('.example-text').textContent;
|
||||
input.value = exampleText;
|
||||
input.dispatchEvent(new Event('input'));
|
||||
input.focus();
|
||||
});
|
||||
});
|
||||
|
||||
// 清空localStorage中的消息 - 使用用户ID作为键
|
||||
localStorage.setItem(`chatMessages_${userId}`, JSON.stringify([]));
|
||||
|
||||
// 在移动设备上关闭侧边栏
|
||||
if (window.innerWidth <= 768) {
|
||||
sidebar.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
// 从localStorage加载消息 - 使用用户ID作为键
|
||||
function loadMessagesFromLocalStorage() {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem(`chatMessages_${userId}`) || '[]');
|
||||
} catch (error) {
|
||||
console.error('Error loading messages from localStorage:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// 保存消息到localStorage - 使用用户ID作为键
|
||||
function saveMessageToLocalStorage(message) {
|
||||
try {
|
||||
const messages = loadMessagesFromLocalStorage();
|
||||
messages.push(message);
|
||||
localStorage.setItem(`chatMessages_${userId}`, JSON.stringify(messages));
|
||||
} catch (error) {
|
||||
console.error('Error saving message to localStorage:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化代码
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 移除原始欢迎屏幕
|
||||
const originalWelcomeScreen = document.getElementById('welcome-screen');
|
||||
if (originalWelcomeScreen) {
|
||||
originalWelcomeScreen.remove();
|
||||
}
|
||||
|
||||
// 清空消息区域,确保不会重复显示消息
|
||||
messagesDiv.innerHTML = '';
|
||||
|
||||
// 加载消息
|
||||
const messages = loadMessagesFromLocalStorage();
|
||||
|
||||
if (messages.length === 0) {
|
||||
// 如果没有消息,显示欢迎屏幕
|
||||
clearChat();
|
||||
} else {
|
||||
// 显示现有消息
|
||||
messages.forEach(msg => {
|
||||
if (msg.role === 'user') {
|
||||
// 使用不保存到localStorage的版本显示消息
|
||||
displayUserMessage(msg.content, new Date(msg.timestamp));
|
||||
} else if (msg.role === 'assistant') {
|
||||
// 使用不保存到localStorage的版本显示消息
|
||||
displayBotMessage(msg.content, new Date(msg.timestamp));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 发送按钮点击事件
|
||||
sendButton.onclick = function() {
|
||||
sendButton.addEventListener('click', function() {
|
||||
sendMessage();
|
||||
};
|
||||
});
|
||||
|
||||
// 输入框按键事件
|
||||
input.addEventListener('keydown', function(event) {
|
||||
@@ -843,6 +805,11 @@
|
||||
// 添加一个等待中的机器人消息
|
||||
const loadingContainer = addLoadingMessage();
|
||||
|
||||
// 清空输入框并重置高度 - 移到这里,确保发送后立即清空
|
||||
input.value = '';
|
||||
input.style.height = '52px';
|
||||
sendButton.disabled = true;
|
||||
|
||||
// 发送到服务器并等待响应
|
||||
fetch('/message', {
|
||||
method: 'POST',
|
||||
@@ -882,11 +849,6 @@
|
||||
// 显示错误消息
|
||||
addBotMessage("抱歉,发生了错误,请稍后再试。", new Date());
|
||||
});
|
||||
|
||||
// 清空输入框并重置高度
|
||||
input.value = '';
|
||||
input.style.height = '52px';
|
||||
sendButton.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1134,6 +1096,86 @@
|
||||
|
||||
// 初始化
|
||||
input.focus();
|
||||
|
||||
// 清空聊天记录并显示欢迎屏幕
|
||||
function clearChat() {
|
||||
// 清空消息区域
|
||||
messagesDiv.innerHTML = '';
|
||||
|
||||
// 创建欢迎屏幕
|
||||
const newWelcomeScreen = document.createElement('div');
|
||||
newWelcomeScreen.id = 'welcome-screen';
|
||||
newWelcomeScreen.innerHTML = `
|
||||
<h1 id="welcome-title">AI 助手</h1>
|
||||
<p id="welcome-subtitle">我可以回答问题、提供信息或者帮助您完成各种任务</p>
|
||||
|
||||
<div class="examples-container">
|
||||
<div class="example-card">
|
||||
<div class="example-title">解释复杂概念</div>
|
||||
<div class="example-text">用简单的语言解释量子计算</div>
|
||||
</div>
|
||||
<div class="example-card">
|
||||
<div class="example-title">创意写作</div>
|
||||
<div class="example-text">写一个关于未来城市的短篇故事</div>
|
||||
</div>
|
||||
<div class="example-card">
|
||||
<div class="example-title">编程帮助</div>
|
||||
<div class="example-text">如何用Python写一个简单的网络爬虫</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 设置样式
|
||||
newWelcomeScreen.style.display = 'flex';
|
||||
newWelcomeScreen.style.flexDirection = 'column';
|
||||
newWelcomeScreen.style.alignItems = 'center';
|
||||
newWelcomeScreen.style.justifyContent = 'center';
|
||||
newWelcomeScreen.style.height = '100%';
|
||||
newWelcomeScreen.style.textAlign = 'center';
|
||||
newWelcomeScreen.style.padding = '20px';
|
||||
|
||||
// 添加到DOM
|
||||
messagesDiv.appendChild(newWelcomeScreen);
|
||||
|
||||
// 绑定示例卡片事件
|
||||
newWelcomeScreen.querySelectorAll('.example-card').forEach(card => {
|
||||
card.addEventListener('click', function() {
|
||||
const exampleText = this.querySelector('.example-text').textContent;
|
||||
input.value = exampleText;
|
||||
input.dispatchEvent(new Event('input'));
|
||||
input.focus();
|
||||
});
|
||||
});
|
||||
|
||||
// 清空localStorage中的消息 - 使用用户ID作为键
|
||||
localStorage.setItem(`chatMessages_${userId}`, JSON.stringify([]));
|
||||
|
||||
// 在移动设备上关闭侧边栏
|
||||
if (window.innerWidth <= 768) {
|
||||
sidebar.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
// 从localStorage加载消息 - 使用用户ID作为键
|
||||
function loadMessagesFromLocalStorage() {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem(`chatMessages_${userId}`) || '[]');
|
||||
} catch (error) {
|
||||
console.error('Error loading messages from localStorage:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// 保存消息到localStorage - 使用用户ID作为键
|
||||
function saveMessageToLocalStorage(message) {
|
||||
try {
|
||||
const messages = loadMessagesFromLocalStorage();
|
||||
messages.push(message);
|
||||
localStorage.setItem(`chatMessages_${userId}`, JSON.stringify(messages));
|
||||
} catch (error) {
|
||||
console.error('Error saving message to localStorage:', error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -13,7 +13,6 @@ from config import conf
|
||||
import os
|
||||
import mimetypes # 添加这行来处理MIME类型
|
||||
|
||||
|
||||
class WebMessage(ChatMessage):
|
||||
def __init__(
|
||||
self,
|
||||
@@ -57,7 +56,7 @@ class WebChannel(ChatChannel):
|
||||
if reply.type in self.NOT_SUPPORT_REPLYTYPE:
|
||||
logger.warning(f"Web channel doesn't support {reply.type} yet")
|
||||
return
|
||||
|
||||
|
||||
# 获取用户ID
|
||||
user_id = context.get("receiver", None)
|
||||
if not user_id:
|
||||
|
||||
Reference in New Issue
Block a user