@@ -35,6 +35,7 @@ function initAiChat() {
3535 // 检查依赖库
3636 if ( typeof marked === 'undefined' || typeof hljs === 'undefined' ) {
3737 console . error ( 'AI Chat Init Error: marked or highlight.js not found.' ) ;
38+ return ;
3839 } else {
3940 marked . setOptions ( {
4041 highlight : function ( code , lang ) {
@@ -55,8 +56,30 @@ function initAiChat() {
5556 stream : true ,
5657 } ;
5758
58- let chatConfig = JSON . parse ( localStorage . getItem ( 'ai_chat_config' ) ) || defaultConfig ;
59+ // --- 修复 1: 安全地加载配置 ---
60+ let chatConfig = defaultConfig ;
61+ try {
62+ const storedConfig = localStorage . getItem ( 'ai_chat_config' ) ;
63+ if ( storedConfig ) {
64+ const parsed = JSON . parse ( storedConfig ) ;
65+ // 合并默认配置,防止旧配置缺少新字段
66+ chatConfig = { ...defaultConfig , ...parsed } ;
67+ }
68+ } catch ( e ) {
69+ console . error ( '加载配置失败,使用默认配置' , e ) ;
70+ }
71+
72+ // --- 修复 2: 安全地加载历史记录 ---
5973 let messageHistory = [ ] ;
74+ try {
75+ const storedHistory = localStorage . getItem ( 'ai_chat_history' ) ;
76+ if ( storedHistory ) {
77+ messageHistory = JSON . parse ( storedHistory ) ;
78+ }
79+ } catch ( e ) {
80+ console . error ( '加载历史记录失败,清空历史' , e ) ;
81+ messageHistory = [ ] ;
82+ }
6083
6184 const settingsBtn = document . getElementById ( 'ai-settings-trigger' ) ;
6285 const sendBtn = document . getElementById ( 'ai-send-btn' ) ;
@@ -66,6 +89,17 @@ function initAiChat() {
6689
6790 if ( modelNameDisplay ) modelNameDisplay . textContent = chatConfig . model || 'AI Model' ;
6891
92+ // --- 修复 3: 初始化时渲染历史消息 ---
93+ if ( messageHistory . length > 0 && chatList ) {
94+ messageHistory . forEach ( ( msg ) => {
95+ // 重新渲染历史消息到界面
96+ // 注意:这里直接调用 appendMessage,它会自动处理 markdown 和高亮
97+ appendMessage ( msg . role , msg . content , false , false ) ;
98+ } ) ;
99+ // 滚动到底部
100+ chatList . scrollTop = chatList . scrollHeight ;
101+ }
102+
69103 // --- 新增:添加复制按钮的逻辑 ---
70104 function addCopyButtons ( container ) {
71105 if ( ! container ) return ;
@@ -127,15 +161,15 @@ function initAiChat() {
127161 <div class="ai-modal-body">
128162 <div class="ai-form-group">
129163 <label class="ai-form-label">API Key</label>
130- <input type="password" id="cfg-api-key" class="ai-form-input" value="${ chatConfig . apiKey } ">
164+ <input type="password" id="cfg-api-key" class="ai-form-input" value="${ chatConfig . apiKey || '' } ">
131165 </div>
132166 <div class="ai-form-group">
133167 <label class="ai-form-label">Base URL</label>
134- <input type="text" id="cfg-base-url" class="ai-form-input" value="${ chatConfig . baseUrl } ">
168+ <input type="text" id="cfg-base-url" class="ai-form-input" value="${ chatConfig . baseUrl || '' } ">
135169 </div>
136170 <div class="ai-form-group">
137171 <label class="ai-form-label">Model Name</label>
138- <input type="text" id="cfg-model" class="ai-form-input" value="${ chatConfig . model } ">
172+ <input type="text" id="cfg-model" class="ai-form-input" value="${ chatConfig . model || '' } ">
139173 </div>
140174 <hr style="border: 0; border-top: 1px solid #d0d7de; margin: 4px 0;">
141175 <div class="ai-toggle-row">
@@ -163,9 +197,9 @@ function initAiChat() {
163197 modalOverlay = createModal ( ) ;
164198 bindModalEvents ( ) ;
165199 }
166- document . getElementById ( 'cfg-api-key' ) . value = chatConfig . apiKey ;
167- document . getElementById ( 'cfg-base-url' ) . value = chatConfig . baseUrl ;
168- document . getElementById ( 'cfg-model' ) . value = chatConfig . model ;
200+ document . getElementById ( 'cfg-api-key' ) . value = chatConfig . apiKey || '' ;
201+ document . getElementById ( 'cfg-base-url' ) . value = chatConfig . baseUrl || '' ;
202+ document . getElementById ( 'cfg-model' ) . value = chatConfig . model || '' ;
169203 document . getElementById ( 'cfg-multi-turn' ) . checked = chatConfig . multiTurn ;
170204 document . getElementById ( 'cfg-stream' ) . checked = chatConfig . stream ;
171205 setTimeout ( ( ) => modalOverlay . classList . add ( 'active' ) , 10 ) ;
@@ -188,8 +222,16 @@ function initAiChat() {
188222 return ;
189223 }
190224 chatConfig = newConfig ;
225+ // 保存配置到 localStorage
191226 localStorage . setItem ( 'ai_chat_config' , JSON . stringify ( chatConfig ) ) ;
192- if ( ! chatConfig . multiTurn ) messageHistory = [ ] ;
227+
228+ if ( ! chatConfig . multiTurn ) {
229+ messageHistory = [ ] ;
230+ // 如果关闭多轮对话,清空界面和历史存储
231+ if ( chatList ) chatList . innerHTML = '' ;
232+ localStorage . removeItem ( 'ai_chat_history' ) ;
233+ }
234+
193235 if ( modelNameDisplay ) modelNameDisplay . textContent = chatConfig . model ;
194236 closeModal ( ) ;
195237 }
@@ -209,6 +251,8 @@ function initAiChat() {
209251
210252 // --- 消息渲染 ---
211253 function appendMessage ( role , text , isStreaming = false , isLoading = false ) {
254+ if ( ! chatList ) return null ;
255+
212256 const msgDiv = document . createElement ( 'div' ) ;
213257 msgDiv . className = `ai-message ${ role === 'user' ? 'ai-message-user' : 'ai-message-system' } ` ;
214258 const bubble = document . createElement ( 'div' ) ;
@@ -256,7 +300,7 @@ function initAiChat() {
256300 return ;
257301 }
258302
259- // --- 新增逻辑: 检测“理解代码”类指令并自动获取编辑器内容 ---
303+ // --- 检测“理解代码”类指令并自动获取编辑器内容 ---
260304 let finalUserText = rawText ;
261305 const codeKeywords = [
262306 '理解我的代码' ,
@@ -269,29 +313,22 @@ function initAiChat() {
269313 '重构这段代码' ,
270314 ] ;
271315
272- // 检查是否触发自动获取代码逻辑
273316 const shouldFetchCode = codeKeywords . some ( ( keyword ) => rawText . includes ( keyword ) ) ;
274317
275318 if ( shouldFetchCode ) {
276- // 检查 editor 对象是否存在且可用 (确保 editor 已在全局或当前作用域初始化)
277319 if ( typeof editor !== 'undefined' && editor && typeof editor . getValue === 'function' ) {
278320 const currentCode = editor . getValue ( ) ;
279321
280322 if ( ! currentCode || currentCode . trim ( ) === '' ) {
281- // 如果编辑器为空,给予提示
282323 finalUserText = `${ rawText } \n\n[注意:当前编辑器内容为空,无法提供代码供你分析。]` ;
283324 } else {
284- // 构造包含代码的完整提示词
285- // 格式:用户指令 + 分隔符 + 代码块
286325 finalUserText = `${ rawText } \n\n以下是当前编辑器中的代码:\n\`\`\`\n${ currentCode } \n\`\`\`` ;
287326 console . log ( '已自动抓取编辑器代码并附加到请求中' ) ;
288327 }
289328 } else {
290- console . warn ( '未检测到 editor 对象,无法自动获取代码。请确保 editor 已全局初始化。' ) ;
291- // 如果 editor 不存在,保持原样发送,依靠用户手动粘贴
329+ console . warn ( '未检测到 editor 对象,无法自动获取代码。' ) ;
292330 }
293331 }
294- // --- 新增逻辑结束 ---
295332
296333 // 界面上显示用户原始输入
297334 appendMessage ( 'user' , rawText ) ;
@@ -300,7 +337,7 @@ function initAiChat() {
300337
301338 const loadingElements = appendMessage ( 'system' , '' , false , true ) ;
302339
303- // 发送时使用 finalUserText (可能包含自动注入的代码)
340+ // 发送时使用 finalUserText
304341 const currentMessages = [ ...messageHistory , { role : 'user' , content : finalUserText } ] ;
305342
306343 let aiBubble = null ;
@@ -321,7 +358,7 @@ function initAiChat() {
321358 body : JSON . stringify ( {
322359 model : chatConfig . model ,
323360 messages : currentMessages ,
324- stream : false , // 注意:原代码此处强制为 false,实际使用模拟流式
361+ stream : false ,
325362 temperature : 0.7 ,
326363 } ) ,
327364 } ) ;
@@ -377,11 +414,25 @@ function initAiChat() {
377414
378415 function finishProcess ( ) {
379416 if ( chatConfig . multiTurn ) {
380- // 存入历史记录时使用 finalUserText 以保持上下文(包含代码)
417+ // 更新内存中的历史
381418 messageHistory . push ( { role : 'user' , content : finalUserText } ) ;
382419 messageHistory . push ( { role : 'assistant' , content : fullResponse } ) ;
420+
421+ // 限制长度
383422 if ( messageHistory . length > 20 ) messageHistory = messageHistory . slice ( - 20 ) ;
423+
424+ // --- 修复 4: 持久化保存历史记录 ---
425+ try {
426+ localStorage . setItem ( 'ai_chat_history' , JSON . stringify ( messageHistory ) ) ;
427+ } catch ( e ) {
428+ console . error ( '保存历史记录失败:' , e ) ;
429+ // 如果存储满了,可以尝试清除最早的记录或提示用户
430+ if ( e . name === 'QuotaExceededError' ) {
431+ alert ( '本地存储空间已满,历史对话可能无法保存。' ) ;
432+ }
433+ }
384434 }
435+
385436 sendBtn . disabled = false ;
386437 sendBtn . textContent = originalBtnText ;
387438 sendBtn . style . opacity = '1' ;
0 commit comments