diff --git a/src/App/Extensions/CosmosDbServiceActivityExtensions.cs b/src/App/Extensions/CosmosDbServiceActivityExtensions.cs
index 62fc396b..73d6142b 100644
--- a/src/App/Extensions/CosmosDbServiceActivityExtensions.cs
+++ b/src/App/Extensions/CosmosDbServiceActivityExtensions.cs
@@ -179,4 +179,61 @@ public static class CosmosDbServiceActivityExtensions
parentId: parentActivityId
);
}
+
+ ///
+ /// Starts an activity for adding or updating a lyrics analyzer prompt style in the database.
+ ///
+ /// The .
+ /// The lyrics analyzer prompt style.
+ /// The parent activity ID.
+ /// The started .
+ public static Activity? StartDbAddOrUpdateLyricsAnalyzerPromptStyleActivity(this ActivitySource activitySource, LyricsAnalyzerPromptStyle promptStyle, string? parentActivityId)
+ {
+ return activitySource.CreateActivity(
+ name: "Database:AddOrUpdateLyricsAnalyzerPromptStyleAsync",
+ kind: ActivityKind.Internal,
+ tags: new ActivityTagsCollection
+ {
+ { "db_Id", promptStyle.Id },
+ { "name", promptStyle.Name },
+ { "shortName", promptStyle.ShortName }
+ },
+ parentId: parentActivityId
+ );
+ }
+
+ ///
+ /// Starts an activity for getting a lyrics analyzer prompt style from the database.
+ ///
+ /// The .
+ /// The short name of the prompt style.
+ /// The parent activity ID.
+ /// The started .
+ public static Activity? StartDbGetLyricsAnalyzerPromptStyleActivity(this ActivitySource activitySource, string shortName, string? parentActivityId)
+ {
+ return activitySource.CreateActivity(
+ name: "Database:GetLyricsAnalyzerPromptStyleAsync",
+ kind: ActivityKind.Internal,
+ tags: new ActivityTagsCollection
+ {
+ { "shortName", shortName }
+ },
+ parentId: parentActivityId
+ );
+ }
+
+ ///
+ /// Starts an activity for getting all lyrics analyzer prompt styles from the database.
+ ///
+ /// The .
+ /// The parent activity ID.
+ /// The started .
+ public static Activity? StartDbGetLyricsAnalyzerPromptStylesActivity(this ActivitySource activitySource, string? parentActivityId)
+ {
+ return activitySource.CreateActivity(
+ name: "Database:GetLyricsAnalyzerPromptStylesAsync",
+ kind: ActivityKind.Internal,
+ parentId: parentActivityId
+ );
+ }
}
\ No newline at end of file
diff --git a/src/App/Handlers/LyricsAnalyzerPromptStyleAutoCompleteHandler.cs b/src/App/Handlers/LyricsAnalyzerPromptStyleAutoCompleteHandler.cs
index 2cab9909..08ab9639 100644
--- a/src/App/Handlers/LyricsAnalyzerPromptStyleAutoCompleteHandler.cs
+++ b/src/App/Handlers/LyricsAnalyzerPromptStyleAutoCompleteHandler.cs
@@ -2,6 +2,7 @@
using Discord.Interactions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using MuzakBot.App.Models.Database.LyricsAnalyzer;
using MuzakBot.App.Models.Itunes;
using MuzakBot.App.Models.MusicBrainz;
using MuzakBot.App.Services;
@@ -10,29 +11,52 @@ namespace MuzakBot.App.Handlers;
public class LyricsAnalyzerPromptStyleAutoCompleteHandler : AutocompleteHandler
{
- private readonly IReadOnlyList _promptStyleOptions = [
- new("Normal", "normal"),
- new("Meme: Tame", "tame-meme"),
- new("Meme: Insane", "insane-meme"),
- new("Meme: Roast", "roast-meme"),
- new("Snobby Music Critic", "snobby-music-critic")
- ];
+ private readonly ILogger _logger;
+ private readonly ICosmosDbService _cosmosDbService;
+
+ public LyricsAnalyzerPromptStyleAutoCompleteHandler(ILogger logger, ICosmosDbService cosmosDbService)
+ {
+ _logger = logger;
+ _cosmosDbService = cosmosDbService;
+ }
public override async Task GenerateSuggestionsAsync(IInteractionContext context, IAutocompleteInteraction autocompleteInteraction, IParameterInfo parameter, IServiceProvider services)
{
List results = new();
- AutocompleteOption? promptStyleInput = autocompleteInteraction.Data.Options.FirstOrDefault(item => item.Name == "prompt-style");
+ LyricsAnalyzerPromptStyle[] promptStyles = await _cosmosDbService.GetLyricsAnalyzerPromptStylesAsync();
+ Array.Sort(promptStyles, (item1, item2) => item1.Name.CompareTo(item2.Name));
+
+ _logger.LogInformation("Returned {Count} prompt styles from the database.", promptStyles.Length);
+
+ AutocompleteOption? promptStyleInput = autocompleteInteraction.Data.Options.FirstOrDefault(item => item.Name == "style");
if (promptStyleInput is null || promptStyleInput.Value is null || string.IsNullOrWhiteSpace(promptStyleInput.Value.ToString()))
{
- return AutocompletionResult.FromSuccess(_promptStyleOptions);
+ _logger.LogInformation("Prompt style input was null or empty, returning all prompt styles.");
+
+ foreach (LyricsAnalyzerPromptStyle promptStyle in promptStyles)
+ {
+ results.Add(new AutocompleteResult
+ {
+ Name = promptStyle.Name,
+ Value = promptStyle.ShortName
+ });
+ }
+
+ return AutocompletionResult.FromSuccess(results.AsEnumerable());
}
- _promptStyleOptions
- .Where(item => item.Value.ToString()!.Contains(promptStyleInput.Value.ToString()!, StringComparison.OrdinalIgnoreCase))
+ promptStyles
+ .Where(item => item.ShortName.Contains(promptStyleInput.Value.ToString()!, StringComparison.OrdinalIgnoreCase))
.ToList()
- .ForEach(item => results.Add(item));
+ .ForEach(item => results.Add(new AutocompleteResult
+ {
+ Name = item.Name,
+ Value = item.ShortName
+ }));
+
+ _logger.LogInformation("Filtered down to {Count} prompt styles based off the input {input}.", results.Count, promptStyleInput.Value.ToString()!);
return AutocompletionResult.FromSuccess(results.AsEnumerable());
}
diff --git a/src/App/JsonSourceGen/DatabaseJsonContext.cs b/src/App/JsonSourceGen/DatabaseJsonContext.cs
index 9284bf35..1eb368db 100644
--- a/src/App/JsonSourceGen/DatabaseJsonContext.cs
+++ b/src/App/JsonSourceGen/DatabaseJsonContext.cs
@@ -19,8 +19,11 @@ namespace MuzakBot.App;
[JsonSerializable(typeof(LyricsAnalyzerConfig))]
[JsonSerializable(typeof(LyricsAnalyzerUserRateLimit))]
[JsonSerializable(typeof(LyricsAnalyzerUserRateLimit[]))]
+[JsonSerializable(typeof(LyricsAnalyzerPromptStyle))]
+[JsonSerializable(typeof(LyricsAnalyzerPromptStyle[]))]
[JsonSerializable(typeof(CosmosDbResponse))]
[JsonSerializable(typeof(CosmosDbResponse))]
[JsonSerializable(typeof(CosmosDbResponse))]
+[JsonSerializable(typeof(CosmosDbResponse))]
internal partial class DatabaseJsonContext : JsonSerializerContext
{}
\ No newline at end of file
diff --git a/src/App/Logging/CosmosDb/CosmosDbServiceLoggingConstants.cs b/src/App/Logging/CosmosDb/CosmosDbServiceLoggingConstants.cs
index 6350e38a..3ff855b7 100644
--- a/src/App/Logging/CosmosDb/CosmosDbServiceLoggingConstants.cs
+++ b/src/App/Logging/CosmosDb/CosmosDbServiceLoggingConstants.cs
@@ -45,5 +45,10 @@ public static class ItemTypes
/// The lyrics analyzer config item type.
///
public const string LyricsAnalyzerConfig = "lyrics analyzer config";
+
+ ///
+ /// The lyrics analyzer prompt style item type.
+ ///
+ public const string LyricsAnalyzerPromptStyle = "lyrics analyzer prompt style";
}
}
\ No newline at end of file
diff --git a/src/App/Logging/OpenAi/OpenAiServiceLogging.cs b/src/App/Logging/OpenAi/OpenAiServiceLogging.cs
index 95149c77..8e3365a0 100644
--- a/src/App/Logging/OpenAi/OpenAiServiceLogging.cs
+++ b/src/App/Logging/OpenAi/OpenAiServiceLogging.cs
@@ -13,13 +13,13 @@ internal static partial class OpenAiServiceLogging
/// The instance.
/// The name of the artist.
/// The name of the song.
- /// The prompt mode being used.
+ /// The prompt style being used.
[LoggerMessage(
EventName = "OpenAiApiService.LyricAnalysis.Start",
Level = LogLevel.Information,
- Message = "Starting lyric analysis for '{artistName} - {songName}' using the '{promptMode}' style."
+ Message = "Starting lyric analysis for '{artistName} - {songName}' using the '{promptStyle}' style."
)]
- public static partial void LogOpenAiApiServiceLyricAnalysisStart(this ILogger logger, string artistName, string songName, string promptMode);
+ public static partial void LogOpenAiApiServiceLyricAnalysisStart(this ILogger logger, string artistName, string songName, string promptStyle);
///
/// Logs a failed lyric analysis.
diff --git a/src/App/Models/CommandModules/LyricsAnalyzerPromptStyleModal.cs b/src/App/Models/CommandModules/LyricsAnalyzerPromptStyleModal.cs
new file mode 100644
index 00000000..bf8b5de5
--- /dev/null
+++ b/src/App/Models/CommandModules/LyricsAnalyzerPromptStyleModal.cs
@@ -0,0 +1,93 @@
+using Discord;
+using Discord.Interactions;
+using MuzakBot.App.Models.Database;
+using MuzakBot.App.Models.Database.LyricsAnalyzer;
+
+namespace MuzakBot.App.Models.CommandModules;
+
+public class LyricsAnalyzerPromptStyleModal : IModal
+{
+ public LyricsAnalyzerPromptStyleModal()
+ {}
+
+ public LyricsAnalyzerPromptStyleModal(LyricsAnalyzerPromptStyle promptStyle)
+ {
+ Name = promptStyle.Name;
+ ShortName = promptStyle.ShortName;
+ AnalysisType = promptStyle.AnalysisType;
+ Prompt = promptStyle.Prompt;
+ NoticeText = promptStyle.NoticeText;
+ }
+
+ public string Title => "Lyrics Analyzer Prompt Style";
+
+ ///
+ /// The name of the prompt style.
+ ///
+ [JsonPropertyName("name")]
+ [InputLabel("Name")]
+ [ModalTextInput(
+ customId: "prompt-style-name",
+ placeholder: "Enter the name of the prompt style",
+ minLength: 1,
+ maxLength: 100,
+ style: TextInputStyle.Short
+ )]
+ public string Name { get; set; } = null!;
+
+ ///
+ /// The short name of the prompt style.
+ ///
+ [JsonPropertyName("shortName")]
+ [InputLabel("Short Name")]
+ [ModalTextInput(
+ customId: "prompt-style-short-name",
+ placeholder: "Enter the short name of the prompt style",
+ minLength: 1,
+ maxLength: 50,
+ style: TextInputStyle.Short
+ )]
+ public string ShortName { get; set; } = null!;
+
+ ///
+ /// The analysis type of the prompt style.
+ ///
+ [JsonPropertyName("analysisType")]
+ [InputLabel("Analysis Type")]
+ [ModalTextInput(
+ customId: "prompt-style-analysis-type",
+ placeholder: "Enter the analysis type of the prompt style",
+ minLength: 1,
+ maxLength: 100,
+ style: TextInputStyle.Short
+ )]
+ public string AnalysisType { get; set; } = null!;
+
+ ///
+ /// The prompt used for the style.
+ ///
+ [JsonPropertyName("prompt")]
+ [InputLabel("Prompt")]
+ [ModalTextInput(
+ customId: "prompt-style-prompt",
+ placeholder: "Enter the prompt used for the style",
+ minLength: 1,
+ maxLength: 4000,
+ style: TextInputStyle.Paragraph
+ )]
+ public string Prompt { get; set; } = null!;
+
+ ///
+ /// The notice text used for the prompt style.
+ ///
+ [JsonPropertyName("noticeText")]
+ [InputLabel("Notice Text")]
+ [ModalTextInput(
+ customId: "prompt-style-notice-text",
+ placeholder: "Enter the notice text used for the prompt style",
+ minLength: 1,
+ maxLength: 4000,
+ style: TextInputStyle.Paragraph
+ )]
+ public string NoticeText { get; set; } = null!;
+}
\ No newline at end of file
diff --git a/src/App/Models/CommandModules/LyricsAnalyzerPromptStyleUserPromptModal.cs b/src/App/Models/CommandModules/LyricsAnalyzerPromptStyleUserPromptModal.cs
new file mode 100644
index 00000000..b7e9319b
--- /dev/null
+++ b/src/App/Models/CommandModules/LyricsAnalyzerPromptStyleUserPromptModal.cs
@@ -0,0 +1,40 @@
+using Discord;
+using Discord.Interactions;
+
+namespace MuzakBot.App.Models.Database.LyricsAnalyzer;
+
+public class LyricsAnalyzerPromptStyleUserPromptModal : IModal
+{
+ public LyricsAnalyzerPromptStyleUserPromptModal()
+ { }
+
+ public LyricsAnalyzerPromptStyleUserPromptModal(LyricsAnalyzerPromptStyle promptStyle)
+ {
+ ShortName = promptStyle.ShortName;
+ UserPrompt = promptStyle.UserPrompt;
+ }
+
+ public string Title => "Lyrics Analyzer Prompt Style";
+
+ [JsonPropertyName("shortName")]
+ [InputLabel("Short name")]
+ [ModalTextInput(
+ customId: "prompt-style-short-name",
+ placeholder: "Enter the short name of the prompt style",
+ minLength: 1,
+ maxLength: 50,
+ style: TextInputStyle.Short
+ )]
+ public string ShortName { get; set; } = null!;
+
+ [JsonPropertyName("userPrompt")]
+ [InputLabel("User prompt")]
+ [ModalTextInput(
+ customId: "prompt-style-user-prompt",
+ placeholder: "Enter the user prompt of the prompt style",
+ minLength: 1,
+ maxLength: 4000,
+ style: TextInputStyle.Paragraph
+ )]
+ public string UserPrompt { get; set; } = null!;
+}
\ No newline at end of file
diff --git a/src/App/Models/Database/LyricsAnalyzer/LyricsAnalyzerPromptStyle.cs b/src/App/Models/Database/LyricsAnalyzer/LyricsAnalyzerPromptStyle.cs
new file mode 100644
index 00000000..0ff3d279
--- /dev/null
+++ b/src/App/Models/Database/LyricsAnalyzer/LyricsAnalyzerPromptStyle.cs
@@ -0,0 +1,113 @@
+using MuzakBot.App.Models.CommandModules;
+
+namespace MuzakBot.App.Models.Database.LyricsAnalyzer;
+
+///
+/// Holds data for a prompt style for the lyrics analyzer.
+///
+public class LyricsAnalyzerPromptStyle : DatabaseItem, ILyricsAnalyzerPromptStyle
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ [JsonConstructor()]
+ public LyricsAnalyzerPromptStyle() { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to initialize from.
+ public LyricsAnalyzerPromptStyle(LyricsAnalyzerPromptStyleModal inputModal)
+ {
+ Id = Guid.NewGuid().ToString();
+ PartitionKey = "prompt-style";
+ UpdateFromModalInput(inputModal);
+ CreatedOn = DateTimeOffset.UtcNow;
+ LastUpdated = DateTimeOffset.UtcNow;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name of the prompt style.
+ /// The short name of the prompt style.
+ /// The description of the prompt style.
+ /// The analysis type of the prompt style.
+ /// The prompt used for the style.
+ /// The notice text used for the prompt style.
+ public LyricsAnalyzerPromptStyle(string name, string shortName, string analysisType, string prompt, string noticeText)
+ {
+ Name = name;
+ ShortName = shortName;
+ AnalysisType = analysisType;
+ Prompt = prompt;
+ NoticeText = noticeText;
+ CreatedOn = DateTimeOffset.UtcNow;
+ LastUpdated = DateTimeOffset.UtcNow;
+ }
+
+ ///
+ /// The name of the prompt style.
+ ///
+ [JsonPropertyName("name")]
+ public string Name { get; set; } = null!;
+
+ ///
+ /// The short name of the prompt style.
+ ///
+ [JsonPropertyName("shortName")]
+ public string ShortName { get; set; } = null!;
+
+ ///
+ /// The analysis type of the prompt style.
+ ///
+ [JsonPropertyName("analysisType")]
+ public string AnalysisType { get; set; } = null!;
+
+ ///
+ /// The prompt used for the style.
+ ///
+ [JsonPropertyName("prompt")]
+ public string Prompt { get; set; } = null!;
+
+ ///
+ /// The prompt used as a user prompt for the style.
+ ///
+ public string UserPrompt { get; set; } = "Briefly explain the lyrics for the song \"{{songName}}\" by {{artistName}}. Format the response in Markdown syntax.";
+
+ ///
+ /// The notice text used for the prompt style.
+ ///
+ [JsonPropertyName("noticeText")]
+ public string NoticeText { get; set; } = null!;
+
+ ///
+ /// The date and time the prompt style was created.
+ ///
+ [JsonPropertyName("createdOn")]
+ public DateTimeOffset CreatedOn { get; set; }
+
+ ///
+ /// The date and time the prompt style was last updated.
+ ///
+ [JsonPropertyName("lastUpdated")]
+ public DateTimeOffset LastUpdated { get; set; }
+
+ ///
+ /// Updates the prompt style from .
+ ///
+ /// The to update from.
+ public void UpdateFromModalInput(LyricsAnalyzerPromptStyleModal inputModal)
+ {
+ Name = inputModal.Name;
+ ShortName = inputModal.ShortName;
+ AnalysisType = inputModal.AnalysisType;
+ Prompt = inputModal.Prompt;
+ NoticeText = inputModal.NoticeText;
+ }
+
+ ///
+ /// Updates the last updated time to the current date and time.
+ ///
+ public void UpdateLastUpdateTime() => LastUpdated = DateTimeOffset.UtcNow;
+}
diff --git a/src/App/Models/Database/LyricsAnalyzer/interface/ILyricsAnalyzerPromptStyle.cs b/src/App/Models/Database/LyricsAnalyzer/interface/ILyricsAnalyzerPromptStyle.cs
new file mode 100644
index 00000000..89f16d29
--- /dev/null
+++ b/src/App/Models/Database/LyricsAnalyzer/interface/ILyricsAnalyzerPromptStyle.cs
@@ -0,0 +1,20 @@
+using MuzakBot.App.Models.CommandModules;
+
+namespace MuzakBot.App.Models.Database.LyricsAnalyzer;
+
+public interface ILyricsAnalyzerPromptStyle
+{
+ string Id { get; set; }
+ string PartitionKey { get; set; }
+ string Name { get; set; }
+ string ShortName { get; set; }
+ string AnalysisType { get; set; }
+ string Prompt { get; set; }
+ string UserPrompt { get; set; }
+ string NoticeText { get; set; }
+ DateTimeOffset CreatedOn { get; set; }
+ DateTimeOffset LastUpdated { get; set; }
+
+ void UpdateFromModalInput(LyricsAnalyzerPromptStyleModal inputModal);
+ void UpdateLastUpdateTime();
+}
diff --git a/src/App/Modules/AdminCommandModule/Commands/HandleCreateLyricsAnalyzerPromptStyleAsync.cs b/src/App/Modules/AdminCommandModule/Commands/HandleCreateLyricsAnalyzerPromptStyleAsync.cs
new file mode 100644
index 00000000..7eb66de4
--- /dev/null
+++ b/src/App/Modules/AdminCommandModule/Commands/HandleCreateLyricsAnalyzerPromptStyleAsync.cs
@@ -0,0 +1,36 @@
+using Discord;
+using Discord.Interactions;
+using Microsoft.Extensions.Logging;
+using MuzakBot.App.Models.CommandModules;
+using MuzakBot.App.Models.Database.LyricsAnalyzer;
+
+namespace MuzakBot.App.Modules;
+
+public partial class AdminCommandModule
+{
+ [SlashCommand(name: "create-prompt-style", description: "Create a new prompt style.")]
+ [RequireOwner]
+ public async Task HandleCreateLyricsAnalyzerPromptStyleAsync()
+ {
+ try
+ {
+ await RespondWithModalAsync(
+ customId: "prompt-style-create"
+ );
+ }
+ catch (Exception ex)
+ {
+ await RespondAsync(
+ embeds: [
+ new EmbedBuilder()
+ .WithTitle("Lyrics Analyzer Prompt Style")
+ .WithDescription($"An error occurred while creating the prompt style:\n\n{ex.Message}")
+ .WithColor(Color.Red)
+ .Build()
+ ]
+ );
+
+ _logger.LogError(ex, "An error occurred while creating the prompt style: {Message}", ex.Message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/App/Modules/AdminCommandModule/Commands/HandleUpdateLyricsAnalyzerPromptStyleAsync.cs b/src/App/Modules/AdminCommandModule/Commands/HandleUpdateLyricsAnalyzerPromptStyleAsync.cs
new file mode 100644
index 00000000..e2c6ec93
--- /dev/null
+++ b/src/App/Modules/AdminCommandModule/Commands/HandleUpdateLyricsAnalyzerPromptStyleAsync.cs
@@ -0,0 +1,65 @@
+using Discord;
+using Discord.Interactions;
+using Microsoft.Extensions.Logging;
+using MuzakBot.App.Handlers;
+using MuzakBot.App.Models.CommandModules;
+using MuzakBot.App.Models.Database.LyricsAnalyzer;
+
+namespace MuzakBot.App.Modules;
+
+public partial class AdminCommandModule
+{
+ [SlashCommand(name: "update-prompt-style", description: "Update a lyrics analyzer prompt style.")]
+ [RequireOwner]
+ public async Task HandleUpdateLyricsAnalyzerPromptStyleAsync(
+ [Summary(name: "style", description: "The prompt style to edit."),
+ Autocomplete(typeof(LyricsAnalyzerPromptStyleAutoCompleteHandler))]
+ string style,
+ [Summary(name: "configType", description: "The configuration type to edit."),
+ Choice(name: "Core", value: "core"),
+ Choice(name: "User prompt", value: "user-prompt")]
+ string configType = "core"
+ )
+ {
+ LyricsAnalyzerPromptStyle? promptStyle = await _cosmosDbService.GetLyricsAnalyzerPromptStyleAsync(style);
+
+ if (promptStyle is null)
+ {
+ EmbedBuilder embed = new EmbedBuilder()
+ .WithTitle("Lyrics Analyzer Prompt Style")
+ .WithDescription($"A prompt style with the short name `{style}` does not exist.")
+ .WithColor(Color.Red);
+
+ await Context.Interaction.FollowupAsync(
+ embeds: [
+ embed.Build()
+ ]
+ );
+
+ return;
+ }
+
+ if (configType == "core")
+ {
+ LyricsAnalyzerPromptStyleModal promptStyleModal = new(promptStyle);
+
+ await RespondWithModalAsync(
+ customId: $"prompt-style-edit",
+ modal: promptStyleModal
+ );
+
+ return;
+ }
+
+ if (configType == "user-prompt")
+ {
+ LyricsAnalyzerPromptStyleUserPromptModal promptStyleUserPromptModal = new(promptStyle);
+ await RespondWithModalAsync(
+ customId: $"prompt-style-edit-user-prompt",
+ modal: promptStyleUserPromptModal
+ );
+
+ return;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/App/Modules/AdminCommandModule/ModalInteractions/HandleCreatePromptStyleModalAsync.cs b/src/App/Modules/AdminCommandModule/ModalInteractions/HandleCreatePromptStyleModalAsync.cs
new file mode 100644
index 00000000..bcbcdf60
--- /dev/null
+++ b/src/App/Modules/AdminCommandModule/ModalInteractions/HandleCreatePromptStyleModalAsync.cs
@@ -0,0 +1,73 @@
+using Discord;
+using Discord.Interactions;
+using Microsoft.Extensions.Logging;
+using MuzakBot.App.Models.CommandModules;
+using MuzakBot.App.Models.Database.LyricsAnalyzer;
+
+namespace MuzakBot.App.Modules;
+
+public partial class AdminCommandModule
+{
+ [ModalInteraction("prompt-style-create")]
+ public async Task HandleCreatePromptStyleModalAsync(LyricsAnalyzerPromptStyleModal promptStyleModal)
+ {
+ await Context.Interaction.DeferAsync(
+ ephemeral: true
+ );
+
+ LyricsAnalyzerPromptStyle promptStyle = new(promptStyleModal);
+
+ EmbedBuilder embed;
+
+ bool promptStyleExists = await _cosmosDbService.GetLyricsAnalyzerPromptStyleAsync(promptStyle.ShortName) is not null;
+
+ if (promptStyleExists)
+ {
+ embed = new EmbedBuilder()
+ .WithTitle("Lyrics Analyzer Prompt Style")
+ .WithDescription($"A prompt style with the short name `{promptStyle.ShortName}` already exists.")
+ .WithColor(Color.Red);
+
+ await Context.Interaction.FollowupAsync(
+ embeds: [
+ embed.Build()
+ ]
+ );
+
+ return;
+ }
+
+ try
+ {
+ await _cosmosDbService.AddOrUpdateLyricsAnalyzerPromptStyleAsync(promptStyle);
+ }
+ catch (Exception ex)
+ {
+ embed = new EmbedBuilder()
+ .WithTitle("Lyrics Analyzer Prompt Style")
+ .WithDescription($"An error occurred while creating the prompt style:\n\n{ex.Message}")
+ .WithColor(Color.Red);
+
+ await Context.Interaction.FollowupAsync(
+ embeds: [
+ embed.Build()
+ ]
+ );
+
+ _logger.LogError(ex, "An error occurred while creating the prompt style: {Message}", ex.Message);
+
+ return;
+ }
+
+ embed = new EmbedBuilder()
+ .WithTitle("Lyrics Analyzer Prompt Style")
+ .WithDescription($"Successfully created prompt style **{promptStyle.Name}**.")
+ .WithColor(Color.Green);
+
+ await Context.Interaction.FollowupAsync(
+ embeds: [
+ embed.Build()
+ ]
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/App/Modules/AdminCommandModule/ModalInteractions/HandleEditPromptStyleModalAsync.cs b/src/App/Modules/AdminCommandModule/ModalInteractions/HandleEditPromptStyleModalAsync.cs
new file mode 100644
index 00000000..27a02ac8
--- /dev/null
+++ b/src/App/Modules/AdminCommandModule/ModalInteractions/HandleEditPromptStyleModalAsync.cs
@@ -0,0 +1,80 @@
+using Discord;
+using Discord.Interactions;
+using Microsoft.Extensions.Logging;
+using MuzakBot.App.Handlers;
+using MuzakBot.App.Models.CommandModules;
+using MuzakBot.App.Models.Database.LyricsAnalyzer;
+
+namespace MuzakBot.App.Modules;
+
+public partial class AdminCommandModule
+{
+ [ModalInteraction("prompt-style-edit")]
+ public async Task HandleEditPromptStyleModalAsync(LyricsAnalyzerPromptStyleModal promptStyleModal)
+ {
+ await Context.Interaction.DeferAsync(
+ ephemeral: true
+ );
+
+ EmbedBuilder embed;
+
+ LyricsAnalyzerPromptStyle promptStyle = new(promptStyleModal);
+
+ LyricsAnalyzerPromptStyle? existingPromptStyle = await _cosmosDbService.GetLyricsAnalyzerPromptStyleAsync(promptStyle.ShortName);
+
+ if (existingPromptStyle is null)
+ {
+ embed = new EmbedBuilder()
+ .WithTitle("Lyrics Analyzer Prompt Style")
+ .WithDescription("The prompt style short name appears to have been changed.\n\n**Prompt style short names cannot be changed!**")
+ .WithColor(Color.Red);
+
+ await Context.Interaction.FollowupAsync(
+ embeds: [
+ embed.Build()
+ ]
+ );
+
+ return;
+ }
+
+ promptStyle.Id = existingPromptStyle.Id;
+ promptStyle.PartitionKey = existingPromptStyle.PartitionKey;
+ promptStyle.UserPrompt = existingPromptStyle.UserPrompt;
+
+ promptStyle.UpdateLastUpdateTime();
+
+ try
+ {
+ await _cosmosDbService.AddOrUpdateLyricsAnalyzerPromptStyleAsync(promptStyle);
+ }
+ catch (Exception ex)
+ {
+ embed = new EmbedBuilder()
+ .WithTitle("Lyrics Analyzer Prompt Style")
+ .WithDescription($"An error occurred while updating the prompt style:\n\n{ex.Message}")
+ .WithColor(Color.Red);
+
+ await Context.Interaction.FollowupAsync(
+ embeds: [
+ embed.Build()
+ ]
+ );
+
+ _logger.LogError(ex, "An error occurred while updating the prompt style: {Message}", ex.Message);
+
+ return;
+ }
+
+ embed = new EmbedBuilder()
+ .WithTitle("Lyrics Analyzer Prompt Style")
+ .WithDescription($"Successfully updated prompt style **{promptStyle.Name}**.")
+ .WithColor(Color.Green);
+
+ await Context.Interaction.FollowupAsync(
+ embeds: [
+ embed.Build()
+ ]
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/App/Modules/AdminCommandModule/ModalInteractions/HandleEditUserPromptStyleModalAsync.cs b/src/App/Modules/AdminCommandModule/ModalInteractions/HandleEditUserPromptStyleModalAsync.cs
new file mode 100644
index 00000000..8c815180
--- /dev/null
+++ b/src/App/Modules/AdminCommandModule/ModalInteractions/HandleEditUserPromptStyleModalAsync.cs
@@ -0,0 +1,76 @@
+using Discord;
+using Discord.Interactions;
+using Microsoft.Extensions.Logging;
+using MuzakBot.App.Handlers;
+using MuzakBot.App.Models.CommandModules;
+using MuzakBot.App.Models.Database.LyricsAnalyzer;
+
+namespace MuzakBot.App.Modules;
+
+public partial class AdminCommandModule
+{
+ [ModalInteraction("prompt-style-edit-user-prompt")]
+ public async Task HandleEditUserPromptStyleModalAsync(LyricsAnalyzerPromptStyleUserPromptModal userPromptModal)
+ {
+ await Context.Interaction.DeferAsync(
+ ephemeral: true
+ );
+
+ EmbedBuilder embed;
+
+ LyricsAnalyzerPromptStyle? promptStyle = await _cosmosDbService.GetLyricsAnalyzerPromptStyleAsync(userPromptModal.ShortName);
+
+ if (promptStyle is null)
+ {
+ embed = new EmbedBuilder()
+ .WithTitle("Lyrics Analyzer Prompt Style")
+ .WithDescription("The prompt style short name appears to have been changed.\n\n**Prompt style short names cannot be changed!**")
+ .WithColor(Color.Red);
+
+ await Context.Interaction.FollowupAsync(
+ embeds: [
+ embed.Build()
+ ]
+ );
+
+ return;
+ }
+
+ promptStyle.UserPrompt = userPromptModal.UserPrompt;
+
+ promptStyle.UpdateLastUpdateTime();
+
+ try
+ {
+ await _cosmosDbService.AddOrUpdateLyricsAnalyzerPromptStyleAsync(promptStyle);
+ }
+ catch (Exception ex)
+ {
+ embed = new EmbedBuilder()
+ .WithTitle("Lyrics Analyzer Prompt Style")
+ .WithDescription($"An error occurred while updating the prompt style:\n\n{ex.Message}")
+ .WithColor(Color.Red);
+
+ await Context.Interaction.FollowupAsync(
+ embeds: [
+ embed.Build()
+ ]
+ );
+
+ _logger.LogError(ex, "An error occurred while updating the prompt style: {Message}", ex.Message);
+
+ return;
+ }
+
+ embed = new EmbedBuilder()
+ .WithTitle("Lyrics Analyzer Prompt Style")
+ .WithDescription($"Successfully updated prompt style **{promptStyle.Name}**.")
+ .WithColor(Color.Green);
+
+ await Context.Interaction.FollowupAsync(
+ embeds: [
+ embed.Build()
+ ]
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/App/Modules/LyricsAnalyzerCommandModule/Commands/HandleLyricsAnalyzerAsync.cs b/src/App/Modules/LyricsAnalyzerCommandModule/Commands/HandleLyricsAnalyzerAsync.cs
index 0ea7e213..510de530 100644
--- a/src/App/Modules/LyricsAnalyzerCommandModule/Commands/HandleLyricsAnalyzerAsync.cs
+++ b/src/App/Modules/LyricsAnalyzerCommandModule/Commands/HandleLyricsAnalyzerAsync.cs
@@ -40,12 +40,8 @@ private async Task HandleLyricsAnalyzerAsync(
]
string songName,
[Summary(name: "style", description: "The style of the response"),
- Choice("Normal", "normal"),
- Choice("Snobby Music Critic", "snobby"),
- Choice("Meme - Tame", "tame-meme"),
- Choice("Meme - Insane", "insane-meme"),
- Choice("Meme - Roast", "roast-meme")]
- string promptMode = "noraml",
+ Autocomplete(typeof(LyricsAnalyzerPromptStyleAutoCompleteHandler))]
+ string promptMode = "normal",
[Summary(name: "private", description: "Whether or not to send the response privately")]
bool isPrivateResponse = false
)
@@ -127,6 +123,39 @@ await FollowupAsync(
}
}
+ LyricsAnalyzerPromptStyle? promptStyle;
+
+ try
+ {
+ promptStyle = await _cosmosDbService.GetLyricsAnalyzerPromptStyleAsync(promptMode, activity?.Id);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error getting prompt style from database.");
+ await FollowupAsync(
+ embed: GenerateErrorEmbed("An error occurred while getting the prompt style. 😥").Build(),
+ components: GenerateRemoveComponent().Build(),
+ ephemeral: isPrivateResponse
+ );
+
+ activity?.SetStatus(ActivityStatusCode.Error);
+
+ return;
+ }
+
+ if (promptStyle is null)
+ {
+ await FollowupAsync(
+ embed: GenerateErrorEmbed("An error occurred while getting the prompt style. 😥").Build(),
+ components: GenerateRemoveComponent().Build(),
+ ephemeral: isPrivateResponse
+ );
+
+ activity?.SetStatus(ActivityStatusCode.Error);
+
+ return;
+ }
+
string lyrics = string.Empty;
bool isSongLyricsItemInDb = false;
try
@@ -221,7 +250,7 @@ await FollowupAsync(
artistName: artistName,
songName: songName,
lyrics: lyrics,
- promptMode: promptMode,
+ promptStyle: promptStyle,
parentActivityId: activity?.Id
);
@@ -246,18 +275,7 @@ await FollowupAsync(
StringBuilder lyricsResponseBuilder = new($"# \"{songName}\" by _{artistName}_\n\n");
- if (promptMode == "snobby")
- {
- lyricsResponseBuilder.AppendLine("## Lyrics review\n\n");
- }
- else if (promptMode == "roast-meme")
- {
- lyricsResponseBuilder.AppendLine("## Lyrics roast\n\n");
- }
- else
- {
- lyricsResponseBuilder.AppendLine("## Lyrics analysis\n\n");
- }
+ lyricsResponseBuilder.AppendLine($"## {promptStyle.AnalysisType}\n\n");
string[] analysisLines = openAiChatCompletion.Choices[0].Message.Content.Split(Environment.NewLine);
@@ -271,17 +289,9 @@ await FollowupAsync(
lyricsResponseBuilder.AppendLine($"> {analysisLines[i]}");
}
- string embedDescription = promptMode switch
- {
- "snobby" => "These results were generated by an \"AI\"\nand **are not guaranteed** to be accurate.",
- "roast-meme" => "These results were generated by an \"AI\",\n**are not guaranteed** to be accurate,\nand is not intended to be taken seriously",
- "tame-meme" or "insane-meme" => "These results were generated by an \"AI\"\nand **are definitely not** accurate\nbecause haha meme mode go brrrrr 😳",
- _ => "These results were generated by an \"AI\"\nand **are not guaranteed** to be accurate."
- };
-
EmbedBuilder embedBuilder = new EmbedBuilder()
.WithTitle("⚠️ Note")
- .WithDescription(embedDescription)
+ .WithDescription(promptStyle.NoticeText)
.WithColor(Color.DarkTeal)
.WithFooter("(Powered by OpenAI's GPT-4)");
diff --git a/src/App/Services/CosmosDbService/LyricsAnalyzer/AddOrUpdateLyricsAnalyzerPromptStyleAsync.cs b/src/App/Services/CosmosDbService/LyricsAnalyzer/AddOrUpdateLyricsAnalyzerPromptStyleAsync.cs
new file mode 100644
index 00000000..2232a107
--- /dev/null
+++ b/src/App/Services/CosmosDbService/LyricsAnalyzer/AddOrUpdateLyricsAnalyzerPromptStyleAsync.cs
@@ -0,0 +1,82 @@
+using System.Net;
+using Microsoft.Azure.Cosmos;
+using Microsoft.Extensions.Logging;
+using MuzakBot.App.Extensions;
+using MuzakBot.App.Logging.CosmosDb;
+using MuzakBot.App.Models.Database.LyricsAnalyzer;
+
+namespace MuzakBot.App.Services;
+
+public partial class CosmosDbService
+{
+ ///
+ /// Adds or updates the lyrics analyzer prompt style in the database.
+ ///
+ /// The prompt style to add or update.
+ ///
+ public async Task AddOrUpdateLyricsAnalyzerPromptStyleAsync(LyricsAnalyzerPromptStyle promptStyle) => await AddOrUpdateLyricsAnalyzerPromptStyleAsync(promptStyle, null);
+
+ ///
+ /// Adds or updates the lyrics analyzer prompt style in the database.
+ ///
+ /// The prompt style to add or update.
+ /// The parent activity ID.
+ ///
+ public async Task AddOrUpdateLyricsAnalyzerPromptStyleAsync(LyricsAnalyzerPromptStyle promptStyle, string? parentActivityId)
+ {
+ using var activity = _activitySource.StartDbAddOrUpdateLyricsAnalyzerPromptStyleActivity(
+ promptStyle: promptStyle,
+ parentActivityId: parentActivityId
+ );
+
+ _logger.LogAddOrUpdateOperationStart(
+ itemType: CosmosDbServiceLoggingConstants.ItemTypes.LyricsAnalyzerPromptStyle,
+ id: promptStyle.Id
+ );
+
+ Container container = _cosmosDbClient.GetContainer(
+ databaseId: _options.DatabaseName,
+ containerId: "prompt-styles"
+ );
+
+ string promptStyleJson = JsonSerializer.Serialize(
+ value: promptStyle,
+ jsonTypeInfo: DatabaseJsonContext.Default.LyricsAnalyzerPromptStyle
+ );
+
+ using MemoryStream itemPayload = new();
+ await JsonSerializer.SerializeAsync(
+ utf8Json: itemPayload,
+ value: promptStyle,
+ jsonTypeInfo: DatabaseJsonContext.Default.LyricsAnalyzerPromptStyle
+ );
+
+ try
+ {
+ await container.UpsertItemStreamAsync(
+ streamPayload: itemPayload,
+ partitionKey: new PartitionKey(promptStyle.PartitionKey)
+ );
+
+ _logger.LogAddOrUpdateOperationAdded(
+ itemType: CosmosDbServiceLoggingConstants.ItemTypes.LyricsAnalyzerPromptStyle,
+ id: promptStyle.Id,
+ state: CosmosDbServiceLoggingConstants.OperationTypes.Added
+ );
+ }
+ catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.Conflict)
+ {
+ await container.ReplaceItemStreamAsync(
+ streamPayload: itemPayload,
+ id: promptStyle.Id,
+ partitionKey: new PartitionKey(promptStyle.PartitionKey)
+ );
+
+ _logger.LogAddOrUpdateOperationAdded(
+ itemType: CosmosDbServiceLoggingConstants.ItemTypes.LyricsAnalyzerPromptStyle,
+ id: promptStyle.Id,
+ state: CosmosDbServiceLoggingConstants.OperationTypes.Updated
+ );
+ }
+ }
+}
diff --git a/src/App/Services/CosmosDbService/LyricsAnalyzer/GetLyricsAnalyzerPromptStyleAsync.cs b/src/App/Services/CosmosDbService/LyricsAnalyzer/GetLyricsAnalyzerPromptStyleAsync.cs
new file mode 100644
index 00000000..d869db22
--- /dev/null
+++ b/src/App/Services/CosmosDbService/LyricsAnalyzer/GetLyricsAnalyzerPromptStyleAsync.cs
@@ -0,0 +1,89 @@
+using System.Diagnostics;
+using Microsoft.Azure.Cosmos;
+using Microsoft.Extensions.Logging;
+using MuzakBot.App.Extensions;
+using MuzakBot.App.Logging.CosmosDb;
+using MuzakBot.App.Models.CosmosDb;
+using MuzakBot.App.Models.Database.LyricsAnalyzer;
+
+namespace MuzakBot.App.Services;
+
+public partial class CosmosDbService
+{
+ ///
+ /// Gets a specific lyrics analyzer prompt style from the database.
+ ///
+ /// The short name of the prompt style.
+ /// The retrieved lyrics analyzer prompt style.
+ ///
+ public async Task GetLyricsAnalyzerPromptStyleAsync(string shortName) => await GetLyricsAnalyzerPromptStyleAsync(shortName, null);
+
+ ///
+ /// Gets a specific lyrics analyzer prompt style from the database.
+ ///
+ /// The short name of the prompt style.
+ /// The parent activity ID.
+ /// The retrieved lyrics analyzer prompt style.
+ ///
+ public async Task GetLyricsAnalyzerPromptStyleAsync(string shortName, string? parentActivityId)
+ {
+ using var activity = _activitySource.StartDbGetLyricsAnalyzerPromptStyleActivity(
+ shortName: shortName,
+ parentActivityId: parentActivityId
+ );
+
+ _logger.LogGetOperationStart(
+ itemType: CosmosDbServiceLoggingConstants.ItemTypes.LyricsAnalyzerPromptStyle,
+ id: shortName
+ );
+
+ Container container = _cosmosDbClient.GetContainer(
+ databaseId: _options.DatabaseName,
+ containerId: "prompt-styles"
+ );
+
+ var query = new QueryDefinition(
+ query: "SELECT * FROM c WHERE c.partitionKey = 'prompt-style' AND c.shortName = @shortName"
+ )
+ .WithParameter("@shortName", shortName);
+
+ CosmosDbResponse? cosmosDbResponse;
+
+ try
+ {
+ using FeedIterator feedIterator = container.GetItemQueryStreamIterator(
+ queryDefinition: query,
+ requestOptions: new()
+ {
+ PartitionKey = new PartitionKey("prompt-style")
+ }
+ );
+
+ using ResponseMessage response = await feedIterator.ReadNextAsync();
+
+ cosmosDbResponse = await JsonSerializer.DeserializeAsync(
+ utf8Json: response.Content,
+ jsonTypeInfo: DatabaseJsonContext.Default.CosmosDbResponseLyricsAnalyzerPromptStyle
+ );
+ }
+ catch (Exception ex)
+ {
+ _logger.LogGetOperationFailed(
+ itemType: CosmosDbServiceLoggingConstants.ItemTypes.LyricsAnalyzerPromptStyle,
+ id: shortName,
+ exception: ex
+ );
+
+ activity?.SetStatus(ActivityStatusCode.Error);
+
+ throw;
+ }
+
+ if (cosmosDbResponse is null || cosmosDbResponse.Documents is null)
+ {
+ return null;
+ }
+
+ return cosmosDbResponse.Documents.FirstOrDefault();
+ }
+}
\ No newline at end of file
diff --git a/src/App/Services/CosmosDbService/LyricsAnalyzer/GetLyricsAnalyzerPromptStylesAsync.cs b/src/App/Services/CosmosDbService/LyricsAnalyzer/GetLyricsAnalyzerPromptStylesAsync.cs
new file mode 100644
index 00000000..3cc1deff
--- /dev/null
+++ b/src/App/Services/CosmosDbService/LyricsAnalyzer/GetLyricsAnalyzerPromptStylesAsync.cs
@@ -0,0 +1,103 @@
+using System.Diagnostics;
+using Microsoft.Azure.Cosmos;
+using Microsoft.Extensions.Logging;
+using MuzakBot.App.Extensions;
+using MuzakBot.App.Logging.CosmosDb;
+using MuzakBot.App.Models.CosmosDb;
+using MuzakBot.App.Models.Database.LyricsAnalyzer;
+
+namespace MuzakBot.App.Services;
+
+public partial class CosmosDbService
+{
+ ///
+ /// Gets all lyrics analyzer prompt styles from the database.
+ ///
+ /// The retrieved lyrics analyzer prompt styles.
+ public async Task GetLyricsAnalyzerPromptStylesAsync() => await GetLyricsAnalyzerPromptStylesAsync(null);
+
+ ///
+ /// Gets all lyrics analyzer prompt styles from the database.
+ ///
+ /// The parent activity ID.
+ /// The retrieved lyrics analyzer prompt styles.
+ public async Task GetLyricsAnalyzerPromptStylesAsync(string? parentActivityId)
+ {
+ using var activity = _activitySource.StartDbGetLyricsAnalyzerPromptStylesActivity(
+ parentActivityId: parentActivityId
+ );
+
+ _logger.LogGetOperationStart(
+ itemType: CosmosDbServiceLoggingConstants.ItemTypes.LyricsAnalyzerPromptStyle,
+ id: "all"
+ );
+
+ Container container = _cosmosDbClient.GetContainer(
+ databaseId: _options.DatabaseName,
+ containerId: "prompt-styles"
+ );
+
+ var query = new QueryDefinition(
+ query: "SELECT * FROM c WHERE c.partitionKey = 'prompt-style'"
+ );
+
+ int resultCount = await GetResultCountAsync(
+ container: container,
+ coreQuery: "WHERE c.partitionKey = 'prompt-style'"
+ );
+
+ _logger.LogInformation("Found {Count} prompt styles in the database.", resultCount);
+
+ LyricsAnalyzerPromptStyle[] promptStyles = new LyricsAnalyzerPromptStyle[resultCount];
+
+ using FeedIterator feedIterator = container.GetItemQueryStreamIterator(
+ queryDefinition: query,
+ requestOptions: new()
+ {
+ PartitionKey = new PartitionKey("prompt-style")
+ }
+ );
+
+
+ while (feedIterator.HasMoreResults)
+ {
+ using ResponseMessage response = await feedIterator.ReadNextAsync();
+
+ CosmosDbResponse? cosmosDbResponse = await JsonSerializer.DeserializeAsync(
+ utf8Json: response.Content,
+ jsonTypeInfo: DatabaseJsonContext.Default.CosmosDbResponseLyricsAnalyzerPromptStyle
+ );
+
+ if (cosmosDbResponse is null || cosmosDbResponse.Documents is null)
+ {
+ NullReferenceException nullResponseException = new(
+ message: "The Cosmos DB response or its documents were null."
+ );
+
+ _logger.LogGetOperationFailed(
+ itemType: CosmosDbServiceLoggingConstants.ItemTypes.LyricsAnalyzerPromptStyle,
+ id: "all",
+ exception: nullResponseException
+ );
+
+ activity?.SetStatus(ActivityStatusCode.Error);
+
+ throw nullResponseException;
+ }
+
+ int i = 0;
+ foreach (var promptStyleItem in cosmosDbResponse!.Documents!)
+ {
+ promptStyles[i] = promptStyleItem;
+ i++;
+ }
+ }
+
+ _logger.LogGetOperationFound(
+ itemType: CosmosDbServiceLoggingConstants.ItemTypes.LyricsAnalyzerPromptStyle,
+ id: "all"
+ );
+
+ return promptStyles;
+ }
+}
\ No newline at end of file
diff --git a/src/App/Services/CosmosDbService/interfaces/ICosmosDbService.cs b/src/App/Services/CosmosDbService/interfaces/ICosmosDbService.cs
index c2333ccb..e435b5df 100644
--- a/src/App/Services/CosmosDbService/interfaces/ICosmosDbService.cs
+++ b/src/App/Services/CosmosDbService/interfaces/ICosmosDbService.cs
@@ -21,4 +21,13 @@ public interface ICosmosDbService : IDisposable
Task GetSongLyricsItemAsync(string artistName, string songName);
Task GetSongLyricsItemAsync(string artistName, string songName, string? parentActivityId);
+
+ Task AddOrUpdateLyricsAnalyzerPromptStyleAsync(LyricsAnalyzerPromptStyle promptStyle);
+ Task AddOrUpdateLyricsAnalyzerPromptStyleAsync(LyricsAnalyzerPromptStyle promptStyle, string? parentActivityId);
+
+ Task GetLyricsAnalyzerPromptStyleAsync(string shortName);
+ Task GetLyricsAnalyzerPromptStyleAsync(string shortName, string? parentActivityId);
+
+ Task GetLyricsAnalyzerPromptStylesAsync();
+ Task GetLyricsAnalyzerPromptStylesAsync(string? parentActivityId);
}
\ No newline at end of file
diff --git a/src/App/Services/OpenAiService/OpenAiService.cs b/src/App/Services/OpenAiService/OpenAiService.cs
index 85805e02..18c8f5e7 100644
--- a/src/App/Services/OpenAiService/OpenAiService.cs
+++ b/src/App/Services/OpenAiService/OpenAiService.cs
@@ -4,6 +4,7 @@
using Microsoft.Extensions.Options;
using MuzakBot.App.Extensions;
using MuzakBot.App.Logging.OpenAi;
+using MuzakBot.App.Models.Database.LyricsAnalyzer;
using MuzakBot.App.Models.OpenAi;
namespace MuzakBot.App.Services;
@@ -40,7 +41,7 @@ public OpenAiService(IOptions options, IHttpClientFactory
/// The lyrics of the song.
/// The lyric analysis from the API.
/// The response from the OpenAI API was null.
- public async Task GetLyricAnalysisAsync(string artistName, string songName, string lyrics, string promptMode) => await GetLyricAnalysisAsync(artistName, songName, lyrics, promptMode, null);
+ public async Task GetLyricAnalysisAsync(string artistName, string songName, string lyrics, LyricsAnalyzerPromptStyle promptStyle) => await GetLyricAnalysisAsync(artistName, songName, lyrics, promptStyle, null);
///
/// Gets the lyric analysis for a song using the OpenAI API.
@@ -51,11 +52,11 @@ public OpenAiService(IOptions options, IHttpClientFactory
/// The ID of the parent activity (optional).
/// The lyric analysis from the API.
/// The response from the OpenAI API was null.
- public async Task GetLyricAnalysisAsync(string artistName, string songName, string lyrics, string promptMode, string? parentActivityId)
+ public async Task GetLyricAnalysisAsync(string artistName, string songName, string lyrics, LyricsAnalyzerPromptStyle promptStyle, string? parentActivityId)
{
using var activity = _activitySource.StartGetLyricAnalysisAsyncActivity(artistName, songName, parentActivityId);
- _logger.LogOpenAiApiServiceLyricAnalysisStart(artistName, songName, promptMode);
+ _logger.LogOpenAiApiServiceLyricAnalysisStart(artistName, songName, promptStyle.ShortName);
using var client = _httpClientFactory.CreateClient("OpenAiApiClient");
@@ -66,22 +67,6 @@ public OpenAiService(IOptions options, IHttpClientFactory
requestMessage.Headers.Authorization = new("Bearer", _apiKey);
- string systemPrompt = promptMode switch
- {
- "snobby" => LyricsAnalysisPromptConstants.SnobbyMusicCriticPrompt,
- "roast-meme" => LyricsAnalysisPromptConstants.RoastMemePrompt,
- "tame-meme" => LyricsAnalysisPromptConstants.TameMemePrompt,
- "insane-meme" => LyricsAnalysisPromptConstants.InsaneMemePrompt,
- _ => LyricsAnalysisPromptConstants.NormalPrompt
- };
-
- string userPrompt = promptMode switch
- {
- "snobby" => $"Briefly review and scathingly critique the lyrics for the song \"{songName}\" by {artistName}. Format the response in Markdown syntax.",
- "roast-meme" => $"Briefly roast the lyrics for the song \"{songName}\" by {artistName}. Format the response in Markdown syntax.",
- _ => $"Briefly explain the lyrics for the song \"{songName}\" by {artistName}. Format the response in Markdown syntax."
- };
-
OpenAiChatCompletionRequest request = new()
{
Model = "gpt-4-1106-preview",
@@ -95,7 +80,7 @@ public OpenAiService(IOptions options, IHttpClientFactory
new()
{
Role = "system",
- Content = systemPrompt
+ Content = promptStyle.Prompt
},
new()
{
@@ -105,7 +90,7 @@ public OpenAiService(IOptions options, IHttpClientFactory
new()
{
Role = "user",
- Content = userPrompt
+ Content = promptStyle.UserPrompt.Replace("{{songName}}", songName).Replace("{{artistName}}", artistName)
}
]
};
diff --git a/src/App/Services/OpenAiService/interfaces/IOpenAiService.cs b/src/App/Services/OpenAiService/interfaces/IOpenAiService.cs
index bc22edf9..0c83b89e 100644
--- a/src/App/Services/OpenAiService/interfaces/IOpenAiService.cs
+++ b/src/App/Services/OpenAiService/interfaces/IOpenAiService.cs
@@ -1,3 +1,4 @@
+using MuzakBot.App.Models.Database.LyricsAnalyzer;
using MuzakBot.App.Models.OpenAi;
namespace MuzakBot.App.Services;
@@ -7,6 +8,6 @@ namespace MuzakBot.App.Services;
///
public interface IOpenAiService : IDisposable
{
- Task GetLyricAnalysisAsync(string artistName, string songName, string lyrics, string promptMode);
- Task GetLyricAnalysisAsync(string artistName, string songName, string lyrics, string promptMode, string? parentActivityId);
+ Task GetLyricAnalysisAsync(string artistName, string songName, string lyrics, LyricsAnalyzerPromptStyle promptStyle);
+ Task GetLyricAnalysisAsync(string artistName, string songName, string lyrics, LyricsAnalyzerPromptStyle promptStyle, string? parentActivityId);
}
\ No newline at end of file