Skip to content

Commit e872eab

Browse files
committed
fix: 改进聊天页面显示
1 parent 97087f2 commit e872eab

File tree

4 files changed

+144
-18
lines changed

4 files changed

+144
-18
lines changed

package-lock.json

Lines changed: 20 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@
414414
"cheerio": "^1.0.0",
415415
"exceljs": "^4.4.0",
416416
"execa": "^9.5.2",
417+
"formdata-node": "^6.0.3",
417418
"iconv-lite": "^0.6.3",
418419
"jschardet": "^3.1.4",
419420
"jsdom": "^26.1.0",

src/resources/chatPanel.css

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,53 @@ button {
164164
}
165165

166166
think {
167-
color: #9ccc9c; /* 柔和的绿色 */
167+
color: #9ccc9c;
168168
font-style: italic;
169169
opacity: 0.8;
170-
border-left: 3px solid #4d9375; /* 左侧装饰线 */
170+
border-left: 3px solid #4d9375;
171171
padding-left: 0.8em;
172172
margin: 0.5em 0;
173-
display: block; /* 确保块级显示 */
173+
display: block;
174174
white-space: pre-wrap;
175+
}
176+
177+
tool_call {
178+
display: block;
179+
background: rgba(20, 20, 30, 0.95);
180+
border: 1px solid #00b7b7;
181+
border-radius: 8px;
182+
padding: 16px;
183+
margin: 12px 0;
184+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
185+
font-family: 'Courier New', Courier, monospace;
186+
font-size: 15px;
187+
line-height: 1.6;
188+
color: #ffffff;
189+
position: relative;
190+
transition: all 0.2s ease;
191+
}
192+
193+
tool_call::before {
194+
content: '🔧 Tool Call';
195+
display: block;
196+
font-size: 13px;
197+
font-weight: bold;
198+
color: #ffffff;
199+
background: #00b7b7;
200+
padding: 6px 10px;
201+
border-radius: 6px 6px 0 0;
202+
margin: -16px -16px 12px -16px;
203+
border-bottom: 1px solid #00b7b7;
204+
}
205+
206+
tool_call:hover {
207+
transform: translateY(-2px);
208+
box-shadow: 0 4px 8px rgba(0, 183, 183, 0.3);
209+
}
210+
211+
tool_call code {
212+
background: rgba(255, 255, 255, 0.15);
213+
padding: 2px 5px;
214+
border-radius: 3px;
215+
color: #00b7b7;
175216
}

src/resources/chatPanelScript.js

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,78 @@ function ensureCopyButtons() {
147147
});
148148
}
149149

150+
function ensureTagPreProcess(content) {
151+
let processedContent = content;
152+
153+
// Handle unclosed <think> tags
154+
if (processedContent.includes('<think>') && !processedContent.includes('</think>')) {
155+
processedContent += '</think>';
156+
}
157+
158+
// Handle <tool_call> tags
159+
const lastToolCallIndex = processedContent.lastIndexOf('<tool_call>');
160+
if (lastToolCallIndex !== -1) {
161+
// Check if there's a </tool_call> after the last <tool_call>
162+
const contentAfterLastToolCall = processedContent.slice(lastToolCallIndex);
163+
if (!contentAfterLastToolCall.includes('</tool_call>')) {
164+
processedContent += '</tool_call>';
165+
}
166+
}
167+
168+
return processedContent;
169+
}
170+
171+
function processMathBlocks(input) {
172+
// Regex to match %%...%% blocks
173+
const percentPairRegex = /%%([\s\S]*?)%%/g;
174+
175+
// Process the input string
176+
return input.replace(percentPairRegex, (percentMatch, percentContent) => {
177+
// Regex to match $$...$$ blocks within %% content
178+
const mathBlockRegex = /\$\$([\s\S]*?)\$\$/g;
179+
180+
// Process $$...$$ blocks within the %% content
181+
const processedContent = percentContent.replace(mathBlockRegex, (mathMatch, mathContent) => {
182+
// Trim and check if the math content has newlines
183+
const trimmedContent = mathContent.trim();
184+
if (!trimmedContent.includes('\n')) {
185+
// No newlines, return unchanged
186+
return `$$${trimmedContent}$$`;
187+
}
188+
189+
// Replace newlines with \\ and wrap in aligned
190+
const singleLineContent = trimmedContent
191+
.split('\n')
192+
.map(line => line.trim())
193+
.filter(line => line.length > 0)
194+
.join(' \\\\ ');
195+
196+
return `$$ \\begin{aligned} ${singleLineContent} \\end{aligned} $$`;
197+
});
198+
199+
// Return the processed %% block
200+
return `%%${processedContent}%%`;
201+
});
202+
}
203+
204+
function separateThinkContent(input) {
205+
// Initialize outputs
206+
let thinkStr = '';
207+
let answerStr = input;
208+
209+
// Regex to match <think>...</think> (non-greedy)
210+
const thinkRegex = /<think>([\s\S]*?)<\/think>/;
211+
212+
// Find the first <think>...</think> match
213+
const match = input.match(thinkRegex);
214+
if (match) {
215+
thinkStr = match[0]; // Full <think>...</think> content
216+
answerStr = input.replace(thinkRegex, ''); // Remove <think>...</think>
217+
}
218+
219+
return { thinkStr, answerStr };
220+
}
221+
150222
// 渲染消息
151223
async function renderMessage(role, content, index) {
152224
const lastChild = chat.lastElementChild;
@@ -164,14 +236,16 @@ async function renderMessage(role, content, index) {
164236

165237
if (role === 'model') {
166238
let markdownContent = targetDiv.dataset.markdownContent;
167-
168-
if (markdownContent.includes('<think>') && !markdownContent.includes('</think>')){
169-
markdownContent += "</think>";
170-
}
239+
markdownContent = ensureTagPreProcess(markdownContent);
171240

172241
markdownContent = markdownContent.replace(/\$\$/g, '&doller; &doller; 包裹');
173242

174-
targetDiv.innerHTML = marked.parse(markdownContent, {
243+
markdownContent = processMathBlocks(markdownContent);
244+
245+
const { thinkStr, answerStr } = separateThinkContent(markdownContent);
246+
markdownContent = answerStr;
247+
248+
targetDiv.innerHTML = thinkStr + marked.parse(markdownContent, {
175249
breaks: false,
176250
mangle: false,
177251
headerIds: false,

0 commit comments

Comments
 (0)