using AuthorBuddy.Web.Data; using AuthorBuddy.Web.Models; using LiteDB; namespace AuthorBuddy.Web.Services; public class SettingsService : ISettingsService { private const string KeyOllamaUrl = "ollama_url"; private const string KeyLlamaCppUrl = "llama_cpp_url"; private const string KeyBackend = "llm_backend"; private const string KeyRagModel = "ollama_rag_model"; private const string KeyStyleModel = "ollama_style_model"; private const string KeySpellingModel = "ollama_spelling_model"; private const string KeyTheme = "theme"; private const string KeyLektorPrompt = "ollama_lektor_prompt"; private const string KeyFactCheckTemplate = "ollama_fact_check"; private const string KeySpellingPrompt = "ollama_spelling_prompt"; private const string KeyAdvocatusDiaboli = "ollama_advocatus_diaboli"; private const string KeyHookFinder = "ollama_hook_finder"; private const string KeyEli5 = "ollama_eli5"; private const string KeyCoAuthor = "ollama_coauthor"; private const string KeyLektorTemp = "ollama_lektor_temp"; private const string KeyFactCheckTemp = "ollama_fact_check_temp"; private const string KeySpellingTemp = "ollama_spelling_temp"; private const string KeyAdvocatusDiaboliTemp = "ollama_advocatus_diaboli_temp"; private const string KeyHookFinderTemp = "ollama_hook_finder_temp"; private const string KeyEli5Temp = "ollama_eli5_temp"; private const string KeyCoAuthorTemp = "ollama_coauthor_temp"; private const string KeyTechLastenheft = "tech_lastenheft"; private const string KeyTechPflichtenheft = "tech_pflichtenheft"; private const string KeyTechUseCase = "tech_usecase"; private const string KeyTechStakeholder = "tech_stakeholder"; private const string KeyTechGlossar = "tech_glossar"; private const string KeyTechQualitaet = "tech_qualitaet"; private const string KeyTechRisiko = "tech_risiko"; private const string KeyTechLastenheftTemp = "tech_lastenheft_temp"; private const string KeyTechPflichtenheftTemp = "tech_pflichtenheft_temp"; private const string KeyTechUseCaseTemp = "tech_usecase_temp"; private const string KeyTechStakeholderTemp = "tech_stakeholder_temp"; private const string KeyTechGlossarTemp = "tech_glossar_temp"; private const string KeyTechQualitaetTemp = "tech_qualitaet_temp"; private const string KeyTechRisikoTemp = "tech_risiko_temp"; private const string KeyQuickMarkdownPrompt = "quick_md_prompt"; private const string KeyQuickMarkdownTemp = "quick_md_temp"; private const string KeyChatPrompt = "chat_prompt"; private const string KeyChatTemp = "chat_temp"; private const string KeyLanguage = "language"; private const string KeyLastProjectId = "last_project_id"; private readonly ILiteDatabase _db; private readonly OllamaSettings _ollamaConfig; private int? _currentUserId; private int? _currentProjectId; public SettingsService(ILiteDatabase db, OllamaSettings ollamaConfig) { _db = db; _ollamaConfig = ollamaConfig; } public int? CurrentProjectId { get => _currentProjectId; set => _currentProjectId = value; } public string? CurrentFilePath { get; set; } public string? PendingAssistantInput { get; set; } public string? PendingAssistantOutput { get; set; } public Task GetLastProjectIdAsync() { var col = _db.GetCollection("settings"); var setting = col.FindOne(s => s.Key == KeyLastProjectId && s.UserId == _currentUserId && s.ProjectId == null); if (setting != null && int.TryParse(setting.Value, out var id)) return Task.FromResult(id); return Task.FromResult(null); } public Task SaveLastProjectIdAsync(int projectId) { var col = _db.GetCollection("settings"); var existing = col.FindOne(s => s.Key == KeyLastProjectId && s.UserId == _currentUserId && s.ProjectId == null); if (existing != null) { existing.Value = projectId.ToString(); col.Update(existing); } else { col.Insert(new SettingEntity { Key = KeyLastProjectId, Value = projectId.ToString(), UserId = _currentUserId, ProjectId = null }); } return Task.CompletedTask; } private string? GetSetting(string key, int? userId, int? projectId) { var col = _db.GetCollection("settings"); var matches = col.Find(s => s.Key == key && (s.UserId == userId || s.UserId == null) && (s.ProjectId == projectId || s.ProjectId == null)); return matches .OrderByDescending(s => s.UserId != null) .ThenByDescending(s => s.ProjectId != null) .FirstOrDefault()?.Value; } private string? Get(string key) { return GetSetting(key, _currentUserId, _currentProjectId); } private string? GetGlobal(string key) { var col = _db.GetCollection("settings"); return col.FindOne(s => s.Key == key && s.UserId == null && s.ProjectId == null)?.Value; } private void SetGlobal(string key, string value) { var col = _db.GetCollection("settings"); var existing = col.FindOne(s => s.Key == key && s.UserId == null && s.ProjectId == null); if (existing != null) { existing.Value = value; col.Update(existing); } else { col.Insert(new SettingEntity { Key = key, Value = value, UserId = null, ProjectId = null }); } } private void Set(string key, string value) { var col = _db.GetCollection("settings"); var existing = col.FindOne(s => s.Key == key && s.UserId == _currentUserId && s.ProjectId == null); if (existing != null) { existing.Value = value; col.Update(existing); } else { col.Insert(new SettingEntity { Key = key, Value = value, UserId = _currentUserId, ProjectId = null }); } } public Task GetOllamaUrlAsync() => Task.FromResult(GetGlobal(KeyOllamaUrl)); public Task GetLlamaCppUrlAsync() => Task.FromResult(GetGlobal(KeyLlamaCppUrl)); public Task GetBackendAsync() => Task.FromResult(GetGlobal(KeyBackend)); public Task GetRagModelAsync() => Task.FromResult(GetGlobal(KeyRagModel)); public Task GetStyleModelAsync() => Task.FromResult(GetGlobal(KeyStyleModel)); public Task GetLektorSystemPromptAsync() => Task.FromResult(Get(KeyLektorPrompt)); public Task GetFactCheckTemplateAsync() => Task.FromResult(Get(KeyFactCheckTemplate)); public Task GetSpellingPromptAsync() => Task.FromResult(Get(KeySpellingPrompt)); public Task GetSpellingModelAsync() => Task.FromResult(GetGlobal(KeySpellingModel)); public Task GetAdvocatusDiaboliPromptAsync() => Task.FromResult(Get(KeyAdvocatusDiaboli)); public Task GetHookFinderPromptAsync() => Task.FromResult(Get(KeyHookFinder)); public Task GetEli5PromptAsync() => Task.FromResult(Get(KeyEli5)); public Task GetCoAuthorBrainstormingPromptAsync() => Task.FromResult(Get(KeyCoAuthor)); public Task GetLektorTempAsync() => Task.FromResult(double.TryParse(Get(KeyLektorTemp), out var v) ? v : _ollamaConfig.LektorTemp); public Task GetFactCheckTempAsync() => Task.FromResult(double.TryParse(Get(KeyFactCheckTemp), out var v) ? v : _ollamaConfig.FactCheckTemp); public Task GetSpellingTempAsync() => Task.FromResult(double.TryParse(Get(KeySpellingTemp), out var v) ? v : _ollamaConfig.SpellingTemp); public Task GetAdvocatusDiaboliTempAsync() => Task.FromResult(double.TryParse(Get(KeyAdvocatusDiaboliTemp), out var v) ? v : _ollamaConfig.AdvocatusDiaboliTemp); public Task GetHookFinderTempAsync() => Task.FromResult(double.TryParse(Get(KeyHookFinderTemp), out var v) ? v : _ollamaConfig.HookFinderTemp); public Task GetEli5TempAsync() => Task.FromResult(double.TryParse(Get(KeyEli5Temp), out var v) ? v : _ollamaConfig.Eli5Temp); public Task GetCoAuthorTempAsync() => Task.FromResult(double.TryParse(Get(KeyCoAuthorTemp), out var v) ? v : _ollamaConfig.CoAuthorTemp); public Task GetTechLastenheftPromptAsync() => Task.FromResult(Get(KeyTechLastenheft)); public Task GetTechPflichtenheftPromptAsync() => Task.FromResult(Get(KeyTechPflichtenheft)); public Task GetTechUseCasePromptAsync() => Task.FromResult(Get(KeyTechUseCase)); public Task GetTechStakeholderPromptAsync() => Task.FromResult(Get(KeyTechStakeholder)); public Task GetTechGlossarPromptAsync() => Task.FromResult(Get(KeyTechGlossar)); public Task GetTechQualitaetPromptAsync() => Task.FromResult(Get(KeyTechQualitaet)); public Task GetTechRisikoPromptAsync() => Task.FromResult(Get(KeyTechRisiko)); public Task GetTechLastenheftTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechLastenheftTemp), out var v) ? v : _ollamaConfig.TechLastenheftTemp); public Task GetTechPflichtenheftTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechPflichtenheftTemp), out var v) ? v : _ollamaConfig.TechPflichtenheftTemp); public Task GetTechUseCaseTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechUseCaseTemp), out var v) ? v : _ollamaConfig.TechUseCaseTemp); public Task GetTechStakeholderTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechStakeholderTemp), out var v) ? v : _ollamaConfig.TechStakeholderTemp); public Task GetTechGlossarTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechGlossarTemp), out var v) ? v : _ollamaConfig.TechGlossarTemp); public Task GetTechQualitaetTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechQualitaetTemp), out var v) ? v : _ollamaConfig.TechQualitaetTemp); public Task GetTechRisikoTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechRisikoTemp), out var v) ? v : _ollamaConfig.TechRisikoTemp); public Task GetThemeAsync() => Task.FromResult(Get(KeyTheme)); public Task GetLanguageAsync() => Task.FromResult(Get(KeyLanguage)); public Task SaveLanguageAsync(string language) { Set(KeyLanguage, language); _ollamaConfig.Language = language; return Task.CompletedTask; } public Task SaveOllamaUrlAsync(string url) { SetGlobal(KeyOllamaUrl, url); _ollamaConfig.OllamaUrl = url; return Task.CompletedTask; } public Task SaveLlamaCppUrlAsync(string url) { SetGlobal(KeyLlamaCppUrl, url); _ollamaConfig.LlamaCppUrl = url; return Task.CompletedTask; } public Task SaveBackendAsync(string backend) { SetGlobal(KeyBackend, backend); _ollamaConfig.Backend = backend; return Task.CompletedTask; } public Task SaveRagModelAsync(string model) { SetGlobal(KeyRagModel, model); _ollamaConfig.EmbedModel = model; return Task.CompletedTask; } public Task SaveStyleModelAsync(string model) { SetGlobal(KeyStyleModel, model); _ollamaConfig.StyleModel = model; return Task.CompletedTask; } public Task SaveLektorSystemPromptAsync(string prompt) { Set(KeyLektorPrompt, prompt); _ollamaConfig.LektorSystemPrompt = prompt; return Task.CompletedTask; } public Task SaveFactCheckTemplateAsync(string prompt) { Set(KeyFactCheckTemplate, prompt); _ollamaConfig.FactCheckTemplate = prompt; return Task.CompletedTask; } public Task SaveSpellingPromptAsync(string prompt) { Set(KeySpellingPrompt, prompt); _ollamaConfig.SpellingPrompt = prompt; return Task.CompletedTask; } public Task SaveSpellingModelAsync(string model) { SetGlobal(KeySpellingModel, model); _ollamaConfig.SpellingModel = model; return Task.CompletedTask; } public Task SaveAdvocatusDiaboliPromptAsync(string prompt) { Set(KeyAdvocatusDiaboli, prompt); _ollamaConfig.AdvocatusDiaboliPrompt = prompt; return Task.CompletedTask; } public Task SaveHookFinderPromptAsync(string prompt) { Set(KeyHookFinder, prompt); _ollamaConfig.HookFinderPrompt = prompt; return Task.CompletedTask; } public Task SaveEli5PromptAsync(string prompt) { Set(KeyEli5, prompt); _ollamaConfig.Eli5Prompt = prompt; return Task.CompletedTask; } public Task SaveCoAuthorBrainstormingPromptAsync(string prompt) { Set(KeyCoAuthor, prompt); _ollamaConfig.CoAuthorBrainstormingPrompt = prompt; return Task.CompletedTask; } public Task SaveLektorTempAsync(double temp) { Set(KeyLektorTemp, temp.ToString("F1")); _ollamaConfig.LektorTemp = temp; return Task.CompletedTask; } public Task SaveFactCheckTempAsync(double temp) { Set(KeyFactCheckTemp, temp.ToString("F1")); _ollamaConfig.FactCheckTemp = temp; return Task.CompletedTask; } public Task SaveSpellingTempAsync(double temp) { Set(KeySpellingTemp, temp.ToString("F1")); _ollamaConfig.SpellingTemp = temp; return Task.CompletedTask; } public Task SaveAdvocatusDiaboliTempAsync(double temp) { Set(KeyAdvocatusDiaboliTemp, temp.ToString("F1")); _ollamaConfig.AdvocatusDiaboliTemp = temp; return Task.CompletedTask; } public Task SaveHookFinderTempAsync(double temp) { Set(KeyHookFinderTemp, temp.ToString("F1")); _ollamaConfig.HookFinderTemp = temp; return Task.CompletedTask; } public Task SaveEli5TempAsync(double temp) { Set(KeyEli5Temp, temp.ToString("F1")); _ollamaConfig.Eli5Temp = temp; return Task.CompletedTask; } public Task SaveCoAuthorTempAsync(double temp) { Set(KeyCoAuthorTemp, temp.ToString("F1")); _ollamaConfig.CoAuthorTemp = temp; return Task.CompletedTask; } public Task GetQuickMarkdownPromptAsync() => Task.FromResult(Get(KeyQuickMarkdownPrompt)); public Task SaveQuickMarkdownPromptAsync(string prompt) { Set(KeyQuickMarkdownPrompt, prompt); _ollamaConfig.QuickMarkdownPrompt = prompt; return Task.CompletedTask; } public Task GetQuickMarkdownTempAsync() => Task.FromResult(double.TryParse(Get(KeyQuickMarkdownTemp), out var v) ? v : _ollamaConfig.QuickMarkdownTemp); public Task SaveQuickMarkdownTempAsync(double temp) { Set(KeyQuickMarkdownTemp, temp.ToString("F1")); _ollamaConfig.QuickMarkdownTemp = temp; return Task.CompletedTask; } public Task GetChatPromptAsync() => Task.FromResult(Get(KeyChatPrompt)); public Task SaveChatPromptAsync(string prompt) { Set(KeyChatPrompt, prompt); _ollamaConfig.ChatPrompt = prompt; return Task.CompletedTask; } public Task GetChatTempAsync() => Task.FromResult(double.TryParse(Get(KeyChatTemp), out var v) ? v : _ollamaConfig.ChatTemp); public Task SaveChatTempAsync(double temp) { Set(KeyChatTemp, temp.ToString("F1")); _ollamaConfig.ChatTemp = temp; return Task.CompletedTask; } public Task SaveTechLastenheftPromptAsync(string prompt) { Set(KeyTechLastenheft, prompt); _ollamaConfig.TechLastenheftPrompt = prompt; return Task.CompletedTask; } public Task SaveTechPflichtenheftPromptAsync(string prompt) { Set(KeyTechPflichtenheft, prompt); _ollamaConfig.TechPflichtenheftPrompt = prompt; return Task.CompletedTask; } public Task SaveTechUseCasePromptAsync(string prompt) { Set(KeyTechUseCase, prompt); _ollamaConfig.TechUseCasePrompt = prompt; return Task.CompletedTask; } public Task SaveTechStakeholderPromptAsync(string prompt) { Set(KeyTechStakeholder, prompt); _ollamaConfig.TechStakeholderPrompt = prompt; return Task.CompletedTask; } public Task SaveTechGlossarPromptAsync(string prompt) { Set(KeyTechGlossar, prompt); _ollamaConfig.TechGlossarPrompt = prompt; return Task.CompletedTask; } public Task SaveTechQualitaetPromptAsync(string prompt) { Set(KeyTechQualitaet, prompt); _ollamaConfig.TechQualitaetPrompt = prompt; return Task.CompletedTask; } public Task SaveTechRisikoPromptAsync(string prompt) { Set(KeyTechRisiko, prompt); _ollamaConfig.TechRisikoPrompt = prompt; return Task.CompletedTask; } public Task SaveTechLastenheftTempAsync(double temp) { Set(KeyTechLastenheftTemp, temp.ToString("F1")); _ollamaConfig.TechLastenheftTemp = temp; return Task.CompletedTask; } public Task SaveTechPflichtenheftTempAsync(double temp) { Set(KeyTechPflichtenheftTemp, temp.ToString("F1")); _ollamaConfig.TechPflichtenheftTemp = temp; return Task.CompletedTask; } public Task SaveTechUseCaseTempAsync(double temp) { Set(KeyTechUseCaseTemp, temp.ToString("F1")); _ollamaConfig.TechUseCaseTemp = temp; return Task.CompletedTask; } public Task SaveTechStakeholderTempAsync(double temp) { Set(KeyTechStakeholderTemp, temp.ToString("F1")); _ollamaConfig.TechStakeholderTemp = temp; return Task.CompletedTask; } public Task SaveTechGlossarTempAsync(double temp) { Set(KeyTechGlossarTemp, temp.ToString("F1")); _ollamaConfig.TechGlossarTemp = temp; return Task.CompletedTask; } public Task SaveTechQualitaetTempAsync(double temp) { Set(KeyTechQualitaetTemp, temp.ToString("F1")); _ollamaConfig.TechQualitaetTemp = temp; return Task.CompletedTask; } public Task SaveTechRisikoTempAsync(double temp) { Set(KeyTechRisikoTemp, temp.ToString("F1")); _ollamaConfig.TechRisikoTemp = temp; return Task.CompletedTask; } public Task SaveThemeAsync(string theme) { Set(KeyTheme, theme); return Task.CompletedTask; } public Task> GetUsersAsync() { var col = _db.GetCollection("users"); return Task.FromResult(col.FindAll().ToList()); } public Task GetCurrentUserAsync() { var col = _db.GetCollection("users"); if (_currentUserId != null) { var user = col.FindById(_currentUserId.Value); if (user != null) return Task.FromResult(user); } return Task.FromResult(col.FindAll().FirstOrDefault() ?? new UserEntity()); } public void SetCurrentUser(int userId) { _currentUserId = userId; } public Task CreateUserAsync(string name) { var col = _db.GetCollection("users"); var hasUsers = col.FindAll().Any(); var user = new UserEntity { Name = name, Roles = new List { hasUsers ? UserRole.Author : UserRole.Administrator } }; col.Insert(user); return Task.FromResult(user); } private void MigrateSchema() { const string schemaKey = "_schema_version"; var settings = _db.GetCollection("settings"); var schemaSetting = settings.FindOne(s => s.Key == schemaKey && s.UserId == null && s.ProjectId == null); var currentVersion = int.TryParse(schemaSetting?.Value, out var v) ? v : 0; if (currentVersion < 1) { var users = _db.GetCollection("users"); var all = users.FindAll().OrderBy(u => u.Id).ToList(); if (all.Count > 0) { all[0].Roles = new List { UserRole.Administrator }; foreach (var u in all) { u.IsActive = true; users.Update(u); } } //var authorExists = all.Any(u => u.Name == "Author"); //if (!authorExists) //{ // var authorUser = new UserEntity // { // Name = "Author", // PasswordHash = TotpHelper.HashPassword("author123"), // TwoFactorEnabled = false, // TwoFactorSecret = string.Empty, // Role = UserRole.Author, // IsActive = true // }; // users.Insert(authorUser); //} var projects = _db.GetCollection("projects"); var orphaned = projects.Find(p => p.UserId == 0).ToList(); if (orphaned.Count > 0) { var admin = users.FindAll().OrderBy(u => u.Id).FirstOrDefault(); if (admin != null) { foreach (var p in orphaned) { p.UserId = admin.Id; projects.Update(p); } } } currentVersion = 1; } if (currentVersion < 2) { var llmKeys = new[] { KeyOllamaUrl, KeyRagModel, KeyStyleModel, KeySpellingModel }; foreach (var key in llmKeys) { var perUser = settings.Find(s => s.Key == key && s.UserId != null).ToList(); foreach (var s in perUser) settings.Delete(s.Id); if (settings.FindOne(s => s.Key == key && s.UserId == null && s.ProjectId == null) == null) { var defaultValue = key switch { var k when k == KeyOllamaUrl => _ollamaConfig.OllamaUrl, var k when k == KeyRagModel => _ollamaConfig.EmbedModel, var k when k == KeyStyleModel => _ollamaConfig.StyleModel, var k when k == KeySpellingModel => _ollamaConfig.SpellingModel, _ => "" }; settings.Insert(new SettingEntity { Key = key, Value = defaultValue, UserId = null, ProjectId = null }); } } currentVersion = 2; } if (schemaSetting != null) { schemaSetting.Value = currentVersion.ToString(); settings.Update(schemaSetting); } else { settings.Insert(new SettingEntity { Key = schemaKey, Value = currentVersion.ToString(), UserId = null, ProjectId = null }); } } public Task LoadProjectSettingsAsync() { var globalKeys = new[] { KeyOllamaUrl, KeyLlamaCppUrl, KeyBackend, KeyRagModel, KeyStyleModel, KeySpellingModel }; foreach (var key in globalKeys) { var val = GetGlobal(key); if (val == null) continue; switch (key) { case var k when k == KeyOllamaUrl: _ollamaConfig.OllamaUrl = val; break; case var k when k == KeyLlamaCppUrl: _ollamaConfig.LlamaCppUrl = val; break; case var k when k == KeyBackend: _ollamaConfig.Backend = val; break; case var k when k == KeyRagModel: _ollamaConfig.EmbedModel = val; break; case var k when k == KeyStyleModel: _ollamaConfig.StyleModel = val; break; case var k when k == KeySpellingModel: _ollamaConfig.SpellingModel = val; break; } } var tempMap = new (string Key, Action Setter)[] { (KeyLektorTemp, val => _ollamaConfig.LektorTemp = val), (KeyFactCheckTemp, val => _ollamaConfig.FactCheckTemp = val), (KeySpellingTemp, val => _ollamaConfig.SpellingTemp = val), (KeyAdvocatusDiaboliTemp, val => _ollamaConfig.AdvocatusDiaboliTemp = val), (KeyHookFinderTemp, val => _ollamaConfig.HookFinderTemp = val), (KeyEli5Temp, val => _ollamaConfig.Eli5Temp = val), (KeyCoAuthorTemp, val => _ollamaConfig.CoAuthorTemp = val), (KeyTechLastenheftTemp, val => _ollamaConfig.TechLastenheftTemp = val), (KeyTechPflichtenheftTemp, val => _ollamaConfig.TechPflichtenheftTemp = val), (KeyTechUseCaseTemp, val => _ollamaConfig.TechUseCaseTemp = val), (KeyTechStakeholderTemp, val => _ollamaConfig.TechStakeholderTemp = val), (KeyTechGlossarTemp, val => _ollamaConfig.TechGlossarTemp = val), (KeyTechQualitaetTemp, val => _ollamaConfig.TechQualitaetTemp = val), (KeyTechRisikoTemp, val => _ollamaConfig.TechRisikoTemp = val), }; foreach (var entry in tempMap) { var val = Get(entry.Key); if (val != null && double.TryParse(val, out var d)) entry.Setter(d); } var userEntries = new (string Key, Action Setter)[] { (KeyTheme, val => _ollamaConfig.Theme = val), (KeyLektorPrompt, val => _ollamaConfig.LektorSystemPrompt = val), (KeyFactCheckTemplate, val => _ollamaConfig.FactCheckTemplate = val), (KeySpellingPrompt, val => _ollamaConfig.SpellingPrompt = val), (KeyAdvocatusDiaboli, val => _ollamaConfig.AdvocatusDiaboliPrompt = val), (KeyHookFinder, val => _ollamaConfig.HookFinderPrompt = val), (KeyEli5, val => _ollamaConfig.Eli5Prompt = val), (KeyCoAuthor, val => _ollamaConfig.CoAuthorBrainstormingPrompt = val), (KeyTechLastenheft, val => _ollamaConfig.TechLastenheftPrompt = val), (KeyTechPflichtenheft, val => _ollamaConfig.TechPflichtenheftPrompt = val), (KeyTechUseCase, val => _ollamaConfig.TechUseCasePrompt = val), (KeyTechStakeholder, val => _ollamaConfig.TechStakeholderPrompt = val), (KeyTechGlossar, val => _ollamaConfig.TechGlossarPrompt = val), (KeyTechQualitaet, val => _ollamaConfig.TechQualitaetPrompt = val), (KeyTechRisiko, val => _ollamaConfig.TechRisikoPrompt = val), (KeyLanguage, val => _ollamaConfig.Language = val), }; foreach (var entry in userEntries) { var val = Get(entry.Key); if (val != null) entry.Setter(val); } return Task.CompletedTask; } public Task InitializeAsync() { MigrateSchema(); var settings = _db.GetCollection("settings"); var globalEntries = new (string Key, string Default)[] { (KeyOllamaUrl, _ollamaConfig.OllamaUrl), (KeyLlamaCppUrl, _ollamaConfig.LlamaCppUrl), (KeyBackend, _ollamaConfig.Backend), (KeyRagModel, _ollamaConfig.EmbedModel), (KeyStyleModel, _ollamaConfig.StyleModel), (KeySpellingModel, _ollamaConfig.SpellingModel), }; foreach (var entry in globalEntries) { var existing = settings.FindOne(s => s.Key == entry.Key && s.UserId == null && s.ProjectId == null); if (existing != null) { var val = existing.Value; if (entry.Key == KeyOllamaUrl) _ollamaConfig.OllamaUrl = val; else if (entry.Key == KeyLlamaCppUrl) _ollamaConfig.LlamaCppUrl = val; else if (entry.Key == KeyBackend) _ollamaConfig.Backend = val; else if (entry.Key == KeyRagModel) _ollamaConfig.EmbedModel = val; else if (entry.Key == KeyStyleModel) _ollamaConfig.StyleModel = val; else if (entry.Key == KeySpellingModel) _ollamaConfig.SpellingModel = val; } else { settings.Insert(new SettingEntity { Key = entry.Key, Value = entry.Default, UserId = null, ProjectId = null }); } } if (_currentUserId == null) { var firstUser = _db.GetCollection("users").FindAll().FirstOrDefault(); if (firstUser == null) return Task.CompletedTask; _currentUserId = firstUser.Id; } var lang = _ollamaConfig.Language; var userEntries = new (string Key, string Default)[] { (KeyTheme, _ollamaConfig.Theme), (KeyLanguage, lang), (KeyLektorPrompt, lang == "en" ? _ollamaConfig.LektorSystemPromptEn : _ollamaConfig.LektorSystemPrompt), (KeyFactCheckTemplate, lang == "en" ? _ollamaConfig.FactCheckTemplateEn : _ollamaConfig.FactCheckTemplate), (KeySpellingPrompt, lang == "en" ? _ollamaConfig.SpellingPromptEn : _ollamaConfig.SpellingPrompt), (KeyAdvocatusDiaboli, lang == "en" ? _ollamaConfig.AdvocatusDiaboliPromptEn : _ollamaConfig.AdvocatusDiaboliPrompt), (KeyHookFinder, lang == "en" ? _ollamaConfig.HookFinderPromptEn : _ollamaConfig.HookFinderPrompt), (KeyEli5, lang == "en" ? _ollamaConfig.Eli5PromptEn : _ollamaConfig.Eli5Prompt), (KeyCoAuthor, lang == "en" ? _ollamaConfig.CoAuthorBrainstormingPromptEn : _ollamaConfig.CoAuthorBrainstormingPrompt), (KeyTechLastenheft, lang == "en" ? _ollamaConfig.TechLastenheftPromptEn : _ollamaConfig.TechLastenheftPrompt), (KeyTechPflichtenheft, lang == "en" ? _ollamaConfig.TechPflichtenheftPromptEn : _ollamaConfig.TechPflichtenheftPrompt), (KeyTechUseCase, lang == "en" ? _ollamaConfig.TechUseCasePromptEn : _ollamaConfig.TechUseCasePrompt), (KeyTechStakeholder, lang == "en" ? _ollamaConfig.TechStakeholderPromptEn : _ollamaConfig.TechStakeholderPrompt), (KeyTechGlossar, lang == "en" ? _ollamaConfig.TechGlossarPromptEn : _ollamaConfig.TechGlossarPrompt), (KeyTechQualitaet, lang == "en" ? _ollamaConfig.TechQualitaetPromptEn : _ollamaConfig.TechQualitaetPrompt), (KeyTechRisiko, lang == "en" ? _ollamaConfig.TechRisikoPromptEn : _ollamaConfig.TechRisikoPrompt), (KeyLektorTemp, _ollamaConfig.LektorTemp.ToString("F1")), (KeyFactCheckTemp, _ollamaConfig.FactCheckTemp.ToString("F1")), (KeySpellingTemp, _ollamaConfig.SpellingTemp.ToString("F1")), (KeyAdvocatusDiaboliTemp, _ollamaConfig.AdvocatusDiaboliTemp.ToString("F1")), (KeyHookFinderTemp, _ollamaConfig.HookFinderTemp.ToString("F1")), (KeyEli5Temp, _ollamaConfig.Eli5Temp.ToString("F1")), (KeyCoAuthorTemp, _ollamaConfig.CoAuthorTemp.ToString("F1")), (KeyTechLastenheftTemp, _ollamaConfig.TechLastenheftTemp.ToString("F1")), (KeyTechPflichtenheftTemp, _ollamaConfig.TechPflichtenheftTemp.ToString("F1")), (KeyTechUseCaseTemp, _ollamaConfig.TechUseCaseTemp.ToString("F1")), (KeyTechStakeholderTemp, _ollamaConfig.TechStakeholderTemp.ToString("F1")), (KeyTechGlossarTemp, _ollamaConfig.TechGlossarTemp.ToString("F1")), (KeyTechQualitaetTemp, _ollamaConfig.TechQualitaetTemp.ToString("F1")), (KeyTechRisikoTemp, _ollamaConfig.TechRisikoTemp.ToString("F1")), }; foreach (var entry in userEntries) { var existing = settings.FindOne(s => s.Key == entry.Key && s.UserId == _currentUserId && s.ProjectId == _currentProjectId); if (existing != null) { var val = existing.Value; if (entry.Key == KeyTheme) _ollamaConfig.Theme = val; else if (entry.Key == KeyLanguage) _ollamaConfig.Language = val; else if (entry.Key == KeyLektorPrompt) _ollamaConfig.LektorSystemPrompt = val; else if (entry.Key == KeyFactCheckTemplate) _ollamaConfig.FactCheckTemplate = val; else if (entry.Key == KeySpellingPrompt) _ollamaConfig.SpellingPrompt = val; else if (entry.Key == KeyAdvocatusDiaboli) _ollamaConfig.AdvocatusDiaboliPrompt = val; else if (entry.Key == KeyHookFinder) _ollamaConfig.HookFinderPrompt = val; else if (entry.Key == KeyEli5) _ollamaConfig.Eli5Prompt = val; else if (entry.Key == KeyCoAuthor) _ollamaConfig.CoAuthorBrainstormingPrompt = val; else if (entry.Key == KeyLektorTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.LektorTemp = t; } else if (entry.Key == KeyFactCheckTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.FactCheckTemp = t; } else if (entry.Key == KeySpellingTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.SpellingTemp = t; } else if (entry.Key == KeyAdvocatusDiaboliTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.AdvocatusDiaboliTemp = t; } else if (entry.Key == KeyHookFinderTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.HookFinderTemp = t; } else if (entry.Key == KeyEli5Temp) { if (double.TryParse(val, out var t)) _ollamaConfig.Eli5Temp = t; } else if (entry.Key == KeyCoAuthorTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.CoAuthorTemp = t; } else if (entry.Key == KeyTechLastenheft) _ollamaConfig.TechLastenheftPrompt = val; else if (entry.Key == KeyTechPflichtenheft) _ollamaConfig.TechPflichtenheftPrompt = val; else if (entry.Key == KeyTechUseCase) _ollamaConfig.TechUseCasePrompt = val; else if (entry.Key == KeyTechStakeholder) _ollamaConfig.TechStakeholderPrompt = val; else if (entry.Key == KeyTechGlossar) _ollamaConfig.TechGlossarPrompt = val; else if (entry.Key == KeyTechQualitaet) _ollamaConfig.TechQualitaetPrompt = val; else if (entry.Key == KeyTechRisiko) _ollamaConfig.TechRisikoPrompt = val; else if (entry.Key == KeyTechLastenheftTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechLastenheftTemp = t; } else if (entry.Key == KeyTechPflichtenheftTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechPflichtenheftTemp = t; } else if (entry.Key == KeyTechUseCaseTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechUseCaseTemp = t; } else if (entry.Key == KeyTechStakeholderTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechStakeholderTemp = t; } else if (entry.Key == KeyTechGlossarTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechGlossarTemp = t; } else if (entry.Key == KeyTechQualitaetTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechQualitaetTemp = t; } else if (entry.Key == KeyTechRisikoTemp) { if (double.TryParse(val, out var t)) _ollamaConfig.TechRisikoTemp = t; } } else { settings.Insert(new SettingEntity { Key = entry.Key, Value = entry.Default, UserId = _currentUserId, ProjectId = _currentProjectId }); } } return Task.CompletedTask; } }