Skip to content

Commit bf35f72

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents e48c573 + 7ea7be0 commit bf35f72

27 files changed

+357
-274
lines changed

MyApp/MarkdownPagesBase.cs

Lines changed: 67 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Markdig.Extensions.CustomContainers;
1212
using ServiceStack.IO;
1313
using ServiceStack.Text;
14+
using Markdig.Extensions.Diagrams;
1415

1516
namespace MyApp;
1617

@@ -112,6 +113,7 @@ public virtual MarkdownPipeline CreatePipeline()
112113
.UseAdvancedExtensions()
113114
.UseAutoLinkHeadings()
114115
.UseHeadingsMap()
116+
.UseCustomDiagramExtension()
115117
.UseCustomContainers(MarkdigConfig.Instance.ConfigureContainers);
116118
MarkdigConfig.Instance.ConfigurePipeline?.Invoke(builder);
117119

@@ -374,6 +376,45 @@ public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
374376
}
375377
}
376378

379+
public class MermaidBlockRenderer(CodeBlockRenderer? underlyingRenderer = null) : HtmlObjectRenderer<CodeBlock>
380+
{
381+
private readonly CodeBlockRenderer underlyingRenderer = underlyingRenderer ?? new CodeBlockRenderer();
382+
protected override void Write(HtmlRenderer renderer, CodeBlock obj)
383+
{
384+
if (obj is not FencedCodeBlock fencedCodeBlock || obj.Parser is not FencedCodeBlockParser parser)
385+
{
386+
underlyingRenderer.Write(renderer, obj);
387+
return;
388+
}
389+
390+
var attributes = obj.TryGetAttributes() ?? new HtmlAttributes();
391+
attributes.AddClass("mermaid not-prose");
392+
var txt = GetContent(obj);
393+
renderer
394+
.Write("<pre")
395+
.WriteAttributes(attributes)
396+
.Write(">")
397+
.Write(txt)
398+
.WriteLine("</pre>");
399+
}
400+
private static string GetContent(LeafBlock obj)
401+
{
402+
var code = new StringBuilder();
403+
foreach (var line in obj.Lines.Lines)
404+
{
405+
var slice = line.Slice;
406+
if (slice.Text == null)
407+
continue;
408+
409+
var lineText = slice.Text.Substring(slice.Start, slice.Length);
410+
code.AppendLine();
411+
code.Append(lineText);
412+
}
413+
414+
return code.ToString();
415+
}
416+
}
417+
377418
public class FilesCodeBlockRenderer(CodeBlockRenderer? underlyingRenderer = null) : HtmlObjectRenderer<CodeBlock>
378419
{
379420
private readonly CodeBlockRenderer underlyingRenderer = underlyingRenderer ?? new CodeBlockRenderer();
@@ -614,55 +655,6 @@ protected override void Write(HtmlRenderer renderer, CustomContainer obj)
614655
}
615656
}
616657

617-
public class MermaidContainerRenderer : HtmlObjectRenderer<CustomContainer>
618-
{
619-
protected override void Write(HtmlRenderer renderer, CustomContainer obj)
620-
{
621-
renderer.EnsureLine();
622-
if (renderer.EnableHtmlForBlock)
623-
{
624-
renderer.Write("<div class=\"mermaid-diagram\">");
625-
renderer.WriteLine("<pre class=\"mermaid\">");
626-
}
627-
628-
// Write the Mermaid diagram content
629-
if (obj.FirstOrDefault() is LeafBlock leafBlock)
630-
{
631-
// There has to be an official API to resolve the original text from a renderer?
632-
string? FindOriginalText(ContainerBlock? block)
633-
{
634-
if (block != null)
635-
{
636-
if (block.FirstOrDefault(x => x is LeafBlock { Lines.Count: > 0 }) is LeafBlock first)
637-
return first.Lines.Lines[0].Slice.Text;
638-
return FindOriginalText(block.Parent);
639-
}
640-
641-
return null;
642-
}
643-
644-
var originalSource = leafBlock.Lines.Count > 0
645-
? leafBlock.Lines.Lines[0].Slice.Text
646-
: FindOriginalText(obj.Parent);
647-
if (originalSource == null)
648-
{
649-
HostContext.Resolve<ILogger<PreContainerRenderer>>().LogError("Could not find original Text");
650-
renderer.WriteLine($"Could not find original Text");
651-
}
652-
else
653-
{
654-
renderer.WriteEscape(originalSource.AsSpan().Slice(leafBlock.Span.Start, leafBlock.Span.Length));
655-
}
656-
}
657-
658-
if (renderer.EnableHtmlForBlock)
659-
{
660-
renderer.WriteLine("</pre>");
661-
renderer.WriteLine("</div>");
662-
}
663-
}
664-
}
665-
666658
public class IncludeContainerInlineRenderer : HtmlObjectRenderer<CustomContainerInline>
667659
{
668660
protected override void Write(HtmlRenderer renderer, CustomContainerInline obj)
@@ -812,7 +804,8 @@ public void AddBuiltInContainers(string[]? exclude = null)
812804
{
813805
CodeBlocks = new()
814806
{
815-
["files"] = origRenderer => new FilesCodeBlockRenderer(origRenderer)
807+
["files"] = origRenderer => new FilesCodeBlockRenderer(origRenderer),
808+
["mermaid"] = origRenderer => new MermaidBlockRenderer(origRenderer),
816809
};
817810
BlockContainers = new()
818811
{
@@ -846,7 +839,6 @@ public void AddBuiltInContainers(string[]? exclude = null)
846839
},
847840
["pre"] = new PreContainerRenderer(),
848841
["youtube"] = new YouTubeContainerRenderer(),
849-
["mermaid"] = new MermaidContainerRenderer(),
850842
};
851843
InlineContainers = new()
852844
{
@@ -915,6 +907,24 @@ public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
915907
}
916908
}
917909

910+
public class CustomDiagramExtension : IMarkdownExtension
911+
{
912+
public void Setup(MarkdownPipelineBuilder pipeline)
913+
{
914+
}
915+
916+
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
917+
{
918+
if (renderer is HtmlRenderer htmlRenderer)
919+
{
920+
var codeRenderer = htmlRenderer.ObjectRenderers.FindExact<CodeBlockRenderer>()!;
921+
// TODO: Add other well known diagram languages
922+
//codeRenderer.BlocksAsDiv.Add("mermaid");
923+
codeRenderer.BlocksAsDiv.Add("nomnoml");
924+
}
925+
}
926+
}
927+
918928
public class HeadingsMapExtension : IMarkdownExtension
919929
{
920930
public void Setup(MarkdownPipelineBuilder pipeline)
@@ -1004,6 +1014,12 @@ public static MarkdownPipelineBuilder UseCustomContainers(this MarkdownPipelineB
10041014
pipeline.Extensions.AddIfNotAlready(ext);
10051015
return pipeline;
10061016
}
1017+
1018+
public static MarkdownPipelineBuilder UseCustomDiagramExtension(this MarkdownPipelineBuilder pipeline)
1019+
{
1020+
pipeline.Extensions.ReplaceOrAdd<DiagramExtension>(new CustomDiagramExtension());
1021+
return pipeline;
1022+
}
10071023
}
10081024

10091025
public class DocumentMap

MyApp/MyApp.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
</Target>
2222

2323
<ItemGroup>
24-
<PackageReference Include="Markdig" Version="0.33.*" />
24+
<PackageReference Include="Markdig" Version="0.37.*" />
2525
<PackageReference Include="ServiceStack" Version="8.*" />
2626
<PackageReference Include="ServiceStack.Mvc" Version="8.*" />
2727

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,35 @@
11
<script type="module">
22
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
3-
mermaid.initialize({ startOnLoad: true });
3+
mermaid.initialize({
4+
startOnLoad: true,
5+
theme: 'base',
6+
'themeVariables': {
7+
'primaryColor': '#fff',
8+
'lineColor': '#333',
9+
'primaryBorderColor': 'rgb(67 56 202)', // text-indigo-700
10+
'secondaryColor': '#fff',
11+
'primaryTextColor': '#333',
12+
'tertiaryColor': '#333'
13+
}
14+
});
415
</script>
516
<style>
6-
.mermaid-diagram {
7-
margin-top: 1rem;
8-
margin-bottom: 1rem;
9-
padding: 1rem;
10-
background-color: #f3f4f6;
11-
border-radius: 0.5rem;
12-
overflow-x: auto;
13-
}
14-
.mermaid-diagram pre.mermaid {
15-
font-size: 0.875rem;
16-
background-color: #f3f4f6 !important;
17-
}
18-
/* Ensure text color remains visible in both light and dark modes */
19-
.mermaid-diagram pre.mermaid,
20-
.mermaid-diagram pre.mermaid * {
21-
color: #333 !important;
22-
}
23-
/* Specifically target SVG text elements */
24-
.mermaid-diagram pre.mermaid svg text {
25-
fill: #333 !important;
26-
}
27-
/* Ensure edge labels remain visible */
28-
.mermaid-diagram pre.mermaid .edgeLabel {
29-
background-color: #f3f4f6;
30-
color: #333;
31-
}
32-
/* Override any Tailwind dark mode styles */
33-
@@media (prefers-color-scheme: dark) {
34-
.mermaid-diagram pre.mermaid,
35-
.mermaid-diagram pre.mermaid *,
36-
.mermaid-diagram pre.mermaid svg text,
37-
.mermaid-diagram pre.mermaid .edgeLabel {
38-
color: #333 !important;
39-
}
40-
}
41-
</style>
17+
pre.mermaid {
18+
background-color: #fff !important;
19+
}
20+
.dark pre.mermaid {
21+
background-color: #000 !important; /*bg-gray-800*/
22+
}
23+
.dark pre.mermaid .edgeLabel, .dark pre.mermaid .edgeLabel p, .dark pre.mermad .labelBkg {
24+
background-color: #000 !important;
25+
}
26+
.dark pre.mermaid .edgeLabel, .dark pre.mermaid .edgeLabel p {
27+
color: rgb(209 213 219) !important;
28+
}
29+
.dark pre.mermaid .flowchart-link {
30+
stroke: rgb(209 213 219) !important;
31+
}
32+
.dark pre.mermaid .node rect {
33+
stroke: #fff !important;
34+
}
35+
</style>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
These endpoints are used in a similar way to other AI Server endpoints where you can provide:
2+
- `RefId` - provide a unique identifier to track requests
3+
- `Tag` - categorize like requests under a common group
4+
5+
In addition **Queue** requests can provide:
6+
- `ReplyTo` - URL to send a POST request to when the request is complete
File renamed without changes.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
title: Image to Image
3+
---
4+
5+
## Using Image to Image Endpoints
6+
7+
::include ai-server/endpoint-usage.md::
8+
9+
### Image to Image {#image-to-image}
10+
11+
::include ai-server/cs/image-to-image-1.cs.md::
12+
13+
### Queue Image to Image {#queue-image-to-image}
14+
15+
::include ai-server/cs/queue-image-to-image-1.cs.md::
16+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
title: Image to Text
3+
---
4+
5+
## Using Image to Text Endpoints
6+
7+
::include ai-server/endpoint-usage.md::
8+
9+
### Image to Text {#image-to-text}
10+
11+
::include ai-server/cs/image-to-text-1.cs.md::
12+
13+
### Queue Image to Text {#queue-image-to-text}
14+
15+
::include ai-server/cs/queue-image-to-text-1.cs.md::
16+
17+
:::info
18+
Ensure that the ComfyUI Agent has the Florence 2 model downloaded and installed for the Image-To-Text functionality to work.
19+
This can be done by setting the `DEFAULT_MODELS` environment variable in the `.env` file to include `image-to-text`
20+
:::
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
title: Image Upscale
3+
---
4+
5+
## Using Image Upscale Endpoints
6+
7+
::include ai-server/endpoint-usage.md::
8+
9+
### Image Upscale {#image-upscale}
10+
11+
::include ai-server/cs/image-upscale-1.cs.md::
12+
13+
### Queue Image Upscale {#queue-image-upscale}
14+
15+
::include ai-server/cs/queue-image-upscale-1.cs.md::
16+
17+
## Additional Functionality
18+
19+
AI Server also provides Image-To-Text generation using the ComfyUI Agent that utilizes the [Florence 2 model](https://huggingface.co/microsoft/Florence-2-base). The ComfyUI Agent must have this model downloaded and installed to support this functionality.
20+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
title: Image with Mask
3+
---
4+
5+
## Using Image with Mask Endpoints
6+
7+
::include ai-server/endpoint-usage.md::
8+
9+
### Image with Mask {#image-with-mask}
10+
11+
::include ai-server/cs/image-with-mask-1.cs.md::
12+
13+
### Queue Image with Mask {#queue-image-with-mask}
14+
15+
::include ai-server/cs/queue-image-with-mask-1.cs.md::
16+

MyApp/_pages/ai-server/index.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,20 @@ description: Introduction to AI Server and its key features
55

66
AI Server is a way to orchestrate your AI requests through a single self-hosted application to control what AI Providers you use without impacting your client integrations. It serves as a private gateway to process LLM, AI, and image transformation requests, dynamically delegating tasks across multiple providers including Ollama, OpenRouter, Replicate, Comfy UI, utilizing models like Whisper, SDXL, Flux, and tools like ffmpeg.
77

8+
```mermaid
9+
flowchart TB
10+
A[AI Server]
11+
A --> D{LLM APIs}
12+
A --> C{Ollama}
13+
A --> E{Media APIs}
14+
A --> F{Comfy UI
15+
+
16+
FFmpeg}
17+
D --> D1[OpenRouter / OpenAI / Mistral / Anthropic / Google Cloud / Groq]
18+
E --> E1[Replicate / dall-e-3 / Text to speech]
19+
F --> F1[Diffusion / Whisper / TTS]
20+
```
21+
822
## Key Features
923

1024
- **Unified AI Gateway**: Centralize all your AI requests through a single self-hosted service.

0 commit comments

Comments
 (0)