using System.Text;
using Microsoft.Extensions.FileProviders;
#if RELEASE
using System.Reflection;
#endif
namespace AIStudio.Tools;
///
/// Reads files which come with AI Studio, such as prompts, guides, or the built-in plugins.
///
///
/// The files lie below the project folder and are listed as EmbeddedResource in the project file. A development
/// build reads them from the disk, so that a change shows without building again; a release reads them from the
/// resources embedded into the app. Paths are relative to the project folder and use forward slashes.
///
public static class AppResources
{
///
/// Gets a file provider for a folder of the app.
///
/// The folder, relative to the project folder, e.g., "Plugins".
/// The file provider, whose paths are relative to that folder.
public static IFileProvider FolderProvider(string relativeFolder)
{
var folder = Normalize(relativeFolder);
#if DEBUG
return new PhysicalFileProvider(Path.Join(Environment.CurrentDirectory, folder));
#else
return new ManifestEmbeddedFileProvider(Assembly.GetAssembly(typeof(Program))!, folder);
#endif
}
///
/// Reads a text file of the app.
///
/// The file, relative to the project folder, e.g., "Assistants/PromptOptimizer/prompting_guideline.md".
/// The cancellation token.
/// The text, or an empty string when the app has no such file.
public static async Task ReadTextAsync(string relativePath, CancellationToken token = default)
{
var path = Normalize(relativePath);
#if DEBUG
var filePath = Path.Join(Environment.CurrentDirectory, path);
return File.Exists(filePath) ? await File.ReadAllTextAsync(filePath, Encoding.UTF8, token) : string.Empty;
#else
var file = new ManifestEmbeddedFileProvider(Assembly.GetAssembly(typeof(Program))!).GetFileInfo(path);
if (!file.Exists || file.IsDirectory)
return string.Empty;
await using var stream = file.CreateReadStream();
using var reader = new StreamReader(stream, Encoding.UTF8);
return await reader.ReadToEndAsync(token);
#endif
}
///
/// Turns a path into the form both kinds of builds understand: forward slashes, without a slash at either end.
///
/// The path.
private static string Normalize(string relativePath) => relativePath.Replace('\\', '/').Trim('/');
}