Skip to content

Commit 0937b35

Browse files
committed
feat(Chat): add deepseek support
1 parent 9f1df2b commit 0937b35

File tree

4 files changed

+173
-3
lines changed

4 files changed

+173
-3
lines changed

src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@
7474
<PackageReference Include="BootstrapBlazor.Middleware" Version="9.0.0" />
7575
<PackageReference Include="Longbow.Logging" Version="9.0.0" />
7676
<PackageReference Include="Longbow.Tasks" Version="9.0.0" />
77+
<PackageReference Include="Markdig" Version="0.40.0" />
78+
<PackageReference Include="Markdown.ColorCode" Version="3.0.0" />
7779
</ItemGroup>
7880

7981
<ItemGroup>
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
@using Markdig
2+
@using Markdown.ColorCode
3+
@using ColorCode.Styling
4+
@using System.Text.RegularExpressions
5+
@using ColorCode
6+
@using ColorCode.Compilation.Languages
7+
@using Markdown = Markdig.Markdown
8+
@inherits ComponentBase
9+
10+
<div id="@(Id ?? string.Empty)">
11+
@((MarkupString)(AsMarkdown ?? string.Empty))
12+
</div>
13+
14+
<style>
15+
.think {
16+
margin-bottom: 0;
17+
font-size: 16px;
18+
font-weight: 400;
19+
color: #A0A0A0;
20+
border-left: 3px solid #dfdbdb;
21+
padding-left: 10px;
22+
}
23+
</style>
24+
25+
@code {
26+
[Parameter]
27+
public required string Content { get; set; }
28+
29+
[Parameter]
30+
public string? Id { get; set; }
31+
32+
public string? AsMarkdown;
33+
34+
string? Embedding { get; set; }
35+
36+
protected override void OnInitialized()
37+
{
38+
markdownPipeline = new MarkdownPipelineBuilder()
39+
.UsePipeTables()
40+
.UseAdvancedExtensions()
41+
.UseColorCode(styleDictionary: StyleDictionary.DefaultLight,
42+
additionalLanguages: new List<ILanguage>()
43+
{
44+
new Json(),
45+
new CSharp(),
46+
new Cpp(),
47+
new Css(),
48+
new Html(),
49+
new JavaScript(),
50+
new Php(),
51+
})
52+
.UseAutoLinks()
53+
.UseEmojiAndSmiley()
54+
.UseMediaLinks()
55+
.UseCitations()
56+
.UseMathematics()
57+
.UseAutoLinks()
58+
.UseDiagrams()
59+
.Build();
60+
}
61+
62+
protected override void OnParametersSet()
63+
{
64+
var embeddingsRemoved = RemoveEmbeddingsElement(Content);
65+
AsMarkdown = GetMarkdown(embeddingsRemoved);
66+
StateHasChanged();
67+
}
68+
69+
private MarkdownPipeline? markdownPipeline;
70+
71+
private string GetMarkdown(string toHtml)
72+
{
73+
try
74+
{
75+
if (string.IsNullOrEmpty(toHtml))
76+
return string.Empty;
77+
78+
// 处理未封闭的 think 标签
79+
toHtml = HandleUnclosedThinkTags(toHtml);
80+
81+
// 处理正常的 think 标签
82+
var thinkPattern = @"<\s*think\b[^>]*>(.*?)<\s*/\s*think\s*>";
83+
toHtml = Regex.Replace(toHtml, thinkPattern, @"<div class=""think"">$1</div>", RegexOptions.Singleline | RegexOptions.IgnoreCase);
84+
toHtml = RemoveEmbeddingsElement(toHtml);
85+
86+
var html = Markdown.ToHtml(toHtml, markdownPipeline);
87+
88+
var pattern = "(<div style=\"color:#DADADA;background-color:#1E1E1E;\"><pre>(.*?)</pre></div>)";
89+
var matches = Regex.Matches(html, pattern, RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.IgnoreCase);
90+
91+
for (var i = matches.Count - 1; i >= 0; i--)
92+
{
93+
var match = matches[i].ToString();
94+
var id = "copy" + i;
95+
var replacement = $"<button data-clipboard-target=\"#{id}\" class=\"float-end copyBtn mt-0\">Copy</button>" + match;
96+
html = html.Remove(matches[i].Index, matches[i].Length).Insert(matches[i].Index, replacement);
97+
}
98+
99+
return html;
100+
}
101+
catch (Exception)
102+
{
103+
return "error markdowncontent.razor";
104+
}
105+
}
106+
107+
private string HandleUnclosedThinkTags(string content)
108+
{
109+
if (string.IsNullOrEmpty(content))
110+
return content;
111+
112+
// 匹配开始标签
113+
var openTagPattern = @"<\s*think\b[^>]*>";
114+
var closeTagPattern = @"<\s*/\s*think\s*>";
115+
116+
var openTags = Regex.Matches(content, openTagPattern);
117+
var closeTags = Regex.Matches(content, closeTagPattern);
118+
119+
// 如果开始标签数量等于结束标签数量,说明标签都是配对的
120+
if (openTags.Count == closeTags.Count)
121+
return content;
122+
123+
// 处理未封闭的标签
124+
var parts = Regex.Split(content, openTagPattern);
125+
if (parts.Length <= 1)
126+
return content;
127+
128+
var result = parts[0]; // 保留第一部分的内容
129+
for (int i = 1; i < parts.Length; i++)
130+
{
131+
var part = parts[i];
132+
// 检查这部分是否已经包含结束标签
133+
if (!part.Contains("</think>", StringComparison.OrdinalIgnoreCase))
134+
{
135+
// 没有结束标签,添加一个完整的 think 标签包装
136+
result += $"<think>{part}</think>";
137+
}
138+
else
139+
{
140+
// 已经有结束标签,保持原样
141+
result += $"<think>{part}";
142+
}
143+
}
144+
145+
return result;
146+
}
147+
148+
private string RemoveEmbeddingsElement(string data)
149+
{
150+
if (string.IsNullOrEmpty(data))
151+
{
152+
return "";
153+
}
154+
string pattern = @"\[EMBEDDINGS\](.*?)\[/EMBEDDINGS\]";
155+
var matches = Regex.Matches(data, pattern, RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
156+
157+
if (matches.Count == 0)
158+
{
159+
return data;
160+
}
161+
162+
data = Regex.Replace(data, pattern, "", RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
163+
164+
Embedding = $"{matches[0].Groups[1].Value}";
165+
return data;
166+
}
167+
}

src/BootstrapBlazor.Server/Components/Pages/Chats.razor

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
</div>
3838
<div class="msg-body">
3939
<div class="msg-time">@message.Time.ToString("HH:mm:ss")</div>
40-
<div>@message.Content</div>
40+
@* <div>@message.Content</div> *@
41+
<MarkdownContent Content="@message.Content" Id="mdcontent" />
4142
@if (message.Role == ChatRole.Assistant)
4243
{
4344
<div class="msg-desc">AI-generated content may be incorrect</div>

src/BootstrapBlazor.Server/Components/Samples/Markdowns.razor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ public partial class Markdowns
2121
private string? AsyncValue { get; set; }
2222

2323
[NotNull]
24-
private Markdown? MarkdownSetValue { get; set; }
24+
private BootstrapBlazor.Components.Markdown? MarkdownSetValue { get; set; }
2525

2626
[NotNull]
27-
private Markdown? Markdown { get; set; }
27+
private BootstrapBlazor.Components.Markdown? Markdown { get; set; }
2828

2929
private string JsString { get; set; } = @"```js
3030
console.log('test');

0 commit comments

Comments
 (0)