Skip to content

Commit 380f9de

Browse files
committed
Added helper classes
1 parent e6d32dc commit 380f9de

File tree

6 files changed

+574
-21
lines changed

6 files changed

+574
-21
lines changed

ChartGeneratorAISample/ChartGenerator/ChartGenerator.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
<PackageReference Include="SampleBrowser.Maui.Base" Version="*" />
7070
<PackageReference Include="Syncfusion.Maui.AIAssistView" Version="*" />
7171
<PackageReference Include="Syncfusion.Maui.PdfViewer" Version="*" />
72+
<PackageReference Include="Syncfusion.Maui.Popup" Version="*" />
7273
<PackageReference Include="Syncfusion.Maui.Toolkit" Version="*" />
7374
</ItemGroup>
7475

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<IsFirstTimeProjectOpen>False</IsFirstTimeProjectOpen>
5+
<ActiveDebugFramework>net9.0-windows10.0.19041.0</ActiveDebugFramework>
6+
<ActiveDebugProfile>Windows Machine</ActiveDebugProfile>
7+
</PropertyGroup>
8+
</Project>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Syncfusion.Maui.Core.Internals;
7+
using Syncfusion.Maui.Toolkit.Charts;
8+
9+
#if ANDROID
10+
using PlatformView = Android.Widget.EditText;
11+
#elif WINDOWS
12+
using PlatformView = Microsoft.UI.Xaml.Controls.TextBox;
13+
#endif
14+
using PointerEventArgs = Syncfusion.Maui.Core.Internals.PointerEventArgs;
15+
namespace ChartGenerator
16+
{
17+
public class CustomEditor : Editor, IKeyboardListener
18+
{
19+
public CustomEditor()
20+
{
21+
this.AddKeyboardListener(this);
22+
}
23+
#if WINDOWS || ANDROID
24+
protected override void OnHandlerChanged()
25+
{
26+
#if WINDOWS
27+
// Hide editor border and underline.
28+
var platformView = this.Handler?.PlatformView as PlatformView;
29+
if (platformView != null)
30+
{
31+
this.ApplyTextBoxStyle(platformView);
32+
}
33+
#else
34+
var platformView = this.Handler?.PlatformView as PlatformView;
35+
if (platformView != null)
36+
{
37+
this.ApplyTextBoxStyle(platformView);
38+
}
39+
#endif
40+
base.OnHandlerChanged();
41+
}
42+
#endif
43+
#if WINDOWS || ANDROID
44+
private void ApplyTextBoxStyle(PlatformView? platformView)
45+
{
46+
if (platformView != null)
47+
{
48+
#if WINDOWS
49+
var textBoxStyle = new Microsoft.UI.Xaml.Style(typeof(Microsoft.UI.Xaml.Controls.TextBox));
50+
textBoxStyle.Setters.Add(new Microsoft.UI.Xaml.Setter() { Property = Microsoft.UI.Xaml.Controls.Control.BorderBrushProperty, Value = new Microsoft.UI.Xaml.Media.SolidColorBrush(Windows.UI.Color.FromArgb(0, 0, 0, 0)) });
51+
textBoxStyle.Setters.Add(new Microsoft.UI.Xaml.Setter() { Property = Microsoft.UI.Xaml.Controls.Control.BorderThicknessProperty, Value = new Thickness(0) });
52+
53+
platformView.Resources.Add(typeof(Microsoft.UI.Xaml.Controls.TextBox), textBoxStyle);
54+
#else
55+
platformView.Background = null;
56+
platformView.SetPadding(0, 0, 0, 0);
57+
#endif
58+
}
59+
}
60+
#endif
61+
public void OnKeyDown(KeyEventArgs args)
62+
{
63+
}
64+
65+
public void OnKeyUp(KeyEventArgs args)
66+
{
67+
}
68+
69+
public void OnPreviewKeyDown(KeyEventArgs args)
70+
{
71+
if (args.Key == KeyboardKey.Enter && !args.IsShiftKeyPressed)
72+
{
73+
var bindingContext = this.BindingContext as ChartViewModel;
74+
args.Handled = true;
75+
if (!string.IsNullOrWhiteSpace(bindingContext.InputText))
76+
{
77+
bindingContext.SendButtonCommand.Execute(null);
78+
}
79+
}
80+
}
81+
}
82+
}
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Text.RegularExpressions;
6+
using System.Threading.Tasks;
7+
8+
namespace ChartGenerator
9+
{
10+
public class HtmlConverter
11+
{
12+
public string ConvertToHTML(string aiResponse)
13+
{
14+
StringBuilder htmlBuilder = new StringBuilder();
15+
htmlBuilder.AppendLine("<html>");
16+
htmlBuilder.AppendLine("<head>");
17+
htmlBuilder.AppendLine("<title>AI Response</title>");
18+
htmlBuilder.AppendLine("<style>");
19+
htmlBuilder.AppendLine("body { font-family: Arial, sans-serif; line-height:1.6;}");
20+
htmlBuilder.AppendLine("h1, h2 { color: #33, margin-bottom: 10px; }");
21+
htmlBuilder.AppendLine("p, li { margin-bottom: 5px;}");
22+
htmlBuilder.AppendLine("blockquote { border-left: 3px solid #ccc; margin: 10; padding-left: 10px; color: #555; }");
23+
htmlBuilder.AppendLine("span {display: inline-block; padding: 5px 10px; background-color: #f0f0f0; border-radius: 8px; font-size: 14px; font-family: Consolas, monospace; }");
24+
htmlBuilder.AppendLine("</style>");
25+
//htmlBuilder.AppendLine("<script type=\"text/javascript\">");
26+
//htmlBuilder.AppendLine("function reportHeight() {");
27+
//htmlBuilder.AppendLine(" var height = document.body.scrollHeight;");
28+
//htmlBuilder.AppendLine(" window.dispatchEvent(new CustomEvent('reportHeight', { detail: height })); ");
29+
//htmlBuilder.AppendLine(" window.location.href = 'autofit://' + height;");
30+
//htmlBuilder.AppendLine("}");
31+
//htmlBuilder.AppendLine("window.onload = reportHeight;");
32+
//htmlBuilder.AppendLine("window.onresize = reportHeight;");
33+
//htmlBuilder.AppendLine("</script>");
34+
htmlBuilder.AppendLine("</head>");
35+
htmlBuilder.AppendLine("<body>");
36+
37+
var paragraphs = aiResponse.Split(new[] { "<br>", "\n\n" }, StringSplitOptions.RemoveEmptyEntries);
38+
for (int i = 0; i < paragraphs.Count(); i++)
39+
{
40+
var paragraph = paragraphs[i];
41+
if (IsHeading(paragraph))
42+
{
43+
int level = 0;
44+
var title = TrimHashFromTitle(paragraph, out level);
45+
title = ConvertToHtmlBold(title);
46+
if (level == 1)
47+
htmlBuilder.AppendLine($"<h1>{title}</h1>");
48+
else if (level == 2)
49+
htmlBuilder.AppendLine($"<h2>{title}</h2>");
50+
else if (level == 3)
51+
htmlBuilder.AppendLine($"<h3>{title}</h3>");
52+
else if (level == 4)
53+
htmlBuilder.AppendLine($"<h4>{title}</h4>");
54+
else if (level == 5)
55+
htmlBuilder.AppendLine($"<h5>{title}</h5>");
56+
else if (level == 6)
57+
htmlBuilder.AppendLine($"<h6>{title}</h6>");
58+
}
59+
// Implement list parsing here
60+
// else if (IsList(paragraph))
61+
// {
62+
// ConvertToHtmlList(paragraph, htmlBuilder);
63+
// }
64+
else if (IsQuote(paragraph))
65+
{
66+
htmlBuilder.AppendLine($"<blockquote>{paragraph.Trim()}</blockquote>");
67+
}
68+
else if (IsURL(paragraph))
69+
{
70+
htmlBuilder.AppendLine($"<a href=\"{paragraph.Trim()}\">{paragraph.Trim()}</a>");
71+
}
72+
else if (HasURLText(paragraph))
73+
{
74+
ConvertMarkdownToHtml(paragraph, htmlBuilder);
75+
}
76+
else if (ContainsBoldPattern(paragraph))
77+
{
78+
htmlBuilder.AppendLine($"<p>{ConvertToHtmlBold(paragraph)}</p>");
79+
}
80+
else if (paragraph.Contains("```"))
81+
{
82+
htmlBuilder.AppendLine("<table style='border: 1px solid black; border-collapse: collapse; width:100%; '>");
83+
htmlBuilder.AppendLine("<tr><td>");
84+
htmlBuilder.AppendLine("<pre style='margin:10px !important; font-size: 14px; line-height: 1.5; font-family: Consolas, monospace;'>");
85+
htmlBuilder.AppendLine("<code>");
86+
var codeSnippetIndex = 0;
87+
for (codeSnippetIndex = i + 1; codeSnippetIndex < paragraphs.Count(); codeSnippetIndex++)
88+
{
89+
var codeSnippet = paragraphs[codeSnippetIndex];
90+
if (codeSnippet.Contains("```"))
91+
break;
92+
htmlBuilder.AppendLine(codeSnippet);
93+
}
94+
htmlBuilder.AppendLine("</code></pre>");
95+
htmlBuilder.AppendLine("</td></tr></table>");
96+
i = codeSnippetIndex;
97+
}
98+
else if (HasBackticks(paragraph))
99+
{
100+
FormatBackTicks(htmlBuilder, paragraph);
101+
}
102+
else
103+
{
104+
htmlBuilder.AppendLine($"<p>{paragraph.Trim()}</p>");
105+
}
106+
}
107+
108+
htmlBuilder.AppendLine("</body>");
109+
htmlBuilder.AppendLine("</html>");
110+
return htmlBuilder.ToString();
111+
}
112+
public string TrimHashFromTitle(string title, out int headingLevel)
113+
{
114+
headingLevel = 0;
115+
116+
// Loop from 4 to 1 to check for "####", "###", "##", and "#"
117+
for (int i = 4; i > 0; i--)
118+
{
119+
string hashes = new string('#', i);
120+
int index = title.IndexOf(hashes);
121+
if (index != -1)
122+
{
123+
headingLevel = i;
124+
// Trim the found hashes from the title and any leading/trailing spaces
125+
return title.Substring(0, index).Trim() + title.Substring(index + i).Trim();
126+
}
127+
}
128+
129+
// If no hashes are found, return the original title
130+
return title;
131+
}
132+
private bool IsHeading(string text)
133+
{
134+
// Detect headings, e.g., all caps or specific prefixes
135+
return text == text.ToUpper() || Regex.IsMatch(text, @"^#");
136+
}
137+
138+
private bool IsList(string text)
139+
{
140+
// Detect bullet points or ordered lists
141+
return text.StartsWith("- ");// || Regex.IsMatch(text, @"^\d+\.");
142+
}
143+
144+
private bool IsQuote(string text)
145+
{
146+
// Simplistic quote detection
147+
return text.StartsWith("\"") && text.EndsWith("\"");
148+
}
149+
150+
private bool HasBackticks(string text)
151+
{
152+
var backtickPattern = @"`[^`]*`";
153+
return Regex.IsMatch(text, backtickPattern);
154+
}
155+
156+
private void FormatBackTicks(StringBuilder htmlBuilder, string text)
157+
{
158+
var backtickPattern = @"`([^`]*)`";
159+
var formattedText = Regex.Replace(text, backtickPattern, "<span>$1</span>");
160+
htmlBuilder.AppendLine($"<p>{formattedText}</p>");
161+
}
162+
163+
private bool IsURL(string text)
164+
{
165+
// URL detection based on simple regex
166+
var directURLPattern = @"^(http|https):\/\/[^\s$.?#].[^\s]*$";
167+
return Regex.IsMatch(text, directURLPattern);
168+
}
169+
private bool HasURLText(string markdown)
170+
{
171+
// Define the regex pattern to extract URLs from Markdown links.
172+
string pattern = @"\[(.*?)\]\((http[s]?:\/\/[^\s\)]+)\)";
173+
174+
// Create a match to extract the text and URL from the Markdown link.
175+
Match match = Regex.Match(markdown, pattern, RegexOptions.IgnoreCase);
176+
if (match.Success)
177+
{
178+
return IsURL(match.Groups[2].Value);
179+
}
180+
return false;
181+
}
182+
private static string ConvertMarkdownToHtml(string markdown, StringBuilder htmlBuilder)
183+
{
184+
// Define the regex pattern to extract URLs from Markdown links.
185+
string pattern = @"\[(.*?)\]\((http[s]?:\/\/[^\s\)]+)\)";
186+
187+
// Create a match to extract the text and URL from the Markdown link.
188+
Match match = Regex.Match(markdown, pattern, RegexOptions.IgnoreCase);
189+
if (match.Success)
190+
{
191+
string linkText = match.Groups[1].Value; // Group 1 contains the link text.
192+
string url = match.Groups[2].Value; // Group 2 contains the URL.
193+
194+
htmlBuilder.AppendLine($"<p><a href=\"{url.Trim()}\">{linkText.Trim()}</a></p>");
195+
}
196+
197+
// Return original text if no Markdown link is found.
198+
return markdown;
199+
}
200+
201+
private string ConvertToHtmlBold(string input)
202+
{
203+
string pattern = @"\*\*(.*?)\*\*";
204+
string result = Regex.Replace(input, pattern, "<strong>$1</strong>");
205+
if (HasBackticks(result))
206+
{
207+
var backtickPattern = @"`([^`]*)`";
208+
var formattedText = Regex.Replace(result, backtickPattern, "<span>$1</span>");
209+
return formattedText;
210+
}
211+
return result;
212+
}
213+
214+
private bool ContainsBoldPattern(string input)
215+
{
216+
string pattern = @"\*\*.+?\*\*";
217+
return Regex.IsMatch(input, pattern);
218+
}
219+
220+
private void ConvertToHtmlList(string paragraph, StringBuilder htmlBuilder)
221+
{
222+
var items = paragraph.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
223+
htmlBuilder.AppendLine("<ol>");
224+
foreach (var item in items)
225+
{
226+
htmlBuilder.AppendLine($"<li>{item.Trim().TrimStart('-').Trim()}</li>");
227+
}
228+
htmlBuilder.AppendLine("</ol>");
229+
}
230+
}
231+
}

0 commit comments

Comments
 (0)