@@ -5,7 +5,6 @@ const CONFIG = {
apiUrl : 'https://open.bigmodel.cn/api/paas/v4/chat/completions' ,
apiKey : '2259e33a1357460abe17919aaf81e73d.K44a8LPQTmFM5PKm' ,
model : 'glm-4.5-air' ,
thinkingModel : 'glm-z1-flash' , // 智谱思考模型
maxTokens : 2048
} ;
@@ -180,14 +179,24 @@ function openConversation(id) {
<!-- 功能开关栏 -->
<div class="feature-bar">
<button class="feature-btn thinking-btn ${ enableThinking ? 'active' : '' } " id="thinkingBtn ">
<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg >
<span>深度思考</span >
</butto n>
< button class="feature-btn search-btn ${ enableSearch ? 'active' : '' } " id="searchBtn" >
<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 7 9.5 7 14 9.01 14 9.5 11.99 14 9.5 14z"/></svg >
<span>联网搜索</span >
</butto n>
<div class="feature-left ">
<button class="feature-btn thinking-btn ${ enableThinking ? 'active' : '' } " id="thinkingBtn" >
<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg >
<span>深度思考</spa n>
</ button>
<button class="feature-btn search-btn ${ enableSearch ? 'active' : '' } " id="searchBtn" >
<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 7 9.5 7 14 9.01 14 9.5 11.99 14 9.5 14z"/></svg >
<span>联网搜索</spa n>
</button>
</div>
<div class="feature-right">
<button class="feature-btn nav-btn" id="scrollTopBtn" title="回到顶部">
<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/></svg>
</button>
<button class="feature-btn nav-btn" id="scrollBottomBtn" title="回到底部">
<svg viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z"/></svg>
</button>
</div>
</div>
<div class="input-area">
@@ -265,6 +274,32 @@ function openConversation(id) {
} ) ;
}
// 绑定置顶置底按钮事件
const scrollTopBtn = document . getElementById ( 'scrollTopBtn' ) ;
const scrollBottomBtn = document . getElementById ( 'scrollBottomBtn' ) ;
if ( scrollTopBtn ) {
scrollTopBtn . addEventListener ( 'click' , ( ) => {
if ( messagesContainer ) {
messagesContainer . scrollTo ( {
top : 0 ,
behavior : 'smooth'
} ) ;
}
} ) ;
}
if ( scrollBottomBtn ) {
scrollBottomBtn . addEventListener ( 'click' , ( ) => {
if ( messagesContainer ) {
messagesContainer . scrollTo ( {
top : messagesContainer . scrollHeight ,
behavior : 'smooth'
} ) ;
}
} ) ;
}
// 绑定输入事件
userInput . addEventListener ( 'keydown' , handleKeyDown ) ;
userInput . addEventListener ( 'input' , ( e ) => autoResize ( e . target ) ) ;
@@ -418,8 +453,19 @@ async function streamGenerate(userMsgIndex) {
contentEl . innerHTML = '<span class="streaming-cursor">▌</span>' ;
try {
// 根据开关选择模型
const model = enableThinking ? CONFIG . thinkingModel : CONFIG . model ;
// 构建请求体 - 统一使用 glm-4.5-air, 通过 thinking 参数控制
const requestBody = {
model : CONFIG . model ,
messages : currentConversation . messages . slice ( 0 , aiMessageIndex ) . map ( m => ( {
role : m . role ,
content : m . content
} ) ) ,
max _tokens : CONFIG . maxTokens ,
stream : true ,
thinking : {
type : enableThinking ? 'enabled' : 'disabled'
}
} ;
const response = await fetch ( CONFIG . apiUrl , {
method : 'POST' ,
@@ -427,15 +473,7 @@ async function streamGenerate(userMsgIndex) {
'Content-Type' : 'application/json' ,
'Authorization' : ` Bearer ${ CONFIG . apiKey } `
} ,
body : JSON . stringify ( {
model : model ,
messages : currentConversation . messages . slice ( 0 , aiMessageIndex ) . map ( m => ( {
role : m . role ,
content : m . content
} ) ) ,
max _tokens : CONFIG . maxTokens ,
stream : true
} )
body : JSON . stringify ( requestBody )
} ) ;
if ( ! response . ok ) {
@@ -512,6 +550,58 @@ async function streamGenerate(userMsgIndex) {
currentConversation . updatedAt = Date . now ( ) ;
saveConversations ( ) ;
renderMessages ( ) ;
// 自动总结标题: 第一次对话和每隔5次对话
const totalMessages = currentConversation . messages . length ;
if ( totalMessages === 1 || totalMessages % 5 === 0 ) {
await generateConversationTitle ( ) ;
}
}
}
// 生成对话标题
async function generateConversationTitle ( ) {
if ( ! currentConversation ) return ;
// 构建对话摘要
const conversationText = currentConversation . messages . map ( m =>
` ${ m . role === 'user' ? '用户' : 'AI' } : ${ m . content . slice ( 0 , 200 ) } `
) . join ( '\n' ) ;
const titlePrompt = ` 请用不超过10个字总结以下对话的主题, 只输出标题, 不要其他内容:
${ conversationText } ` ;
try {
const response = await fetch ( CONFIG . apiUrl , {
method : 'POST' ,
headers : {
'Content-Type' : 'application/json' ,
'Authorization' : ` Bearer ${ CONFIG . apiKey } `
} ,
body : JSON . stringify ( {
model : CONFIG . model ,
messages : [ { role : 'user' , content : titlePrompt } ] ,
max _tokens : 50
} )
} ) ;
if ( response . ok ) {
const data = await response . json ( ) ;
const newTitle = data . choices ? . [ 0 ] ? . message ? . content ? . trim ( ) ;
if ( newTitle && newTitle . length > 0 && newTitle . length <= 15 ) {
currentConversation . title = newTitle ;
currentConversation . updatedAt = Date . now ( ) ;
saveConversations ( ) ;
// 更新页面标题显示
const titleEl = document . querySelector ( '.header h1' ) ;
if ( titleEl ) {
titleEl . textContent = newTitle ;
}
}
}
} catch ( error ) {
console . error ( '生成标题失败:' , error ) ;
}
}