@@ -102,87 +102,152 @@ export class ChatPanel {
102102 <head>
103103 <meta charset="UTF-8">
104104 <meta name="viewport" content="width=device-width, initial-scale=1.0">
105+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: https:; script-src vscode-resource: 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; style-src vscode-resource: 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; font-src https://cdn.jsdelivr.net;">
105106 <title>Chat with Model</title>
107+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css">
108+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected] /dist/katex.min.css"> 106109 <style>
110+ #chat {
111+ height: calc(100vh - 150px);
112+ overflow-y: auto;
113+ padding: 8px;
114+ }
107115 .user {
108- color: black; /* 黑色字体 */
109- background-color: #a3a3a3; /* 浅灰色背景 */
116+ background-color: #a3a3a3;
117+ color: black;
118+ padding: 12px;
119+ margin: 8px 0;
120+ border-radius: 4px;
121+ white-space: pre-wrap;
110122 }
111123 .model {
112- color: white; /* 白色字体 */
124+ background-color: #333;
125+ color: white;
126+ padding: 12px;
127+ margin: 8px 0;
128+ border-radius: 4px;
113129 }
114- #chat {
115- height: calc(100vh - 150px);
116- overflow-y: auto;
130+ .model pre code {
131+ background-color: #444 !important;
132+ padding: 1em;
133+ border-radius: 4px;
134+ display: block;
135+ overflow-x: auto;
136+ }
137+ .model code {
138+ background-color: #444;
139+ padding: 2px 4px;
140+ border-radius: 3px;
141+ }
142+ .katex {
143+ color: white !important;
144+ background-color: transparent !important;
117145 }
118146 #input-container {
119147 position: fixed;
120148 bottom: 0;
121149 width: 100%;
122- background-color: white ;
150+ background-color: var(--vscode-editor-background) ;
123151 padding: 10px;
152+ box-sizing: border-box;
124153 }
125- #chat div {
126- white-space: pre-wrap; /* 保留换行符 */
127- margin-bottom: 8px; /* 段落间距(可选) */
154+ #input {
155+ width: 100%;
156+ height: 100px;
157+ padding: 8px;
158+ margin-bottom: 8px;
159+ color: var(--vscode-input-foreground);
160+ background-color: var(--vscode-input-background);
161+ border: 1px solid var(--vscode-input-border);
162+ }
163+ button {
164+ padding: 8px 16px;
165+ background-color: var(--vscode-button-background);
166+ color: var(--vscode-button-foreground);
167+ border: none;
168+ cursor: pointer;
128169 }
129170 </style>
130171 </head>
131172 <body>
132173 <div id="chat"></div>
133174 <div id="input-container">
134- <textarea id="input" placeholder="Type your message here..." style="width: 100%; height: 100px; "></textarea>
175+ <textarea id="input" placeholder="Type your message here... (Ctrl+Enter to send) "></textarea>
135176 <button id="send">Send</button>
136177 <button id="reset">Reset</button>
137178 </div>
179+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
180+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
181+ <script defer src="https://cdn.jsdelivr.net/npm/[email protected] /dist/katex.min.js"></script> 182+ <script defer src="https://cdn.jsdelivr.net/npm/[email protected] /dist/contrib/auto-render.min.js"></script> 138183 <script>
139184 const vscode = acquireVsCodeApi();
140185 const chat = document.getElementById('chat');
141186 const input = document.getElementById('input');
142- const send = document.getElementById('send');
143- const reset = document.getElementById('reset');
144-
145- input.addEventListener('keydown', (event) => {
146- if (event.key === 'Enter' && event.ctrlKey) {
147- vscode.postMessage({
148- command: 'sendMessage',
149- text: input.value
187+
188+ // 初始化代码高亮
189+ hljs.configure({ ignoreUnescapedHTML: true });
190+
191+ // 消息处理
192+ window.addEventListener('message', (event) => {
193+ const { role, content } = event.data;
194+ const lastChild = chat.lastElementChild;
195+
196+ let targetDiv;
197+ if (lastChild && lastChild.classList.contains(role)) {
198+ targetDiv = lastChild;
199+ targetDiv.dataset.markdownContent += content;
200+ } else {
201+ targetDiv = document.createElement('div');
202+ targetDiv.className = role;
203+ targetDiv.dataset.markdownContent = content;
204+ chat.appendChild(targetDiv);
205+ }
206+
207+ if (role === 'model') {
208+ // 解析Markdown
209+ targetDiv.innerHTML = marked.parse(targetDiv.dataset.markdownContent, {
210+ breaks: true,
211+ highlight: (code, lang) => {
212+ const validLang = hljs.getLanguage(lang) ? lang : 'plaintext';
213+ return hljs.highlight(code, { language: validLang }).value;
214+ }
150215 });
151- input.value = '';
216+
217+ // 渲染数学公式
218+ renderMathInElement(targetDiv, {
219+ delimiters: [
220+ { left: '$$', right: '$$', display: true },
221+ { left: '$', right: '$', display: false }
222+ ],
223+ throwOnError: false
224+ });
225+
226+ // 重新高亮代码块
227+ hljs.highlightAll();
228+ } else {
229+ // 用户消息保持纯文本
230+ targetDiv.textContent = targetDiv.dataset.markdownContent;
152231 }
232+
233+ chat.scrollTop = chat.scrollHeight;
153234 });
154235
155- send.addEventListener('click', () => {
156- vscode.postMessage({
157- command: 'sendMessage',
158- text: input.value
159- });
236+ // 发送消息逻辑
237+ document.getElementById('send').addEventListener('click', () => {
238+ vscode.postMessage({ command: 'sendMessage', text: input.value });
160239 input.value = '';
161240 });
162241
163- reset.addEventListener('click', () => {
164- vscode.postMessage({
165- command: 'reset'
166- });
242+ document.getElementById('reset').addEventListener('click', () => {
243+ vscode.postMessage({ command: 'reset' });
167244 });
168245
169- window.addEventListener('message', (event) => {
170- const { role, content } = event.data;
171- const chat = document.getElementById('chat');
172- const lastChild = chat.lastElementChild;
173-
174- // 合并到同一角色元素
175- if (lastChild && lastChild.className === role) {
176- lastChild.textContent += content;
177- } else {
178- const div = document.createElement('div');
179- div.className = role;
180- div.textContent = content;
181- chat.appendChild(div);
246+ input.addEventListener('keydown', (e) => {
247+ if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
248+ vscode.postMessage({ command: 'sendMessage', text: input.value });
249+ input.value = '';
182250 }
183-
184- // 自动滚动到底部
185- chat.scrollTop = chat.scrollHeight;
186251 });
187252 </script>
188253 </body>
@@ -197,13 +262,27 @@ export class ChatPanel {
197262 case 'sendMessage' :
198263 this . _conversation . push ( { role : 'user' , content : message . text } ) ;
199264 this . _panel . webview . postMessage ( { role : 'user' , content : message . text } ) ;
200- const response = await callDeepSeekApi ( message . text , 'You are a helpful assistant.' , webviewOutputChannel , true ) ;
201- this . _conversation . push ( { role : 'model' , content : response || '' } ) ;
202- this . _panel . webview . postMessage ( { role : 'model' , content : response || '' } ) ;
265+
266+ try {
267+ const response = await callDeepSeekApi (
268+ message . text ,
269+ 'You are a helpful assistant. Always format answers with Markdown.' ,
270+ webviewOutputChannel ,
271+ true
272+ ) ;
273+
274+ this . _conversation . push ( { role : 'model' , content : response || '' } ) ;
275+ } catch ( error ) {
276+ this . _panel . webview . postMessage ( {
277+ role : 'model' ,
278+ content : `**Error**: ${ error instanceof Error ? error . message : 'Unknown error' } `
279+ } ) ;
280+ }
203281 break ;
282+
204283 case 'reset' :
205284 this . _conversation = [ ] ;
206- this . _panel . webview . html = this . _getHtmlForWebview ( ) ;
285+ this . _panel . webview . postMessage ( { command : 'clearHistory' } ) ;
207286 break ;
208287 }
209288 }
0 commit comments