diff --git a/app/MindWork AI Studio/Pages/About.razor b/app/MindWork AI Studio/Pages/About.razor
index 32c8b5df..d4a37762 100644
--- a/app/MindWork AI Studio/Pages/About.razor
+++ b/app/MindWork AI Studio/Pages/About.razor
@@ -3,6 +3,22 @@
About MindWork AI Studio
+
+
+ Pandoc Verfügbarkeit prüfen
+
+ @(isChecking ? "Überprüfe..." : "Pandoc überprüfen")
+
+ @statusMessage
+
+
+
+ Pandoc Installation
+
+ Install Pandoc
+
+
+
diff --git a/app/MindWork AI Studio/Pages/About.razor.cs b/app/MindWork AI Studio/Pages/About.razor.cs
index 51727506..94e5d612 100644
--- a/app/MindWork AI Studio/Pages/About.razor.cs
+++ b/app/MindWork AI Studio/Pages/About.razor.cs
@@ -174,4 +174,30 @@ public partial class About : ComponentBase
{
await this.MessageBus.SendMessage(this, Event.USER_SEARCH_FOR_UPDATE);
}
+
+ // TODO: DELETE FOR DEBUGGING ONLY
+ private bool isChecking;
+ private string statusMessage = string.Empty;
+ private async Task CheckPandoc()
+ {
+ this.isChecking = true;
+ this.statusMessage = "Überprüfe die Verfügbarkeit von Pandoc...";
+ this.StateHasChanged(); // Aktualisiere die UI
+ var isPandocAvailable = await Pandoc.IsPandocAvailableAsync();
+ if (isPandocAvailable)
+ {
+ this.statusMessage = "Pandoc ist verfügbar und erfüllt die Mindestversion.";
+ }
+ else
+ {
+ this.statusMessage = "Pandoc ist nicht verfügbar oder die installierte Version ist zu niedrig.";
+ }
+ this.isChecking = false;
+ this.StateHasChanged(); // Aktualisiere die UI
+ }
+
+ private async Task InstallPandoc()
+ {
+ var installPandoc = Pandoc.InstallPandocAsync(this.RustService);
+ }
}
diff --git a/app/MindWork AI Studio/Tools/Error.cs b/app/MindWork AI Studio/Tools/Error.cs
index a3ba6c61..77f8d7c2 100644
--- a/app/MindWork AI Studio/Tools/Error.cs
+++ b/app/MindWork AI Studio/Tools/Error.cs
@@ -13,4 +13,19 @@ public readonly record struct Error(string Icon, string Message)
config.VisibleStateDuration = 14_000;
});
}
+}
+
+public readonly record struct Success(string Icon, string Message)
+{
+ public void Show(ISnackbar snackbar)
+ {
+ var icon = this.Icon;
+ snackbar.Add(this.Message, Severity.Success, config =>
+ {
+ config.Icon = icon;
+ config.IconSize = Size.Large;
+ config.HideTransitionDuration = 600;
+ config.VisibleStateDuration = 10_000;
+ });
+ }
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Tools/Event.cs b/app/MindWork AI Studio/Tools/Event.cs
index 213adf29..76a5051b 100644
--- a/app/MindWork AI Studio/Tools/Event.cs
+++ b/app/MindWork AI Studio/Tools/Event.cs
@@ -11,6 +11,7 @@ public enum Event
STARTUP_PLUGIN_SYSTEM,
PLUGINS_RELOADED,
SHOW_ERROR,
+ SHOW_SUCCESS,
// Update events:
USER_SEARCH_FOR_UPDATE,
diff --git a/app/MindWork AI Studio/Tools/MessageBus.cs b/app/MindWork AI Studio/Tools/MessageBus.cs
index 06a2dfd8..3d48a7bb 100644
--- a/app/MindWork AI Studio/Tools/MessageBus.cs
+++ b/app/MindWork AI Studio/Tools/MessageBus.cs
@@ -67,6 +67,8 @@ public sealed class MessageBus
}
public Task SendError(Error error) => this.SendMessage(null, Event.SHOW_ERROR, error);
+
+ public Task SendSuccess(Success success) => this.SendMessage(null, Event.SHOW_SUCCESS, success);
public void DeferMessage(ComponentBase? sendingComponent, Event triggeredEvent, T? data = default)
{
diff --git a/app/MindWork AI Studio/Tools/Pandoc.cs b/app/MindWork AI Studio/Tools/Pandoc.cs
new file mode 100644
index 00000000..73cdc6ad
--- /dev/null
+++ b/app/MindWork AI Studio/Tools/Pandoc.cs
@@ -0,0 +1,136 @@
+using System.Diagnostics;
+using System.IO.Compression;
+using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
+using AIStudio.Components;
+using AIStudio.Tools.Services;
+
+namespace AIStudio.Tools;
+
+public static partial class Pandoc
+{
+ private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger("PluginFactory");
+ private static readonly string DOWNLOAD_URL = "https://github.com/jgm/pandoc/releases/download/3.6.4/pandoc-3.6.4-windows-x86_64.zip";
+ private static readonly Version MINIMUM_REQUIRED_VERSION = new Version(3, 6);
+
+ ///
+ /// Checks if pandoc is available on the system and can be started as a process
+ ///
+ /// True, if pandoc is available and the minimum required version is met, else False.
+ public static async Task IsPandocAvailableAsync()
+ {
+ try
+ {
+ var startInfo = new ProcessStartInfo
+ {
+ FileName = GetPandocExecutableName(),
+ Arguments = "--version",
+ RedirectStandardOutput = true,
+ UseShellExecute = false,
+ CreateNoWindow = true
+ };
+ using var process = Process.Start(startInfo);
+ if (process == null)
+ {
+ await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Help, "The pandoc process could not be started."));
+ LOG.LogInformation("The pandoc process was not started, it was null");
+ return false;
+ }
+
+ var output = await process.StandardOutput.ReadToEndAsync();
+ await process.WaitForExitAsync();
+ if (process.ExitCode != 0)
+ {
+ await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Error, $"The pandoc process exited unexpectedly."));
+ LOG.LogError("The pandoc process was exited with code {ProcessExitCode}", process.ExitCode);
+ return false;
+ }
+
+ var versionMatch = PandocRegex().Match(output);
+ if (!versionMatch.Success)
+ {
+ await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Terminal, $"pandoc --version returned an invalid format."));
+ LOG.LogError("pandoc --version returned an invalid format:\n {Output}", output);
+ return false;
+ }
+ var versions = versionMatch.Groups[1].Value.Split('.');
+ var major = int.Parse(versions[0]);
+ var minor = int.Parse(versions[1]);
+ var installedVersion = new Version(major, minor);
+
+ if (installedVersion >= MINIMUM_REQUIRED_VERSION)
+ {
+ await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, $"Pandoc {installedVersion.ToString()} is installed."));
+ return true;
+ }
+
+ await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Build, $"Pandoc {installedVersion.ToString()} is installed, but it doesn't match the required version ({MINIMUM_REQUIRED_VERSION.ToString()})."));
+ LOG.LogInformation("Pandoc {Installed} is installed, but it does not match the required version ({Requirement})", installedVersion.ToString(), MINIMUM_REQUIRED_VERSION.ToString());
+ return false;
+
+ }
+ catch (Exception e)
+ {
+ await MessageBus.INSTANCE.SendError(new (@Icons.Material.Filled.AppsOutage, "Pandoc is not installed."));
+ LOG.LogError("Pandoc is not installed and threw an exception:\n {Message}", e.Message);
+ return false;
+ }
+ }
+
+ public static async Task InstallPandocAsync(RustService rustService)
+ {
+ var dataDir = await rustService.GetDataDirectory();
+ await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Help, $"{dataDir}"));
+ var installDir = Path.Join(dataDir, "pandoc");
+
+ try
+ {
+ if (!Directory.Exists(installDir))
+ Directory.CreateDirectory(installDir);
+
+ using var client = new HttpClient();
+ var response = await client.GetAsync(DOWNLOAD_URL);
+ if (response.IsSuccessStatusCode)
+ {
+ var fileBytes = await response.Content.ReadAsByteArrayAsync();
+ var tempZipPath = Path.Join(Path.GetTempPath(), "pandoc.zip");
+ await File.WriteAllBytesAsync(tempZipPath, fileBytes);
+ ZipFile.ExtractToDirectory(tempZipPath, installDir);
+ File.Delete(tempZipPath);
+
+ var currentPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine);
+ var pandocDir = Path.Join(currentPath, "pandoc-3.6.4");
+ if (currentPath != null && !currentPath.Contains(pandocDir))
+ {
+ Environment.SetEnvironmentVariable(
+ "PATH",
+ $"{currentPath};{pandocDir}",
+ EnvironmentVariableTarget.Machine);
+ Console.WriteLine("Pandoc-Verzeichnis zum PATH hinzugefügt.");
+ }
+ else
+ {
+ Console.WriteLine("Pandoc-Verzeichnis ist bereits im PATH.");
+ }
+
+ await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, $"Pandoc {MINIMUM_REQUIRED_VERSION.ToString()} was installed successfully."));
+ }
+ else
+ {
+ Console.WriteLine("Fehler beim Herunterladen von Pandoc.");
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Fehler: {ex.Message}");
+ }
+ }
+
+ ///
+ /// Returns the name of the pandoc executable based on the running operating system
+ ///
+ private static string GetPandocExecutableName() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "pandoc.exe" : "pandoc";
+
+ [GeneratedRegex(@"pandoc(?:\.exe)?\s*([0-9]+\.[0-9]+)")]
+ private static partial Regex PandocRegex();
+}
\ No newline at end of file