From 375be805a1acfaef63eef55b014303e40cc13626 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 15 Sep 2024 21:14:56 +0200 Subject: [PATCH] Add job posting assistant (#150) --- .../JobPosting/AssistantJobPostings.razor | 15 + .../JobPosting/AssistantJobPostings.razor.cs | 283 ++++++++++++++++++ .../Components/ConfigurationText.razor | 11 +- .../Components/ConfigurationText.razor.cs | 53 +++- app/MindWork AI Studio/Pages/Assistants.razor | 1 + app/MindWork AI Studio/Pages/Settings.razor | 20 ++ ...xtensions.cs => LLMProvidersExtensions.cs} | 2 +- app/MindWork AI Studio/Routes.razor.cs | 1 + .../Settings/DataModel/Data.cs | 10 +- .../Settings/DataModel/DataJobPostings.cs | 66 ++++ app/MindWork AI Studio/Tools/Components.cs | 1 + .../Tools/ComponentsExtensions.cs | 4 + app/MindWork AI Studio/Tools/Event.cs | 1 + .../wwwroot/changelog/v0.9.12.md | 4 + 14 files changed, 461 insertions(+), 11 deletions(-) create mode 100644 app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor create mode 100644 app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor.cs rename app/MindWork AI Studio/Provider/{ProvidersExtensions.cs => LLMProvidersExtensions.cs} (98%) create mode 100644 app/MindWork AI Studio/Settings/DataModel/DataJobPostings.cs create mode 100644 app/MindWork AI Studio/wwwroot/changelog/v0.9.12.md diff --git a/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor b/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor new file mode 100644 index 0000000..ba41922 --- /dev/null +++ b/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor @@ -0,0 +1,15 @@ +@attribute [Route(Routes.ASSISTANT_JOB_POSTING)] +@inherits AssistantBaseCore + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor.cs b/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor.cs new file mode 100644 index 0000000..8da1250 --- /dev/null +++ b/app/MindWork AI Studio/Assistants/JobPosting/AssistantJobPostings.razor.cs @@ -0,0 +1,283 @@ +namespace AIStudio.Assistants.JobPosting; + +public partial class AssistantJobPostings : AssistantBaseCore +{ + public override Tools.Components Component => Tools.Components.JOB_POSTING_ASSISTANT; + + protected override string Title => "Job Posting"; + + protected override string Description => + """ + Provide some key points about the job you want to post. The AI will then + formulate a suggestion that you can finalize. + """; + + protected override string SystemPrompt => + $""" + You are an experienced specialist in personnel matters. You write job postings. + You follow the usual guidelines in the country of the posting. You ensure that + no individuals are discriminated against or excluded by the job posting. You do + not ask any questions and you do not repeat the task. You provide your response + in a Markdown format. Missing information necessary for the job posting, you try + to derive from the other details provided. + + Structure of your response: + --- + # + <Description of the job and the company> + + # <TASKS> + <Describe what takes the job entails> + + # <QUALIFICATIONS> + <What qualifications are required> + + # <RESPONSIBILITIES> + <What responsibilities are associated with the job> + + <When available, closing details such as the entry date etc.> + + --- + + You write the job posting in the following language: {this.SystemPromptLanguage()}. + """; + + protected override IReadOnlyList<IButtonData> FooterButtons => []; + + protected override string SubmitText => "Create the job posting"; + + protected override Func<Task> SubmitAction => this.CreateJobPosting; + + protected override bool SubmitDisabled => false; + + protected override bool AllowProfiles => false; + + protected override void ResetFrom() + { + this.inputEntryDate = string.Empty; + this.inputValidUntil = string.Empty; + if (!this.MightPreselectValues()) + { + this.selectedTargetLanguage = CommonLanguages.AS_IS; + this.customTargetLanguage = string.Empty; + this.inputMandatoryInformation = string.Empty; + this.inputJobDescription = string.Empty; + this.inputQualifications = string.Empty; + this.inputResponsibilities = string.Empty; + this.inputCompanyName = string.Empty; + this.inputWorkLocation = string.Empty; + this.inputCountryLegalFramework = string.Empty; + } + } + + protected override bool MightPreselectValues() + { + if (this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions) + { + this.inputMandatoryInformation = this.SettingsManager.ConfigurationData.JobPostings.PreselectedMandatoryInformation; + if(string.IsNullOrWhiteSpace(this.inputJobDescription)) + this.inputJobDescription = this.SettingsManager.ConfigurationData.JobPostings.PreselectedJobDescription; + this.inputQualifications = this.SettingsManager.ConfigurationData.JobPostings.PreselectedQualifications; + this.inputResponsibilities = this.SettingsManager.ConfigurationData.JobPostings.PreselectedResponsibilities; + this.inputCompanyName = this.SettingsManager.ConfigurationData.JobPostings.PreselectedCompanyName; + this.inputWorkLocation = this.SettingsManager.ConfigurationData.JobPostings.PreselectedWorkLocation; + this.inputCountryLegalFramework = this.SettingsManager.ConfigurationData.JobPostings.PreselectedCountryLegalFramework; + this.selectedTargetLanguage = this.SettingsManager.ConfigurationData.JobPostings.PreselectedTargetLanguage; + this.customTargetLanguage = this.SettingsManager.ConfigurationData.JobPostings.PreselectOtherLanguage; + return true; + } + + return false; + } + + private string inputMandatoryInformation = string.Empty; + private string inputJobDescription = string.Empty; + private string inputQualifications = string.Empty; + private string inputResponsibilities = string.Empty; + private string inputCompanyName = string.Empty; + private string inputEntryDate = string.Empty; + private string inputValidUntil = string.Empty; + private string inputWorkLocation = string.Empty; + private string inputCountryLegalFramework = string.Empty; + private CommonLanguages selectedTargetLanguage = CommonLanguages.AS_IS; + private string customTargetLanguage = string.Empty; + + #region Overrides of ComponentBase + + protected override async Task OnInitializedAsync() + { + var deferredContent = MessageBus.INSTANCE.CheckDeferredMessages<string>(Event.SEND_TO_JOB_POSTING_ASSISTANT).FirstOrDefault(); + if (deferredContent is not null) + this.inputJobDescription = deferredContent; + + await base.OnInitializedAsync(); + } + + #endregion + + private string? ValidateCustomLanguage(string language) + { + if(this.selectedTargetLanguage == CommonLanguages.OTHER && string.IsNullOrWhiteSpace(language)) + return "Please provide a custom target language."; + + return null; + } + + private string? ValidateJobDescription(string jobDescription) + { + if(string.IsNullOrWhiteSpace(jobDescription)) + return "Please provide a job description."; + + return null; + } + + private string? ValidateCountryLegalFramework(string countryLegalFramework) + { + if(string.IsNullOrWhiteSpace(countryLegalFramework)) + return "Please provide the country where the job is posted (legal framework)."; + + return null; + } + + private string SystemPromptLanguage() + { + if(this.selectedTargetLanguage is CommonLanguages.AS_IS) + return "Use the same language as the input"; + + if(this.selectedTargetLanguage is CommonLanguages.OTHER) + return this.customTargetLanguage; + + return this.selectedTargetLanguage.Name(); + } + + private string UserPromptMandatoryInformation() + { + if(string.IsNullOrWhiteSpace(this.inputMandatoryInformation)) + return string.Empty; + + return $""" + # Mandatory Information + {this.inputMandatoryInformation} + + """; + } + + private string UserPromptJobDescription() + { + if(string.IsNullOrWhiteSpace(this.inputJobDescription)) + return string.Empty; + + return $""" + # Job Description + {this.inputJobDescription} + + """; + } + + private string UserPromptQualifications() + { + if(string.IsNullOrWhiteSpace(this.inputQualifications)) + return string.Empty; + + return $""" + # Qualifications + {this.inputQualifications} + + """; + } + + private string UserPromptResponsibilities() + { + if(string.IsNullOrWhiteSpace(this.inputResponsibilities)) + return string.Empty; + + return $""" + # Responsibilities + {this.inputResponsibilities} + + """; + } + + private string UserPromptCompanyName() + { + if(string.IsNullOrWhiteSpace(this.inputCompanyName)) + return string.Empty; + + return $""" + # Company Name + {this.inputCompanyName} + + """; + } + + private string UserPromptEntryDate() + { + if(string.IsNullOrWhiteSpace(this.inputEntryDate)) + return string.Empty; + + return $""" + # Entry Date + {this.inputEntryDate} + + """; + } + + private string UserPromptValidUntil() + { + if(string.IsNullOrWhiteSpace(this.inputValidUntil)) + return string.Empty; + + return $""" + # Job Posting Valid Until + {this.inputValidUntil} + + """; + } + + private string UserPromptWorkLocation() + { + if(string.IsNullOrWhiteSpace(this.inputWorkLocation)) + return string.Empty; + + return $""" + # Work Location + {this.inputWorkLocation} + + """; + } + + private string UserPromptCountryLegalFramework() + { + if(string.IsNullOrWhiteSpace(this.inputCountryLegalFramework)) + return string.Empty; + + return $""" + # Country where the job is posted (legal framework) + {this.inputCountryLegalFramework} + + """; + } + + private async Task CreateJobPosting() + { + await this.form!.Validate(); + if (!this.inputIsValid) + return; + + this.CreateChatThread(); + var time = this.AddUserRequest( + $""" + {this.UserPromptCompanyName()} + {this.UserPromptCountryLegalFramework()} + {this.UserPromptMandatoryInformation()} + {this.UserPromptJobDescription()} + {this.UserPromptQualifications()} + {this.UserPromptResponsibilities()} + {this.UserPromptWorkLocation()} + {this.UserPromptEntryDate()} + {this.UserPromptValidUntil()} + """); + + await this.AddAIResponseAsync(time); + } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/ConfigurationText.razor b/app/MindWork AI Studio/Components/ConfigurationText.razor index 73d07be..a3cc323 100644 --- a/app/MindWork AI Studio/Components/ConfigurationText.razor +++ b/app/MindWork AI Studio/Components/ConfigurationText.razor @@ -3,16 +3,17 @@ <MudTextField T="string" Text="@this.Text()" - TextChanged="@this.OptionChanged" + TextChanged="@this.InternalUpdate" Label="@this.OptionDescription" Disabled="@this.Disabled()" - Class="mb-3" + Class="@MARGIN_CLASS" Adornment="Adornment.Start" AdornmentIcon="@this.Icon" AdornmentColor="@this.IconColor" UserAttributes="@SPELLCHECK_ATTRIBUTES" - Lines="1" - Immediate="@false" - DebounceInterval="500" + Lines="@this.NumLines" + AutoGrow="@this.AutoGrow" + MaxLines="@this.GetMaxLines" + Immediate="@true" Variant="Variant.Outlined" /> \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/ConfigurationText.razor.cs b/app/MindWork AI Studio/Components/ConfigurationText.razor.cs index e6cd379..4e6bb7f 100644 --- a/app/MindWork AI Studio/Components/ConfigurationText.razor.cs +++ b/app/MindWork AI Studio/Components/ConfigurationText.razor.cs @@ -1,5 +1,7 @@ using Microsoft.AspNetCore.Components; +using Timer = System.Timers.Timer; + namespace AIStudio.Components; public partial class ConfigurationText : ConfigurationBase @@ -11,7 +13,7 @@ public partial class ConfigurationText : ConfigurationBase public Func<string> Text { get; set; } = () => string.Empty; /// <summary> - /// An action which is called when the option is changed. + /// An action which is called when the text was changed. /// </summary> [Parameter] public Action<string> TextUpdate { get; set; } = _ => { }; @@ -27,6 +29,55 @@ public partial class ConfigurationText : ConfigurationBase /// </summary> [Parameter] public Color IconColor { get; set; } = Color.Default; + + /// <summary> + /// How many lines should the textfield have? + /// </summary> + [Parameter] + public int NumLines { get; set; } = 1; + + /// <summary> + /// What is the maximum number of lines? + /// </summary> + [Parameter] + public int MaxLines { get; set; } = 12; + + private string internalText = string.Empty; + private Timer timer = new(TimeSpan.FromMilliseconds(500)) + { + AutoReset = false + }; + + #region Overrides of ConfigurationBase + + protected override async Task OnInitializedAsync() + { + this.timer.Elapsed += async (_, _) => await this.InvokeAsync(async () => await this.OptionChanged(this.internalText)); + await base.OnInitializedAsync(); + } + + #region Overrides of ComponentBase + + protected override async Task OnParametersSetAsync() + { + this.internalText = this.Text(); + await base.OnParametersSetAsync(); + } + + #endregion + + #endregion + + private bool AutoGrow => this.NumLines > 1; + + private int GetMaxLines => this.AutoGrow ? this.MaxLines : 1; + + private void InternalUpdate(string text) + { + this.timer.Stop(); + this.internalText = text; + this.timer.Start(); + } private async Task OptionChanged(string updatedText) { diff --git a/app/MindWork AI Studio/Pages/Assistants.razor b/app/MindWork AI Studio/Pages/Assistants.razor index da377d7..2368878 100644 --- a/app/MindWork AI Studio/Pages/Assistants.razor +++ b/app/MindWork AI Studio/Pages/Assistants.razor @@ -24,6 +24,7 @@ <AssistantBlock Name="E-Mail" Description="Generate an e-mail for a given context." Icon="@Icons.Material.Filled.Email" Link="@Routes.ASSISTANT_EMAIL"/> <AssistantBlock Name="My Tasks" Description="Analyze a text or an email for tasks you need to complete." Icon="@Icons.Material.Filled.Task" Link="@Routes.ASSISTANT_MY_TASKS"/> <AssistantBlock Name="Agenda Planner" Description="Generate an agenda for a given meeting, seminar, etc." Icon="@Icons.Material.Filled.CalendarToday" Link="@Routes.ASSISTANT_AGENDA"/> + <AssistantBlock Name="Job Posting" Description="Generate a job posting for a given job description." Icon="@Icons.Material.Filled.Work" Link="@Routes.ASSISTANT_JOB_POSTING"/> <AssistantBlock Name="Legal Check" Description="Ask a question about a legal document." Icon="@Icons.Material.Filled.Gavel" Link="@Routes.ASSISTANT_LEGAL_CHECK"/> <AssistantBlock Name="Icon Finder" Description="Using a LLM to find an icon for a given context." Icon="@Icons.Material.Filled.FindInPage" Link="@Routes.ASSISTANT_ICON_FINDER"/> </MudStack> diff --git a/app/MindWork AI Studio/Pages/Settings.razor b/app/MindWork AI Studio/Pages/Settings.razor index 27e565e..df5ed94 100644 --- a/app/MindWork AI Studio/Pages/Settings.razor +++ b/app/MindWork AI Studio/Pages/Settings.razor @@ -342,6 +342,26 @@ </MudPaper> </ExpansionPanel> + <ExpansionPanel HeaderIcon="@Icons.Material.Filled.Work" HeaderText="Assistant: Job Postings"> + <MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg"> + <ConfigurationOption OptionDescription="Preselect job posting options?" LabelOn="Job posting options are preselected" LabelOff="No job posting options are preselected" State="@(() => this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions = updatedState)" OptionHelp="When enabled, you can preselect some job posting options. This is might be useful when you prefer a specific LLM model."/> + <ConfigurationText OptionDescription="Preselect the company name?" Disabled="@(() => !this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions)" Icon="@Icons.Material.Filled.Warehouse" Text="@(() => this.SettingsManager.ConfigurationData.JobPostings.PreselectedCompanyName)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.JobPostings.PreselectedCompanyName = updatedText)" /> + <ConfigurationText OptionDescription="Preselect some mandatory information about the job posting?" NumLines="6" Disabled="@(() => !this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions)" Icon="@Icons.Material.Filled.TextSnippet" Text="@(() => this.SettingsManager.ConfigurationData.JobPostings.PreselectedMandatoryInformation)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.JobPostings.PreselectedMandatoryInformation = updatedText)" /> + <ConfigurationText OptionDescription="Preselect the job description?" NumLines="3" MaxLines="6" Disabled="@(() => !this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions)" Icon="@Icons.Material.Filled.Settings" Text="@(() => this.SettingsManager.ConfigurationData.JobPostings.PreselectedJobDescription)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.JobPostings.PreselectedJobDescription = updatedText)" /> + <ConfigurationText OptionDescription="Preselect the job qualifications?" NumLines="3" MaxLines="6" Disabled="@(() => !this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions)" Icon="@Icons.Material.Filled.Settings" Text="@(() => this.SettingsManager.ConfigurationData.JobPostings.PreselectedQualifications)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.JobPostings.PreselectedQualifications = updatedText)" /> + <ConfigurationText OptionDescription="Preselect the job responsibilities?" NumLines="3" MaxLines="6" Disabled="@(() => !this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions)" Icon="@Icons.Material.Filled.Settings" Text="@(() => this.SettingsManager.ConfigurationData.JobPostings.PreselectedResponsibilities)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.JobPostings.PreselectedResponsibilities = updatedText)" /> + <ConfigurationText OptionDescription="Preselect the work location?" Disabled="@(() => !this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions)" Icon="@Icons.Material.Filled.MyLocation" Text="@(() => this.SettingsManager.ConfigurationData.JobPostings.PreselectedWorkLocation)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.JobPostings.PreselectedWorkLocation = updatedText)" /> + <ConfigurationText OptionDescription="Preselect the country (legal framework)?" Disabled="@(() => !this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions)" Icon="@Icons.Material.Filled.Flag" Text="@(() => this.SettingsManager.ConfigurationData.JobPostings.PreselectedCountryLegalFramework)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.JobPostings.PreselectedCountryLegalFramework = updatedText)" /> + <ConfigurationSelect OptionDescription="Preselect the language" Disabled="@(() => !this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.JobPostings.PreselectedTargetLanguage)" Data="@ConfigurationSelectDataFactory.GetCommonLanguagesOptionalData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.JobPostings.PreselectedTargetLanguage = selectedValue)" OptionHelp="Which target language should be preselected?"/> + @if (this.SettingsManager.ConfigurationData.JobPostings.PreselectedTargetLanguage is CommonLanguages.OTHER) + { + <ConfigurationText OptionDescription="Preselect another target language" Disabled="@(() => !this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions)" Icon="@Icons.Material.Filled.Translate" Text="@(() => this.SettingsManager.ConfigurationData.JobPostings.PreselectOtherLanguage)" TextUpdate="@(updatedText => this.SettingsManager.ConfigurationData.JobPostings.PreselectOtherLanguage = updatedText)"/> + } + <ConfigurationMinConfidenceSelection Disabled="@(() => !this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions)" RestrictToGlobalMinimumConfidence="@true" SelectedValue="@(() => this.SettingsManager.ConfigurationData.JobPostings.MinimumProviderConfidence)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.JobPostings.MinimumProviderConfidence = selectedValue)"/> + <ConfigurationProviderSelection Component="Components.JOB_POSTING_ASSISTANT" Data="@this.availableProviders" Disabled="@(() => !this.SettingsManager.ConfigurationData.JobPostings.PreselectOptions)" SelectedValue="@(() => this.SettingsManager.ConfigurationData.JobPostings.PreselectedProvider)" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.JobPostings.PreselectedProvider = selectedValue)"/> + </MudPaper> + </ExpansionPanel> + <ExpansionPanel HeaderIcon="@Icons.Material.Filled.Gavel" HeaderText="Assistant: Legal Check"> <ConfigurationOption OptionDescription="Hide the web content reader?" LabelOn="Web content reader is hidden" LabelOff="Web content reader is shown" State="@(() => this.SettingsManager.ConfigurationData.LegalCheck.HideWebContentReader)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.LegalCheck.HideWebContentReader = updatedState)" OptionHelp="When activated, the web content reader is hidden and cannot be used. As a result, the user interface becomes a bit easier to use."/> <MudPaper Class="pa-3 mb-8 border-dashed border rounded-lg"> diff --git a/app/MindWork AI Studio/Provider/ProvidersExtensions.cs b/app/MindWork AI Studio/Provider/LLMProvidersExtensions.cs similarity index 98% rename from app/MindWork AI Studio/Provider/ProvidersExtensions.cs rename to app/MindWork AI Studio/Provider/LLMProvidersExtensions.cs index 8a4a971..3037e87 100644 --- a/app/MindWork AI Studio/Provider/ProvidersExtensions.cs +++ b/app/MindWork AI Studio/Provider/LLMProvidersExtensions.cs @@ -7,7 +7,7 @@ using AIStudio.Settings; namespace AIStudio.Provider; -public static class ProvidersExtensions +public static class LLMProvidersExtensions { /// <summary> /// Returns the human-readable name of the provider. diff --git a/app/MindWork AI Studio/Routes.razor.cs b/app/MindWork AI Studio/Routes.razor.cs index f65d7ec..7b3e24e 100644 --- a/app/MindWork AI Studio/Routes.razor.cs +++ b/app/MindWork AI Studio/Routes.razor.cs @@ -21,5 +21,6 @@ public sealed partial class Routes public const string ASSISTANT_LEGAL_CHECK = "/assistant/legal-check"; public const string ASSISTANT_SYNONYMS = "/assistant/synonyms"; public const string ASSISTANT_MY_TASKS = "/assistant/my-tasks"; + public const string ASSISTANT_JOB_POSTING = "/assistant/job-posting"; // ReSharper restore InconsistentNaming } \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/DataModel/Data.cs b/app/MindWork AI Studio/Settings/DataModel/Data.cs index 5970f6d..720d0e0 100644 --- a/app/MindWork AI Studio/Settings/DataModel/Data.cs +++ b/app/MindWork AI Studio/Settings/DataModel/Data.cs @@ -58,11 +58,13 @@ public sealed class Data public DataRewriteImprove RewriteImprove { get; init; } = new(); - public DataEMail EMail { get; set; } = new(); + public DataEMail EMail { get; init; } = new(); - public DataLegalCheck LegalCheck { get; set; } = new(); + public DataLegalCheck LegalCheck { get; init; } = new(); - public DataSynonyms Synonyms { get; set; } = new(); + public DataSynonyms Synonyms { get; init; } = new(); - public DataMyTasks MyTasks { get; set; } = new(); + public DataMyTasks MyTasks { get; init; } = new(); + + public DataJobPostings JobPostings { get; init; } = new(); } \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/DataModel/DataJobPostings.cs b/app/MindWork AI Studio/Settings/DataModel/DataJobPostings.cs new file mode 100644 index 0000000..add799e --- /dev/null +++ b/app/MindWork AI Studio/Settings/DataModel/DataJobPostings.cs @@ -0,0 +1,66 @@ +using AIStudio.Provider; + +namespace AIStudio.Settings.DataModel; + +public sealed class DataJobPostings +{ + /// <summary> + /// Do we want to preselect any translator options? + /// </summary> + public bool PreselectOptions { get; set; } + + /// <summary> + /// The mandatory information for the job posting. + /// </summary> + public string PreselectedMandatoryInformation { get; set; } = string.Empty; + + /// <summary> + /// The job description. + /// </summary> + public string PreselectedJobDescription { get; set; } = string.Empty; + + /// <summary> + /// The qualifications required for the job. + /// </summary> + public string PreselectedQualifications { get; set; } = string.Empty; + + /// <summary> + /// What are the responsibilities of the job? + /// </summary> + public string PreselectedResponsibilities { get; set; } = string.Empty; + + /// <summary> + /// Which company name should be preselected? + /// </summary> + public string PreselectedCompanyName { get; set; } = string.Empty; + + /// <summary> + /// Where should the work be done? + /// </summary> + public string PreselectedWorkLocation { get; set; } = string.Empty; + + /// <summary> + /// The preselected country legal framework. + /// </summary> + public string PreselectedCountryLegalFramework { get; set; } = string.Empty; + + /// <summary> + /// Preselect the target language? + /// </summary> + public CommonLanguages PreselectedTargetLanguage { get; set; } = CommonLanguages.EN_US; + + /// <summary> + /// Preselect any other language? + /// </summary> + public string PreselectOtherLanguage { get; set; } = string.Empty; + + /// <summary> + /// The minimum confidence level required for a provider to be considered. + /// </summary> + public ConfidenceLevel MinimumProviderConfidence { get; set; } = ConfidenceLevel.NONE; + + /// <summary> + /// The preselected translator provider. + /// </summary> + public string PreselectedProvider { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/Components.cs b/app/MindWork AI Studio/Tools/Components.cs index 1076585..ccebcd0 100644 --- a/app/MindWork AI Studio/Tools/Components.cs +++ b/app/MindWork AI Studio/Tools/Components.cs @@ -15,6 +15,7 @@ public enum Components LEGAL_CHECK_ASSISTANT, SYNONYMS_ASSISTANT, MY_TASKS_ASSISTANT, + JOB_POSTING_ASSISTANT, CHAT, } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ComponentsExtensions.cs b/app/MindWork AI Studio/Tools/ComponentsExtensions.cs index e2b4628..f9f9e8e 100644 --- a/app/MindWork AI Studio/Tools/ComponentsExtensions.cs +++ b/app/MindWork AI Studio/Tools/ComponentsExtensions.cs @@ -18,6 +18,7 @@ public static class ComponentsExtensions Components.LEGAL_CHECK_ASSISTANT => "Legal Check Assistant", Components.SYNONYMS_ASSISTANT => "Synonym Assistant", Components.MY_TASKS_ASSISTANT => "My Tasks Assistant", + Components.JOB_POSTING_ASSISTANT => "Job Posting Assistant", Components.CHAT => "New Chat", @@ -37,6 +38,7 @@ public static class ComponentsExtensions Components.LEGAL_CHECK_ASSISTANT => new(Event.SEND_TO_LEGAL_CHECK_ASSISTANT, Routes.ASSISTANT_LEGAL_CHECK), Components.SYNONYMS_ASSISTANT => new(Event.SEND_TO_SYNONYMS_ASSISTANT, Routes.ASSISTANT_SYNONYMS), Components.MY_TASKS_ASSISTANT => new(Event.SEND_TO_MY_TASKS_ASSISTANT, Routes.ASSISTANT_MY_TASKS), + Components.JOB_POSTING_ASSISTANT => new(Event.SEND_TO_JOB_POSTING_ASSISTANT, Routes.ASSISTANT_JOB_POSTING), Components.CHAT => new(Event.SEND_TO_CHAT, Routes.CHAT), @@ -56,6 +58,7 @@ public static class ComponentsExtensions Components.LEGAL_CHECK_ASSISTANT => settingsManager.ConfigurationData.LegalCheck.PreselectOptions ? settingsManager.ConfigurationData.LegalCheck.MinimumProviderConfidence : default, Components.SYNONYMS_ASSISTANT => settingsManager.ConfigurationData.Synonyms.PreselectOptions ? settingsManager.ConfigurationData.Synonyms.MinimumProviderConfidence : default, Components.MY_TASKS_ASSISTANT => settingsManager.ConfigurationData.MyTasks.PreselectOptions ? settingsManager.ConfigurationData.MyTasks.MinimumProviderConfidence : default, + Components.JOB_POSTING_ASSISTANT => settingsManager.ConfigurationData.JobPostings.PreselectOptions ? settingsManager.ConfigurationData.JobPostings.MinimumProviderConfidence : default, _ => default, }; @@ -73,6 +76,7 @@ public static class ComponentsExtensions Components.LEGAL_CHECK_ASSISTANT => settingsManager.ConfigurationData.LegalCheck.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.LegalCheck.PreselectedProvider) : default, Components.SYNONYMS_ASSISTANT => settingsManager.ConfigurationData.Synonyms.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Synonyms.PreselectedProvider) : default, Components.MY_TASKS_ASSISTANT => settingsManager.ConfigurationData.MyTasks.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.MyTasks.PreselectedProvider) : default, + Components.JOB_POSTING_ASSISTANT => settingsManager.ConfigurationData.JobPostings.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.JobPostings.PreselectedProvider) : default, Components.CHAT => settingsManager.ConfigurationData.Chat.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Chat.PreselectedProvider) : default, diff --git a/app/MindWork AI Studio/Tools/Event.cs b/app/MindWork AI Studio/Tools/Event.cs index 54ae9d0..691f8b3 100644 --- a/app/MindWork AI Studio/Tools/Event.cs +++ b/app/MindWork AI Studio/Tools/Event.cs @@ -30,4 +30,5 @@ public enum Event SEND_TO_LEGAL_CHECK_ASSISTANT, SEND_TO_SYNONYMS_ASSISTANT, SEND_TO_MY_TASKS_ASSISTANT, + SEND_TO_JOB_POSTING_ASSISTANT, } \ No newline at end of file diff --git a/app/MindWork AI Studio/wwwroot/changelog/v0.9.12.md b/app/MindWork AI Studio/wwwroot/changelog/v0.9.12.md new file mode 100644 index 0000000..7d252de --- /dev/null +++ b/app/MindWork AI Studio/wwwroot/changelog/v0.9.12.md @@ -0,0 +1,4 @@ +# v0.9.12, build 187 (2024-09-xx xx:xx UTC) +- Added a job posting assistant to the business category. +- Fixed margin-related issue in the `ConfigurationText` component. +- Refactored the `ConfigurationText` component to debounce the input field to prevent unnecessary configuration updates. The component now also supports multiline text. \ No newline at end of file