diff --git a/MyApp.ServiceInterface/Data/AppConfig.cs b/MyApp.ServiceInterface/Data/AppConfig.cs index 32c1768..344c512 100644 --- a/MyApp.ServiceInterface/Data/AppConfig.cs +++ b/MyApp.ServiceInterface/Data/AppConfig.cs @@ -38,8 +38,18 @@ public class AppConfig public HashSet AllTags { get; set; } = []; public List ModelUsers { get; set; } = []; + public static string[] DeprecatedModels = ["deepseek-coder","gemma-2b","qwen-4b","deepseek-coder-33b"]; + + public static (string Model, int Questions)[] GetActiveModelsForQuestions(int level) => + ModelsForQuestions.Where(x => x.Questions == level && !DeprecatedModels.Contains(x.Model)).ToArray(); + public static (string Model, int Questions)[] ModelsForQuestions = [ + ("deepseek-coder", 0), + ("gemma-2b", 0), + ("qwen-4b", 0), + ("deepseek-coder-33b", 100), + ("phi", 0), ("codellama", 0), ("mistral", 0), @@ -49,12 +59,13 @@ public static (string Model, int Questions)[] ModelsForQuestions = ("mixtral", 5), ("gpt3.5-turbo", 10), ("claude3-haiku", 25), - ("command-r", 50), - ("wizardlm", 100), - ("claude3-sonnet", 175), - ("command-r-plus", 150), - ("gpt4-turbo", 250), - ("claude3-opus", 400), + ("llama3-70b", 50), + ("command-r", 100), + ("wizardlm", 175), + ("claude3-sonnet", 250), + ("command-r-plus", 350), + ("gpt4-turbo", 450), + ("claude3-opus", 600), ]; public static int[] QuestionLevels = ModelsForQuestions.Select(x => x.Questions).Distinct().OrderBy(x => x).ToArray(); @@ -106,6 +117,26 @@ public int GetReputationValue(string? userName) => ? 1 : reputation; + public bool CanUseModel(string userName, string model) + { + if (Stats.IsAdminOrModerator(userName)) + return true; + var questionsCount = GetQuestionCount(userName); + + var modelLevel = GetModelLevel(model); + return modelLevel != -1 && questionsCount >= modelLevel; + } + + public int GetModelLevel(string model) + { + foreach (var entry in ModelsForQuestions) + { + if (entry.Model == model) + return entry.Questions; + } + return -1; + } + public int GetQuestionCount(string? userName) => userName switch { "stackoverflow" or "reddit" or "discourse" => 5, @@ -207,13 +238,21 @@ public List GetAnswerModelUsersFor(string? userName) { var questionsCount = GetQuestionCount(userName); - var models = ModelsForQuestions.Where(x => x.Questions <= questionsCount) + var models = GetActiveModelsForQuestions(questionsCount) .Select(x => x.Model) .ToList(); + + // Remove lower quality models if (models.Contains("gemma")) models.RemoveAll(x => x == "gemma:2b"); + if (models.Contains("mixtral")) + models.RemoveAll(x => x == "mistral"); if (models.Contains("deepseek-coder:33b")) models.RemoveAll(x => x == "deepseek-coder:6.7b"); + if (models.Contains("gpt-4-turbo")) + models.RemoveAll(x => x == "gpt3.5-turbo"); + if (models.Contains("command-r-plus")) + models.RemoveAll(x => x == "command-r"); if (models.Contains("claude-3-opus")) models.RemoveAll(x => x is "claude-3-haiku" or "claude-3-sonnet"); if (models.Contains("claude-3-sonnet")) diff --git a/MyApp.ServiceInterface/QuestionServices.cs b/MyApp.ServiceInterface/QuestionServices.cs index 4a3aa97..6bc8104 100644 --- a/MyApp.ServiceInterface/QuestionServices.cs +++ b/MyApp.ServiceInterface/QuestionServices.cs @@ -350,6 +350,28 @@ public async Task Any(CreateComment request) if (question.LockedDate != null) throw HttpError.Conflict($"{question.GetPostType()} is locked"); + var createdBy = GetUserName(); + + // If the comment is for a model answer, have the model respond to the comment + var answerCreator = request.Id.Contains('-') + ? request.Id.RightPart('-') + : null; + var modelCreator = answerCreator != null + ? appConfig.GetModelUser(answerCreator) + : null; + + if (modelCreator?.UserName != null) + { + var canUseModel = appConfig.CanUseModel(createdBy, modelCreator.UserName); + if (!canUseModel) + { + var userCount = appConfig.GetQuestionCount(createdBy); + log.LogWarning("User {UserName} ({UserCount}) attempted to use model {ModelUserName} ({ModelCount})", + createdBy, userCount, modelCreator.UserName, appConfig.GetModelLevel(modelCreator.UserName)); + throw HttpError.Forbidden("You have not met the requirements to access this model"); + } + } + var postId = question.Id; var meta = await questions.GetMetaAsync(postId); @@ -357,8 +379,6 @@ public async Task Any(CreateComment request) var comments = meta.Comments.GetOrAdd(request.Id, key => new()); var body = request.Body.GenerateComment(); - var createdBy = GetUserName(); - var newComment = new Comment { Body = body, @@ -378,14 +398,7 @@ public async Task Any(CreateComment request) await questions.SaveMetaAsync(postId, meta); - // If the comment is for a model answer, have the model respond to the comment - var answerCreator = request.Id.Contains('-') - ? request.Id.RightPart('-') - : null; - var modelCreator = answerCreator != null - ? appConfig.GetModelUser(answerCreator) - : null; - if (modelCreator != null) + if (modelCreator?.UserName != null) { var answer = await questions.GetAnswerAsPostAsync(request.Id); if (answer != null) diff --git a/MyApp.ServiceInterface/UserServices.cs b/MyApp.ServiceInterface/UserServices.cs index 6cba7c7..61af0c7 100644 --- a/MyApp.ServiceInterface/UserServices.cs +++ b/MyApp.ServiceInterface/UserServices.cs @@ -106,6 +106,7 @@ public async Task Any(UserPostData request) var to = new UserPostDataResponse { Watching = watchingPost, + QuestionsAsked = appConfig.GetQuestionCount(userName), UpVoteIds = allUserPostVotes.Where(x => x.Score > 0).Select(x => x.RefId).ToSet(), DownVoteIds = allUserPostVotes.Where(x => x.Score < 0).Select(x => x.RefId).ToSet(), }; diff --git a/MyApp/Components/App.razor b/MyApp/Components/App.razor index bfb03ce..27a674d 100644 --- a/MyApp/Components/App.razor +++ b/MyApp/Components/App.razor @@ -18,10 +18,11 @@ ["app.mjs"] = ($"{baseUrl}/mjs/app.mjs", $"{baseUrl}/mjs/app.mjs"), ["dtos.mjs"] = ($"{baseUrl}/mjs/dtos.mjs", $"{baseUrl}/mjs/dtos.mjs"), ["vue"] = ($"{baseUrl}/lib/mjs/vue.mjs", $"{baseUrl}/lib/mjs/vue.min.mjs"), + ["marked"] = ($"{baseUrl}/lib/mjs/marked.mjs", $"{baseUrl}/lib/mjs/marked.min.mjs"), + ["markdown"] = ($"{baseUrl}/lib/mjs/markdown.mjs", $"{baseUrl}/lib/mjs/markdown.mjs"), ["@servicestack/client"] = ($"{baseUrl}/lib/mjs/servicestack-client.mjs", $"{baseUrl}/lib/mjs/servicestack-client.min.mjs"), ["@servicestack/vue"] = ($"{baseUrl}/lib/mjs/servicestack-vue.mjs", $"{baseUrl}/lib/mjs/servicestack-vue.min.mjs"), }) - diff --git a/MyApp/Components/Pages/Questions/Ask.razor b/MyApp/Components/Pages/Questions/Ask.razor index 4ddbf0f..dc9f1f1 100644 --- a/MyApp/Components/Pages/Questions/Ask.razor +++ b/MyApp/Components/Pages/Questions/Ask.razor @@ -71,7 +71,7 @@ }