Recommended UI Approaches for Azure AI Services Output

When displaying output from Azure AI services (like Cognitive Services, OpenAI, etc.), the UI should be tailored to the specific service and use case. Here are recommended approaches:

1. Text-Based AI Services (Language, Translation, etc.)

Recommended UI Components:

MudBlazor (for Blazor apps):

<MudPaper Elevation="3" Class="pa-4 my-4">
    <MudText Typo="Typo.h6">AI Analysis</MudText>
    <MudText>@_aiResponse</MudText>
    @if (!string.IsNullOrEmpty(_sentiment))
    {
        <MudChip Color="@(_sentiment == "Positive" ? Color.Success : 
                       _sentiment == "Negative" ? Color.Error : Color.Warning)"
                Class="mt-2">
            @_sentiment Sentiment
        </MudChip>
    }
</MudPaper>

For key phrases extraction:

<MudChipSet>
    @foreach (var phrase in _keyPhrases)
    {
        <MudChip>@phrase</MudChip>
    }
</MudChipSet>

2. Computer Vision/Image Analysis

Recommended UI:

<div style="position: relative;">
    <img src="@_imageUrl" style="max-width: 100%;" />
    @foreach (var obj in _detectedObjects)
    {
        <div style="position: absolute; 
                   left: @(obj.BoundingBox.Left * 100)%; 
                   top: @(obj.BoundingBox.Top * 100)%;
                   width: @(obj.BoundingBox.Width * 100)%;
                   height: @(obj.BoundingBox.Height * 100)%;
                   border: 2px solid red;">
            <span style="background: white; padding: 2px;">@obj.ObjectProperty</span>
        </div>
    }
</div>

3. Chat/Conversational AI (Azure OpenAI)

Recommended UI:

<MudContainer MaxWidth="MaxWidth.Medium">
    <MudPaper Elevation="3" Class="pa-4" Style="height: 60vh; overflow-y: auto;">
        @foreach (var message in _chatHistory)
        {
            <MudCard Class="my-2" Elevation="1">
                <MudCardHeader>
                    <MudAvatar>@(message.Role == "user" ? "U" : "AI")</MudAvatar>
                    <MudText Typo="Typo.subtitle2">@message.Role</MudText>
                </MudCardHeader>
                <MudCardContent>
                    <MarkdownString Value="@message.Content" />
                </MudCardContent>
            </MudCard>
        }
    </MudPaper>
    
    <MudTextField @bind-Value="_userMessage" 
                 Label="Type your message" 
                 Variant="Variant.Outlined"
                 FullWidth
                 Class="mt-4">
        <Adornment>
            <MudButton OnClick="SendMessage" 
                      Icon="@Icons.Material.Filled.Send"
                      Disabled="@_isProcessing" />
        </Adornment>
    </MudTextField>
</MudContainer>

4. Form Recognizer/Data Extraction

Recommended UI:

<MudTable Items="@_extractedData" Hover="true">
    <HeaderContent>
        <MudTh>Field</MudTh>
        <MudTh>Value</MudTh>
        <MudTh>Confidence</MudTh>
    </HeaderContent>
    <RowTemplate>
        <MudTd>@context.FieldName</MudTd>
        <MudTd>@context.Value</MudTd>
        <MudTd>
            <MudProgressLinear Value="@(context.Confidence * 100)" 
                              Color="@(context.Confidence > 0.9 ? Color.Success : 
                                     context.Confidence > 0.7 ? Color.Warning : Color.Error)"/>
        </MudTd>
    </RowTemplate>
</MudTable>

5. Custom Decision/Recommendation Services

Recommended UI:

<MudGrid>
    @foreach (var recommendation in _recommendations)
    {
        <MudItem xs="12" sm="6" md="4">
            <MudCard Elevation="5" Class="h-100">
                <MudCardHeader>
                    <MudAvatar Color="Color.Primary">@recommendation.Score.ToString("P0")</MudAvatar>
                    <MudText Typo="Typo.h6">@recommendation.Title</MudText>
                </MudCardHeader>
                <MudCardContent>
                    @recommendation.Description
                </MudCardContent>
                <MudCardActions>
                    <MudButton Variant="Variant.Text" Color="Color.Primary">View Details</MudButton>
                </MudCardActions>
            </MudCard>
        </MudItem>
    }
</MudGrid>

Best Practices for Azure AI UI

Visual Feedback:

Show loading states during API calls

<MudProgressCircular Indeterminate="true" Color="Color.Primary" 
                    Visible="@_isLoading" Class="my-4" />

Error Handling:

@if (!string.IsNullOrEmpty(_errorMessage))
{
    <MudAlert Severity="Severity.Error" Variant="Variant.Filled">
        @_errorMessage
    </MudAlert>
}

Confidence Indicators:

Visualize confidence scores for uncertain predictions

<MudTooltip Text="@($"Confidence: {_confidence:P2}")">
    <MudIcon Icon="@(_confidence > 0.9 ? Icons.Material.Filled.CheckCircle : 
                    _confidence > 0.7 ? Icons.Material.Filled.Warning : 
                    Icons.Material.Filled.Error)"
            Color="@(_confidence > 0.9 ? Color.Success : 
                   _confidence > 0.7 ? Color.Warning : Color.Error)" />
</MudTooltip>

Interactive Exploration:

Allow users to refine/correct AI outputs

<MudTextField @bind-Value="_correctedText" 
             Label="Correct the AI output"
             Visible="@_showCorrectionField" />

Responsive Design:

Ensure UI works across devices

<MudGrid>
    <MudItem xs="12" md="6">
        <!-- Input controls -->
    </MudItem>
    <MudItem xs="12" md="6">
        <!-- AI output -->
    </MudItem>
</MudGrid>

For enterprise applications, consider adding:

  • Export capabilities (PDF, CSV)
  • Audit trails of AI interactions
  • User feedback mechanisms (“Was this helpful?”)
  • Explanation components for AI decisions

Sharing a Single Model Across Multiple Child Components in Blazor WebAssembly

There are several effective ways to share a single model (data object) between multiple child components in Blazor WebAssembly. Here are the best approaches:

1. Cascading Parameters (Best for hierarchical components)
<!-- ParentComponent.razor -->
@page "/parent"

<CascadingValue Value="@SharedModel">
    <ChildComponent1 />
    <ChildComponent2 />
</CascadingValue>

@code {
    private MyModel SharedModel { get; set; } = new MyModel();
}

<!-- ChildComponent1.razor -->
@code {
    [CascadingParameter]
    public MyModel SharedModel { get; set; }
}

<!-- ChildComponent2.razor -->
@code {
    [CascadingParameter]
    public MyModel SharedModel { get; set; }
}

2. Component Parameters (Best for direct parent-child relationships)

<!-- ParentComponent.razor -->
@page "/parent"

<ChildComponent1 Model="@SharedModel" />
<ChildComponent2 Model="@SharedModel" />

@code {
    private MyModel SharedModel { get; set; } = new MyModel();
}

<!-- ChildComponent1.razor -->
@code {
    [Parameter]
    public MyModel Model { get; set; }
}

<!-- ChildComponent2.razor -->
@code {
    [Parameter]
    public MyModel Model { get; set; }
}

3. State Management Service (Best for app-wide sharing)

// SharedModelService.cs
public class SharedModelService
{
    private MyModel _model = new();
    
    public MyModel Model 
    {
        get => _model;
        set
        {
            _model = value;
            NotifyStateChanged();
        }
    }
    
    public event Action OnChange;
    
    private void NotifyStateChanged() => OnChange?.Invoke();
}

Register the service in Program.cs:

builder.Services.AddSingleton<SharedModelService>();

Use in components:

@inject SharedModelService ModelService

@code {
    protected override void OnInitialized()
    {
        ModelService.OnChange += StateHasChanged;
    }
    
    private void UpdateModel()
    {
        ModelService.Model.Property = "New Value";
    }
}

4. EventCallback Pattern (For parent-child communication)

<!-- ParentComponent.razor -->
@page "/parent"

<ChildComponent1 Model="@SharedModel" ModelChanged="@HandleModelChanged" />
<ChildComponent2 Model="@SharedModel" ModelChanged="@HandleModelChanged" />

@code {
    private MyModel SharedModel { get; set; } = new();
    
    private void HandleModelChanged(MyModel updatedModel)
    {
        SharedModel = updatedModel;
        StateHasChanged(); // Refresh all components
    }
}

<!-- ChildComponent1.razor -->
@code {
    [Parameter]
    public MyModel Model { get; set; }
    
    [Parameter]
    public EventCallback<MyModel> ModelChanged { get; set; }
    
    private async Task UpdateModel()
    {
        Model.Property = "New Value";
        await ModelChanged.InvokeAsync(Model);
    }
}

5. Fluxor/Redux Pattern (For complex state management)

// Install package
dotnet add package Fluxor.Blazor.Web

// Define state
public record MyModelState
{
    public MyModel Model { get; init; } = new();
}

// Define actions
public record UpdateModelAction(MyModel Model);

// Create reducer
public static class Reducers
{
    [ReducerMethod]
    public static MyModelState ReduceUpdateModelAction(MyModelState state, UpdateModelAction action)
        => state with { Model = action.Model };
}

Use in components:

@inject IState<MyModelState> ModelState
@inject IDispatcher Dispatcher

<p>@ModelState.Value.Model.Property</p>

<button @onclick="UpdateModel">Update</button>

@code {
    private void UpdateModel()
    {
        var updatedModel = ModelState.Value.Model with { Property = "New Value" };
        Dispatcher.Dispatch(new UpdateModelAction(updatedModel));
    }
}

  1. For simple parent-child relationships: Use Component Parameters
  2. For deep component trees: Use Cascading Parameters
  3. For app-wide state: Use State Management Service or Fluxor
  4. For complex applications: Consider Fluxor/Redux pattern
  5. Immutable models: When sharing models, consider making them immutable or implementing proper change notifications

Performance Considerations

  • Avoid excessive re-rendering by implementing ShouldRender
  • Use [Parameter] public MyModel Model { get; set; } carefully as it can cause unnecessary renders
  • For large models, consider using view models or DTOs instead of full domain models

AI and Nvidia’s chips relationship

It all starts with video games

The company (Nvidia), founded in 1993 at a California Denny’s, became a breakthrough hit in the late ’90s and early 2000s because it led the world in the creation of Graphics Processing Units, which are the chips that allow for good 3D graphics in video games. Nvidia’s chips were used in the Xbox, PlayStation 3 and Nintendo Switch, and are a staple in pretty much every gaming computer.

A graphics processing unit (GPU) is different from a standard computer chip (a central processing unit / CPU) because it does one thing really well:

  • It turns 3D models into advanced math. For video games, this means sweet graphics.

So, Nvidia had been doing cool stuff for decades. But then computer programmers stumbled upon more use cases for GPUs.

The first new use case stems from the fact that GPUs can solve complex math problems, but use a lot of energy (electricity) to do so.

So, when the anonymous creator of Bitcoin wanted a way to limit the number of imaginary digital coins that could be minted, he(?) set up a system that would throttle the creation of new coins by forcing you to solve a mathematical riddle with your GPU first.

The result: with crypto mining, you could literally use GPUs to mint (theoretical) money. Your costs would come in the form of buying the hardware and paying for the electricity to operate it.

This did result in the production and proliferation of a lot of GPUs, which eventually found their third (and much more productive) purpose.

Why AI and 3D video games are the same

The building blocks of an AI model are “tokens,” which are words or parts of words. (For example, “think” is a token, and “-ing” is also a token, and the two tokens can be connected to form the word “thinking.”)

Once you have tokens, you need to connect them in a way that helps your model understand how often they are associated with one another. The way you do this is with very advanced mathematics (linear algebra) that eventually forms vectors that connect every token to every other token.

To visualize this, imagine you’re standing out in a field looking up at the night sky. Every star is a token/word. Now, imagine a bunch of lines drawn from every star to every other star. With millions of stars, you’d have trillions and trillions of lines (vectors) connecting them. And from earth, this would look sort of like a giant 3D web of vectors.

Doing the math to connect all the tokens in all the languages for all the content in the world requires a lot of computing power. And GPUs – which were designed specifically for advanced multi-dimensional math for video games – are the perfect chips for the job.

This is how a video game company ended up at the cutting edge of AI, jockeying with Microsoft and Apple for the title of most valuable company in the world.

Show/Hide element in Blazor WebAssembly

Blazor WebAssembly doesn’t allow direct manipulation of DOM. Here is how to show/hide DOM element without using Javascript Interop;

The hidden html attribute also works to hide an element.

<p hidden>This paragraph should be hidden.</p>

To bind to Model:

 <p hidden="@HideLabel">I am Hidden When HideLabel == true</p>

 <p hidden="@(!HideLabel)">I am Hidden when Hidelabel == false</p>
    
 <button @onclick="@Toggle">Show/Hide</button>

 @code {
      private bool HideLabel { get; set; } = false;
      private void Toggle()
      {
         HideLabel =   !HideLabel;
      }      
 } 

Edit: You can also use a CSS class to hide/show an element:

<div class="font-italic @(HideLabel ? "d-none" : "d-show")">
   I am Hidden When HideLabel == true
</div>

Reference

https://stackoverflow.com/questions/63693734/how-to-show-hide-an-element-in-real-time-blazor

Convert Enum to List in C#

We can use LINQ for this;

public class EnumModel
{
    public int Value { get; set; }
    public string Name { get; set; }
}

public enum MyEnum
{
    Name1=1,
    Name2=2,
    Name3=3
}

public class Test
{
        List<EnumModel> enums = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).Select(c => new EnumModel() { Value = (int)c, Name = c.ToString() }).ToList();

        // A list of Names only, does away with the need of EnumModel 
        List<string> MyNames = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).Select(c => c.ToString()).ToList();

        // A list of Values only, does away with the need of EnumModel 
        List<int> myValues = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).Select(c => (int)c).ToList();

        // A dictionnary of <string,int>
        Dictionary<string,int> myDic = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).ToDictionary(k => k.ToString(), v => (int)v);
}

Reference

https://stackoverflow.com/questions/1167361/how-do-i-convert-an-enum-to-a-list-in-c