fix(ui): sanitize json tool leaks, optimize markdown list and typography, update ai avatar
This commit is contained in:
parent
4fd682ff77
commit
e87b91146d
@ -592,6 +592,9 @@ class DeepviewSSEServer:
|
||||
else:
|
||||
systemPrompt += f"\n\n## 通用模式\n企业知识库目录:{orgDir}/wiki/\n平台规则参考:{platformDir}/wiki/\n"
|
||||
|
||||
# 强调输出纪律,从源头杜绝输出底层 JSON 结构给前端
|
||||
systemPrompt += "\n\n【严格输出规范】\n严禁在最终回答中输出任何 JSON 结构、工具调用过程记录、文件读取错误等底层调试信息。你必须将系统结果和发现转化为专业、流畅的文档级 Markdown 给医生阅读!\n"
|
||||
|
||||
# 3. 加载上下文履历,实现真正的 Stateful Context
|
||||
history = db.get_messages_as_conversation(chatId)
|
||||
|
||||
|
||||
@ -395,28 +395,44 @@
|
||||
.chat-send-btn:disabled { background: #cbd5e1; color: #f1f5f9; }
|
||||
/* Markdown in Chat */
|
||||
.markdown-body {
|
||||
font-family: inherit;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
font-size: 15px;
|
||||
color: #1e293b;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
.markdown-body p {
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.markdown-body p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.markdown-body strong {
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
}
|
||||
.markdown-body ul, .markdown-body ol {
|
||||
padding-left: 20px;
|
||||
margin-bottom: 8px;
|
||||
padding-left: 24px;
|
||||
margin-bottom: 12px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.markdown-body ul {
|
||||
list-style-type: disc;
|
||||
}
|
||||
.markdown-body ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
.markdown-body li {
|
||||
margin-bottom: 4px;
|
||||
margin-bottom: 6px;
|
||||
display: list-item;
|
||||
}
|
||||
.markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4 {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 8px;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 10px;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
line-height: 1.3;
|
||||
color: #0f172a;
|
||||
}
|
||||
.markdown-body h3, .markdown-body h4 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
@ -136,7 +136,7 @@
|
||||
|
||||
<!-- AI 头像:方形 -->
|
||||
<div class="msg-avatar ai-avatar" *ngIf="msg.role !== 'user'">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>
|
||||
</div>
|
||||
|
||||
<div class="msg-bubble markdown-body" [class.streaming]="msg.isStreaming" [innerHTML]="msg.htmlContent || msg.rawContent"></div>
|
||||
|
||||
@ -127,7 +127,8 @@ export class App implements OnDestroy, OnInit {
|
||||
const currentStreamingMsg = this.chatMessages.find(m => m.isStreaming && m.role === 'agent');
|
||||
if (currentStreamingMsg) {
|
||||
currentStreamingMsg.rawContent = (currentStreamingMsg.rawContent || '') + payload.text;
|
||||
currentStreamingMsg.htmlContent = marked.parse(currentStreamingMsg.rawContent) as string;
|
||||
const displayStr = this.sanitizeStreamingContent(currentStreamingMsg.rawContent);
|
||||
currentStreamingMsg.htmlContent = marked.parse(displayStr) as string;
|
||||
}
|
||||
break;
|
||||
case 'agent:thinking':
|
||||
@ -141,7 +142,11 @@ export class App implements OnDestroy, OnInit {
|
||||
activeStreamingMsg.isStreaming = false;
|
||||
if (payload.fullAnswer) {
|
||||
activeStreamingMsg.rawContent = payload.fullAnswer;
|
||||
activeStreamingMsg.htmlContent = marked.parse(activeStreamingMsg.rawContent || '') as string;
|
||||
const finalStr = this.sanitizeStreamingContent(activeStreamingMsg.rawContent || '');
|
||||
activeStreamingMsg.htmlContent = marked.parse(finalStr) as string;
|
||||
} else {
|
||||
const finalFallbackStr = this.sanitizeStreamingContent(activeStreamingMsg.rawContent || '');
|
||||
activeStreamingMsg.htmlContent = marked.parse(finalFallbackStr) as string;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -458,7 +463,8 @@ export class App implements OnDestroy, OnInit {
|
||||
if (res && res.messages && res.messages.length > 0) {
|
||||
this.chatMessages = res.messages.map((m: any) => {
|
||||
const rawContent = m.content || '';
|
||||
const htmlContent = marked.parse(rawContent) as string;
|
||||
const displayStr = this.sanitizeStreamingContent(rawContent);
|
||||
const htmlContent = marked.parse(displayStr) as string;
|
||||
return {
|
||||
role: m.role,
|
||||
rawContent: rawContent,
|
||||
@ -509,4 +515,16 @@ export class App implements OnDestroy, OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private sanitizeStreamingContent(raw: string): string {
|
||||
if (!raw) return '';
|
||||
let text = raw;
|
||||
// Strip markdown JSON block wrappings entirely
|
||||
text = text.replace(/```json\s*\{[\s\S]*?\}\s*```/g, '');
|
||||
// Strip bare unescaped JSON tool reports which match specific sigs
|
||||
text = text.replace(/\{"content":[\s\S]*?\}/g, '');
|
||||
text = text.replace(/\{"total_count":[\s\S]*?\}/g, '');
|
||||
// Strip trailing tool garbage that might be partially yielded
|
||||
return text.trim();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user