Merge branch '42-add-about-page' into 'main'

Resolve "Add about page"

Closes #42, #2, #48, and #29

See merge request products/mindwork-ai-studio!5
This commit is contained in:
Thorsten 2024-05-25 18:16:08 +00:00
commit 719b0ed848
35 changed files with 511 additions and 65 deletions

View File

@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="Tauri Dev" type="ShConfigurationType"> <configuration default="false" name="Tauri Dev" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value="cargo tauri dev" /> <option name="SCRIPT_TEXT" value="cargo tauri dev --no-watch" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" /> <option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value="" /> <option name="SCRIPT_PATH" value="" />
<option name="SCRIPT_OPTIONS" value="" /> <option name="SCRIPT_OPTIONS" value="" />

View File

@ -1,5 +1,3 @@
using MudBlazor;
namespace AIStudio.Chat; namespace AIStudio.Chat;
/// <summary> /// <summary>

View File

@ -34,19 +34,10 @@
<MudSkeleton Width="100%"/> <MudSkeleton Width="100%"/>
} }
else else
{
@if (this.Content.IsStreaming)
{
<MudText Typo="Typo.body1" Style="white-space: pre-wrap;">
@textContent.Text
</MudText>
}
else
{ {
<MudMarkdown Value="@textContent.Text"/> <MudMarkdown Value="@textContent.Text"/>
} }
} }
}
break; break;

View File

@ -1,9 +1,6 @@
using AIStudio.Tools; using AIStudio.Tools;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using MudBlazor;
namespace AIStudio.Chat; namespace AIStudio.Chat;

View File

@ -1,8 +1,6 @@
using AIStudio.Provider; using AIStudio.Provider;
using AIStudio.Settings; using AIStudio.Settings;
using Microsoft.JSInterop;
namespace AIStudio.Chat; namespace AIStudio.Chat;
/// <summary> /// <summary>

View File

@ -1,8 +1,6 @@
using AIStudio.Provider; using AIStudio.Provider;
using AIStudio.Settings; using AIStudio.Settings;
using Microsoft.JSInterop;
namespace AIStudio.Chat; namespace AIStudio.Chat;
/// <summary> /// <summary>

View File

@ -1,8 +1,6 @@
using AIStudio.Provider; using AIStudio.Provider;
using AIStudio.Settings; using AIStudio.Settings;
using Microsoft.JSInterop;
namespace AIStudio.Chat; namespace AIStudio.Chat;
/// <summary> /// <summary>

View File

@ -0,0 +1,20 @@
<MudItem xs="6" Style="display:flex;">
<MudCard Style="display: flex; flex-direction: column; width: 100%;">
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.h6">@this.Header</MudText>
</CardHeaderContent>
<CardHeaderActions>
<MudTooltip Text="Open the repository or website">
<MudIconButton Variant="Variant.Outlined" Icon="@Icons.Material.Filled.ForkLeft" Color="Color.Default" Href="@this.RepositoryUrl" Target="_blank"/>
</MudTooltip>
</CardHeaderActions>
</MudCardHeader>
<MudCardContent>
<MudText>@this.UseCase</MudText>
</MudCardContent>
<MudCardActions Class="mt-auto">
<MudButton Size="Size.Small" Variant="Variant.Outlined" Color="Color.Primary" Href="@this.LicenseUrl" Target="_blank">License: @this.LicenseName</MudButton>
</MudCardActions>
</MudCard>
</MudItem>

View File

@ -0,0 +1,26 @@
using Microsoft.AspNetCore.Components;
namespace AIStudio.Components.Blocks;
public partial class ThirdPartyComponent : ComponentBase
{
[Parameter]
public string Name { get; set; } = string.Empty;
[Parameter]
public string UseCase { get; set; } = string.Empty;
[Parameter]
public string Developer { get; set; } = string.Empty;
[Parameter]
public string LicenseName { get; set; } = string.Empty;
[Parameter]
public string LicenseUrl { get; set; } = string.Empty;
[Parameter]
public string RepositoryUrl { get; set; } = string.Empty;
private string Header => $"{this.Name} ({this.Developer})";
}

View File

@ -1,7 +1,5 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace AIStudio.Components.CommonDialogs; namespace AIStudio.Components.CommonDialogs;
/// <summary> /// <summary>

View File

@ -5,9 +5,18 @@
<MudDrawerContainer Class="mud-height-full absolute"> <MudDrawerContainer Class="mud-height-full absolute">
<MudDrawer Elevation="0" Variant="@DrawerVariant.Mini" OpenMiniOnHover="@true" Color="Color.Default"> <MudDrawer Elevation="0" Variant="@DrawerVariant.Mini" OpenMiniOnHover="@true" Color="Color.Default">
<MudNavMenu> <MudNavMenu>
<MudTooltip Text="Home" Placement="Placement.Right">
<MudNavLink Href="/" Icon="@Icons.Material.Filled.Home">Home</MudNavLink> <MudNavLink Href="/" Icon="@Icons.Material.Filled.Home">Home</MudNavLink>
</MudTooltip>
<MudTooltip Text="Chats" Placement="Placement.Right">
<MudNavLink Href="/chat" Icon="@Icons.Material.Filled.Chat">Chats</MudNavLink> <MudNavLink Href="/chat" Icon="@Icons.Material.Filled.Chat">Chats</MudNavLink>
</MudTooltip>
<MudTooltip Text="About" Placement="Placement.Right">
<MudNavLink Href="/about" Icon="@Icons.Material.Filled.Info">About</MudNavLink>
</MudTooltip>
<MudTooltip Text="Settings" Placement="Placement.Right">
<MudNavLink Href="/settings" Icon="@Icons.Material.Filled.Settings">Settings</MudNavLink> <MudNavLink Href="/settings" Icon="@Icons.Material.Filled.Settings">Settings</MudNavLink>
</MudTooltip>
</MudNavMenu> </MudNavMenu>
</MudDrawer> </MudDrawer>
</MudDrawerContainer> </MudDrawerContainer>

View File

@ -1,6 +1,5 @@
using AIStudio.Settings; using AIStudio.Settings;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
namespace AIStudio.Components.Layout; namespace AIStudio.Components.Layout;

View File

@ -0,0 +1,50 @@
@page "/about"
<MudText Typo="Typo.h3" Class="mb-2">About MindWork AI Studio</MudText>
<MudCard Class="mb-3">
<MudCardHeader>
<div class="d-flex align-center">
<MudIcon Icon="@Icons.Material.Filled.Layers" Size="Size.Medium" class="mr-3"/>
<MudText Typo="Typo.h6">Versions</MudText>
</div>
</MudCardHeader>
<MudCardContent>
<MudText>
The following list shows the versions of the MindWork AI Studio, the used compilers, build time, etc.:
</MudText>
<MudList Clickable="@true">
<MudListItem Icon="@Icons.Material.Outlined.Chat" Text="@VersionApp"/>
<MudListItem Icon="@Icons.Material.Outlined.Timer" Text="@BuildTime"/>
<MudListItem Icon="@Icons.Material.Outlined.Build" Text="@VersionDotnetSdk"/>
<MudListItem Icon="@Icons.Material.Outlined.Memory" Text="@VersionDotnet"/>
<MudListItem Icon="@Icons.Material.Outlined.Build" Text="@VersionRust"/>
<MudListItem Icon="@Icons.Material.Outlined.Widgets" Text="@MudBlazorVersion"/>
<MudListItem Icon="@Icons.Material.Outlined.Memory" Text="@TauriVersion"/>
</MudList>
</MudCardContent>
</MudCard>
<MudExpansionPanels>
<MudExpansionPanel>
<TitleContent>
<div class="d-flex align-center">
<MudIcon Icon="@Icons.Material.Filled.AutoAwesomeMotion" Size="Size.Medium" class="mr-3"/>
<MudText Typo="Typo.h6">Used Open Source Projects</MudText>
</div>
</TitleContent>
<ChildContent>
<MudGrid Spacing="1">
<ThirdPartyComponent Name=".NET" Developer="Microsoft & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/dotnet/runtime/blob/main/LICENSE.TXT" RepositoryUrl="https://github.com/dotnet" UseCase="The C# language is used for the implementation of the user interface and the backend. To implement the user interface with C#, the Blazor technology from ASP.NET Core is used. All these technologies are integrated into the .NET SDK."/>
<ThirdPartyComponent Name="MudBlazor" Developer="Jonny Larsson, Meinrad Recheis & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/MudBlazor/MudBlazor/blob/dev/LICENSE" RepositoryUrl="https://github.com/MudBlazor/MudBlazor/" UseCase="Building on .NET, ASP.NET Core, and Blazor, MudBlazor is used as a library for designing and developing the user interface. It is a great project that significantly accelerates the development of advanced user interfaces with Blazor."/>
<ThirdPartyComponent Name="MudBlazor.Markdown" Developer="My Nihongo & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/MyNihongo/MudBlazor.Markdown/blob/main/LICENSE" RepositoryUrl="https://github.com/MyNihongo/MudBlazor.Markdown" UseCase="This component is used to render Markdown text. This is important because the LLM often responds with Markdown-formatted text, allowing us to present it in a way that is easier to read."/>
<ThirdPartyComponent Name="Rust" Developer="Graydon Hoare, Rust Foundation & Open Source Community" LicenseName="MIT & Apache-2.0" LicenseUrl="https://github.com/rust-lang/rust?tab=readme-ov-file#license" RepositoryUrl="https://github.com/rust-lang/rust" UseCase="The .NET backend cannot be started as a desktop app. Therefore, I use a second backend in Rust, which I call runtime. With Rust as the runtime, Tauri can be used to realize a typical desktop app. Thanks to Rust, this app can be offered for Windows, macOS, and Linux desktops. Rust is a great language for developing safe and high-performance software."/>
<ThirdPartyComponent Name="Tauri" Developer="Daniel Thompson-Yvetot, Lucas Nogueira, Tensor, Boscop, Serge Zaitsev, George Burton & Open Source Community" LicenseName="MIT & Apache-2.0" LicenseUrl="https://github.com/tauri-apps/tauri?tab=readme-ov-file#licenses" RepositoryUrl="https://github.com/tauri-apps/tauri" UseCase="Tauri is used to host the Blazor user interface. It is a great project that allows the creation of desktop applications using web technologies. I love Tauri!"/>
<ThirdPartyComponent Name="serde" Developer="Erick Tryzelaar, David Tolnay & Open Source Community" LicenseName="MIT & Apache-2.0" LicenseUrl="https://github.com/serde-rs/serde?tab=readme-ov-file#license" RepositoryUrl="https://github.com/serde-rs/serde" UseCase="Now we have multiple systems, some developed in .NET and others in Rust. The data format JSON is responsible for translating data between both worlds (called data serialization and deserialization). Serde takes on this task in the Rust world. The counterpart in the .NET world is an integral part of .NET and is located in System.Text.Json."/>
<ThirdPartyComponent Name="keyring" Developer="Walther Chen, Daniel Brotsky & Open Source Community" LicenseName="MIT & Apache-2.0" LicenseUrl="https://github.com/hwchen/keyring-rs?tab=readme-ov-file#license" RepositoryUrl="https://github.com/hwchen/keyring-rs" UseCase="In order to use any LLM, each user must store their so-called token for each LLM provider. This token must be kept secure, similar to a password. The safest way to do this is offered by operating systems like macOS, Windows, and Linux: They have mechanisms to store such data, if available, on special security hardware. Since this is currently not possible in .NET, we use this Rust library."/>
<ThirdPartyComponent Name="arboard" Developer="Artur Kovacs, Avi Weinstock, 1Password & Open Source Community" LicenseName="MIT & Apache-2.0" LicenseUrl="https://github.com/1Password/arboard" RepositoryUrl="https://github.com/1Password/arboard" UseCase="To be able to use the responses of the LLM in other apps, we often use the clipboard of the respective operating system. Unfortunately, in .NET there is no solution that works with all operating systems. Therefore, I have opted for this library in Rust. This way, data transfer to other apps works on every system."/>
<ThirdPartyComponent Name="tokio" Developer="Alex Crichton & Open Source Community" LicenseName="MIT" LicenseUrl="https://github.com/tokio-rs/tokio/blob/master/LICENSE" RepositoryUrl="https://github.com/tokio-rs/tokio" UseCase="Code in the Rust language can be specified as synchronous or asynchronous. Unlike .NET and the C# language, Rust cannot execute asynchronous code by itself. Rust requires support in the form of an executor for this. Tokio is one such executor."/>
<ThirdPartyComponent Name="flexi_logger" Developer="emabee & Open Source Community" LicenseName="MIT & Apache-2.0" LicenseUrl="https://github.com/emabee/flexi_logger" RepositoryUrl="https://github.com/emabee/flexi_logger" UseCase="This Rust library is used to output the app's messages to the terminal. This is helpful during development and troubleshooting. This feature is initially invisible; when the app is started via the terminal, the messages become visible."/>
</MudGrid>
</ChildContent>
</MudExpansionPanel>
</MudExpansionPanels>

View File

@ -0,0 +1,25 @@
using System.Reflection;
using Microsoft.AspNetCore.Components;
namespace AIStudio.Components.Pages;
public partial class About : ComponentBase
{
private static readonly Assembly ASSEMBLY = Assembly.GetExecutingAssembly();
private static readonly MetaDataAttribute META_DATA = ASSEMBLY.GetCustomAttribute<MetaDataAttribute>()!;
private static string VersionDotnet => $"Used .NET compiler: v{META_DATA.DotnetVersion}";
private static string VersionDotnetSdk => $"Used .NET SDK: v{META_DATA.DotnetSdkVersion}";
private static string VersionRust => $"Used Rust compiler: v{META_DATA.RustVersion}";
private static string VersionApp => $"MindWork AI Studio: v{META_DATA.Version} (commit {META_DATA.AppCommitHash}, build {META_DATA.BuildNum})";
private static string BuildTime => $"Build time: {META_DATA.BuildTime}";
private static string MudBlazorVersion => $"MudBlazor: v{META_DATA.MudBlazorVersion}";
private static string TauriVersion => $"Tauri: v{META_DATA.TauriVersion}";
}

View File

@ -4,9 +4,6 @@ using AIStudio.Settings;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;
using MudBlazor;
namespace AIStudio.Components.Pages; namespace AIStudio.Components.Pages;

View File

@ -2,9 +2,6 @@ using AIStudio.Components.CommonDialogs;
using AIStudio.Provider; using AIStudio.Provider;
using AIStudio.Settings; using AIStudio.Settings;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using MudBlazor;
// ReSharper disable ClassNeverInstantiated.Global // ReSharper disable ClassNeverInstantiated.Global

View File

@ -8,4 +8,5 @@
@using Microsoft.JSInterop @using Microsoft.JSInterop
@using AIStudio @using AIStudio
@using AIStudio.Components @using AIStudio.Components
@using AIStudio.Components.Blocks
@using MudBlazor @using MudBlazor

View File

@ -0,0 +1,5 @@
// Global using directives
global using Microsoft.JSInterop;
global using MudBlazor;

View File

@ -1,9 +1,5 @@
using AIStudio.Tools; using AIStudio.Tools;
using Microsoft.JSInterop;
using MudBlazor;
// ReSharper disable ClassNeverInstantiated.Global // ReSharper disable ClassNeverInstantiated.Global
namespace AIStudio; namespace AIStudio;

View File

@ -0,0 +1,33 @@
namespace AIStudio;
[AttributeUsage(AttributeTargets.Assembly)]
public class MetaDataAttribute(
string version,
string buildTime,
uint buildNum,
string dotnetSdkVersion,
string dotnetVersion,
string rustVersion,
string mudBlazorVersion,
string tauriVersion,
string appCommitHash
) : Attribute
{
public string BuildTime { get; } = buildTime;
public string Version { get; } = version;
public uint BuildNum { get; } = buildNum;
public string DotnetVersion { get; } = dotnetVersion;
public string DotnetSdkVersion { get; } = dotnetSdkVersion;
public string RustVersion { get; } = rustVersion;
public string MudBlazorVersion { get; } = mudBlazorVersion;
public string TauriVersion { get; } = tauriVersion;
public string AppCommitHash { get; } = appCommitHash;
}

View File

@ -1,6 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<!-- Using Microsoft.Build.Tasks.Core.dll to be able to read files -->
<UsingTask TaskName="ReadLinesFromFile" AssemblyFile="$(MSBuildBinPath)\Microsoft.Build.Tasks.Core.dll" />
<PropertyGroup> <PropertyGroup>
<Authors>Thorsten Sommer</Authors>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<WarningsAsErrors>CS8600;CS8602;CS8603</WarningsAsErrors> <WarningsAsErrors>CS8600;CS8602;CS8603</WarningsAsErrors>
@ -29,7 +33,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<!-- Remove launchSettings.json from the project --> <!-- Remove some files from the solution view -->
<None Remove="Properties\launchSettings.json" /> <None Remove="Properties\launchSettings.json" />
<None Remove="build.nu" /> <None Remove="build.nu" />
</ItemGroup> </ItemGroup>
@ -40,9 +44,52 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.4" /> <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.5" />
<PackageReference Include="MudBlazor" Version="6.19.1" /> <PackageReference Include="MudBlazor" Version="6.19.1" />
<PackageReference Include="MudBlazor.Markdown" Version="0.1.3" /> <PackageReference Include="MudBlazor.Markdown" Version="1.0.0" />
</ItemGroup> </ItemGroup>
<!-- Read the meta data file -->
<Target Name="ReadMetaData" BeforeTargets="BeforeBuild">
<Error Text="The ../../metadata.txt file was not found!" Condition="!Exists('../../metadata.txt')" />
<ReadLinesFromFile File="../../metadata.txt">
<Output TaskParameter="Lines" PropertyName="Metadata" />
</ReadLinesFromFile>
<PropertyGroup>
<MetaVersion>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 0 ])</MetaVersion>
<MetaBuildTime>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 1 ])</MetaBuildTime>
<MetaBuild>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 2 ])</MetaBuild>
<MetaDotnetSdkVersion>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 3 ])</MetaDotnetSdkVersion>
<MetaDotnetVersion>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 4 ])</MetaDotnetVersion>
<MetaRustVersion>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 5 ])</MetaRustVersion>
<MetaMudBlazorVersion>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 6 ])</MetaMudBlazorVersion>
<MetaTauriVersion>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 7 ])</MetaTauriVersion>
<MetaAppCommitHash>$([System.String]::Copy( $(Metadata) ).Split( ';' )[ 8 ])</MetaAppCommitHash>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<AssemblyVersion>$(MetaVersion)</AssemblyVersion>
<FileVersion>$(MetaVersion)</FileVersion>
<InformationalVersion>$(MetaVersion)</InformationalVersion>
</PropertyGroup>
<ItemGroup>
<AssemblyAttribute Include="AIStudio.MetaDataAttribute">
<_Parameter1>$(MetaVersion)</_Parameter1>
<_Parameter2>$(MetaBuildTime)</_Parameter2>
<_Parameter3>$(MetaBuild)</_Parameter3>
<_Parameter3_TypeName>System.UInt32</_Parameter3_TypeName>
<_Parameter4>$(MetaDotnetSdkVersion)</_Parameter4>
<_Parameter5>$(MetaDotnetVersion)</_Parameter5>
<_Parameter6>$(MetaRustVersion)</_Parameter6>
<_Parameter7>$(MetaMudBlazorVersion)</_Parameter7>
<_Parameter8>$(MetaTauriVersion)</_Parameter8>
<_Parameter9>$(MetaAppCommitHash)</_Parameter9>
</AssemblyAttribute>
</ItemGroup>
</Target>
</Project> </Project>

View File

@ -3,7 +3,6 @@ using AIStudio.Components;
using AIStudio.Settings; using AIStudio.Settings;
using AIStudio.Tools; using AIStudio.Tools;
using MudBlazor;
using MudBlazor.Services; using MudBlazor.Services;
#if !DEBUG #if !DEBUG

View File

@ -1,8 +1,5 @@
using AIStudio.Chat; using AIStudio.Chat;
using AIStudio.Settings; using AIStudio.Settings;
using Microsoft.JSInterop;
using MudBlazor;
namespace AIStudio.Provider; namespace AIStudio.Provider;

View File

@ -3,10 +3,6 @@ using System.Runtime.CompilerServices;
using AIStudio.Chat; using AIStudio.Chat;
using AIStudio.Settings; using AIStudio.Settings;
using Microsoft.JSInterop;
using MudBlazor;
namespace AIStudio.Provider; namespace AIStudio.Provider;
public class NoProvider : IProvider public class NoProvider : IProvider

View File

@ -6,10 +6,6 @@ using System.Text.Json;
using AIStudio.Chat; using AIStudio.Chat;
using AIStudio.Settings; using AIStudio.Settings;
using Microsoft.JSInterop;
using MudBlazor;
namespace AIStudio.Provider.OpenAI; namespace AIStudio.Provider.OpenAI;
/// <summary> /// <summary>

View File

@ -3,9 +3,6 @@ using System.Text.RegularExpressions;
using AIStudio.Provider; using AIStudio.Provider;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using MudBlazor;
namespace AIStudio.Settings; namespace AIStudio.Settings;

View File

@ -1,6 +1,5 @@
using System.Text.Json; using System.Text.Json;
using AIStudio.Provider; using AIStudio.Provider;
using Microsoft.JSInterop;
// ReSharper disable NotAccessedPositionalProperty.Local // ReSharper disable NotAccessedPositionalProperty.Local

View File

@ -1,7 +1,3 @@
using Microsoft.JSInterop;
using MudBlazor;
namespace AIStudio.Tools; namespace AIStudio.Tools;
/// <summary> /// <summary>

View File

@ -6,6 +6,43 @@ def are_assets_exist [rid: string]: string -> bool {
$"bin/release/net8.0/($rid)/publish/wwwroot/_content/MudBlazor/MudBlazor.min.css" | path exists $"bin/release/net8.0/($rid)/publish/wwwroot/_content/MudBlazor/MudBlazor.min.css" | path exists
} }
def "main help" []: nothing -> nothing {
print "Usage: nu build.nu [action]"
print ""
print "Optional Actions:"
print "-----------------"
print " fix_web_assets Prepare the web assets; run this once for each release on one platform; changes will be committed."
print ""
print " metadata Update the metadata file; run this on every platform right before the release; changes will be"
print " committed once; there should be no differences between the platforms."
print ""
print "Actions:"
print "---------"
print " prepare [action] Prepare the project for a release; increases the version & build numbers, updates the build time,"
print " and runs fix_web_assets; run this once for each release on one platform; changes will be committed."
print " The action can be 'major', 'minor', or 'patch'. The version will be updated accordingly."
print ""
print " publish Publish the project for all supported RIDs; run this on every platform."
print ""
}
def "main prepare" [action: string]: string -> nothing {
if (update_app_version $action) {
main fix_web_assets
inc_build_number
update_build_time
main metadata
}
}
def "main metadata" []: nothing -> nothing {
update_dotnet_version
update_rust_version
update_mudblazor_version
update_tauri_version
update_project_commit_hash
}
def "main fix_web_assets" []: nothing -> nothing { def "main fix_web_assets" []: nothing -> nothing {
# Get the matching RIDs for the current OS: # Get the matching RIDs for the current OS:
@ -29,6 +66,8 @@ def "main fix_web_assets" []: nothing -> nothing {
def "main publish" []: nothing -> nothing { def "main publish" []: nothing -> nothing {
main metadata
# Ensure, that the dist directory exists: # Ensure, that the dist directory exists:
mkdir bin/dist mkdir bin/dist
@ -51,7 +90,7 @@ def "main publish" []: nothing -> nothing {
print "==============================" print "=============================="
print $"Start building for ($rid)..." print $"Start building for ($rid)..."
^dotnet publish --configuration release --runtime $rid ^dotnet publish --configuration release --runtime $rid --disable-build-servers --force
let final_filename = match $rid { let final_filename = match $rid {
"win-x64" => "mindworkAIStudio-x86_64-pc-windows-msvc.exe", "win-x64" => "mindworkAIStudio-x86_64-pc-windows-msvc.exe",
@ -121,3 +160,169 @@ def get_rids []: nothing -> list {
def get_os []: nothing -> string { def get_os []: nothing -> string {
(sys).host.name | str downcase (sys).host.name | str downcase
} }
def update_build_time []: nothing -> nothing {
mut meta_lines = open --raw ../../metadata.txt | lines
mut build_time = $meta_lines.1
let updated_build_time = (date now | date to-timezone UTC | format date "%Y-%m-%d %H:%M:%S")
print $"Updated build time from ($build_time) to ($updated_build_time) UTC."
$build_time = $"($updated_build_time) UTC"
$meta_lines.1 = $build_time
$meta_lines | save --raw --force ../../metadata.txt
}
def inc_build_number []: nothing -> nothing {
mut meta_lines = open --raw ../../metadata.txt | lines
mut build_number = $meta_lines.2 | into int
let updated_build_number = ([$build_number, 1] | math sum)
print $"Incremented build number from ($build_number) to ($updated_build_number)."
$build_number = $updated_build_number
$meta_lines.2 = ($build_number | into string)
$meta_lines | save --raw --force ../../metadata.txt
}
def update_dotnet_version []: nothing -> nothing {
mut meta_lines = open --raw ../../metadata.txt | lines
mut dotnet_sdk_version = $meta_lines.3
mut dotnet_version = $meta_lines.4
let dotnet_data = (^dotnet --info) | parse --regex '(?s).NET SDK:\s+Version:\s+(?P<sdkVersion>[0-9.]+).+Commit:\s+(?P<sdkCommit>[a-zA-Z0-9]+).+Host:\s+Version:\s+(?P<hostVersion>[0-9.]+).+Commit:\s+(?P<hostCommit>[a-zA-Z0-9]+)'
let sdk_version = $dotnet_data.sdkVersion.0
let host_version = $dotnet_data.hostVersion.0
let sdkCommit = $dotnet_data.sdkCommit.0
let hostCommit = $dotnet_data.hostCommit.0
print $"Updated .NET SDK version from ($dotnet_sdk_version) to ($sdk_version) \(commit ($sdkCommit)\)."
$meta_lines.3 = $"($sdk_version) \(commit ($sdkCommit)\)"
print $"Updated .NET version from ($dotnet_version) to ($host_version) \(commit ($hostCommit)\)."
$meta_lines.4 = $"($host_version) \(commit ($hostCommit)\)"
$meta_lines | save --raw --force ../../metadata.txt
}
def update_rust_version []: nothing -> nothing {
mut meta_lines = open --raw ../../metadata.txt | lines
mut rust_version = $meta_lines.5
let rust_data = (^rustc -Vv) | parse --regex 'rustc (?<version>[0-9.]+) \((?<commit>[a-zA-Z0-9]+)'
let version = $rust_data.version.0
let commit = $rust_data.commit.0
print $"Updated Rust version from ($rust_version) to ($version) \(commit ($commit)\)."
$meta_lines.5 = $"($version) \(commit ($commit)\)"
$meta_lines | save --raw --force ../../metadata.txt
}
def update_mudblazor_version []: nothing -> nothing {
mut meta_lines = open --raw ../../metadata.txt | lines
mut mudblazor_version = $meta_lines.6
let mudblazor_data = (^dotnet list package) | parse --regex 'MudBlazor\s+(?<version>[0-9.]+)'
let version = $mudblazor_data.version.0
print $"Updated MudBlazor version from ($mudblazor_version) to ($version)."
$meta_lines.6 = $version
$meta_lines | save --raw --force ../../metadata.txt
}
def update_tauri_version []: nothing -> nothing {
mut meta_lines = open --raw ../../metadata.txt | lines
mut tauri_version = $meta_lines.7
cd ../../runtime
let tauri_data = (^cargo tree --depth 1) | parse --regex 'tauri\s+v(?<version>[0-9.]+)'
let version = $tauri_data.version.0
cd "../app/MindWork AI Studio"
print $"Updated Tauri version from ($tauri_version) to ($version)."
$meta_lines.7 = $version
$meta_lines | save --raw --force ../../metadata.txt
}
def update_app_version [action: string]: string -> bool {
mut meta_lines = open --raw ../../metadata.txt | lines
mut app_version = $meta_lines.0
let version_data = $app_version | parse --regex '(?P<major>[0-9]+)\.(?P<minor>[0-9]+)\.(?P<patch>[0-9]+)'
if $action == "major" {
mut major = $version_data.major | into int
$major = ([$major.0, 1] | math sum)
let updated_version = [$major, 0, 0] | str join "."
print $"Updated app version from ($app_version) to ($updated_version)."
$meta_lines.0 = $updated_version
} else if $action == "minor" {
let major = $version_data.major | into int
mut minor = $version_data.minor | into int
$minor = ([$minor.0, 1] | math sum)
let updated_version = [$major.0, $minor, 0] | str join "."
print $"Updated app version from ($app_version) to ($updated_version)."
$meta_lines.0 = $updated_version
} else if $action == "patch" {
let major = $version_data.major | into int
let minor = $version_data.minor | into int
mut patch = $version_data.patch | into int
$patch = ([$patch.0, 1] | math sum)
let updated_version = [$major.0, $minor.0, $patch] | str join "."
print $"Updated app version from ($app_version) to ($updated_version)."
$meta_lines.0 = $updated_version
} else {
print $"Invalid action '($action)'. Please use 'major', 'minor', or 'patch'."
return false
}
$meta_lines | save --raw --force ../../metadata.txt
return true
}
def update_project_commit_hash []: nothing -> nothing {
mut meta_lines = open --raw ../../metadata.txt | lines
mut commit_hash = $meta_lines.8
# Check, if the work directory is clean. We allow, that the metadata file is dirty:
let git_status = (^git status --porcelain) | lines
let dirty_files = $git_status | length
let first_is_metadata = ($dirty_files > 0 and $git_status.0 =~ '^\sM\s+metadata.txt$')
let git_tag_response = ^git describe --tags --exact-match | complete
let state = {
num_dirty: $dirty_files,
first_is_metadata: $first_is_metadata,
git_tag_present: ($git_tag_response.exit_code == 0),
git_tag: $git_tag_response.stdout
}
let commit_postfix = match $state {
{ num_dirty: $num_dirty, first_is_metadata: _, git_tag_present: _, git_tag: _ } if $num_dirty > 1 => ", dev debug",
{ num_dirty: $num_dirty, first_is_metadata: false, git_tag_present: _, git_tag: _ } if $num_dirty == 1 => ", dev debug",
{ num_dirty: $num_dirty, first_is_metadata: true, git_tag_present: false, git_tag: _ } if $num_dirty == 1 => ", dev testing",
{ num_dirty: $num_dirty, first_is_metadata: false, git_tag_present: false, git_tag: _ } if $num_dirty == 0 => ", dev testing",
{ num_dirty: $num_dirty, first_is_metadata: true, git_tag_present: true, git_tag: $tag } if $num_dirty == 1 => $", release $tag",
{ num_dirty: $num_dirty, first_is_metadata: false, git_tag_present: true, git_tag: $tag } if $num_dirty == 0 => $", release $tag",
_ => "-dev unknown"
}
# Use the first ten characters of the commit hash:
let updated_commit_hash = (^git rev-parse HEAD) | str substring 0..10 | append $commit_postfix | str join
print $"Updated commit hash from ($commit_hash) to ($updated_commit_hash)."
$meta_lines.8 = $updated_commit_hash
$meta_lines | save --raw --force ../../metadata.txt
}

9
metadata.txt Normal file
View File

@ -0,0 +1,9 @@
0.4.0
2024-05-25 18:05:54 UTC
140
8.0.205 (commit 3e1383b780)
8.0.5 (commit 087e15321b)
1.78.0 (commit 9b00956e5)
6.19.1
1.6.1
5920663365, dev debug

2
runtime/Cargo.lock generated
View File

@ -2189,7 +2189,7 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]] [[package]]
name = "mindwork-ai-studio" name = "mindwork-ai-studio"
version = "0.1.0" version = "0.4.0"
dependencies = [ dependencies = [
"arboard", "arboard",
"flexi_logger", "flexi_logger",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mindwork-ai-studio" name = "mindwork-ai-studio"
version = "0.1.0" version = "0.4.0"
edition = "2021" edition = "2021"
description = "MindWork AI Studio" description = "MindWork AI Studio"
authors = ["Thorsten Sommer"] authors = ["Thorsten Sommer"]

View File

@ -2,6 +2,54 @@ use std::path::PathBuf;
fn main() { fn main() {
tauri_build::build(); tauri_build::build();
// Tells Cargo to re-run this script only, when the version.txt file was changed:
println!("cargo:rerun-if-changed=../metadata.txt");
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
println!("cargo:rustc-env=OUT_DIR={}", out_dir.to_str().unwrap()); println!("cargo:rustc-env=OUT_DIR={}", out_dir.to_str().unwrap());
let metadata = include_str!("../metadata.txt");
let mut metadata_lines = metadata.lines();
let version = metadata_lines.next().unwrap();
update_cargo_toml("Cargo.toml", version);
update_tauri_conf("tauri.conf.json", version);
}
fn update_cargo_toml(cargo_path: &str, version: &str) {
let cargo_toml = std::fs::read_to_string(cargo_path).unwrap();
let cargo_toml_lines = cargo_toml.lines();
let mut new_cargo_toml = String::new();
for line in cargo_toml_lines {
if line.starts_with("version = ") {
new_cargo_toml.push_str(&format!("version = \"{version}\""));
} else {
new_cargo_toml.push_str(line);
}
new_cargo_toml.push('\n');
}
std::fs::write(cargo_path, new_cargo_toml).unwrap();
}
fn update_tauri_conf(tauri_conf_path: &str, version: &str) {
let tauri_conf = std::fs::read_to_string(tauri_conf_path).unwrap();
let tauri_conf_lines = tauri_conf.lines();
let mut new_tauri_conf = String::new();
for line in tauri_conf_lines {
// The version in Tauri's config is formatted like this:
// "version": "0.1.0-alpha.0"
// Please notice, that the version number line might have a leading tab, etc.
if line.contains("\"version\": ") {
new_tauri_conf.push_str(&format!("\t\"version\": \"{version}\""));
} else {
new_tauri_conf.push_str(line);
}
new_tauri_conf.push('\n');
}
std::fs::write(tauri_conf_path, new_tauri_conf).unwrap();
} }

View File

@ -18,11 +18,32 @@ use log::{debug, error, info, warn};
fn main() { fn main() {
let metadata = include_str!("../../metadata.txt");
let mut metadata_lines = metadata.lines();
let app_version = metadata_lines.next().unwrap();
let build_time = metadata_lines.next().unwrap();
let build_number = metadata_lines.next().unwrap();
let dotnet_sdk_version = metadata_lines.next().unwrap();
let dotnet_version = metadata_lines.next().unwrap();
let rust_version = metadata_lines.next().unwrap();
let mud_blazor_version = metadata_lines.next().unwrap();
let tauri_version = metadata_lines.next().unwrap();
let app_commit_hash = metadata_lines.next().unwrap();
Logger::try_with_str("debug").expect("Cannot create logging") Logger::try_with_str("debug").expect("Cannot create logging")
.log_to_stdout() .log_to_stdout()
.adaptive_format_for_stdout(AdaptiveFormat::Detailed) .adaptive_format_for_stdout(AdaptiveFormat::Detailed)
.start().expect("Cannot start logging"); .start().expect("Cannot start logging");
info!("Starting MindWork AI Studio:");
info!(".. Version: v{app_version} (commit {app_commit_hash}, build {build_number})");
info!(".. Build time: {build_time}");
info!(".. .NET SDK: v{dotnet_sdk_version}");
info!(".. .NET: v{dotnet_version}");
info!(".. Rust: v{rust_version}");
info!(".. MudBlazor: v{mud_blazor_version}");
info!(".. Tauri: v{tauri_version}");
if is_dev() { if is_dev() {
warn!("Running in development mode."); warn!("Running in development mode.");
} else { } else {

View File

@ -6,7 +6,7 @@
}, },
"package": { "package": {
"productName": "MindWork AI Studio", "productName": "MindWork AI Studio",
"version": "0.1.0" "version": "0.4.0"
}, },
"tauri": { "tauri": {
"allowlist": { "allowlist": {