mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-03-29 13:51:37 +00:00
Added init math rendering
This commit is contained in:
parent
a2bd67eda3
commit
1f05bc3197
@ -96,7 +96,18 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudMarkdown Value="@NormalizeMarkdownForRendering(textContent.Text)" Props="Markdown.DefaultConfig" Styling="@this.MarkdownStyling" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE" />
|
var renderSegments = GetMarkdownRenderSegments(textContent.Text);
|
||||||
|
foreach (var segment in renderSegments)
|
||||||
|
{
|
||||||
|
if (segment.Type is MarkdownRenderSegmentType.MARKDOWN)
|
||||||
|
{
|
||||||
|
<MudMarkdown Value="@segment.Content" Props="Markdown.DefaultConfig" Styling="@this.MarkdownStyling" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE" />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<MathJaxBlock Value="@segment.Content" Class="mb-5" />
|
||||||
|
}
|
||||||
|
}
|
||||||
@if (textContent.Sources.Count > 0)
|
@if (textContent.Sources.Count > 0)
|
||||||
{
|
{
|
||||||
<MudMarkdown Value="@textContent.Sources.ToMarkdown()" Props="Markdown.DefaultConfig" Styling="@this.MarkdownStyling" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE" />
|
<MudMarkdown Value="@textContent.Sources.ToMarkdown()" Props="Markdown.DefaultConfig" Styling="@this.MarkdownStyling" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE" />
|
||||||
|
|||||||
@ -2,6 +2,7 @@ using AIStudio.Components;
|
|||||||
using AIStudio.Dialogs;
|
using AIStudio.Dialogs;
|
||||||
using AIStudio.Tools.Services;
|
using AIStudio.Tools.Services;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace AIStudio.Chat;
|
namespace AIStudio.Chat;
|
||||||
|
|
||||||
@ -194,6 +195,72 @@ public partial class ContentBlockComponent : MSGComponentBase
|
|||||||
CodeBlock = { Theme = this.CodeColorPalette },
|
CodeBlock = { Theme = this.CodeColorPalette },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static IReadOnlyList<MarkdownRenderSegment> GetMarkdownRenderSegments(string text)
|
||||||
|
{
|
||||||
|
var normalized = NormalizeMarkdownForRendering(text);
|
||||||
|
if (string.IsNullOrWhiteSpace(normalized))
|
||||||
|
return [];
|
||||||
|
|
||||||
|
var normalizedWithUnixLineEndings = normalized.Replace("\r\n", "\n", StringComparison.Ordinal).Replace('\r', '\n');
|
||||||
|
var lines = normalizedWithUnixLineEndings.Split('\n');
|
||||||
|
var markdownBuilder = new StringBuilder();
|
||||||
|
var mathBuilder = new StringBuilder();
|
||||||
|
var segments = new List<MarkdownRenderSegment>();
|
||||||
|
string? activeCodeFenceMarker = null;
|
||||||
|
var inMathBlock = false;
|
||||||
|
|
||||||
|
foreach (var line in lines)
|
||||||
|
{
|
||||||
|
var trimmedLine = line.Trim();
|
||||||
|
|
||||||
|
if (!inMathBlock && TryUpdateCodeFenceState(trimmedLine, ref activeCodeFenceMarker))
|
||||||
|
{
|
||||||
|
AppendLine(markdownBuilder, line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeCodeFenceMarker is not null)
|
||||||
|
{
|
||||||
|
AppendLine(markdownBuilder, line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trimmedLine == "$$")
|
||||||
|
{
|
||||||
|
if (inMathBlock)
|
||||||
|
{
|
||||||
|
segments.Add(new(MarkdownRenderSegmentType.MATH_BLOCK, mathBuilder.ToString().Trim('\r', '\n')));
|
||||||
|
mathBuilder.Clear();
|
||||||
|
inMathBlock = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FlushMarkdownSegment();
|
||||||
|
inMathBlock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendLine(inMathBlock ? mathBuilder : markdownBuilder, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inMathBlock)
|
||||||
|
return [new(MarkdownRenderSegmentType.MARKDOWN, normalized)];
|
||||||
|
|
||||||
|
FlushMarkdownSegment();
|
||||||
|
return segments.Count > 0 ? segments : [new(MarkdownRenderSegmentType.MARKDOWN, normalized)];
|
||||||
|
|
||||||
|
void FlushMarkdownSegment()
|
||||||
|
{
|
||||||
|
if (markdownBuilder.Length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
segments.Add(new(MarkdownRenderSegmentType.MARKDOWN, markdownBuilder.ToString()));
|
||||||
|
markdownBuilder.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string NormalizeMarkdownForRendering(string text)
|
private static string NormalizeMarkdownForRendering(string text)
|
||||||
{
|
{
|
||||||
var cleaned = text.RemoveThinkTags().Trim();
|
var cleaned = text.RemoveThinkTags().Trim();
|
||||||
@ -221,6 +288,39 @@ public partial class ContentBlockComponent : MSGComponentBase
|
|||||||
|
|
||||||
return content.Contains("</", StringComparison.Ordinal) || content.Contains("/>", StringComparison.Ordinal);
|
return content.Contains("</", StringComparison.Ordinal) || content.Contains("/>", StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool TryUpdateCodeFenceState(string trimmedLine, ref string? activeCodeFenceMarker)
|
||||||
|
{
|
||||||
|
string? fenceMarker = null;
|
||||||
|
if (trimmedLine.StartsWith("```", StringComparison.Ordinal))
|
||||||
|
fenceMarker = "```";
|
||||||
|
else if (trimmedLine.StartsWith("~~~", StringComparison.Ordinal))
|
||||||
|
fenceMarker = "~~~";
|
||||||
|
|
||||||
|
if (fenceMarker is null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
activeCodeFenceMarker = activeCodeFenceMarker is null
|
||||||
|
? fenceMarker
|
||||||
|
: activeCodeFenceMarker == fenceMarker
|
||||||
|
? null
|
||||||
|
: activeCodeFenceMarker;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AppendLine(StringBuilder builder, string line)
|
||||||
|
{
|
||||||
|
builder.AppendLine(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum MarkdownRenderSegmentType
|
||||||
|
{
|
||||||
|
MARKDOWN,
|
||||||
|
MATH_BLOCK,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly record struct MarkdownRenderSegment(MarkdownRenderSegmentType Type, string Content);
|
||||||
|
|
||||||
private async Task RemoveBlock()
|
private async Task RemoveBlock()
|
||||||
{
|
{
|
||||||
|
|||||||
5
app/MindWork AI Studio/Chat/MathJaxBlock.razor
Normal file
5
app/MindWork AI Studio/Chat/MathJaxBlock.razor
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@namespace AIStudio.Chat
|
||||||
|
|
||||||
|
<div class="@this.RootClass" style="white-space: pre-wrap;">
|
||||||
|
@this.MathText
|
||||||
|
</div>
|
||||||
30
app/MindWork AI Studio/Chat/MathJaxBlock.razor.cs
Normal file
30
app/MindWork AI Studio/Chat/MathJaxBlock.razor.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace AIStudio.Chat;
|
||||||
|
|
||||||
|
public partial class MathJaxBlock
|
||||||
|
{
|
||||||
|
private const string MATH_JAX_SCRIPT_ID = "mudblazor-markdown-mathjax";
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string Value { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string Class { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private IJSRuntime JsRuntime { get; init; } = null!;
|
||||||
|
|
||||||
|
private string RootClass => string.IsNullOrWhiteSpace(this.Class)
|
||||||
|
? "chat-mathjax-block"
|
||||||
|
: $"chat-mathjax-block {this.Class}";
|
||||||
|
|
||||||
|
private string MathText => $"$${Environment.NewLine}{this.Value}{Environment.NewLine}$$";
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
await this.JsRuntime.InvokeVoidAsync("appendMathJaxScript", MATH_JAX_SCRIPT_ID);
|
||||||
|
await this.JsRuntime.InvokeVoidAsync("refreshMathJaxScript");
|
||||||
|
await base.OnAfterRenderAsync(firstRender);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -150,4 +150,19 @@
|
|||||||
.sources-card-header {
|
.sources-card-header {
|
||||||
top: 0em !important;
|
top: 0em !important;
|
||||||
left: 2.2em !important;
|
left: 2.2em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-mathjax-block {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-mathjax-block mjx-container[display="true"] {
|
||||||
|
text-align: left !important;
|
||||||
|
margin-left: 0 !important;
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-mathjax-block mjx-container[display="true"] mjx-math {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user