mirror of
				https://github.com/MindWorkAI/AI-Studio.git
				synced 2025-11-04 01:20:21 +00:00 
			
		
		
		
	Implemented the icon finder assistant
This commit is contained in:
		
							parent
							
								
									1f31dc70a0
								
							
						
					
					
						commit
						a5ebce4815
					
				@ -0,0 +1,68 @@
 | 
			
		||||
@page "/assistant/icons"
 | 
			
		||||
@using AIStudio.Chat
 | 
			
		||||
@using AIStudio.Settings
 | 
			
		||||
 | 
			
		||||
<MudText Typo="Typo.h3" Class="mb-2 mr-3">
 | 
			
		||||
    Icon Finder
 | 
			
		||||
</MudText>
 | 
			
		||||
 | 
			
		||||
<InnerScrolling HeaderHeight="12.3em">
 | 
			
		||||
    <ChildContent>
 | 
			
		||||
        <MudForm @ref="@this.form" @bind-IsValid="@this.inputIsValid" @bind-Errors="@this.inputIssues" Class="pr-2">
 | 
			
		||||
            <MudText Typo="Typo.body1" Align="Align.Justify" Class="mb-6">
 | 
			
		||||
                Finding the right icon for a context, such as for a piece of text, is not easy. The first challenge:
 | 
			
		||||
                You need to extract a concept from your context, such as from a text. Let's take an example where
 | 
			
		||||
                your text contains statements about multiple departments. The sought-after concept could be "departments."
 | 
			
		||||
                The next challenge is that we need to anticipate the bias of the icon designers: under the search term
 | 
			
		||||
                "departments," there may be no relevant icons or only unsuitable ones. Depending on the icon source,
 | 
			
		||||
                it might be more effective to search for "buildings," for instance. LLMs assist you with both steps.
 | 
			
		||||
            </MudText>
 | 
			
		||||
 | 
			
		||||
            <MudTextField T="string" @bind-Text="@this.inputContext" Validation="@this.ValidatingContext" AdornmentIcon="@Icons.Material.Filled.TextFields" Adornment="Adornment.Start" Label="Yout context" Variant="Variant.Outlined" Lines="3" AutoGrow="@true" MaxLines="12" Class="mb-3"/>
 | 
			
		||||
 | 
			
		||||
            <MudStack Row="@true" AlignItems="AlignItems.Center" Class="mb-3">
 | 
			
		||||
                <MudSelect T="IconSources" @bind-Value="@this.selectedIconSource" AdornmentIcon="@Icons.Material.Filled.Source" Adornment="Adornment.Start" Label="Your icon source" Variant="Variant.Outlined" Margin="Margin.Dense">
 | 
			
		||||
                    @foreach (var source in Enum.GetValues<IconSources>())
 | 
			
		||||
                    {
 | 
			
		||||
                        <MudSelectItem Value="@source">@source.Name()</MudSelectItem>
 | 
			
		||||
                    }
 | 
			
		||||
                </MudSelect>
 | 
			
		||||
                @if (this.selectedIconSource is not IconSources.GENERIC)
 | 
			
		||||
                {
 | 
			
		||||
                    <MudButton Href="@this.selectedIconSource.URL()" Target="_blank" Variant="Variant.Filled" Size="Size.Medium">Open website</MudButton>
 | 
			
		||||
                }
 | 
			
		||||
            </MudStack>
 | 
			
		||||
            
 | 
			
		||||
            <MudSelect T="Provider" @bind-Value="@this.selectedProvider" Validation="@this.ValidatingProvider" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Apps" Margin="Margin.Dense" Label="Provider" Class="mb-3 rounded-lg" Variant="Variant.Outlined">
 | 
			
		||||
                @foreach (var provider in this.SettingsManager.ConfigurationData.Providers)
 | 
			
		||||
                {
 | 
			
		||||
                    <MudSelectItem Value="@provider"/>
 | 
			
		||||
                }
 | 
			
		||||
            </MudSelect>
 | 
			
		||||
 | 
			
		||||
            <MudButton Variant="Variant.Filled" Class="mb-3" OnClick="() => this.FindIcon()">
 | 
			
		||||
                Find icons
 | 
			
		||||
            </MudButton>
 | 
			
		||||
        </MudForm>
 | 
			
		||||
 | 
			
		||||
        @if (this.inputIssues.Any())
 | 
			
		||||
        {
 | 
			
		||||
            <MudPaper Class="pr-2 mt-3" Outlined="@true">
 | 
			
		||||
                <MudText Typo="Typo.h6">Issues</MudText>
 | 
			
		||||
                <MudList Clickable="@true">
 | 
			
		||||
                    @foreach (var issue in this.inputIssues)
 | 
			
		||||
                    {
 | 
			
		||||
                        <MudListItem Icon="@Icons.Material.Filled.Error" IconColor="Color.Error">
 | 
			
		||||
                            @issue
 | 
			
		||||
                        </MudListItem>
 | 
			
		||||
                    }
 | 
			
		||||
                </MudList>
 | 
			
		||||
            </MudPaper>
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @if (this.resultingContentBlock is not null)
 | 
			
		||||
        {
 | 
			
		||||
            <ContentBlockComponent Role="@this.resultingContentBlock.Role" Type="@this.resultingContentBlock.ContentType" Time="@this.resultingContentBlock.Time" Content="@this.resultingContentBlock.Content" Class="mr-2"/>
 | 
			
		||||
        }
 | 
			
		||||
    </ChildContent>
 | 
			
		||||
</InnerScrolling>
 | 
			
		||||
@ -0,0 +1,134 @@
 | 
			
		||||
using AIStudio.Chat;
 | 
			
		||||
using AIStudio.Provider;
 | 
			
		||||
using AIStudio.Settings;
 | 
			
		||||
 | 
			
		||||
using Microsoft.AspNetCore.Components;
 | 
			
		||||
 | 
			
		||||
namespace AIStudio.Components.Pages.IconFinder;
 | 
			
		||||
 | 
			
		||||
public partial class AssistantIconFinder : ComponentBase
 | 
			
		||||
{
 | 
			
		||||
    [Inject]
 | 
			
		||||
    private SettingsManager SettingsManager { get; set; } = null!;
 | 
			
		||||
    
 | 
			
		||||
    [Inject]
 | 
			
		||||
    public IJSRuntime JsRuntime { get; init; } = null!;
 | 
			
		||||
 | 
			
		||||
    [Inject]
 | 
			
		||||
    public Random RNG { get; set; } = null!;
 | 
			
		||||
    
 | 
			
		||||
    private ChatThread? chatThread;
 | 
			
		||||
    private ContentBlock? resultingContentBlock;
 | 
			
		||||
    private AIStudio.Settings.Provider selectedProvider;
 | 
			
		||||
    private MudForm form = null!;
 | 
			
		||||
    private bool inputIsValid;
 | 
			
		||||
    private string[] inputIssues = [];
 | 
			
		||||
    private string inputContext = string.Empty;
 | 
			
		||||
    private IconSources selectedIconSource;
 | 
			
		||||
 | 
			
		||||
    #region Overrides of ComponentBase
 | 
			
		||||
 | 
			
		||||
    protected override async Task OnAfterRenderAsync(bool firstRender)
 | 
			
		||||
    {
 | 
			
		||||
        // Reset the validation when not editing and on the first render.
 | 
			
		||||
        // We don't want to show validation errors when the user opens the dialog.
 | 
			
		||||
        if(firstRender)
 | 
			
		||||
            this.form.ResetValidation();
 | 
			
		||||
        
 | 
			
		||||
        await base.OnAfterRenderAsync(firstRender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #endregion
 | 
			
		||||
 | 
			
		||||
    private string? ValidatingContext(string context)
 | 
			
		||||
    {
 | 
			
		||||
        if(string.IsNullOrWhiteSpace(context))
 | 
			
		||||
            return "Please provide a context. This will help the AI to find the right icon. You might type just a keyword or copy a sentence from your text, e.g., from a slide where you want to use the icon.";
 | 
			
		||||
        
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private string? ValidatingProvider(AIStudio.Settings.Provider provider)
 | 
			
		||||
    {
 | 
			
		||||
        if(provider.UsedProvider == Providers.NONE)
 | 
			
		||||
            return "Please select a provider.";
 | 
			
		||||
        
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async Task FindIcon()
 | 
			
		||||
    {
 | 
			
		||||
        await this.form.Validate();
 | 
			
		||||
        if (!this.inputIsValid)
 | 
			
		||||
            return;
 | 
			
		||||
        
 | 
			
		||||
        //
 | 
			
		||||
        // Create a new chat thread:
 | 
			
		||||
        //
 | 
			
		||||
        this.chatThread = new()
 | 
			
		||||
        {
 | 
			
		||||
            WorkspaceId = Guid.Empty,
 | 
			
		||||
            ChatId = Guid.NewGuid(),
 | 
			
		||||
            Name = string.Empty,
 | 
			
		||||
            Seed = this.RNG.Next(),
 | 
			
		||||
            SystemPrompt = SYSTEM_PROMPT,
 | 
			
		||||
            Blocks = [],
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        //
 | 
			
		||||
        // Add the user's request to the thread:
 | 
			
		||||
        //
 | 
			
		||||
        var time = DateTimeOffset.Now;
 | 
			
		||||
        this.chatThread.Blocks.Add(new ContentBlock
 | 
			
		||||
        {
 | 
			
		||||
            Time = time,
 | 
			
		||||
            ContentType = ContentType.TEXT,
 | 
			
		||||
            Role = ChatRole.USER,
 | 
			
		||||
            Content = new ContentText
 | 
			
		||||
            {
 | 
			
		||||
                Text =
 | 
			
		||||
                $"""
 | 
			
		||||
                   {this.selectedIconSource.Prompt()} I search for an icon for the following context:
 | 
			
		||||
                   
 | 
			
		||||
                   ```
 | 
			
		||||
                   {this.inputContext}
 | 
			
		||||
                   ```
 | 
			
		||||
                """,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        //
 | 
			
		||||
        // Add the AI response to the thread:
 | 
			
		||||
        //
 | 
			
		||||
        var aiText = new ContentText
 | 
			
		||||
        {
 | 
			
		||||
            // We have to wait for the remote
 | 
			
		||||
            // for the content stream: 
 | 
			
		||||
            InitialRemoteWait = true,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        this.resultingContentBlock = new ContentBlock
 | 
			
		||||
        {
 | 
			
		||||
            Time = time,
 | 
			
		||||
            ContentType = ContentType.TEXT,
 | 
			
		||||
            Role = ChatRole.AI,
 | 
			
		||||
            Content = aiText,
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        this.chatThread?.Blocks.Add(this.resultingContentBlock);
 | 
			
		||||
        
 | 
			
		||||
        // Use the selected provider to get the AI response.
 | 
			
		||||
        // By awaiting this line, we wait for the entire
 | 
			
		||||
        // content to be streamed.
 | 
			
		||||
        await aiText.CreateFromProviderAsync(this.selectedProvider.UsedProvider.CreateProvider(this.selectedProvider.InstanceName, this.selectedProvider.Hostname), this.JsRuntime, this.SettingsManager, this.selectedProvider.Model, this.chatThread);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private const string SYSTEM_PROMPT = 
 | 
			
		||||
        """
 | 
			
		||||
        I can search for icons using US English keywords. Please help me come up with the right search queries.
 | 
			
		||||
        I don't want you to translate my requests word-for-word into US English. Instead, you should provide keywords
 | 
			
		||||
        that are likely to yield suitable icons. For example, I might ask for an icon about departments, but icons
 | 
			
		||||
        related to the keyword "buildings" might be the best match. Provide your keywords in a Markdown list without
 | 
			
		||||
        quotation marks.
 | 
			
		||||
        """;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
namespace AIStudio.Components.Pages.IconFinder;
 | 
			
		||||
 | 
			
		||||
public static class IconSourceExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static string Name(this IconSources iconSource) => iconSource switch
 | 
			
		||||
    {
 | 
			
		||||
        IconSources.FLAT_ICON => "Flaticon",
 | 
			
		||||
        IconSources.FONT_AWESOME => "Font Awesome",
 | 
			
		||||
        IconSources.MATERIAL_ICONS => "Material Icons",
 | 
			
		||||
        IconSources.FEATHER_ICONS => "Feather Icons",
 | 
			
		||||
        IconSources.BOOTSTRAP_ICONS => "Bootstrap Icons",
 | 
			
		||||
        IconSources.ICONS8 => "Icons8",
 | 
			
		||||
            
 | 
			
		||||
        _ => "Generic",
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    public static string Prompt(this IconSources iconSource) => iconSource switch
 | 
			
		||||
    {
 | 
			
		||||
        IconSources.FLAT_ICON => "My icon source is Flaticon.",
 | 
			
		||||
        IconSources.FONT_AWESOME => "I look for an icon on Font Awesome. Please provide just valid icon names. Valid icon names are using the format `fa-icon-name`.",
 | 
			
		||||
        IconSources.MATERIAL_ICONS => "I look for a Material icon. Please provide just valid icon names. Valid icon names are using the format `IconName`.",
 | 
			
		||||
        IconSources.FEATHER_ICONS => "My icon source is Feather Icons. Please provide just valid icon names. Valid icon names usiing the format `icon-name`.",
 | 
			
		||||
        IconSources.BOOTSTRAP_ICONS => "I look for an icon for Bootstrap. Please provide just valid icon names. Valid icon names are using the format `bi-icon-name`.",
 | 
			
		||||
        IconSources.ICONS8 => "I look for an icon on Icons8.",
 | 
			
		||||
            
 | 
			
		||||
        _ => string.Empty,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    public static string URL(this IconSources iconSource) => iconSource switch
 | 
			
		||||
    {
 | 
			
		||||
        IconSources.FLAT_ICON => "https://www.flaticon.com/",
 | 
			
		||||
        IconSources.FONT_AWESOME => "https://fontawesome.com/",
 | 
			
		||||
        IconSources.MATERIAL_ICONS => "https://material.io/resources/icons/",
 | 
			
		||||
        IconSources.FEATHER_ICONS => "https://feathericons.com/",
 | 
			
		||||
        IconSources.BOOTSTRAP_ICONS => "https://icons.getbootstrap.com/",
 | 
			
		||||
        IconSources.ICONS8 => "https://icons8.com/",
 | 
			
		||||
            
 | 
			
		||||
        _ => string.Empty,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,13 @@
 | 
			
		||||
namespace AIStudio.Components.Pages.IconFinder;
 | 
			
		||||
 | 
			
		||||
public enum IconSources
 | 
			
		||||
{
 | 
			
		||||
    GENERIC,
 | 
			
		||||
        
 | 
			
		||||
    ICONS8,
 | 
			
		||||
    FLAT_ICON,
 | 
			
		||||
    FONT_AWESOME,
 | 
			
		||||
    MATERIAL_ICONS,
 | 
			
		||||
    FEATHER_ICONS,
 | 
			
		||||
    BOOTSTRAP_ICONS,
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user