AuthorBuddy/Services/SettingsService.cs

831 lines
35 KiB
C#
Raw Permalink Normal View History

2026-05-16 16:13:35 +02:00
using AuthorBuddy.Web.Data;
using AuthorBuddy.Web.Models;
2026-05-20 06:12:54 +02:00
using LiteDB;
2026-05-16 16:13:35 +02:00
namespace AuthorBuddy.Web.Services;
public class SettingsService : ISettingsService
{
private const string KeyOllamaUrl = "ollama_url";
2026-05-31 19:31:27 +02:00
private const string KeyLlamaCppUrl = "llama_cpp_url";
private const string KeyBackend = "llm_backend";
2026-05-16 16:13:35 +02:00
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";
2026-05-20 06:12:54 +02:00
private const string KeyAdvocatusDiaboli = "ollama_advocatus_diaboli";
private const string KeyHookFinder = "ollama_hook_finder";
private const string KeyEli5 = "ollama_eli5";
2026-05-31 19:31:27 +02:00
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";
2026-06-21 07:52:03 +02:00
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";
2026-05-20 07:27:41 +02:00
private const string KeyLanguage = "language";
private const string KeyLastProjectId = "last_project_id";
2026-05-16 16:13:35 +02:00
2026-05-20 06:12:54 +02:00
private readonly ILiteDatabase _db;
2026-05-16 16:13:35 +02:00
private readonly OllamaSettings _ollamaConfig;
2026-05-17 07:27:18 +02:00
private int? _currentUserId;
private int? _currentProjectId;
2026-05-16 16:13:35 +02:00
2026-05-20 06:12:54 +02:00
public SettingsService(ILiteDatabase db, OllamaSettings ollamaConfig)
2026-05-16 16:13:35 +02:00
{
2026-05-20 06:12:54 +02:00
_db = db;
2026-05-16 16:13:35 +02:00
_ollamaConfig = ollamaConfig;
}
2026-05-17 07:27:18 +02:00
public int? CurrentProjectId
2026-05-16 16:13:35 +02:00
{
2026-05-17 07:27:18 +02:00
get => _currentProjectId;
set => _currentProjectId = value;
2026-05-16 16:13:35 +02:00
}
2026-05-20 06:12:54 +02:00
public string? CurrentFilePath { get; set; }
2026-05-20 07:27:41 +02:00
public string? PendingAssistantInput { get; set; }
public string? PendingAssistantOutput { get; set; }
2026-05-20 06:12:54 +02:00
public Task<int?> GetLastProjectIdAsync()
{
var col = _db.GetCollection<SettingEntity>("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<int?>(id);
return Task.FromResult<int?>(null);
}
public Task SaveLastProjectIdAsync(int projectId)
{
var col = _db.GetCollection<SettingEntity>("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)
2026-05-17 07:27:18 +02:00
{
2026-05-20 06:12:54 +02:00
var col = _db.GetCollection<SettingEntity>("settings");
2026-05-16 16:13:35 +02:00
2026-05-20 06:12:54 +02:00
var matches = col.Find(s =>
2026-05-17 07:27:18 +02:00
s.Key == key &&
(s.UserId == userId || s.UserId == null) &&
(s.ProjectId == projectId || s.ProjectId == null));
2026-05-16 16:13:35 +02:00
2026-05-20 06:12:54 +02:00
return matches
2026-05-17 07:27:18 +02:00
.OrderByDescending(s => s.UserId != null)
.ThenByDescending(s => s.ProjectId != null)
2026-05-20 06:12:54 +02:00
.FirstOrDefault()?.Value;
2026-05-17 07:27:18 +02:00
}
2026-05-20 06:12:54 +02:00
private string? Get(string key)
2026-05-17 07:27:18 +02:00
{
2026-05-25 06:38:16 +02:00
return GetSetting(key, _currentUserId, _currentProjectId);
2026-05-17 07:27:18 +02:00
}
2026-05-16 16:13:35 +02:00
2026-05-31 19:31:27 +02:00
private string? GetGlobal(string key)
{
var col = _db.GetCollection<SettingEntity>("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<SettingEntity>("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 });
}
}
2026-05-20 06:12:54 +02:00
private void Set(string key, string value)
2026-05-16 16:13:35 +02:00
{
2026-05-20 06:12:54 +02:00
var col = _db.GetCollection<SettingEntity>("settings");
2026-05-17 07:27:18 +02:00
2026-05-20 06:12:54 +02:00
var existing = col.FindOne(s =>
s.Key == key && s.UserId == _currentUserId && s.ProjectId == null);
2026-05-17 07:27:18 +02:00
2026-05-16 16:13:35 +02:00
if (existing != null)
2026-05-17 07:27:18 +02:00
{
2026-05-16 16:13:35 +02:00
existing.Value = value;
2026-05-20 06:12:54 +02:00
col.Update(existing);
2026-05-17 07:27:18 +02:00
}
2026-05-16 16:13:35 +02:00
else
2026-05-17 07:27:18 +02:00
{
2026-05-20 06:12:54 +02:00
col.Insert(new SettingEntity
2026-05-17 07:27:18 +02:00
{
Key = key,
Value = value,
UserId = _currentUserId,
2026-05-20 06:12:54 +02:00
ProjectId = null
2026-05-17 07:27:18 +02:00
});
}
2026-05-16 16:13:35 +02:00
}
2026-05-31 19:31:27 +02:00
public Task<string?> GetOllamaUrlAsync() => Task.FromResult(GetGlobal(KeyOllamaUrl));
public Task<string?> GetLlamaCppUrlAsync() => Task.FromResult(GetGlobal(KeyLlamaCppUrl));
public Task<string?> GetBackendAsync() => Task.FromResult(GetGlobal(KeyBackend));
public Task<string?> GetRagModelAsync() => Task.FromResult(GetGlobal(KeyRagModel));
public Task<string?> GetStyleModelAsync() => Task.FromResult(GetGlobal(KeyStyleModel));
2026-05-20 06:12:54 +02:00
public Task<string?> GetLektorSystemPromptAsync() => Task.FromResult(Get(KeyLektorPrompt));
public Task<string?> GetFactCheckTemplateAsync() => Task.FromResult(Get(KeyFactCheckTemplate));
public Task<string?> GetSpellingPromptAsync() => Task.FromResult(Get(KeySpellingPrompt));
2026-05-31 19:31:27 +02:00
public Task<string?> GetSpellingModelAsync() => Task.FromResult(GetGlobal(KeySpellingModel));
2026-05-20 06:12:54 +02:00
public Task<string?> GetAdvocatusDiaboliPromptAsync() => Task.FromResult(Get(KeyAdvocatusDiaboli));
public Task<string?> GetHookFinderPromptAsync() => Task.FromResult(Get(KeyHookFinder));
public Task<string?> GetEli5PromptAsync() => Task.FromResult(Get(KeyEli5));
2026-05-31 19:31:27 +02:00
public Task<string?> GetCoAuthorBrainstormingPromptAsync() => Task.FromResult(Get(KeyCoAuthor));
public Task<double> GetLektorTempAsync() => Task.FromResult(double.TryParse(Get(KeyLektorTemp), out var v) ? v : _ollamaConfig.LektorTemp);
public Task<double> GetFactCheckTempAsync() => Task.FromResult(double.TryParse(Get(KeyFactCheckTemp), out var v) ? v : _ollamaConfig.FactCheckTemp);
public Task<double> GetSpellingTempAsync() => Task.FromResult(double.TryParse(Get(KeySpellingTemp), out var v) ? v : _ollamaConfig.SpellingTemp);
public Task<double> GetAdvocatusDiaboliTempAsync() => Task.FromResult(double.TryParse(Get(KeyAdvocatusDiaboliTemp), out var v) ? v : _ollamaConfig.AdvocatusDiaboliTemp);
public Task<double> GetHookFinderTempAsync() => Task.FromResult(double.TryParse(Get(KeyHookFinderTemp), out var v) ? v : _ollamaConfig.HookFinderTemp);
public Task<double> GetEli5TempAsync() => Task.FromResult(double.TryParse(Get(KeyEli5Temp), out var v) ? v : _ollamaConfig.Eli5Temp);
public Task<double> GetCoAuthorTempAsync() => Task.FromResult(double.TryParse(Get(KeyCoAuthorTemp), out var v) ? v : _ollamaConfig.CoAuthorTemp);
public Task<string?> GetTechLastenheftPromptAsync() => Task.FromResult(Get(KeyTechLastenheft));
public Task<string?> GetTechPflichtenheftPromptAsync() => Task.FromResult(Get(KeyTechPflichtenheft));
public Task<string?> GetTechUseCasePromptAsync() => Task.FromResult(Get(KeyTechUseCase));
public Task<string?> GetTechStakeholderPromptAsync() => Task.FromResult(Get(KeyTechStakeholder));
public Task<string?> GetTechGlossarPromptAsync() => Task.FromResult(Get(KeyTechGlossar));
public Task<string?> GetTechQualitaetPromptAsync() => Task.FromResult(Get(KeyTechQualitaet));
public Task<string?> GetTechRisikoPromptAsync() => Task.FromResult(Get(KeyTechRisiko));
public Task<double> GetTechLastenheftTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechLastenheftTemp), out var v) ? v : _ollamaConfig.TechLastenheftTemp);
public Task<double> GetTechPflichtenheftTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechPflichtenheftTemp), out var v) ? v : _ollamaConfig.TechPflichtenheftTemp);
public Task<double> GetTechUseCaseTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechUseCaseTemp), out var v) ? v : _ollamaConfig.TechUseCaseTemp);
public Task<double> GetTechStakeholderTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechStakeholderTemp), out var v) ? v : _ollamaConfig.TechStakeholderTemp);
public Task<double> GetTechGlossarTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechGlossarTemp), out var v) ? v : _ollamaConfig.TechGlossarTemp);
public Task<double> GetTechQualitaetTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechQualitaetTemp), out var v) ? v : _ollamaConfig.TechQualitaetTemp);
public Task<double> GetTechRisikoTempAsync() => Task.FromResult(double.TryParse(Get(KeyTechRisikoTemp), out var v) ? v : _ollamaConfig.TechRisikoTemp);
2026-05-20 06:12:54 +02:00
public Task<string?> GetThemeAsync() => Task.FromResult(Get(KeyTheme));
2026-05-20 07:27:41 +02:00
public Task<string?> GetLanguageAsync() => Task.FromResult(Get(KeyLanguage));
public Task SaveLanguageAsync(string language)
{
Set(KeyLanguage, language);
_ollamaConfig.Language = language;
return Task.CompletedTask;
}
2026-05-20 06:12:54 +02:00
public Task SaveOllamaUrlAsync(string url)
2026-05-16 16:13:35 +02:00
{
2026-05-31 19:31:27 +02:00
SetGlobal(KeyOllamaUrl, url);
2026-05-16 16:13:35 +02:00
_ollamaConfig.OllamaUrl = url;
2026-05-20 06:12:54 +02:00
return Task.CompletedTask;
2026-05-16 16:13:35 +02:00
}
2026-05-31 19:31:27 +02:00
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;
}
2026-05-20 06:12:54 +02:00
public Task SaveRagModelAsync(string model)
2026-05-16 16:13:35 +02:00
{
2026-05-31 19:31:27 +02:00
SetGlobal(KeyRagModel, model);
2026-05-20 06:12:54 +02:00
_ollamaConfig.EmbedModel = model;
return Task.CompletedTask;
2026-05-16 16:13:35 +02:00
}
2026-05-20 06:12:54 +02:00
public Task SaveStyleModelAsync(string model)
2026-05-16 16:13:35 +02:00
{
2026-05-31 19:31:27 +02:00
SetGlobal(KeyStyleModel, model);
2026-05-16 16:13:35 +02:00
_ollamaConfig.StyleModel = model;
2026-05-20 06:12:54 +02:00
return Task.CompletedTask;
2026-05-16 16:13:35 +02:00
}
2026-05-20 06:12:54 +02:00
public Task SaveLektorSystemPromptAsync(string prompt)
2026-05-16 16:13:35 +02:00
{
2026-05-20 06:12:54 +02:00
Set(KeyLektorPrompt, prompt);
2026-05-16 16:13:35 +02:00
_ollamaConfig.LektorSystemPrompt = prompt;
2026-05-20 06:12:54 +02:00
return Task.CompletedTask;
2026-05-16 16:13:35 +02:00
}
2026-05-20 06:12:54 +02:00
public Task SaveFactCheckTemplateAsync(string prompt)
2026-05-16 16:13:35 +02:00
{
2026-05-20 06:12:54 +02:00
Set(KeyFactCheckTemplate, prompt);
2026-05-16 16:13:35 +02:00
_ollamaConfig.FactCheckTemplate = prompt;
2026-05-20 06:12:54 +02:00
return Task.CompletedTask;
2026-05-16 16:13:35 +02:00
}
2026-05-17 07:27:18 +02:00
2026-05-20 06:12:54 +02:00
public Task SaveSpellingPromptAsync(string prompt)
2026-05-16 16:13:35 +02:00
{
2026-05-20 06:12:54 +02:00
Set(KeySpellingPrompt, prompt);
2026-05-16 16:13:35 +02:00
_ollamaConfig.SpellingPrompt = prompt;
2026-05-20 06:12:54 +02:00
return Task.CompletedTask;
2026-05-16 16:13:35 +02:00
}
2026-05-20 06:12:54 +02:00
public Task SaveSpellingModelAsync(string model)
2026-05-16 16:13:35 +02:00
{
2026-05-31 19:31:27 +02:00
SetGlobal(KeySpellingModel, model);
2026-05-16 16:13:35 +02:00
_ollamaConfig.SpellingModel = model;
2026-05-20 06:12:54 +02:00
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;
2026-05-16 16:13:35 +02:00
}
2026-05-31 19:31:27 +02:00
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;
}
2026-06-21 07:52:03 +02:00
public Task<string?> GetQuickMarkdownPromptAsync() => Task.FromResult(Get(KeyQuickMarkdownPrompt));
public Task SaveQuickMarkdownPromptAsync(string prompt)
{
Set(KeyQuickMarkdownPrompt, prompt);
_ollamaConfig.QuickMarkdownPrompt = prompt;
return Task.CompletedTask;
}
public Task<double> 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<string?> GetChatPromptAsync() => Task.FromResult(Get(KeyChatPrompt));
public Task SaveChatPromptAsync(string prompt)
{
Set(KeyChatPrompt, prompt);
_ollamaConfig.ChatPrompt = prompt;
return Task.CompletedTask;
}
public Task<double> 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;
}
2026-05-31 19:31:27 +02:00
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;
}
2026-05-16 16:13:35 +02:00
public Task SaveThemeAsync(string theme)
2026-05-20 06:12:54 +02:00
{
Set(KeyTheme, theme);
return Task.CompletedTask;
}
2026-05-16 16:13:35 +02:00
2026-05-20 06:12:54 +02:00
public Task<List<UserEntity>> GetUsersAsync()
2026-05-17 07:27:18 +02:00
{
2026-05-20 06:12:54 +02:00
var col = _db.GetCollection<UserEntity>("users");
return Task.FromResult(col.FindAll().ToList());
2026-05-17 07:27:18 +02:00
}
2026-05-20 06:12:54 +02:00
public Task<UserEntity> GetCurrentUserAsync()
2026-05-17 07:27:18 +02:00
{
2026-05-20 06:12:54 +02:00
var col = _db.GetCollection<UserEntity>("users");
2026-05-25 06:38:16 +02:00
if (_currentUserId != null)
{
var user = col.FindById(_currentUserId.Value);
if (user != null) return Task.FromResult(user);
}
return Task.FromResult(col.FindAll().FirstOrDefault() ?? new UserEntity());
2026-05-17 07:27:18 +02:00
}
2026-05-25 06:38:16 +02:00
public void SetCurrentUser(int userId)
2026-05-17 07:27:18 +02:00
{
_currentUserId = userId;
}
2026-05-20 06:12:54 +02:00
public Task<UserEntity> CreateUserAsync(string name)
2026-05-17 07:27:18 +02:00
{
2026-05-20 06:12:54 +02:00
var col = _db.GetCollection<UserEntity>("users");
2026-05-25 06:38:16 +02:00
var hasUsers = col.FindAll().Any();
var user = new UserEntity
{
Name = name,
2026-06-21 07:52:03 +02:00
Roles = new List<UserRole> { hasUsers ? UserRole.Author : UserRole.Administrator }
2026-05-25 06:38:16 +02:00
};
2026-05-20 06:12:54 +02:00
col.Insert(user);
return Task.FromResult(user);
}
2026-05-25 06:38:16 +02:00
private void MigrateSchema()
{
const string schemaKey = "_schema_version";
var settings = _db.GetCollection<SettingEntity>("settings");
2026-05-31 19:31:27 +02:00
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;
2026-05-25 06:38:16 +02:00
2026-05-31 19:31:27 +02:00
if (currentVersion < 1)
2026-05-25 06:38:16 +02:00
{
2026-05-31 19:31:27 +02:00
var users = _db.GetCollection<UserEntity>("users");
var all = users.FindAll().OrderBy(u => u.Id).ToList();
if (all.Count > 0)
2026-05-25 06:38:16 +02:00
{
2026-06-21 07:52:03 +02:00
all[0].Roles = new List<UserRole> { UserRole.Administrator };
2026-05-31 19:31:27 +02:00
foreach (var u in all)
{
u.IsActive = true;
users.Update(u);
}
2026-05-25 06:38:16 +02:00
}
2026-05-31 19:31:27 +02:00
2026-06-21 07:52:03 +02:00
//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);
//}
2026-05-31 19:31:27 +02:00
var projects = _db.GetCollection<ProjectEntity>("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;
2026-05-25 06:38:16 +02:00
}
2026-05-31 19:31:27 +02:00
if (currentVersion < 2)
2026-05-25 06:38:16 +02:00
{
2026-05-31 19:31:27 +02:00
var llmKeys = new[] { KeyOllamaUrl, KeyRagModel, KeyStyleModel, KeySpellingModel };
foreach (var key in llmKeys)
2026-05-25 06:38:16 +02:00
{
2026-05-31 19:31:27 +02:00
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;
2026-05-25 06:38:16 +02:00
}
2026-05-31 19:31:27 +02:00
if (schemaSetting != null)
2026-05-25 06:38:16 +02:00
{
2026-05-31 19:31:27 +02:00
schemaSetting.Value = currentVersion.ToString();
settings.Update(schemaSetting);
}
else
{
settings.Insert(new SettingEntity { Key = schemaKey, Value = currentVersion.ToString(), UserId = null, ProjectId = null });
}
2026-05-25 06:38:16 +02:00
}
2026-05-20 06:12:54 +02:00
public Task LoadProjectSettingsAsync()
{
2026-05-31 19:31:27 +02:00
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<double> 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<string> Setter)[]
2026-05-20 06:12:54 +02:00
{
(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),
2026-05-31 19:31:27 +02:00
(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),
2026-05-20 07:27:41 +02:00
(KeyLanguage, val => _ollamaConfig.Language = val),
2026-05-20 06:12:54 +02:00
};
2026-05-31 19:31:27 +02:00
foreach (var entry in userEntries)
2026-05-20 06:12:54 +02:00
{
var val = Get(entry.Key);
if (val != null) entry.Setter(val);
}
return Task.CompletedTask;
2026-05-17 07:27:18 +02:00
}
2026-05-25 06:38:16 +02:00
public Task InitializeAsync()
2026-05-16 16:13:35 +02:00
{
2026-05-25 06:38:16 +02:00
MigrateSchema();
2026-05-16 16:13:35 +02:00
2026-05-31 19:31:27 +02:00
var settings = _db.GetCollection<SettingEntity>("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
});
}
}
2026-05-25 06:38:16 +02:00
if (_currentUserId == null)
2026-05-17 07:27:18 +02:00
{
2026-05-25 06:38:16 +02:00
var firstUser = _db.GetCollection<UserEntity>("users").FindAll().FirstOrDefault();
if (firstUser == null) return Task.CompletedTask;
_currentUserId = firstUser.Id;
2026-05-17 07:27:18 +02:00
}
2026-05-20 07:27:41 +02:00
var lang = _ollamaConfig.Language;
2026-05-31 19:31:27 +02:00
var userEntries = new (string Key, string Default)[]
2026-05-16 16:13:35 +02:00
{
(KeyTheme, _ollamaConfig.Theme),
2026-05-20 07:27:41 +02:00
(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),
2026-05-31 19:31:27 +02:00
(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")),
2026-05-16 16:13:35 +02:00
};
2026-05-31 19:31:27 +02:00
foreach (var entry in userEntries)
2026-05-16 16:13:35 +02:00
{
2026-05-20 06:12:54 +02:00
var existing = settings.FindOne(s =>
2026-05-25 06:38:16 +02:00
s.Key == entry.Key && s.UserId == _currentUserId && s.ProjectId == _currentProjectId);
2026-05-17 07:27:18 +02:00
2026-05-16 16:13:35 +02:00
if (existing != null)
{
var val = existing.Value;
2026-05-31 19:31:27 +02:00
if (entry.Key == KeyTheme) _ollamaConfig.Theme = val;
2026-05-20 07:27:41 +02:00
else if (entry.Key == KeyLanguage) _ollamaConfig.Language = val;
2026-05-16 16:13:35 +02:00
else if (entry.Key == KeyLektorPrompt) _ollamaConfig.LektorSystemPrompt = val;
else if (entry.Key == KeyFactCheckTemplate) _ollamaConfig.FactCheckTemplate = val;
else if (entry.Key == KeySpellingPrompt) _ollamaConfig.SpellingPrompt = val;
2026-05-20 06:12:54 +02:00
else if (entry.Key == KeyAdvocatusDiaboli) _ollamaConfig.AdvocatusDiaboliPrompt = val;
else if (entry.Key == KeyHookFinder) _ollamaConfig.HookFinderPrompt = val;
else if (entry.Key == KeyEli5) _ollamaConfig.Eli5Prompt = val;
2026-05-31 19:31:27 +02:00
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; }
2026-05-16 16:13:35 +02:00
}
else
{
2026-05-20 06:12:54 +02:00
settings.Insert(new SettingEntity
2026-05-17 07:27:18 +02:00
{
Key = entry.Key,
Value = entry.Default,
UserId = _currentUserId,
2026-05-25 06:38:16 +02:00
ProjectId = _currentProjectId
2026-05-17 07:27:18 +02:00
});
2026-05-16 16:13:35 +02:00
}
}
2026-05-20 06:12:54 +02:00
return Task.CompletedTask;
2026-05-16 16:13:35 +02:00
}
}