feat: get web app talking to api
This commit is contained in:
@@ -45,6 +45,21 @@ builder.Services.AddRateLimiter(
|
||||
}
|
||||
);
|
||||
|
||||
// TODO: Make CORS more restrictive
|
||||
// only allow requests from the web
|
||||
// client
|
||||
const string corsPolicyName = "cors";
|
||||
|
||||
builder.Services.AddCors(o =>
|
||||
{
|
||||
o.AddPolicy(corsPolicyName, p =>
|
||||
{
|
||||
p.AllowAnyOrigin()
|
||||
.AllowAnyOrigin()
|
||||
.AllowAnyMethod();
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
@@ -57,6 +72,8 @@ if (app.Environment.IsProduction())
|
||||
app.UseRateLimiter();
|
||||
}
|
||||
|
||||
app.UseCors(corsPolicyName);
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseStatusCodePages();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
namespace AltGen.Console.Generate;
|
||||
|
||||
// TODO: Use shared library version of this service
|
||||
sealed class AltGenService(HttpClient client) : IAltGenService
|
||||
{
|
||||
static readonly JsonSerializerOptions JsonOptions = new()
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace AltGen.Shared.Generate;
|
||||
|
||||
public sealed class AltGenService(HttpClient client) : IAltGenService
|
||||
{
|
||||
static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
readonly HttpClient _client = client;
|
||||
|
||||
public async Task<string> GenerateAltTextAsync(GenerateAltTextRequest req)
|
||||
{
|
||||
var byteContent = new ByteArrayContent(req.Image);
|
||||
byteContent.Headers.ContentType = new MediaTypeHeaderValue(req.ContentType);
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, "/generate")
|
||||
{
|
||||
Content = new MultipartFormDataContent
|
||||
{
|
||||
{ new StringContent(req.Provider), "provider" },
|
||||
{ new StringContent(req.ProviderKey), "providerKey" },
|
||||
{ byteContent, "file", req.FileName }
|
||||
}
|
||||
};
|
||||
|
||||
var response = await _client.SendAsync(request);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
if (response.IsSuccessStatusCode is false)
|
||||
{
|
||||
throw new AltTextException("Failed to generate alt text.");
|
||||
}
|
||||
|
||||
var altTextResponse = JsonSerializer.Deserialize<AltTextResponse>(content, JsonOptions) ?? throw new AltTextException("Failed to deserialize response.");
|
||||
|
||||
return altTextResponse.AltText;
|
||||
}
|
||||
}
|
||||
|
||||
record AltTextResponse(string AltText);
|
||||
|
||||
class AltTextException(string message) : Exception(message)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace AltGen.Shared.Generate;
|
||||
|
||||
public record GenerateAltTextRequest(
|
||||
string Provider,
|
||||
string ProviderKey,
|
||||
string FileName,
|
||||
byte[] Image,
|
||||
string ContentType
|
||||
);
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace AltGen.Shared.Generate;
|
||||
|
||||
public interface IAltGenService
|
||||
{
|
||||
public Task<string> GenerateAltTextAsync(GenerateAltTextRequest req);
|
||||
}
|
||||
@@ -10,6 +10,11 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AltGen.Shared\AltGen.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,24 +1,51 @@
|
||||
@inject ILogger<Home> Logger
|
||||
@using AltGen.Shared.Generate
|
||||
@inject ILogger<Home> Logger
|
||||
@inject IAltGenService AltGenService
|
||||
@page "/"
|
||||
@rendermode InteractiveWebAssembly
|
||||
@rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false))
|
||||
|
||||
<PageTitle>AltGen.Web</PageTitle>
|
||||
|
||||
<h1>AI Generated Alt Text</h1>
|
||||
|
||||
<form method="post">
|
||||
<input type="text" @onchange="@(e => Logger.LogInformation("Text changed: {Value}", e.Value))" />
|
||||
<InputFile OnChange="LoadFiles" multiple />
|
||||
<div>
|
||||
<label for="provider">Provider</label>
|
||||
<input type="text" id="provider" name="provider" required @bind="_provider" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="providerKey">Provider Key</label>
|
||||
<input type="password" id="providerKey" name="providerKey" required @bind="_providerKey" />
|
||||
</div>
|
||||
<InputFile OnChange="HandleFileChange" />
|
||||
</form>
|
||||
|
||||
@code {
|
||||
private void LoadFiles(InputFileChangeEventArgs e)
|
||||
{
|
||||
var files = e.GetMultipleFiles(5);
|
||||
private string? _provider;
|
||||
private string? _providerKey;
|
||||
|
||||
foreach (var file in files)
|
||||
private async Task HandleFileChange(InputFileChangeEventArgs e)
|
||||
{
|
||||
Logger.LogInformation("File loaded: {Name}, Size: {Size}", file.Name, file.Size);
|
||||
var file = e.File;
|
||||
|
||||
if (_provider is null || _providerKey is null || file is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var fileBytes = new byte[file.Size];
|
||||
using var stream = file.OpenReadStream();
|
||||
await stream.ReadAsync(fileBytes, 0, (int)file.Size);
|
||||
|
||||
var altText = await AltGenService.GenerateAltTextAsync(new(
|
||||
_provider,
|
||||
_providerKey,
|
||||
file.Name,
|
||||
fileBytes,
|
||||
file.ContentType
|
||||
));
|
||||
|
||||
// TODO: Present on the screen to the user
|
||||
Logger.LogInformation(altText);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using AltGen.Shared.Generate;
|
||||
|
||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
|
||||
// TODO: Read base url
|
||||
// from configuration
|
||||
builder.Services.AddHttpClient<IAltGenService, AltGenService>(c => c.BaseAddress = new("https://localhost:7297"));
|
||||
|
||||
await builder.Build().RunAsync();
|
||||
|
||||
@@ -11,4 +11,8 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AltGen.Shared\AltGen.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -15,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AltGen.Web", "AltGen.Web\Al
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AltGen.Web.Client", "AltGen.Web.Client\AltGen.Web.Client.csproj", "{DCE07E79-23A4-490E-A796-EA140D2040C1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AltGen.Shared", "AltGen.Shared\AltGen.Shared.csproj", "{68D4BC5D-A6FE-41CF-B744-1DB83CCFBC89}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -48,5 +50,9 @@ Global
|
||||
{DCE07E79-23A4-490E-A796-EA140D2040C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DCE07E79-23A4-490E-A796-EA140D2040C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DCE07E79-23A4-490E-A796-EA140D2040C1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{68D4BC5D-A6FE-41CF-B744-1DB83CCFBC89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{68D4BC5D-A6FE-41CF-B744-1DB83CCFBC89}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{68D4BC5D-A6FE-41CF-B744-1DB83CCFBC89}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{68D4BC5D-A6FE-41CF-B744-1DB83CCFBC89}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Reference in New Issue
Block a user