- now mostly working

This commit is contained in:
Roland 2026-05-16 16:13:35 +02:00
parent 5b919715eb
commit 508bf9b86e
22 changed files with 1488 additions and 264 deletions

79
.localpilot/map.txt Normal file
View file

@ -0,0 +1,79 @@
## WORKSPACE EXECUTIVE SUMMARY (YAML)
# Generated: 2026-05-16T15:21:43.3363122+02:00
# Root: E:\ollama_net\ollama\AuthorBuddy.Web
Architecture:
Type: Backend (C#/.NET)
Scale: 25 relevant source files
Components: 0
Controllers: 0
Models: 6
Services: 8
---
- File: AuthorBuddy.Web.csproj
Preview: "<Project Sdk='Microsoft.NET.Sdk.Web'> <PropertyGroup> <TargetFramework>net10.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>en..."
- File: appsettings.Development.json
Preview: "{ 'Logging': { 'LogLevel': { 'Default': 'Information', 'Microsoft.AspNetCore': 'Warning' } } } "
- File: appsettings.json
Preview: "{ 'Logging': { 'LogLevel': { 'Default': 'Information', 'Microsoft.AspNetCore': 'Warning' } }, 'AllowedHosts': '*' } "
- File: AuthorBuddy.Web.slnx
Preview: "<Solution> <Project Path='AuthorBuddy.Web.csproj' /> </Solution> "
- File: Program.cs
Preview: "using AuthorBuddy.Web.Components; using AuthorBuddy.Web.Data; using AuthorBuddy.Web.Models; using AuthorBuddy.Web.Services; using Microsoft.EntityFram..."
- File: Data\AppDbContext.cs
Symbols: [AppDbContext]
Preview: "using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; namespace AuthorBuddy.Web.Data; public class AppDbContext : DbContext { public DbS..."
- File: Data\DocumentMetaEntity.cs
Symbols: [DocumentMetaEntity]
Preview: "using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace AuthorBuddy.Web.Data; [Table('DocumentMeta'..."
- File: Data\ProjectEntity.cs
Symbols: [ProjectEntity]
Preview: "using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace AuthorBuddy.Web.Data; [Table('Projects')] p..."
- File: Data\SettingEntity.cs
Symbols: [SettingEntity]
Preview: "using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace AuthorBuddy.Web.Data; [Table('Settings')] p..."
- File: Models\Chapter.cs
Symbols: [Chapter]
Preview: "namespace AuthorBuddy.Web.Models; public class Chapter { public string Title { get; set; } = string.Empty; public string FilePath { get; set; } = ..."
- File: Models\Constants.cs
Symbols: [Constants]
Preview: "namespace AuthorBuddy.Web.Models; public static class Constants { public static readonly string[] SubFolders = { '00_Drafts', '01_Fakten/Per..."
- File: Models\LLM_Model.cs
Symbols: [LLM_Model, LLM_Model]
Preview: "using System.Text.Json; namespace AuthorBuddy.Web.Models { public class LLM_Model { public LLM_Model(JsonElement model) { if (mode..."
- File: Models\ModelStatus.cs
Symbols: [ModelStatus]
Preview: " //namespace AuthorBuddy.Web.Models; //public class ModelStatus //{ // public string Status { get; private set; } = 'Unknown'; // public double Prog..."
- File: Models\OllamaSettings.cs
Symbols: [OllamaSettings]
Preview: "namespace AuthorBuddy.Web.Models; public class OllamaSettings { public string ChatModel { get; set; } = 'llama3.2'; public string EmbedModel { get..."
- File: Models\Project.cs
Symbols: [Project]
Preview: "namespace AuthorBuddy.Web.Models; public class Project { public int Id { get; internal set; } public string Name { get; internal set; } = string.E..."
- File: Properties\launchSettings.json
Preview: "{ '$schema': 'https://json.schemastore.org/launchsettings.json', 'profiles': { 'http': { 'commandName': 'Project', 'dotnetRunMessages': ..."
- File: Services\FileScannerService.cs
Symbols: [FileScannerService]
Preview: "using AuthorBuddy.Web.Data; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; namespace AuthorBuddy.Web.Services; public class FileSca..."
- File: Services\IFileScannerService.cs
Symbols: [IFileScannerService]
Preview: "namespace AuthorBuddy.Web.Services; public interface IFileScannerService { Task ScanProjectFolderAsync(int projectId, string rootPath, IProgress<str..."
- File: Services\IOllamaService.cs
Symbols: [IOllamaService, IOllamaService]
Preview: " using AuthorBuddy.Web.Models; namespace AuthorBuddy.Web.Services; public interface IOllamaService { Task<IEnumerable<LLM_Model>> GetLocalModelsAsyn..."
- File: Services\IProjectService.cs
Symbols: [IProjectService]
Preview: "using AuthorBuddy.Web.Models; namespace AuthorBuddy.Web.Services; public interface IProjectService { Task<int> CreateNewProjectAsync(string projectN..."
- File: Services\ISettingsService.cs
Symbols: [ISettingsService]
Preview: "namespace AuthorBuddy.Web.Services; public interface ISettingsService { Task<string?> GetAsync(string key); Task SaveAsync(Dictionary<string, stri..."
- File: Services\OllamaService.cs
Symbols: [ChatStream, OllamaService, OllamaService, OllamaService, GetLocalModelsAsync, DeleteModel, ExtractResponseText, PullModelAsync, catch, catch, catch, catch, Chat, Reconfigure]
Preview: "using AuthorBuddy.Web.Models; using System.Net.Http.Json; using System.Text.Json; namespace AuthorBuddy.Web.Services; public class OllamaService : IOl..."
- File: Services\ProjectService.cs
Symbols: [ProjectService]
Preview: "using AuthorBuddy.Web.Data; using AuthorBuddy.Web.Models; using Microsoft.EntityFrameworkCore; namespace AuthorBuddy.Web.Services; public class Projec..."
- File: Services\SettingsService.cs
Symbols: [SettingsService]
Preview: "using AuthorBuddy.Web.Data; using AuthorBuddy.Web.Models; using Microsoft.EntityFrameworkCore; using Microsoft.JSInterop; using static System.Runtime...."
- File: Components\Layout\ReconnectModal.razor.js
Preview: "// Set up event handlers const reconnectModal = document.getElementById('components-reconnect-modal'); reconnectModal.addEventListener('components-rec..."

View file

@ -3,12 +3,108 @@
"WorkspaceRootPath": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\", "WorkspaceRootPath": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\",
"Documents": [ "Documents": [
{ {
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|E:\\ollama_net\\ollama\\AuthorBuddy.Web\\AuthorBuddy.Web.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}", "AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\layout\\mainlayout.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:AuthorBuddy.Web.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}" "RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\layout\\mainlayout.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
}, },
{ {
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|E:\\ollama_net\\ollama\\AuthorBuddy.Web\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}", "AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\isettingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}" "RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\isettingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\settings.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\settings.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\settingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\settingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\ollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\ollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\models\\ollamasettings.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:models\\ollamasettings.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\filescannerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\filescannerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\app.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\app.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\models\\llm_model.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:models\\llm_model.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\editor.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\editor.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\models\\modelstatus.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:models\\modelstatus.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\models.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\models.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\iollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\iollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\ifilescannerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\ifilescannerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\data\\appdbcontext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:data\\appdbcontext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css||{A5401142-F49D-43DB-90B1-F57BA349E55C}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css||{A5401142-F49D-43DB-90B1-F57BA349E55C}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\layout\\navmenu.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\layout\\navmenu.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\layout\\mainlayout.razor.css||{A5401142-F49D-43DB-90B1-F57BA349E55C}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\layout\\mainlayout.razor.css||{A5401142-F49D-43DB-90B1-F57BA349E55C}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\projectservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\projectservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\iprojectservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\iprojectservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\models\\project.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:models\\project.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\data\\projectentity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:data\\projectentity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\authorbuddy.web.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:authorbuddy.web.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}"
} }
], ],
"DocumentGroupContainers": [ "DocumentGroupContainers": [
@ -18,19 +114,322 @@
"DocumentGroups": [ "DocumentGroups": [
{ {
"DockedWidth": 200, "DockedWidth": 200,
"SelectedChildIndex": 2, "SelectedChildIndex": 9,
"Children": [ "Children": [
{
"$type": "Bookmark",
"Name": "ST:0:0:{cce594b6-0c39-4442-ba28-10c64ac7e89f}"
},
{ {
"$type": "Bookmark", "$type": "Bookmark",
"Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}" "Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
}, },
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "OllamaSettings.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
"RelativeDocumentMoniker": "Models\\OllamaSettings.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
"RelativeToolTip": "Models\\OllamaSettings.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAQAAAAcAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T13:39:46.179Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "OllamaService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
"RelativeDocumentMoniker": "Services\\OllamaService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
"RelativeToolTip": "Services\\OllamaService.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAdAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T06:43:46.404Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "FileScannerService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
"RelativeDocumentMoniker": "Services\\FileScannerService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
"RelativeToolTip": "Services\\FileScannerService.cs",
"ViewState": "AgIAACkAAAAAAAAAAIAwwEsAAAAfAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T06:02:53.46Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "Settings.razor",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
"RelativeDocumentMoniker": "Components\\Pages\\Settings.razor",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
"RelativeToolTip": "Components\\Pages\\Settings.razor",
"ViewState": "AgIAADcAAAAAAAAAAADwv0wAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
"WhenOpened": "2026-05-15T16:43:26.6Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "SettingsService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\SettingsService.cs",
"RelativeDocumentMoniker": "Services\\SettingsService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\SettingsService.cs",
"RelativeToolTip": "Services\\SettingsService.cs",
"ViewState": "AgIAAEwAAAAAAAAAAAAewFoAAAAnAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T06:05:12.928Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 8,
"Title": "ThemeService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
"RelativeDocumentMoniker": "Services\\ThemeService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
"RelativeToolTip": "Services\\ThemeService.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T13:35:33.991Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "ISettingsService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ISettingsService.cs",
"RelativeDocumentMoniker": "Services\\ISettingsService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ISettingsService.cs*",
"RelativeToolTip": "Services\\ISettingsService.cs*",
"ViewState": "AgIAAAIAAAAAAAAAAAAxwBcAAAAbAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T13:21:26.951Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 14,
"Title": "IOllamaService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IOllamaService.cs",
"RelativeDocumentMoniker": "Services\\IOllamaService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IOllamaService.cs",
"RelativeToolTip": "Services\\IOllamaService.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAkAAAAPAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T07:20:19.212Z",
"EditorCaption": ""
},
{ {
"$type": "Document", "$type": "Document",
"DocumentIndex": 0, "DocumentIndex": 0,
"Title": "MainLayout.razor",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor*",
"RelativeToolTip": "Components\\Layout\\MainLayout.razor*",
"ViewState": "AgIAAG8AAAAAAAAAAAAAAH0AAAAtAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
"WhenOpened": "2026-05-15T16:04:36.444Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 7,
"Title": "Program.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
"RelativeDocumentMoniker": "Program.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
"RelativeToolTip": "Program.cs",
"ViewState": "AgIAAAYAAAAAAAAAAAAAABUAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T06:03:12.506Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 9,
"Title": "App.razor",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\App.razor",
"RelativeDocumentMoniker": "Components\\App.razor",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\App.razor",
"RelativeToolTip": "Components\\App.razor",
"ViewState": "AgIAAAYAAAAAAAAAAAAAABgAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
"WhenOpened": "2026-05-16T05:42:06.383Z",
"EditorCaption": ""
},
{
"$type": "Bookmark",
"Name": "RST:0:0:{b3f9f954-0ca5-0091-76b4-34a47f44c954}"
},
{
"$type": "Document",
"DocumentIndex": 13,
"Title": "Models.razor",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Models.razor",
"RelativeDocumentMoniker": "Components\\Pages\\Models.razor",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Models.razor",
"RelativeToolTip": "Components\\Pages\\Models.razor",
"ViewState": "AgIAAGgAAAAAAAAAAAApwHQAAAAtAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
"WhenOpened": "2026-05-16T12:51:13.798Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 10,
"Title": "LLM_Model.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\LLM_Model.cs",
"RelativeDocumentMoniker": "Models\\LLM_Model.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\LLM_Model.cs",
"RelativeToolTip": "Models\\LLM_Model.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAqwBQAAAAzAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T12:53:35.486Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 12,
"Title": "ModelStatus.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\ModelStatus.cs",
"RelativeDocumentMoniker": "Models\\ModelStatus.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\ModelStatus.cs",
"RelativeToolTip": "Models\\ModelStatus.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABEAAAADAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T13:01:24.508Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 11,
"Title": "Editor.razor",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Editor.razor",
"RelativeDocumentMoniker": "Components\\Pages\\Editor.razor",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Editor.razor",
"RelativeToolTip": "Components\\Pages\\Editor.razor",
"ViewState": "AgIAAFkAAAAAAAAAAAApwGAAAAAOAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
"WhenOpened": "2026-05-16T13:01:59.743Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 19,
"Title": "MainLayout.razor.css",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor.css",
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor.css",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor.css",
"RelativeToolTip": "Components\\Layout\\MainLayout.razor.css",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003000|",
"WhenOpened": "2026-05-15T16:04:50.455Z"
},
{
"$type": "Document",
"DocumentIndex": 18,
"Title": "NavMenu.razor",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\NavMenu.razor",
"RelativeDocumentMoniker": "Components\\Layout\\NavMenu.razor",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\NavMenu.razor",
"RelativeToolTip": "Components\\Layout\\NavMenu.razor",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
"WhenOpened": "2026-05-15T16:04:37.739Z"
},
{
"$type": "Document",
"DocumentIndex": 15,
"Title": "IFileScannerService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IFileScannerService.cs",
"RelativeDocumentMoniker": "Services\\IFileScannerService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IFileScannerService.cs",
"RelativeToolTip": "Services\\IFileScannerService.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAIAAAAeAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T06:02:56.726Z"
},
{
"$type": "Document",
"DocumentIndex": 22,
"Title": "Project.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\Project.cs",
"RelativeDocumentMoniker": "Models\\Project.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\Project.cs",
"RelativeToolTip": "Models\\Project.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAYAAAAaAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-15T15:57:10.2Z"
},
{
"$type": "Document",
"DocumentIndex": 16,
"Title": "AppDbContext.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
"RelativeDocumentMoniker": "Data\\AppDbContext.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
"RelativeToolTip": "Data\\AppDbContext.cs",
"ViewState": "AgIAABoAAAAAAAAAAAAQwD4AAAAIAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-14T10:50:13.284Z"
},
{
"$type": "Document",
"DocumentIndex": 17,
"Title": "bootstrap-utilities.css",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
"RelativeDocumentMoniker": "wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
"RelativeToolTip": "wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
"ViewState": "AgIAAOgIAAAAAAAAAAAAAPYIAAAIAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003000|",
"WhenOpened": "2026-05-15T16:28:43.874Z"
},
{
"$type": "Document",
"DocumentIndex": 20,
"Title": "ProjectService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ProjectService.cs",
"RelativeDocumentMoniker": "Services\\ProjectService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ProjectService.cs",
"RelativeToolTip": "Services\\ProjectService.cs",
"ViewState": "AgIAAB4AAAAAAAAAAAAowAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-15T15:56:55.229Z"
},
{
"$type": "Document",
"DocumentIndex": 23,
"Title": "ProjectEntity.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\ProjectEntity.cs",
"RelativeDocumentMoniker": "Data\\ProjectEntity.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\ProjectEntity.cs",
"RelativeToolTip": "Data\\ProjectEntity.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-14T10:50:06.549Z"
},
{
"$type": "Document",
"DocumentIndex": 21,
"Title": "IProjectService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IProjectService.cs",
"RelativeDocumentMoniker": "Services\\IProjectService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IProjectService.cs",
"RelativeToolTip": "Services\\IProjectService.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAbAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-14T10:46:30.166Z"
},
{
"$type": "Document",
"DocumentIndex": 24,
"Title": "AuthorBuddy.Web.csproj", "Title": "AuthorBuddy.Web.csproj",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\AuthorBuddy.Web.csproj", "DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\AuthorBuddy.Web.csproj",
"RelativeDocumentMoniker": "AuthorBuddy.Web.csproj", "RelativeDocumentMoniker": "AuthorBuddy.Web.csproj",
@ -38,12 +437,11 @@
"RelativeToolTip": "AuthorBuddy.Web.csproj", "RelativeToolTip": "AuthorBuddy.Web.csproj",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|",
"WhenOpened": "2026-05-14T10:14:30.128Z", "WhenOpened": "2026-05-14T10:14:30.128Z"
"EditorCaption": ""
}, },
{ {
"$type": "Document", "$type": "Document",
"DocumentIndex": 1, "DocumentIndex": 25,
"Title": "appsettings.json", "Title": "appsettings.json",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\appsettings.json", "DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\appsettings.json",
"RelativeDocumentMoniker": "appsettings.json", "RelativeDocumentMoniker": "appsettings.json",
@ -51,8 +449,7 @@
"RelativeToolTip": "appsettings.json", "RelativeToolTip": "appsettings.json",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
"WhenOpened": "2026-05-14T10:14:25.605Z", "WhenOpened": "2026-05-14T10:14:25.605Z"
"EditorCaption": ""
} }
] ]
} }

View file

@ -2,6 +2,102 @@
"Version": 1, "Version": 1,
"WorkspaceRootPath": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\", "WorkspaceRootPath": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\",
"Documents": [ "Documents": [
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\models\\ollamasettings.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:models\\ollamasettings.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\settingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\settingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\ollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\ollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\settings.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\settings.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\layout\\mainlayout.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\layout\\mainlayout.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\isettingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\isettingsservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\filescannerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\filescannerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\app.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\app.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\models\\llm_model.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:models\\llm_model.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\editor.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\editor.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\models\\modelstatus.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:models\\modelstatus.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\pages\\models.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\models.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\iollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\iollamaservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\ifilescannerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\ifilescannerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\data\\appdbcontext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:data\\appdbcontext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css||{A5401142-F49D-43DB-90B1-F57BA349E55C}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css||{A5401142-F49D-43DB-90B1-F57BA349E55C}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\layout\\navmenu.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\layout\\navmenu.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\components\\layout\\mainlayout.razor.css||{A5401142-F49D-43DB-90B1-F57BA349E55C}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\layout\\mainlayout.razor.css||{A5401142-F49D-43DB-90B1-F57BA349E55C}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\projectservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\projectservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\services\\iprojectservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\iprojectservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\models\\project.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:models\\project.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\data\\projectentity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:data\\projectentity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{ {
"AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\authorbuddy.web.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}", "AbsoluteMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|e:\\ollama_net\\ollama\\authorbuddy.web\\authorbuddy.web.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}",
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:authorbuddy.web.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}" "RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:authorbuddy.web.csproj||{FA3CD31E-987B-443A-9B81-186104E8DAC1}"
@ -18,15 +114,322 @@
"DocumentGroups": [ "DocumentGroups": [
{ {
"DockedWidth": 200, "DockedWidth": 200,
"SelectedChildIndex": 1, "SelectedChildIndex": 8,
"Children": [ "Children": [
{ {
"$type": "Bookmark", "$type": "Bookmark",
"Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}" "Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
}, },
{
"$type": "Bookmark",
"Name": "RST:0:0:{b3f9f954-0ca5-0091-76b4-34a47f44c954}"
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "OllamaService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
"RelativeDocumentMoniker": "Services\\OllamaService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
"RelativeToolTip": "Services\\OllamaService.cs",
"ViewState": "AgIAACMAAAAAAAAAAAAwwAAAAAAdAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T06:43:46.404Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "Settings.razor",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
"RelativeDocumentMoniker": "Components\\Pages\\Settings.razor",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
"RelativeToolTip": "Components\\Pages\\Settings.razor",
"ViewState": "AgIAAF8AAAAAAAAAAADwv3EAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
"WhenOpened": "2026-05-15T16:43:26.6Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "SettingsService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\SettingsService.cs",
"RelativeDocumentMoniker": "Services\\SettingsService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\SettingsService.cs",
"RelativeToolTip": "Services\\SettingsService.cs",
"ViewState": "AgIAAEoAAAAAAAAAAAAAAGUAAAA7AAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T06:05:12.928Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 8,
"Title": "ThemeService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
"RelativeDocumentMoniker": "Services\\ThemeService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
"RelativeToolTip": "Services\\ThemeService.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T13:35:33.991Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "ISettingsService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ISettingsService.cs",
"RelativeDocumentMoniker": "Services\\ISettingsService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ISettingsService.cs",
"RelativeToolTip": "Services\\ISettingsService.cs",
"ViewState": "AgIAAAIAAAAAAAAAAAAxwBcAAAAbAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T13:21:26.951Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "MainLayout.razor",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
"RelativeToolTip": "Components\\Layout\\MainLayout.razor",
"ViewState": "AgIAAG8AAAAAAAAAAAAAAH0AAAAtAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
"WhenOpened": "2026-05-15T16:04:36.444Z",
"EditorCaption": ""
},
{ {
"$type": "Document", "$type": "Document",
"DocumentIndex": 0, "DocumentIndex": 0,
"Title": "OllamaSettings.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
"RelativeDocumentMoniker": "Models\\OllamaSettings.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
"RelativeToolTip": "Models\\OllamaSettings.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAqwBMAAAAgAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T13:39:46.179Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "FileScannerService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
"RelativeDocumentMoniker": "Services\\FileScannerService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
"RelativeToolTip": "Services\\FileScannerService.cs",
"ViewState": "AgIAACkAAAAAAAAAAIAwwEsAAAAfAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T06:02:53.46Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 14,
"Title": "IOllamaService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IOllamaService.cs",
"RelativeDocumentMoniker": "Services\\IOllamaService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IOllamaService.cs",
"RelativeToolTip": "Services\\IOllamaService.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAkAAAAPAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T07:20:19.212Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 7,
"Title": "Program.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
"RelativeDocumentMoniker": "Program.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
"RelativeToolTip": "Program.cs",
"ViewState": "AgIAAAYAAAAAAAAAAAAAABUAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T06:03:12.506Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 9,
"Title": "App.razor",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\App.razor",
"RelativeDocumentMoniker": "Components\\App.razor",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\App.razor",
"RelativeToolTip": "Components\\App.razor",
"ViewState": "AgIAAAYAAAAAAAAAAAAAABgAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
"WhenOpened": "2026-05-16T05:42:06.383Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 13,
"Title": "Models.razor",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Models.razor",
"RelativeDocumentMoniker": "Components\\Pages\\Models.razor",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Models.razor",
"RelativeToolTip": "Components\\Pages\\Models.razor",
"ViewState": "AgIAAGgAAAAAAAAAAAApwHQAAAAtAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
"WhenOpened": "2026-05-16T12:51:13.798Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 10,
"Title": "LLM_Model.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\LLM_Model.cs",
"RelativeDocumentMoniker": "Models\\LLM_Model.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\LLM_Model.cs",
"RelativeToolTip": "Models\\LLM_Model.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAqwBQAAAAzAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T12:53:35.486Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 12,
"Title": "ModelStatus.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\ModelStatus.cs",
"RelativeDocumentMoniker": "Models\\ModelStatus.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\ModelStatus.cs",
"RelativeToolTip": "Models\\ModelStatus.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABEAAAADAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T13:01:24.508Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 11,
"Title": "Editor.razor",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Editor.razor",
"RelativeDocumentMoniker": "Components\\Pages\\Editor.razor",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Editor.razor",
"RelativeToolTip": "Components\\Pages\\Editor.razor",
"ViewState": "AgIAAFkAAAAAAAAAAAApwGAAAAAOAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
"WhenOpened": "2026-05-16T13:01:59.743Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 19,
"Title": "MainLayout.razor.css",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor.css",
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor.css",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor.css",
"RelativeToolTip": "Components\\Layout\\MainLayout.razor.css",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003000|",
"WhenOpened": "2026-05-15T16:04:50.455Z"
},
{
"$type": "Document",
"DocumentIndex": 18,
"Title": "NavMenu.razor",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\NavMenu.razor",
"RelativeDocumentMoniker": "Components\\Layout\\NavMenu.razor",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\NavMenu.razor",
"RelativeToolTip": "Components\\Layout\\NavMenu.razor",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
"WhenOpened": "2026-05-15T16:04:37.739Z"
},
{
"$type": "Document",
"DocumentIndex": 15,
"Title": "IFileScannerService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IFileScannerService.cs",
"RelativeDocumentMoniker": "Services\\IFileScannerService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IFileScannerService.cs",
"RelativeToolTip": "Services\\IFileScannerService.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAIAAAAeAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-16T06:02:56.726Z"
},
{
"$type": "Document",
"DocumentIndex": 22,
"Title": "Project.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\Project.cs",
"RelativeDocumentMoniker": "Models\\Project.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\Project.cs",
"RelativeToolTip": "Models\\Project.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAYAAAAaAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-15T15:57:10.2Z"
},
{
"$type": "Document",
"DocumentIndex": 16,
"Title": "AppDbContext.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
"RelativeDocumentMoniker": "Data\\AppDbContext.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
"RelativeToolTip": "Data\\AppDbContext.cs",
"ViewState": "AgIAABoAAAAAAAAAAAAQwD4AAAAIAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-14T10:50:13.284Z"
},
{
"$type": "Document",
"DocumentIndex": 17,
"Title": "bootstrap-utilities.css",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
"RelativeDocumentMoniker": "wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
"RelativeToolTip": "wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
"ViewState": "AgIAAOgIAAAAAAAAAAAAAPYIAAAIAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003000|",
"WhenOpened": "2026-05-15T16:28:43.874Z"
},
{
"$type": "Document",
"DocumentIndex": 20,
"Title": "ProjectService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ProjectService.cs",
"RelativeDocumentMoniker": "Services\\ProjectService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ProjectService.cs",
"RelativeToolTip": "Services\\ProjectService.cs",
"ViewState": "AgIAAB4AAAAAAAAAAAAowAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-15T15:56:55.229Z"
},
{
"$type": "Document",
"DocumentIndex": 23,
"Title": "ProjectEntity.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\ProjectEntity.cs",
"RelativeDocumentMoniker": "Data\\ProjectEntity.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\ProjectEntity.cs",
"RelativeToolTip": "Data\\ProjectEntity.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-14T10:50:06.549Z"
},
{
"$type": "Document",
"DocumentIndex": 21,
"Title": "IProjectService.cs",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IProjectService.cs",
"RelativeDocumentMoniker": "Services\\IProjectService.cs",
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IProjectService.cs",
"RelativeToolTip": "Services\\IProjectService.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAbAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-05-14T10:46:30.166Z"
},
{
"$type": "Document",
"DocumentIndex": 24,
"Title": "AuthorBuddy.Web.csproj", "Title": "AuthorBuddy.Web.csproj",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\AuthorBuddy.Web.csproj", "DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\AuthorBuddy.Web.csproj",
"RelativeDocumentMoniker": "AuthorBuddy.Web.csproj", "RelativeDocumentMoniker": "AuthorBuddy.Web.csproj",
@ -34,12 +437,11 @@
"RelativeToolTip": "AuthorBuddy.Web.csproj", "RelativeToolTip": "AuthorBuddy.Web.csproj",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000758|",
"WhenOpened": "2026-05-14T10:14:30.128Z", "WhenOpened": "2026-05-14T10:14:30.128Z"
"EditorCaption": ""
}, },
{ {
"$type": "Document", "$type": "Document",
"DocumentIndex": 1, "DocumentIndex": 25,
"Title": "appsettings.json", "Title": "appsettings.json",
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\appsettings.json", "DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\appsettings.json",
"RelativeDocumentMoniker": "appsettings.json", "RelativeDocumentMoniker": "appsettings.json",

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
@ -10,7 +10,6 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.5" /> <PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.8" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.8" />
<PackageReference Include="Ollama" Version="1.15.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -15,9 +15,11 @@
</head> </head>
<body> <body>
<Routes /> <Routes @rendermode="InteractiveServer" />
<ReconnectModal /> <ReconnectModal />
<script src="@Assets["_framework/blazor.web.js"]"></script> <script src="@Assets["_framework/blazor.web.js"]"></script>
</body> </body>
</html> </html>

View file

@ -1,5 +1,8 @@
@inherits LayoutComponentBase @inherits LayoutComponentBase
@inject IProjectService ProjectService @inject IProjectService ProjectService
@inject ISettingsService SettingsService
@inject IThemeService ThemeService
@inject OllamaSettings OllamaSettings
<div class="page"> <div class="page">
<div class="main-content"> <div class="main-content">
@ -115,6 +118,17 @@
await LoadProjects(); await LoadProjects();
} }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await SettingsService.InitializeAsync();
var theme = OllamaSettings.Theme;
if (!string.IsNullOrEmpty(theme))
await ThemeService.ApplyTheme(theme);
}
}
private async Task LoadProjects() private async Task LoadProjects()
{ {
try try

View file

@ -70,7 +70,7 @@
try try
{ {
analysisResult = await OllamaService.StreamStyleCheckAsync(editorContent); //analysisResult = await OllamaService.StreamStyleCheckAsync(editorContent);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -94,7 +94,7 @@
try try
{ {
analysisResult = await OllamaService.QuickSpellCheckAsync(editorContent); //analysisResult = await OllamaService.QuickSpellCheckAsync(editorContent);
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -1,7 +1,7 @@
@page "/models" @page "/models"
@inject IOllamaService OllamaService @inject IOllamaService OllamaService
@inject NavigationManager Navigation @inject NavigationManager Navigation
@using Ollama
<PageTitle>Modelle - Author Buddy</PageTitle> <PageTitle>Modelle - Author Buddy</PageTitle>
@ -24,7 +24,7 @@ else
@foreach (var model in localModels) @foreach (var model in localModels)
{ {
<div class="model-card"> <div class="model-card">
<div class="model-name">@model.Model1</div> <div class="model-name">@model.Name</div>
<div class="model-details"> <div class="model-details">
Größe: @FormatSize(model.Size) | Größe: @FormatSize(model.Size) |
Geändert: @model.ModifiedAt?.ToString("g") Geändert: @model.ModifiedAt?.ToString("g")
@ -64,7 +64,7 @@ else
} }
@code { @code {
private List<Ollama.Model> localModels = new(); private List<LLM_Model> localModels = new();
private bool isLoading; private bool isLoading;
private string? errorMessage; private string? errorMessage;
private string modelToPull = string.Empty; private string modelToPull = string.Empty;
@ -111,10 +111,9 @@ else
try try
{ {
var progress = new Progress<ModelStatus>(status => var progress = new Progress<string>(status =>
{ {
pullProgress = status.Progress; pullStatus = status;
pullStatus = status.Status;
InvokeAsync(StateHasChanged); InvokeAsync(StateHasChanged);
}); });

View file

@ -1,7 +1,7 @@
@page "/settings" @page "/settings"
@inject IDbContextFactory<AppDbContext> ContextFactory @inject ISettingsService SettingsService
@inject IThemeService ThemeService
@inject IOllamaService OllamaService @inject IOllamaService OllamaService
@inject OllamaSettings OllamaConfig
@inject NavigationManager Navigation @inject NavigationManager Navigation
@inject IJSRuntime JSRuntime @inject IJSRuntime JSRuntime
@inject IProjectService ProjectService @inject IProjectService ProjectService
@ -10,6 +10,9 @@
<div class="settings-page"> <div class="settings-page">
<div class="settings-layout">
<div class="settings-layout-left">
<div class="settings-section"> <div class="settings-section">
<h3 class="settings-section-title">Modelle</h3> <h3 class="settings-section-title">Modelle</h3>
<div class="form-group"> <div class="form-group">
@ -21,7 +24,7 @@
} }
@foreach (var m in availableModels) @foreach (var m in availableModels)
{ {
<option value="@m.Model1">@m.Model1</option> <option value="@m.Name">@m.Name</option>
} }
</select> </select>
</div> </div>
@ -34,7 +37,7 @@
} }
@foreach (var m in availableModels) @foreach (var m in availableModels)
{ {
<option value="@m.Model1">@m.Model1</option> <option value="@m.Name">@m.Name</option>
} }
</select> </select>
</div> </div>
@ -47,7 +50,7 @@
} }
@foreach (var m in availableModels) @foreach (var m in availableModels)
{ {
<option value="@m.Model1">@m.Model1</option> <option value="@m.Name">@m.Name</option>
} }
</select> </select>
</div> </div>
@ -73,50 +76,70 @@
</select> </select>
</div> </div>
</div> </div>
</div>
<div class="settings-layout-right">
<div class="settings-section">
<h3 class="settings-section-title">Lektor-System-Prompt</h3>
<div class="form-group">
<textarea id="lektorPrompt" @bind="lektorPrompt" rows="6"></textarea>
</div>
</div>
<div class="settings-section"> <div class="settings-section">
<h3 class="settings-section-title">Neues Projekt</h3> <h3 class="settings-section-title">Fact-Check-Vorlage</h3>
<div class="form-group"> <div class="form-group">
<label for="projectName">Projektname:</label> <textarea id="factCheckTemplate" @bind="factCheckTemplate" rows="6"></textarea>
<input id="projectName" @bind="newProjectName" placeholder="Projektname" />
<div class="form-hint">Der Projektordner wird in &quot;Dokumente\AuthorBuddy\&quot; erstellt.</div>
</div> </div>
<button @onclick="CreateProject" disabled="@(string.IsNullOrWhiteSpace(newProjectName))">Projekt erstellen</button>
</div> </div>
<div class="form-actions"> <div class="settings-section">
<button class="primary" @onclick="SaveSettings">Speichern</button> <h3 class="settings-section-title">Rechtschreibprüfungs-Prompt</h3>
<button @onclick='() => Navigation.NavigateTo("/")'>Abbrechen</button> <div class="form-group">
<textarea id="spellingPrompt" @bind="spellingPrompt" rows="6"></textarea>
</div>
</div>
</div> </div>
</div>
<div class="settings-actions">
<button class="btn btn-primary" @onclick="SaveSettings">Speichern</button>
@if (!string.IsNullOrEmpty(statusMessage)) @if (!string.IsNullOrEmpty(statusMessage))
{ {
<div class="settings-status">@statusMessage</div> <span class="settings-status">@statusMessage</span>
} }
</div> </div>
</div>
@code { @code {
private string ragModel = "llama3.2"; private string ragModel = "llama3.2";
private string styleModel = "llama3.2"; private string styleModel = "llama3.2";
private string spellingModel = "phi3:mini"; private string spellingModel = "phi3:mini";
private string selectedTheme = "light"; private string selectedTheme = "light";
private string ollamaUrl = "http://localhost:11434"; private string ollamaUrl = "http://localhost:11434";
private string lektorPrompt = string.Empty;
private string factCheckTemplate = string.Empty;
private string spellingPrompt = string.Empty;
private string newProjectName = string.Empty; private string newProjectName = string.Empty;
private string statusMessage = string.Empty; private string statusMessage = string.Empty;
private List<Ollama.Model> availableModels = new(); private List<LLM_Model> availableModels = new();
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
await using var context = await ContextFactory.CreateDbContextAsync(); ragModel = await SettingsService.GetRagModelAsync() ?? "llama3.2";
styleModel = await SettingsService.GetStyleModelAsync() ?? "llama3.2";
ragModel = await GetSettingAsync(context, "ollama_rag_model") ?? "llama3.2"; spellingModel = await SettingsService.GetSpellingModelAsync() ?? "phi3:mini";
styleModel = await GetSettingAsync(context, "ollama_style_model") ?? "llama3.2"; selectedTheme = await SettingsService.GetThemeAsync() ?? "light";
spellingModel = await GetSettingAsync(context, "ollama_spelling_model") ?? "phi3:mini"; ollamaUrl = await SettingsService.GetOllamaUrlAsync() ?? "http://localhost:11434";
selectedTheme = await GetSettingAsync(context, "theme") ?? "light"; lektorPrompt = await SettingsService.GetLektorSystemPromptAsync() ?? string.Empty;
ollamaUrl = await GetSettingAsync(context, "ollama_url") ?? "http://localhost:11434"; factCheckTemplate = await SettingsService.GetFactCheckTemplateAsync() ?? string.Empty;
spellingPrompt = await SettingsService.GetSpellingPromptAsync() ?? string.Empty;
try try
{ {
var models = await OllamaService.GetLocalModelsAsync(); var models = await OllamaService.GetLocalModelsAsync();
availableModels = models.ToList(); availableModels = models.ToList();
} }
@ -126,75 +149,22 @@
} }
} }
private static async Task<string?> GetSettingAsync(AppDbContext context, string key)
{
var setting = await context.Settings.FindAsync(key);
return setting?.Value;
}
private static async Task SaveSettingAsync(AppDbContext context, string key, string value)
{
var existing = await context.Settings.FindAsync(key);
if (existing != null)
{
existing.Value = value;
}
else
{
context.Settings.Add(new SettingEntity { Key = key, Value = value });
}
}
private async Task SaveSettings() private async Task SaveSettings()
{ {
await using var context = await ContextFactory.CreateDbContextAsync(); await SettingsService.SaveOllamaUrlAsync(ollamaUrl);
await SettingsService.SaveRagModelAsync(ragModel);
await SaveSettingAsync(context, "ollama_rag_model", ragModel); await SettingsService.SaveStyleModelAsync(styleModel);
await SaveSettingAsync(context, "ollama_style_model", styleModel); await SettingsService.SaveSpellingModelAsync(spellingModel);
await SaveSettingAsync(context, "ollama_spelling_model", spellingModel); await SettingsService.SaveThemeAsync(selectedTheme);
await SaveSettingAsync(context, "theme", selectedTheme); await SettingsService.SaveLektorSystemPromptAsync(lektorPrompt);
await SaveSettingAsync(context, "ollama_url", ollamaUrl); await SettingsService.SaveFactCheckTemplateAsync(factCheckTemplate);
await SettingsService.SaveSpellingPromptAsync(spellingPrompt);
await context.SaveChangesAsync(); OllamaService.Reconfigure(ollamaUrl);
OllamaConfig.OllamaUrl = ollamaUrl;
OllamaConfig.ChatModel = ragModel;
OllamaConfig.SpellingModel = spellingModel;
await OllamaService.ReconfigureAsync(ollamaUrl);
statusMessage = "Einstellungen gespeichert."; statusMessage = "Einstellungen gespeichert.";
await ApplyTheme(selectedTheme); await ThemeService.ApplyTheme(selectedTheme);
} }
private async Task CreateProject()
{
if (string.IsNullOrWhiteSpace(newProjectName)) return;
try
{
string rootPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"AuthorBuddy",
newProjectName);
await ProjectService.CreateNewProjectAsync(newProjectName, rootPath);
statusMessage = $"Projekt '{newProjectName}' erstellt unter: {rootPath}";
newProjectName = string.Empty;
}
catch (Exception ex)
{
statusMessage = $"Fehler beim Erstellen: {ex.Message}";
}
}
private async Task ApplyTheme(string theme)
{
await JSRuntime.InvokeVoidAsync("eval",
$"document.getElementById('theme-css')?.remove(); " +
$"var link = document.createElement('link'); " +
$"link.id = 'theme-css'; " +
$"link.rel = 'stylesheet'; " +
$"link.href = 'css/themes/{theme}.css'; " +
$"document.head.appendChild(link);");
}
} }

View file

@ -19,7 +19,7 @@ public class AppDbContext : DbContext
entity.HasKey(e => e.Id); entity.HasKey(e => e.Id);
entity.Property(e => e.Name).IsRequired(); entity.Property(e => e.Name).IsRequired();
entity.Property(e => e.RootPath).IsRequired(); entity.Property(e => e.RootPath).IsRequired();
entity.Property(e => e.LastOpened).HasColumnName("last_opened"); entity.Property(e => e.LastOpened);
}); });
modelBuilder.Entity<SettingEntity>(entity => modelBuilder.Entity<SettingEntity>(entity =>
@ -65,8 +65,8 @@ public class AppDbContext : DbContext
CREATE TABLE IF NOT EXISTS Projects ( CREATE TABLE IF NOT EXISTS Projects (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL, name TEXT NOT NULL,
root_path TEXT NOT NULL, RootPath TEXT NOT NULL,
last_opened DATETIME LastOpened DATETIME
); );
CREATE TABLE IF NOT EXISTS Settings ( CREATE TABLE IF NOT EXISTS Settings (
key TEXT NOT NULL UNIQUE, key TEXT NOT NULL UNIQUE,

30
Models/LLM_Model.cs Normal file
View file

@ -0,0 +1,30 @@
using System.Text.Json;
namespace AuthorBuddy.Web.Models
{
public class LLM_Model
{
public LLM_Model(JsonElement model)
{
if (model.TryGetProperty("name", out var name))
{
Name = name.GetString() ?? "" ;
}
if (model.TryGetProperty("size", out var size))
{
Size = size.GetInt64();
}
if (model.TryGetProperty("modified_at", out var modified))
{
ModifiedAt = modified.GetDateTime();
}
}
public string Name { get; set; } = string.Empty;
public long Size { get; set; }
public DateTime? ModifiedAt { get; set; }
}
}

View file

@ -1,18 +1,18 @@
using Ollama;
namespace AuthorBuddy.Web.Models;
public class ModelStatus //namespace AuthorBuddy.Web.Models;
{
public string Status { get; private set; } = "Unknown";
public double Progress { get; private set; }
public void SetModelStatus(PullModelResponse modelResponse) //public class ModelStatus
{ //{
if (modelResponse.Total > 0 && modelResponse.Completed.HasValue && modelResponse.Completed > 0) // public string Status { get; private set; } = "Unknown";
{ // public double Progress { get; private set; }
Progress = (double)modelResponse.Completed.Value / (double)modelResponse.Total * 100;
Status = modelResponse.Status?.ToString() ?? "Unknown"; // public void SetModelStatus(PullModelResponse modelResponse)
} // {
} // if (modelResponse.Total > 0 && modelResponse.Completed.HasValue && modelResponse.Completed > 0)
} // {
// Progress = (double)modelResponse.Completed.Value / (double)modelResponse.Total * 100;
// Status = modelResponse.Status?.ToString() ?? "Unknown";
// }
// }
//}

View file

@ -2,18 +2,18 @@ namespace AuthorBuddy.Web.Models;
public class OllamaSettings public class OllamaSettings
{ {
public string ChatModel { get; set; } = "llama3.2"; public string StyleModel { get; set; } = "llama3.2";
public string EmbedModel { get; set; } = "mxbai-embed-large"; public string EmbedModel { get; set; } = "mxbai-embed-large";
public string SpellingModel { get; set; } = "phi3:mini"; public string SpellingModel { get; set; } = "phi3:mini";
public string OllamaUrl { get; set; } = "http://localhost:11434"; public string OllamaUrl { get; set; } = "http://localhost:11434";
public string Theme { get; set; } = "light"; public string Theme { get; set; } = "light";
public string LektorSystemPrompt { get; private set; } = "Du bist ein erfahrener Lektor. Analysiere den Text des Autors. " + public string LektorSystemPrompt { get; set; } = "Du bist ein erfahrener Lektor. Analysiere den Text des Autors. " +
"Optimiere ihn auf einen lebendigen, anschaulichen und subjektiven Stil. " + "Optimiere ihn auf einen lebendigen, anschaulichen und subjektiven Stil. " +
"Nutze starke Verben, vermeide unnötige Adjektive und achte auf 'Show, don't tell'. " + "Nutze starke Verben, vermeide unnötige Adjektive und achte auf 'Show, don't tell'. " +
"Antworte direkt mit dem verbesserten Text oder konkreten Vorschlägen."; "Antworte direkt mit dem verbesserten Text oder konkreten Vorschlägen.";
private string FactCheckTemplate { get; set; } = "FAKTEN AUS DER DATENBANK:\n{0}\n\n" + public string FactCheckTemplate { get; set; } = "FAKTEN AUS DER DATENBANK:\n{0}\n\n" +
"FRAGE / KONTEXT:\n{1}\n\n" + "FRAGE / KONTEXT:\n{1}\n\n" +
"Basierend auf den Fakten, schreibe eine kurze, lebendige Ergänzung oder Korrektur."; "Basierend auf den Fakten, schreibe eine kurze, lebendige Ergänzung oder Korrektur.";

View file

@ -12,6 +12,8 @@ builder.Services.AddRazorComponents()
builder.Services.AddSingleton<OllamaSettings>(); builder.Services.AddSingleton<OllamaSettings>();
builder.Services.AddSingleton<IOllamaService, OllamaService>(); builder.Services.AddSingleton<IOllamaService, OllamaService>();
builder.Services.AddSingleton<IFileScannerService, FileScannerService>(); builder.Services.AddSingleton<IFileScannerService, FileScannerService>();
builder.Services.AddSingleton<ISettingsService, SettingsService>();
builder.Services.AddScoped<IThemeService, ThemeService>();
builder.Services.AddSingleton<IProjectService, ProjectService>(); builder.Services.AddSingleton<IProjectService, ProjectService>();
builder.Services.AddDbContextFactory<AppDbContext>(options => builder.Services.AddDbContextFactory<AppDbContext>(options =>

View file

@ -53,7 +53,7 @@ public class FileScannerService : IFileScannerService
{ {
string content = await File.ReadAllTextAsync(path); string content = await File.ReadAllTextAsync(path);
var vector = await _ollama.GetEmbeddingAsync(content); //var vector = await _ollama.GetEmbeddingAsync(content);
using var connection = new SqliteConnection(_connectionString); using var connection = new SqliteConnection(_connectionString);
connection.Open(); connection.Open();
@ -73,7 +73,7 @@ public class FileScannerService : IFileScannerService
var docId = await cmdMeta.ExecuteScalarAsync(); var docId = await cmdMeta.ExecuteScalarAsync();
byte[] blob = ConvertVectorToBytes(vector); byte[] blob = [];// ConvertVectorToBytes(vector);
var cmdVec = connection.CreateCommand(); var cmdVec = connection.CreateCommand();
cmdVec.CommandText = "INSERT INTO vec_documents(rowid, embedding) VALUES (@id, @vec) " + cmdVec.CommandText = "INSERT INTO vec_documents(rowid, embedding) VALUES (@id, @vec) " +
"ON CONFLICT(rowid) DO UPDATE SET embedding = @vec;"; "ON CONFLICT(rowid) DO UPDATE SET embedding = @vec;";

View file

@ -1,15 +1,17 @@
using AuthorBuddy.Web.Models; using AuthorBuddy.Web.Models;
using Ollama;
namespace AuthorBuddy.Web.Services; namespace AuthorBuddy.Web.Services;
public interface IOllamaService public interface IOllamaService
{ {
Task<IEnumerable<Model>> GetLocalModelsAsync(); Task<IEnumerable<LLM_Model>> GetLocalModelsAsync();
Task PullModelAsync(string modelName, IProgress<ModelStatus> progress); Task<bool> PullModelAsync(string modelName, IProgress<string> progress);
Task<IList<double>> GetEmbeddingAsync(string text); //Task<IList<double>> GetEmbeddingAsync(string text);
Task<string> StreamStyleCheckAsync(string input); //Task<string> StreamStyleCheckAsync(string input);
Task<string> AnswerBasedOnFactsAsync(string question, string facts); //Task<string> AnswerBasedOnFactsAsync(string question, string facts);
Task<string> QuickSpellCheckAsync(string text); //Task<string> QuickSpellCheckAsync(string text);
Task ReconfigureAsync(string ollamaUrl); void Reconfigure(string ollamaUrl);
} }

View file

@ -0,0 +1,25 @@
namespace AuthorBuddy.Web.Services;
public interface ISettingsService
{
Task<string?> GetOllamaUrlAsync();
Task<string?> GetRagModelAsync();
Task<string?> GetStyleModelAsync();
Task<string?> GetSpellingModelAsync();
Task<string?> GetThemeAsync();
Task SaveOllamaUrlAsync(string url);
Task SaveRagModelAsync(string model);
Task SaveStyleModelAsync(string model);
Task SaveSpellingModelAsync(string model);
Task SaveThemeAsync(string theme);
Task<string?> GetLektorSystemPromptAsync();
Task<string?> GetFactCheckTemplateAsync();
Task<string?> GetSpellingPromptAsync();
Task SaveLektorSystemPromptAsync(string prompt);
Task SaveFactCheckTemplateAsync(string prompt);
Task SaveSpellingPromptAsync(string prompt);
Task InitializeAsync();
}

View file

@ -0,0 +1,6 @@
namespace AuthorBuddy.Web.Services;
public interface IThemeService
{
Task ApplyTheme(string theme);
}

View file

@ -1,84 +1,218 @@
using AuthorBuddy.Web.Models; using AuthorBuddy.Web.Models;
using Ollama; using System.Text.Json;
namespace AuthorBuddy.Web.Services; namespace AuthorBuddy.Web.Services;
public class OllamaService : IOllamaService, IDisposable public class OllamaService : IOllamaService
{ {
private readonly OllamaSettings _settings; private readonly HttpClient _httpClient;
private OllamaApiClient? _client; private string _baseUrl = "http://localhost:11434";
private string _currentUrl = "http://localhost:11434";
public OllamaService(OllamaSettings settings) public OllamaService()
{ {
_settings = settings; _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(300) };
_currentUrl = settings.OllamaUrl;
_client = new OllamaApiClient(baseUri: new Uri(_currentUrl));
} }
public Task ReconfigureAsync(string ollamaUrl) public void Reconfigure(string url)
{ {
if (_currentUrl != ollamaUrl) _baseUrl = url;
{
_currentUrl = ollamaUrl;
_client?.Dispose();
_client = new OllamaApiClient(baseUri: new Uri(ollamaUrl));
}
return Task.CompletedTask;
} }
private OllamaApiClient Client => _client ??= new OllamaApiClient(baseUri: new Uri(_currentUrl)); public async Task<IEnumerable<LLM_Model>> GetLocalModelsAsync()
public async Task<IEnumerable<Model>> GetLocalModelsAsync()
{ {
var models = await Client.Models.ListModelsAsync(); try
return models.Models ?? Enumerable.Empty<Ollama.Model>(); {
var response = await _httpClient.GetAsync($"{_baseUrl}/api/tags");
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(content);
var root = doc.RootElement;
if (root.TryGetProperty("models", out var models))
{
var modelList = new List<LLM_Model>();
foreach (var model in models.EnumerateArray())
{
modelList.Add(new LLM_Model(model));
} }
return modelList;
public async Task PullModelAsync(string modelName, IProgress<ModelStatus> progress) }
}
return new List<LLM_Model>();
}
catch (Exception)
{ {
var p = new ModelStatus(); return new List<LLM_Model>();
await foreach (var response in Client.Models.PullModelAsync(modelName))
{
p.SetModelStatus(response);
progress?.Report(p);
} }
} }
public async Task<IList<double>> GetEmbeddingAsync(string text) public async Task<string> Chat(string model, string userMessage, string? systemPrompt = null)
{ {
var response = await Client.Embeddings.GenerateEmbeddingAsync( try
model: _settings.EmbedModel, {
prompt: text); var request = new
return response.Embedding ?? Array.Empty<double>(); {
model = model,
prompt = userMessage,
stream = false
};
var response = await _httpClient.PostAsJsonAsync($"{_baseUrl}/api/generate", request);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(content);
var root = doc.RootElement;
if (root.TryGetProperty("response", out var responseText))
{
return responseText.GetString() ?? "";
}
}
return "Fehler bei der Verarbeitung.";
}
catch (Exception ex)
{
return $"Error: {ex.Message}";
}
} }
public async Task<string> StreamStyleCheckAsync(string input) public async IAsyncEnumerable<string> ChatStream(string model, string userMessage, string? systemPrompt = null)
{ {
var systemPrompt = _settings.LektorSystemPrompt; var request = new
var chat = Client.Chat(_settings.ChatModel, systemPrompt); {
var message = await chat.SendAsync(input); model = model,
return message.Content; prompt = userMessage,
stream = true
};
HttpResponseMessage? response = null;
try
{
response = await _httpClient.PostAsync(
$"{_baseUrl}/api/generate",
new StringContent(JsonSerializer.Serialize(request), System.Text.Encoding.UTF8, "application/json")
);
if (response.IsSuccessStatusCode)
{
using var stream = await response.Content.ReadAsStreamAsync();
using var reader = new StreamReader(stream);
string? line;
while ((line = await reader.ReadLineAsync()) != null)
{
var text = ExtractResponseText(line);
if (!string.IsNullOrEmpty(text))
{
yield return text;
}
}
}
}
finally
{
response?.Dispose();
}
} }
public async Task<string> AnswerBasedOnFactsAsync(string question, string facts) private string ExtractResponseText(string jsonLine)
{ {
var prompt = _settings.GetFactCheckPrompt(question, facts); if (string.IsNullOrWhiteSpace(jsonLine))
var chat = Client.Chat(_settings.ChatModel); return string.Empty;
var message = await chat.SendAsync(prompt);
return message.Content; try
{
using var doc = JsonDocument.Parse(jsonLine);
var root = doc.RootElement;
if (root.TryGetProperty("response", out var responseText))
{
return responseText.GetString() ?? string.Empty;
}
}
catch { }
return string.Empty;
} }
public async Task<string> QuickSpellCheckAsync(string text) public async Task<bool> DeleteModel(string modelName)
{ {
var systemPrompt = _settings.SpellingPrompt; try
var chat = Client.Chat(_settings.SpellingModel, systemPrompt); {
var message = await chat.SendAsync(text); var request = new HttpRequestMessage(HttpMethod.Delete, $"{_baseUrl}/api/delete");
return message.Content; request.Content = new StringContent(JsonSerializer.Serialize(new { name = modelName }),
System.Text.Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
return response.IsSuccessStatusCode;
}
catch (Exception)
{
return false;
}
} }
public void Dispose() public async Task<bool> PullModelAsync(string modelName, IProgress<string> progress)
{ {
_client?.Dispose(); try
{
var request = new { name = modelName, stream = true };
var response = await _httpClient.PostAsync(
$"{_baseUrl}/api/pull",
new StringContent(JsonSerializer.Serialize(request), System.Text.Encoding.UTF8, "application/json")
);
if (response.IsSuccessStatusCode)
{
using var stream = await response.Content.ReadAsStreamAsync();
using var reader = new StreamReader(stream);
string? line;
while ((line = await reader.ReadLineAsync()) != null)
{
if (string.IsNullOrWhiteSpace(line)) continue;
try
{
using var doc = JsonDocument.Parse(line);
var root = doc.RootElement;
if (root.TryGetProperty("status", out var status))
{
var statusText = status.GetString() ?? "";
var msg = statusText;
if (root.TryGetProperty("completed", out var completed) &&
root.TryGetProperty("total", out var total))
{
var comp = completed.GetInt64();
var tot = total.GetInt64();
if (tot > 0)
{
var pct = (int)(comp * 100 / tot);
msg = $"{statusText}: {comp}/{tot} ({pct}%)";
}
}
progress?.Report(msg);
if (statusText == "success")
return true;
}
}
catch { }
}
}
return false;
}
catch (Exception)
{
return false;
}
} }
} }

139
Services/SettingsService.cs Normal file
View file

@ -0,0 +1,139 @@
using AuthorBuddy.Web.Data;
using AuthorBuddy.Web.Models;
using Microsoft.EntityFrameworkCore;
namespace AuthorBuddy.Web.Services;
public class SettingsService : ISettingsService
{
private const string KeyOllamaUrl = "ollama_url";
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 readonly IDbContextFactory<AppDbContext> _contextFactory;
private readonly OllamaSettings _ollamaConfig;
public SettingsService(IDbContextFactory<AppDbContext> contextFactory, OllamaSettings ollamaConfig)
{
_contextFactory = contextFactory;
_ollamaConfig = ollamaConfig;
}
private async Task<string?> GetAsync(string key)
{
await using var context = await _contextFactory.CreateDbContextAsync();
var setting = await context.Settings.FindAsync(key);
return setting?.Value;
}
public Task<string?> GetOllamaUrlAsync() => GetAsync(KeyOllamaUrl);
public Task<string?> GetRagModelAsync() => GetAsync(KeyRagModel);
public Task<string?> GetStyleModelAsync() => GetAsync(KeyStyleModel);
public Task<string?> GetLektorSystemPromptAsync() => GetAsync(KeyLektorPrompt);
public Task<string?> GetFactCheckTemplateAsync() => GetAsync(KeyFactCheckTemplate);
public Task<string?> GetSpellingPromptAsync() => GetAsync(KeySpellingPrompt);
public Task<string?> GetSpellingModelAsync() => GetAsync(KeySpellingModel);
public Task<string?> GetThemeAsync() => GetAsync(KeyTheme);
private async Task SetAsync(string key, string value)
{
await using var context = await _contextFactory.CreateDbContextAsync();
var existing = await context.Settings.FindAsync(key);
if (existing != null)
existing.Value = value;
else
context.Settings.Add(new SettingEntity { Key = key, Value = value });
await context.SaveChangesAsync();
}
public async Task SaveOllamaUrlAsync(string url)
{
await SetAsync(KeyOllamaUrl, url);
_ollamaConfig.OllamaUrl = url;
}
public async Task SaveRagModelAsync(string model)
{
await SetAsync(KeyRagModel, model);
_ollamaConfig.StyleModel = model;
}
public async Task SaveStyleModelAsync(string model)
{
await SetAsync(KeyStyleModel, model);
_ollamaConfig.StyleModel = model;
}
public async Task SaveLektorSystemPromptAsync(string prompt)
{
await SetAsync(KeyLektorPrompt, prompt);
_ollamaConfig.LektorSystemPrompt = prompt;
}
public async Task SaveFactCheckTemplateAsync(string prompt)
{
await SetAsync(KeyFactCheckTemplate, prompt);
_ollamaConfig.FactCheckTemplate = prompt;
}
public async Task SaveSpellingPromptAsync(string prompt)
{
await SetAsync(KeySpellingPrompt, prompt);
_ollamaConfig.SpellingPrompt = prompt;
}
public async Task SaveSpellingModelAsync(string model)
{
await SetAsync(KeySpellingModel, model);
_ollamaConfig.SpellingModel = model;
}
public Task SaveThemeAsync(string theme)
=> SetAsync(KeyTheme, theme);
public async Task InitializeAsync()
{
await using var context = await _contextFactory.CreateDbContextAsync();
var entries = new (string Key, string Default)[]
{
(KeyOllamaUrl, _ollamaConfig.OllamaUrl),
(KeyRagModel, _ollamaConfig.StyleModel),
(KeyStyleModel, _ollamaConfig.StyleModel),
(KeySpellingModel, _ollamaConfig.SpellingModel),
(KeyTheme, _ollamaConfig.Theme),
(KeyLektorPrompt, _ollamaConfig.LektorSystemPrompt),
(KeyFactCheckTemplate, _ollamaConfig.FactCheckTemplate),
(KeySpellingPrompt, _ollamaConfig.SpellingPrompt),
};
foreach (var entry in entries)
{
var existing = await context.Settings.FindAsync(entry.Key);
if (existing != null)
{
var val = existing.Value;
if (entry.Key == KeyOllamaUrl) _ollamaConfig.OllamaUrl = val;
else if (entry.Key == KeyRagModel) _ollamaConfig.StyleModel = val;
else if (entry.Key == KeyStyleModel) _ollamaConfig.StyleModel = val;
else if (entry.Key == KeySpellingModel) _ollamaConfig.SpellingModel = val;
else if (entry.Key == KeyTheme) _ollamaConfig.Theme = 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
{
context.Settings.Add(new SettingEntity { Key = entry.Key, Value = entry.Default });
}
}
await context.SaveChangesAsync();
}
}

24
Services/ThemeService.cs Normal file
View file

@ -0,0 +1,24 @@
using Microsoft.JSInterop;
namespace AuthorBuddy.Web.Services;
public class ThemeService : IThemeService
{
private readonly IJSRuntime _js;
public ThemeService(IJSRuntime js)
{
_js = js;
}
public async Task ApplyTheme(string theme)
{
await _js.InvokeVoidAsync("eval",
$"document.getElementById('theme-css')?.remove(); " +
$"var link = document.createElement('link'); " +
$"link.id = 'theme-css'; " +
$"link.rel = 'stylesheet'; " +
$"link.href = 'css/themes/{theme}.css'; " +
$"document.head.appendChild(link);");
}
}

Binary file not shown.