mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-02-12 03:41:38 +00:00
Improved Pandoc handling on dev environments (#634)
Some checks failed
Build and Release / Read metadata (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage deb updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage deb updater) (push) Has been cancelled
Build and Release / Prepare & create release (push) Has been cancelled
Build and Release / Publish release (push) Has been cancelled
Some checks failed
Build and Release / Read metadata (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage deb updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage deb updater) (push) Has been cancelled
Build and Release / Prepare & create release (push) Has been cancelled
Build and Release / Publish release (push) Has been cancelled
This commit is contained in:
parent
f84ea772b4
commit
c9f037bb2c
@ -1,7 +1,4 @@
|
|||||||
using System.Reflection;
|
using AIStudio.Components;
|
||||||
|
|
||||||
using AIStudio.Components;
|
|
||||||
using AIStudio.Tools.Metadata;
|
|
||||||
using AIStudio.Tools.Services;
|
using AIStudio.Tools.Services;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
@ -11,9 +8,8 @@ namespace AIStudio.Dialogs;
|
|||||||
|
|
||||||
public partial class PandocDialog : MSGComponentBase
|
public partial class PandocDialog : MSGComponentBase
|
||||||
{
|
{
|
||||||
private static readonly Assembly ASSEMBLY = Assembly.GetExecutingAssembly();
|
// Use runtime detection instead of metadata to ensure correct RID on dev machines:
|
||||||
private static readonly MetaDataArchitectureAttribute META_DATA_ARCH = ASSEMBLY.GetCustomAttribute<MetaDataArchitectureAttribute>()!;
|
private static readonly RID CPU_ARCHITECTURE = RIDExtensions.GetCurrentRID();
|
||||||
private static readonly RID CPU_ARCHITECTURE = META_DATA_ARCH.Architecture.ToRID();
|
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowInstallationPage { get; set; }
|
public bool ShowInstallationPage { get; set; }
|
||||||
|
|||||||
@ -17,7 +17,10 @@ public static partial class Pandoc
|
|||||||
|
|
||||||
private static readonly Assembly ASSEMBLY = Assembly.GetExecutingAssembly();
|
private static readonly Assembly ASSEMBLY = Assembly.GetExecutingAssembly();
|
||||||
private static readonly MetaDataArchitectureAttribute META_DATA_ARCH = ASSEMBLY.GetCustomAttribute<MetaDataArchitectureAttribute>()!;
|
private static readonly MetaDataArchitectureAttribute META_DATA_ARCH = ASSEMBLY.GetCustomAttribute<MetaDataArchitectureAttribute>()!;
|
||||||
private static readonly RID CPU_ARCHITECTURE = META_DATA_ARCH.Architecture.ToRID();
|
|
||||||
|
// Use runtime detection instead of metadata to ensure correct RID on dev machines:
|
||||||
|
private static readonly RID CPU_ARCHITECTURE = RIDExtensions.GetCurrentRID();
|
||||||
|
private static readonly RID METADATA_ARCHITECTURE = META_DATA_ARCH.Architecture.ToRID();
|
||||||
|
|
||||||
private const string DOWNLOAD_URL = "https://github.com/jgm/pandoc/releases/download";
|
private const string DOWNLOAD_URL = "https://github.com/jgm/pandoc/releases/download";
|
||||||
private const string LATEST_URL = "https://github.com/jgm/pandoc/releases/latest";
|
private const string LATEST_URL = "https://github.com/jgm/pandoc/releases/latest";
|
||||||
@ -26,6 +29,11 @@ public static partial class Pandoc
|
|||||||
private static readonly Version MINIMUM_REQUIRED_VERSION = new (3, 7, 0, 2);
|
private static readonly Version MINIMUM_REQUIRED_VERSION = new (3, 7, 0, 2);
|
||||||
private static readonly Version FALLBACK_VERSION = new (3, 7, 0, 2);
|
private static readonly Version FALLBACK_VERSION = new (3, 7, 0, 2);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tracks whether the first availability check log has been written to avoid log spam on repeated calls.
|
||||||
|
/// </summary>
|
||||||
|
private static bool HAS_LOGGED_AVAILABILITY_CHECK_ONCE;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prepares a Pandoc process by using the Pandoc process builder.
|
/// Prepares a Pandoc process by using the Pandoc process builder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -41,16 +49,39 @@ public static partial class Pandoc
|
|||||||
/// <returns>True, if pandoc is available and the minimum required version is met, else false.</returns>
|
/// <returns>True, if pandoc is available and the minimum required version is met, else false.</returns>
|
||||||
public static async Task<PandocInstallation> CheckAvailabilityAsync(RustService rustService, bool showMessages = true, bool showSuccessMessage = true)
|
public static async Task<PandocInstallation> CheckAvailabilityAsync(RustService rustService, bool showMessages = true, bool showSuccessMessage = true)
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
// Determine if we should log (only on the first call):
|
||||||
|
//
|
||||||
|
var shouldLog = !HAS_LOGGED_AVAILABILITY_CHECK_ONCE;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
// Log a warning if the runtime-detected RID differs from the metadata RID.
|
||||||
|
// This can happen on dev machines where the metadata.txt contains stale values.
|
||||||
|
// We always use the runtime-detected RID for correct behavior.
|
||||||
|
//
|
||||||
|
if (shouldLog && CPU_ARCHITECTURE != METADATA_ARCHITECTURE)
|
||||||
|
{
|
||||||
|
LOG.LogWarning(
|
||||||
|
"Runtime-detected RID '{RuntimeRID}' differs from metadata RID '{MetadataRID}'. Using runtime-detected RID. This is expected on dev machines where metadata.txt may be outdated.",
|
||||||
|
CPU_ARCHITECTURE.ToUserFriendlyName(),
|
||||||
|
METADATA_ARCHITECTURE.ToUserFriendlyName());
|
||||||
|
}
|
||||||
|
|
||||||
var preparedProcess = await PreparePandocProcess().AddArgument("--version").BuildAsync(rustService);
|
var preparedProcess = await PreparePandocProcess().AddArgument("--version").BuildAsync(rustService);
|
||||||
|
if (shouldLog)
|
||||||
|
LOG.LogInformation("Checking Pandoc availability using executable: '{Executable}' (IsLocal: {IsLocal}).", preparedProcess.StartInfo.FileName, preparedProcess.IsLocal);
|
||||||
|
|
||||||
using var process = Process.Start(preparedProcess.StartInfo);
|
using var process = Process.Start(preparedProcess.StartInfo);
|
||||||
if (process == null)
|
if (process == null)
|
||||||
{
|
{
|
||||||
if (showMessages)
|
if (showMessages)
|
||||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Help, TB("Was not able to check the Pandoc installation.")));
|
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Help, TB("Was not able to check the Pandoc installation.")));
|
||||||
|
|
||||||
LOG.LogInformation("The Pandoc process was not started, it was null");
|
if (shouldLog)
|
||||||
|
LOG.LogError("The Pandoc process was not started, it was null. Executable path: '{Executable}'.", preparedProcess.StartInfo.FileName);
|
||||||
|
|
||||||
return new(false, TB("Was not able to check the Pandoc installation."), false, string.Empty, preparedProcess.IsLocal);
|
return new(false, TB("Was not able to check the Pandoc installation."), false, string.Empty, preparedProcess.IsLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +99,9 @@ public static partial class Pandoc
|
|||||||
if (showMessages)
|
if (showMessages)
|
||||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Error, TB("Pandoc is not available on the system or the process had issues.")));
|
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Error, TB("Pandoc is not available on the system or the process had issues.")));
|
||||||
|
|
||||||
|
if (shouldLog)
|
||||||
LOG.LogError("The Pandoc process exited with code {ProcessExitCode}. Error output: '{ErrorText}'", process.ExitCode, error);
|
LOG.LogError("The Pandoc process exited with code {ProcessExitCode}. Error output: '{ErrorText}'", process.ExitCode, error);
|
||||||
|
|
||||||
return new(false, TB("Pandoc is not available on the system or the process had issues."), false, string.Empty, preparedProcess.IsLocal);
|
return new(false, TB("Pandoc is not available on the system or the process had issues."), false, string.Empty, preparedProcess.IsLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +111,9 @@ public static partial class Pandoc
|
|||||||
if (showMessages)
|
if (showMessages)
|
||||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Terminal, TB("Was not able to validate the Pandoc installation.")));
|
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Terminal, TB("Was not able to validate the Pandoc installation.")));
|
||||||
|
|
||||||
LOG.LogError("Pandoc --version returned an invalid format: {Output}", output);
|
if (shouldLog)
|
||||||
|
LOG.LogError("Pandoc --version returned an invalid format: '{Output}'.", output);
|
||||||
|
|
||||||
return new(false, TB("Was not able to validate the Pandoc installation."), false, string.Empty, preparedProcess.IsLocal);
|
return new(false, TB("Was not able to validate the Pandoc installation."), false, string.Empty, preparedProcess.IsLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,14 +126,18 @@ public static partial class Pandoc
|
|||||||
if (showMessages && showSuccessMessage)
|
if (showMessages && showSuccessMessage)
|
||||||
await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, string.Format(TB("Pandoc v{0} is installed."), installedVersionString)));
|
await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, string.Format(TB("Pandoc v{0} is installed."), installedVersionString)));
|
||||||
|
|
||||||
LOG.LogInformation("Pandoc v{0} is installed and matches the required version (v{1})", installedVersionString, MINIMUM_REQUIRED_VERSION.ToString());
|
if (shouldLog)
|
||||||
|
LOG.LogInformation("Pandoc v{0} is installed and matches the required version (v{1}).", installedVersionString, MINIMUM_REQUIRED_VERSION.ToString());
|
||||||
|
|
||||||
return new(true, string.Empty, true, installedVersionString, preparedProcess.IsLocal);
|
return new(true, string.Empty, true, installedVersionString, preparedProcess.IsLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showMessages)
|
if (showMessages)
|
||||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Build, string.Format(TB("Pandoc v{0} is installed, but it doesn't match the required version (v{1})."), installedVersionString, MINIMUM_REQUIRED_VERSION.ToString())));
|
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Build, string.Format(TB("Pandoc v{0} is installed, but it doesn't match the required version (v{1})."), installedVersionString, MINIMUM_REQUIRED_VERSION.ToString())));
|
||||||
|
|
||||||
LOG.LogWarning("Pandoc v{0} is installed, but it does not match the required version (v{1})", installedVersionString, MINIMUM_REQUIRED_VERSION.ToString());
|
if (shouldLog)
|
||||||
|
LOG.LogWarning("Pandoc v{0} is installed, but it does not match the required version (v{1}).", installedVersionString, MINIMUM_REQUIRED_VERSION.ToString());
|
||||||
|
|
||||||
return new(true, string.Format(TB("Pandoc v{0} is installed, but it does not match the required version (v{1})."), installedVersionString, MINIMUM_REQUIRED_VERSION.ToString()), false, installedVersionString, preparedProcess.IsLocal);
|
return new(true, string.Format(TB("Pandoc v{0} is installed, but it does not match the required version (v{1})."), installedVersionString, MINIMUM_REQUIRED_VERSION.ToString()), false, installedVersionString, preparedProcess.IsLocal);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -106,9 +145,15 @@ public static partial class Pandoc
|
|||||||
if (showMessages)
|
if (showMessages)
|
||||||
await MessageBus.INSTANCE.SendError(new(@Icons.Material.Filled.AppsOutage, TB("It seems that Pandoc is not installed.")));
|
await MessageBus.INSTANCE.SendError(new(@Icons.Material.Filled.AppsOutage, TB("It seems that Pandoc is not installed.")));
|
||||||
|
|
||||||
LOG.LogError("Pandoc is not installed and threw an exception: {0}", e.Message);
|
if(shouldLog)
|
||||||
|
LOG.LogError(e, "Pandoc availability check failed. This usually means Pandoc is not installed or not in the system PATH.");
|
||||||
|
|
||||||
return new(false, TB("It seems that Pandoc is not installed."), false, string.Empty, false);
|
return new(false, TB("It seems that Pandoc is not installed."), false, string.Empty, false);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
HAS_LOGGED_AVAILABILITY_CHECK_ONCE = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -13,7 +13,14 @@ public sealed class PandocProcessBuilder
|
|||||||
{
|
{
|
||||||
private static readonly Assembly ASSEMBLY = Assembly.GetExecutingAssembly();
|
private static readonly Assembly ASSEMBLY = Assembly.GetExecutingAssembly();
|
||||||
private static readonly MetaDataArchitectureAttribute META_DATA_ARCH = ASSEMBLY.GetCustomAttribute<MetaDataArchitectureAttribute>()!;
|
private static readonly MetaDataArchitectureAttribute META_DATA_ARCH = ASSEMBLY.GetCustomAttribute<MetaDataArchitectureAttribute>()!;
|
||||||
private static readonly RID CPU_ARCHITECTURE = META_DATA_ARCH.Architecture.ToRID();
|
|
||||||
|
// Use runtime detection instead of metadata to ensure correct RID on dev machines:
|
||||||
|
private static readonly RID CPU_ARCHITECTURE = RIDExtensions.GetCurrentRID();
|
||||||
|
private static readonly RID METADATA_ARCHITECTURE = META_DATA_ARCH.Architecture.ToRID();
|
||||||
|
private static readonly ILogger LOGGER = Program.LOGGER_FACTORY.CreateLogger(nameof(PandocProcessBuilder));
|
||||||
|
|
||||||
|
// Tracks whether the first log has been written to avoid log spam on repeated calls:
|
||||||
|
private static bool HAS_LOGGED_ONCE;
|
||||||
|
|
||||||
private string? providedInputFile;
|
private string? providedInputFile;
|
||||||
private string? providedOutputFile;
|
private string? providedOutputFile;
|
||||||
@ -111,32 +118,109 @@ public sealed class PandocProcessBuilder
|
|||||||
/// <returns>Path to the pandoc executable.</returns>
|
/// <returns>Path to the pandoc executable.</returns>
|
||||||
private static async Task<PandocExecutable> PandocExecutablePath(RustService rustService)
|
private static async Task<PandocExecutable> PandocExecutablePath(RustService rustService)
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
// Determine if we should log (only on the first call):
|
||||||
|
//
|
||||||
|
var shouldLog = !HAS_LOGGED_ONCE;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Log a warning if the runtime-detected RID differs from the metadata RID.
|
||||||
|
// This can happen on dev machines where the metadata.txt contains stale values.
|
||||||
|
// We always use the runtime-detected RID for correct behavior.
|
||||||
|
//
|
||||||
|
if (shouldLog && CPU_ARCHITECTURE != METADATA_ARCHITECTURE)
|
||||||
|
{
|
||||||
|
LOGGER.LogWarning(
|
||||||
|
"Runtime-detected RID '{RuntimeRID}' differs from metadata RID '{MetadataRID}'. Using runtime-detected RID. This is expected on dev machines where metadata.txt may be outdated.",
|
||||||
|
CPU_ARCHITECTURE.ToUserFriendlyName(),
|
||||||
|
METADATA_ARCHITECTURE.ToUserFriendlyName());
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// First, we try to find the pandoc executable in the data directory.
|
// First, we try to find the pandoc executable in the data directory.
|
||||||
// Any local installation should be preferred over the system-wide installation.
|
// Any local installation should be preferred over the system-wide installation.
|
||||||
//
|
//
|
||||||
var localInstallationRootDirectory = await Pandoc.GetPandocDataFolder(rustService);
|
var localInstallationRootDirectory = await Pandoc.GetPandocDataFolder(rustService);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check if the data directory path is valid:
|
||||||
|
//
|
||||||
|
if (string.IsNullOrWhiteSpace(localInstallationRootDirectory))
|
||||||
|
{
|
||||||
|
if (shouldLog)
|
||||||
|
LOGGER.LogWarning("The local data directory path is empty or null. Cannot search for local Pandoc installation.");
|
||||||
|
}
|
||||||
|
else if (!Directory.Exists(localInstallationRootDirectory))
|
||||||
|
{
|
||||||
|
if (shouldLog)
|
||||||
|
LOGGER.LogWarning("The local Pandoc installation directory does not exist: '{LocalInstallationRootDirectory}'.", localInstallationRootDirectory);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// The directory exists, search for the pandoc executable:
|
||||||
|
//
|
||||||
|
var executableName = PandocExecutableName;
|
||||||
|
if (shouldLog)
|
||||||
|
LOGGER.LogInformation("Searching for Pandoc executable '{ExecutableName}' in: '{LocalInstallationRootDirectory}'.", executableName, localInstallationRootDirectory);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var executableName = PandocExecutableName;
|
//
|
||||||
|
// First, check the root directory itself:
|
||||||
|
//
|
||||||
|
var rootExecutablePath = Path.Combine(localInstallationRootDirectory, executableName);
|
||||||
|
if (File.Exists(rootExecutablePath))
|
||||||
|
{
|
||||||
|
if (shouldLog)
|
||||||
|
LOGGER.LogInformation("Found local Pandoc installation at the root path: '{Path}'.", rootExecutablePath);
|
||||||
|
|
||||||
|
HAS_LOGGED_ONCE = true;
|
||||||
|
return new(rootExecutablePath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Then, search all subdirectories:
|
||||||
|
//
|
||||||
var subdirectories = Directory.GetDirectories(localInstallationRootDirectory, "*", SearchOption.AllDirectories);
|
var subdirectories = Directory.GetDirectories(localInstallationRootDirectory, "*", SearchOption.AllDirectories);
|
||||||
foreach (var subdirectory in subdirectories)
|
foreach (var subdirectory in subdirectories)
|
||||||
{
|
{
|
||||||
var pandocPath = Path.Combine(subdirectory, executableName);
|
var pandocPath = Path.Combine(subdirectory, executableName);
|
||||||
if (File.Exists(pandocPath))
|
if (File.Exists(pandocPath))
|
||||||
|
{
|
||||||
|
if (shouldLog)
|
||||||
|
LOGGER.LogInformation("Found local Pandoc installation at: '{Path}'.", pandocPath);
|
||||||
|
|
||||||
|
HAS_LOGGED_ONCE = true;
|
||||||
return new(pandocPath, true);
|
return new(pandocPath, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
|
if (shouldLog)
|
||||||
|
LOGGER.LogWarning("No Pandoc executable found in local installation directory or its subdirectories.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// ignored
|
if (shouldLog)
|
||||||
|
LOGGER.LogWarning(ex, "Error while searching for a local Pandoc installation in: '{LocalInstallationRootDirectory}'.", localInstallationRootDirectory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// When no local installation was found, we assume that the pandoc executable is in the system PATH.
|
// When no local installation was found, we assume that the pandoc executable is in the system PATH:
|
||||||
//
|
//
|
||||||
|
if (shouldLog)
|
||||||
|
LOGGER.LogWarning("Falling back to system PATH for the Pandoc executable: '{ExecutableName}'.", PandocExecutableName);
|
||||||
|
|
||||||
return new(PandocExecutableName, false);
|
return new(PandocExecutableName, false);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
HAS_LOGGED_ONCE = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads the os platform to determine the used executable name.
|
/// Reads the os platform to determine the used executable name.
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
# v26.1.2, build 232 (2026-01-xx xx:xx UTC)
|
# v26.1.2, build 232 (2026-01-xx xx:xx UTC)
|
||||||
- Added the option to hide specific assistants by configuration plugins. This is useful for enterprise environments in organizations.
|
- Added the option to hide specific assistants by configuration plugins. This is useful for enterprise environments in organizations.
|
||||||
- Added the current date and time to the system prompt for better context in conversations. Thanks Peer `peerschuett` for the contribution.
|
- Added the current date and time to the system prompt for better context in conversations. Thanks Peer `peerschuett` for the contribution.
|
||||||
- Added error handling for context window overflow, which can occur with huge file attachments in chats or the document analysis assistant.
|
- Added error handling for the context window overflow, which can occur with huge file attachments in chats or the document analysis assistant.
|
||||||
- Improved error handling for model loading in provider dialogs (LLMs, embeddings, transcriptions).
|
- Improved error handling for model loading in provider dialogs (LLMs, embeddings, transcriptions).
|
||||||
- Improved the microphone handling (transcription preview) so that all sound effects and the voice recording are processed without interruption.
|
- Improved the microphone handling (transcription preview) so that all sound effects and the voice recording are processed without interruption.
|
||||||
- Improved the handling of self-hosted providers in the configuration dialogs (LLMs, embeddings, and transcriptions) when the host cannot provide a list of models.
|
- Improved the handling of self-hosted providers in the configuration dialogs (LLMs, embeddings, and transcriptions) when the host cannot provide a list of models.
|
||||||
- Improved the document analysis assistant (in preview) by allowing users to send results to a new chat to ask follow-up questions. Thanks to Sabrina `Sabrina-devops` for this contribution.
|
- Improved the document analysis assistant (in preview) by allowing users to send results to a new chat to ask follow-up questions. Thanks to Sabrina `Sabrina-devops` for this contribution.
|
||||||
|
- Improved the developer experience by detecting incorrect CPU architecture metadata when checking and installing the Pandoc dependency.
|
||||||
- Improved error messages for failed communication with AI servers.
|
- Improved error messages for failed communication with AI servers.
|
||||||
- Fixed a logging bug that prevented log events from being recorded in some cases.
|
- Fixed a logging bug that prevented log events from being recorded in some cases.
|
||||||
- Fixed a bug that allowed adding a provider (LLM, embedding, or transcription) without selecting a model.
|
- Fixed a bug that allowed adding a provider (LLM, embedding, or transcription) without selecting a model.
|
||||||
|
|||||||
@ -1,7 +1,39 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace SharedTools;
|
namespace SharedTools;
|
||||||
|
|
||||||
public static class RIDExtensions
|
public static class RIDExtensions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Detects the current Runtime Identifier (RID) at runtime based on OS and architecture.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method should be preferred over reading the RID from metadata,
|
||||||
|
/// as the metadata may contain stale values in development environments.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>The detected RID for the current platform.</returns>
|
||||||
|
public static RID GetCurrentRID()
|
||||||
|
{
|
||||||
|
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
|
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||||
|
var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||||
|
var arch = RuntimeInformation.OSArchitecture;
|
||||||
|
|
||||||
|
return (isWindows, isLinux, isMacOS, arch) switch
|
||||||
|
{
|
||||||
|
(true, _, _, Architecture.X64) => RID.WIN_X64,
|
||||||
|
(true, _, _, Architecture.Arm64) => RID.WIN_ARM64,
|
||||||
|
|
||||||
|
(_, true, _, Architecture.X64) => RID.LINUX_X64,
|
||||||
|
(_, true, _, Architecture.Arm64) => RID.LINUX_ARM64,
|
||||||
|
|
||||||
|
(_, _, true, Architecture.X64) => RID.OSX_X64,
|
||||||
|
(_, _, true, Architecture.Arm64) => RID.OSX_ARM64,
|
||||||
|
|
||||||
|
_ => RID.NONE,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static string AsMicrosoftRid(this RID rid) => rid switch
|
public static string AsMicrosoftRid(this RID rid) => rid switch
|
||||||
{
|
{
|
||||||
RID.WIN_X64 => "win-x64",
|
RID.WIN_X64 => "win-x64",
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
use log::warn;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use crate::environment::DATA_DIRECTORY;
|
use crate::environment::DATA_DIRECTORY;
|
||||||
use crate::metadata::META_DATA;
|
use crate::metadata::META_DATA;
|
||||||
|
|
||||||
|
/// Tracks whether the RID mismatch warning has been logged.
|
||||||
|
static HAS_LOGGED_RID_MISMATCH: OnceLock<()> = OnceLock::new();
|
||||||
|
|
||||||
pub struct PandocExecutable {
|
pub struct PandocExecutable {
|
||||||
pub executable: String,
|
pub executable: String,
|
||||||
pub is_local_installation: bool,
|
pub is_local_installation: bool,
|
||||||
@ -156,13 +161,51 @@ impl PandocProcessBuilder {
|
|||||||
Err("Executable not found".into())
|
Err("Executable not found".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads the os platform to determine the used executable name.
|
/// Determines the executable name based on the current OS at runtime.
|
||||||
|
///
|
||||||
|
/// This uses runtime detection instead of metadata to ensure correct behavior
|
||||||
|
/// on dev machines where the metadata may contain stale values.
|
||||||
fn pandoc_executable_name() -> String {
|
fn pandoc_executable_name() -> String {
|
||||||
let metadata = META_DATA.lock().unwrap();
|
// Log a warning (once) if the runtime OS differs from the metadata architecture.
|
||||||
let metadata = metadata.as_ref().unwrap();
|
// This can happen on dev machines where the metadata.txt contains stale values.
|
||||||
|
HAS_LOGGED_RID_MISMATCH.get_or_init(|| {
|
||||||
|
let runtime_os = std::env::consts::OS;
|
||||||
|
let runtime_arch = std::env::consts::ARCH;
|
||||||
|
|
||||||
match metadata.architecture.as_str() {
|
if let Ok(metadata) = META_DATA.lock() {
|
||||||
"win-arm64" | "win-x64" => "pandoc.exe".to_string(),
|
if let Some(metadata) = metadata.as_ref() {
|
||||||
|
let metadata_arch = &metadata.architecture;
|
||||||
|
|
||||||
|
// Determine expected OS from metadata:
|
||||||
|
let metadata_is_windows = metadata_arch.starts_with("win-");
|
||||||
|
let metadata_is_macos = metadata_arch.starts_with("osx-");
|
||||||
|
let metadata_is_linux = metadata_arch.starts_with("linux-");
|
||||||
|
|
||||||
|
// Compare with runtime OS:
|
||||||
|
let runtime_is_windows = runtime_os == "windows";
|
||||||
|
let runtime_is_macos = runtime_os == "macos";
|
||||||
|
let runtime_is_linux = runtime_os == "linux";
|
||||||
|
|
||||||
|
let os_mismatch = (metadata_is_windows != runtime_is_windows)
|
||||||
|
|| (metadata_is_macos != runtime_is_macos)
|
||||||
|
|| (metadata_is_linux != runtime_is_linux);
|
||||||
|
|
||||||
|
if os_mismatch {
|
||||||
|
warn!(
|
||||||
|
Source = "Pandoc";
|
||||||
|
"Runtime-detected OS '{}-{}' differs from metadata architecture '{}'. Using runtime-detected OS. This is expected on dev machines where metadata.txt may be outdated.",
|
||||||
|
runtime_os,
|
||||||
|
runtime_arch,
|
||||||
|
metadata_arch
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Use std::env::consts::OS for runtime detection instead of metadata
|
||||||
|
match std::env::consts::OS {
|
||||||
|
"windows" => "pandoc.exe".to_string(),
|
||||||
_ => "pandoc".to_string(),
|
_ => "pandoc".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user