mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-03 15:27:21 +00:00
Changed the changelog and the ERI specifications to load without a request to the app server
This commit is contained in:
7 files changed
+90
-32
No files matched your search
@@ -13,7 +13,7 @@ namespace AIStudio.Assistants.ERI;
|
|||||||
public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
|
public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
|
||||||
{
|
{
|
||||||
[Inject]
|
[Inject]
|
||||||
private HttpClient HttpClient { get; set; } = null!;
|
private WebRootFiles WebRootFiles { get; set; } = null!;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private IDialogService DialogService { get; init; } = null!;
|
private IDialogService DialogService { get; init; } = null!;
|
||||||
@@ -843,7 +843,7 @@ public partial class AssistantERI : AssistantBaseCore<SettingsDialogERIServer>
|
|||||||
var baseDirectorySnapshot = this.baseDirectory;
|
var baseDirectorySnapshot = this.baseDirectory;
|
||||||
var previouslyGeneratedFilesSnapshot = this.previouslyGeneratedFiles.ToArray();
|
var previouslyGeneratedFilesSnapshot = this.previouslyGeneratedFiles.ToArray();
|
||||||
|
|
||||||
this.eriSpecification = await this.selectedERIVersion.ReadSpecification(this.HttpClient);
|
this.eriSpecification = await this.selectedERIVersion.ReadSpecification(this.WebRootFiles);
|
||||||
if (string.IsNullOrWhiteSpace(this.eriSpecification))
|
if (string.IsNullOrWhiteSpace(this.eriSpecification))
|
||||||
{
|
{
|
||||||
this.AddInputIssue(T("The ERI specification could not be loaded. Please try again later."));
|
this.AddInputIssue(T("The ERI specification could not be loaded. Please try again later."));
|
||||||
|
|||||||
@@ -2,19 +2,7 @@ namespace AIStudio.Assistants.ERI;
|
|||||||
|
|
||||||
public static class ERIVersionExtensions
|
public static class ERIVersionExtensions
|
||||||
{
|
{
|
||||||
public static async Task<string> ReadSpecification(this ERIVersion version, HttpClient httpClient)
|
public static Task<string> ReadSpecification(this ERIVersion version, WebRootFiles webRootFiles) => webRootFiles.ReadTextAsync(version.SpecificationURL());
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var url = version.SpecificationURL();
|
|
||||||
using var response = await httpClient.GetAsync(url);
|
|
||||||
return await response.Content.ReadAsStringAsync();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string SpecificationURL(this ERIVersion version)
|
public static string SpecificationURL(this ERIVersion version)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace AIStudio.Components;
|
|||||||
public partial class Changelog : MSGComponentBase
|
public partial class Changelog : MSGComponentBase
|
||||||
{
|
{
|
||||||
[Inject]
|
[Inject]
|
||||||
private HttpClient HttpClient { get; set; } = null!;
|
private WebRootFiles WebRootFiles { get; set; } = null!;
|
||||||
|
|
||||||
#region Overrides of ComponentBase
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
@@ -23,7 +23,6 @@ public partial class Changelog : MSGComponentBase
|
|||||||
|
|
||||||
private async Task ReadLogAsync()
|
private async Task ReadLogAsync()
|
||||||
{
|
{
|
||||||
using var response = await this.HttpClient.GetAsync($"changelog/{this.SelectedLog.Filename}");
|
this.LogContent = await this.WebRootFiles.ReadTextAsync($"changelog/{this.SelectedLog.Filename}");
|
||||||
this.LogContent = await response.Content.ReadAsStringAsync();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ namespace AIStudio.Pages;
|
|||||||
public partial class Home : MSGComponentBase
|
public partial class Home : MSGComponentBase
|
||||||
{
|
{
|
||||||
[Inject]
|
[Inject]
|
||||||
private HttpClient HttpClient { get; init; } = null!;
|
private WebRootFiles WebRootFiles { get; init; } = null!;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private NavigationManager NavigationManager { get; init; } = null!;
|
private NavigationManager NavigationManager { get; init; } = null!;
|
||||||
@@ -222,8 +222,7 @@ public partial class Home : MSGComponentBase
|
|||||||
private async Task ReadLastChangeAsync()
|
private async Task ReadLastChangeAsync()
|
||||||
{
|
{
|
||||||
var latest = Changelog.LOGS.MaxBy(n => n.Build);
|
var latest = Changelog.LOGS.MaxBy(n => n.Build);
|
||||||
using var response = await this.HttpClient.GetAsync($"changelog/{latest.Filename}");
|
this.LastChangeContent = await this.WebRootFiles.ReadTextAsync($"changelog/{latest.Filename}");
|
||||||
this.LastChangeContent = await response.Content.ReadAsStringAsync();
|
|
||||||
|
|
||||||
await this.InvokeAsync(this.StateHasChanged);
|
await this.InvokeAsync(this.StateHasChanged);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,11 +32,6 @@ using MudBlazor.Services;
|
|||||||
|
|
||||||
using MudExtensions.Services;
|
using MudExtensions.Services;
|
||||||
|
|
||||||
#if !DEBUG
|
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.Extensions.FileProviders;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace AIStudio;
|
namespace AIStudio;
|
||||||
|
|
||||||
internal sealed class Program
|
internal sealed class Program
|
||||||
@@ -283,10 +278,9 @@ internal sealed class Program
|
|||||||
options.KeepAliveInterval = TimeSpan.FromSeconds(30);
|
options.KeepAliveInterval = TimeSpan.FromSeconds(30);
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddSingleton(new HttpClient
|
// For absolute URLs only. The app reads its own files through WebRootFiles:
|
||||||
{
|
builder.Services.AddSingleton(new HttpClient());
|
||||||
BaseAddress = new Uri($"http://127.0.0.1:{appPort}")
|
builder.Services.AddSingleton<WebRootFiles>();
|
||||||
});
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// We listen on the IPv4 loopback address only, where the app window goes. With localhost, the
|
// We listen on the IPv4 loopback address only, where the app window goes. With localhost, the
|
||||||
@@ -356,10 +350,9 @@ internal sealed class Program
|
|||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseDeveloperExceptionPage();
|
app.UseDeveloperExceptionPage();
|
||||||
#else
|
#else
|
||||||
var fileProvider = new ManifestEmbeddedFileProvider(Assembly.GetAssembly(type: typeof(Program))!, "wwwroot");
|
|
||||||
app.UseStaticFiles(new StaticFileOptions
|
app.UseStaticFiles(new StaticFileOptions
|
||||||
{
|
{
|
||||||
FileProvider = fileProvider,
|
FileProvider = app.Services.GetRequiredService<WebRootFiles>().FileProvider,
|
||||||
RequestPath = string.Empty,
|
RequestPath = string.Empty,
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.FileProviders;
|
||||||
|
|
||||||
|
namespace AIStudio.Tools;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the files below wwwroot, which every build embeds into the app.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The app reads files such as its changelogs directly instead of requesting them over HTTP from
|
||||||
|
/// its own server. The release build serves its static files from the same provider.
|
||||||
|
/// </remarks>
|
||||||
|
public sealed class WebRootFiles
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the files below wwwroot.
|
||||||
|
/// </summary>
|
||||||
|
public IFileProvider FileProvider { get; } = new ManifestEmbeddedFileProvider(Assembly.GetAssembly(type: typeof(Program))!, "wwwroot");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a text file below wwwroot.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path below wwwroot, such as <c>changelog/v26.10.1.md</c>.</param>
|
||||||
|
/// <returns>The text of the file, or an empty string when there is no such file.</returns>
|
||||||
|
public async Task<string> ReadTextAsync(string path)
|
||||||
|
{
|
||||||
|
var file = this.FileProvider.GetFileInfo(path);
|
||||||
|
if (!file.Exists)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
await using var fileStream = file.CreateReadStream();
|
||||||
|
using var reader = new StreamReader(fileStream);
|
||||||
|
return await reader.ReadToEndAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using AIStudio.Assistants.ERI;
|
||||||
|
using AIStudio.Tools;
|
||||||
|
|
||||||
|
using Changelog = AIStudio.Components.Changelog;
|
||||||
|
|
||||||
|
namespace AIStudio.Tests.Tools.AppAccess;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks that the app reads the files below wwwroot which it shows itself.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The changelogs and the ERI specifications come from the files embedded into the app, not from a
|
||||||
|
/// request to its own server. A file which is missing there would leave the changelog or the ERI
|
||||||
|
/// assistant empty without any error.
|
||||||
|
/// </remarks>
|
||||||
|
[TestFixture]
|
||||||
|
public sealed class WebRootFilesTests
|
||||||
|
{
|
||||||
|
private static IEnumerable<string> ChangelogFiles() => Changelog.LOGS.Select(log => log.Filename);
|
||||||
|
|
||||||
|
private static IEnumerable<ERIVersion> SpecificationVersions() => Enum.GetValues<ERIVersion>().Where(version => version.WasSpecificationSelected());
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(ChangelogFiles))]
|
||||||
|
public async Task EveryChangelogCanBeRead(string filename)
|
||||||
|
{
|
||||||
|
var text = await new WebRootFiles().ReadTextAsync($"changelog/{filename}");
|
||||||
|
Assert.That(text, Is.Not.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(SpecificationVersions))]
|
||||||
|
public async Task EveryERISpecificationCanBeRead(ERIVersion version)
|
||||||
|
{
|
||||||
|
var text = await version.ReadSpecification(new WebRootFiles());
|
||||||
|
Assert.That(text, Is.Not.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task AMissingFileReadsAsEmptyText()
|
||||||
|
{
|
||||||
|
var text = await new WebRootFiles().ReadTextAsync("changelog/does-not-exist.md");
|
||||||
|
Assert.That(text, Is.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user