- Improve UI
This commit is contained in:
parent
79796bd143
commit
e5515edcab
40 changed files with 2538 additions and 1215 deletions
|
|
@ -1,13 +1,13 @@
|
||||||
## WORKSPACE EXECUTIVE SUMMARY (YAML)
|
## WORKSPACE EXECUTIVE SUMMARY (YAML)
|
||||||
# Generated: 2026-05-16T15:21:43.3363122+02:00
|
# Generated: 2026-05-20T06:11:22.0417511+02:00
|
||||||
# Root: E:\ollama_net\ollama\AuthorBuddy.Web
|
# Root: E:\ollama_net\ollama\AuthorBuddy.Web
|
||||||
Architecture:
|
Architecture:
|
||||||
Type: Backend (C#/.NET)
|
Type: Backend (C#/.NET)
|
||||||
Scale: 25 relevant source files
|
Scale: 34 relevant source files
|
||||||
Components: 0
|
Components: 0
|
||||||
Controllers: 0
|
Controllers: 0
|
||||||
Models: 6
|
Models: 8
|
||||||
Services: 8
|
Services: 14
|
||||||
---
|
---
|
||||||
- File: AuthorBuddy.Web.csproj
|
- File: AuthorBuddy.Web.csproj
|
||||||
Preview: "<Project Sdk='Microsoft.NET.Sdk.Web'> <PropertyGroup> <TargetFramework>net10.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>en..."
|
Preview: "<Project Sdk='Microsoft.NET.Sdk.Web'> <PropertyGroup> <TargetFramework>net10.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>en..."
|
||||||
|
|
@ -18,25 +18,31 @@ Architecture:
|
||||||
- File: AuthorBuddy.Web.slnx
|
- File: AuthorBuddy.Web.slnx
|
||||||
Preview: "<Solution> <Project Path='AuthorBuddy.Web.csproj' /> </Solution> "
|
Preview: "<Solution> <Project Path='AuthorBuddy.Web.csproj' /> </Solution> "
|
||||||
- File: Program.cs
|
- File: Program.cs
|
||||||
Preview: "using AuthorBuddy.Web.Components; using AuthorBuddy.Web.Data; using AuthorBuddy.Web.Models; using AuthorBuddy.Web.Services; using Microsoft.EntityFram..."
|
Preview: "using AuthorBuddy.Web.Components; using AuthorBuddy.Web.Data; using AuthorBuddy.Web.Models; using AuthorBuddy.Web.Services; using LiteDB; var builder ..."
|
||||||
- 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
|
- File: Data\DocumentMetaEntity.cs
|
||||||
Symbols: [DocumentMetaEntity]
|
Symbols: [DocumentMetaEntity]
|
||||||
Preview: "using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace AuthorBuddy.Web.Data; [Table('DocumentMeta'..."
|
Preview: "namespace AuthorBuddy.Web.Data; public class DocumentMetaEntity { public int Id { get; set; } public int? ProjectId { get; set; } public string ..."
|
||||||
|
- File: Data\DocumentVector.cs
|
||||||
|
Symbols: [DocumentVector]
|
||||||
|
Preview: "namespace AuthorBuddy.Web.Data; public class DocumentVector { public int Id { get; set; } public int DocumentMetaId { get; set; } public int Pro..."
|
||||||
- File: Data\ProjectEntity.cs
|
- File: Data\ProjectEntity.cs
|
||||||
Symbols: [ProjectEntity]
|
Symbols: [ProjectEntity]
|
||||||
Preview: "using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace AuthorBuddy.Web.Data; [Table('Projects')] p..."
|
Preview: "namespace AuthorBuddy.Web.Data; public class ProjectEntity { public int Id { get; set; } public string Name { get; set; } = string.Empty; public..."
|
||||||
- File: Data\SettingEntity.cs
|
- File: Data\SettingEntity.cs
|
||||||
Symbols: [SettingEntity]
|
Symbols: [SettingEntity]
|
||||||
Preview: "using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace AuthorBuddy.Web.Data; [Table('Settings')] p..."
|
Preview: "using LiteDB; namespace AuthorBuddy.Web.Data; public class SettingEntity { public int Id { get; set; } public string Key { get; set; } = string.Em..."
|
||||||
|
- File: Data\UserEntity.cs
|
||||||
|
Symbols: [UserEntity]
|
||||||
|
Preview: "namespace AuthorBuddy.Web.Data; public class UserEntity { public int Id { get; set; } public string Name { get; set; } = string.Empty; public bo..."
|
||||||
- File: Models\Chapter.cs
|
- File: Models\Chapter.cs
|
||||||
Symbols: [Chapter]
|
Symbols: [Chapter]
|
||||||
Preview: "namespace AuthorBuddy.Web.Models; public class Chapter { public string Title { get; set; } = string.Empty; public string FilePath { get; set; } = ..."
|
Preview: "namespace AuthorBuddy.Web.Models; public class Chapter { public string Title { get; set; } = string.Empty; public string FilePath { get; set; } = ..."
|
||||||
- File: Models\Constants.cs
|
- File: Models\Constants.cs
|
||||||
Symbols: [Constants]
|
Symbols: [Constants]
|
||||||
Preview: "namespace AuthorBuddy.Web.Models; public static class Constants { public static readonly string[] SubFolders = { '00_Drafts', '01_Fakten/Per..."
|
Preview: "namespace AuthorBuddy.Web.Models; public static class Constants { public static readonly string[] SubFolders = { '00_Drafts', '01_Fakten/Per..."
|
||||||
|
- File: Models\FileTreeItem.cs
|
||||||
|
Symbols: [FileTreeItem]
|
||||||
|
Preview: "namespace AuthorBuddy.Web.Models; public class FileTreeItem { public string Name { get; set; } = string.Empty; public string FullPath { get; set; ..."
|
||||||
- File: Models\LLM_Model.cs
|
- File: Models\LLM_Model.cs
|
||||||
Symbols: [LLM_Model, LLM_Model]
|
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..."
|
Preview: "using System.Text.Json; namespace AuthorBuddy.Web.Models { public class LLM_Model { public LLM_Model(JsonElement model) { if (mode..."
|
||||||
|
|
@ -45,35 +51,56 @@ Architecture:
|
||||||
Preview: " //namespace AuthorBuddy.Web.Models; //public class ModelStatus //{ // public string Status { get; private set; } = 'Unknown'; // public double Prog..."
|
Preview: " //namespace AuthorBuddy.Web.Models; //public class ModelStatus //{ // public string Status { get; private set; } = 'Unknown'; // public double Prog..."
|
||||||
- File: Models\OllamaSettings.cs
|
- File: Models\OllamaSettings.cs
|
||||||
Symbols: [OllamaSettings]
|
Symbols: [OllamaSettings]
|
||||||
Preview: "namespace AuthorBuddy.Web.Models; public class OllamaSettings { public string ChatModel { get; set; } = 'llama3.2'; public string EmbedModel { get..."
|
Preview: "namespace AuthorBuddy.Web.Models; public class OllamaSettings { public string StyleModel { get; set; } = 'gemma4:e4b'; public string EmbedModel { ..."
|
||||||
- File: Models\Project.cs
|
- File: Models\Project.cs
|
||||||
Symbols: [Project]
|
Symbols: [Project]
|
||||||
Preview: "namespace AuthorBuddy.Web.Models; public class Project { public int Id { get; internal set; } public string Name { get; internal set; } = string.E..."
|
Preview: "namespace AuthorBuddy.Web.Models; public class Project { public int Id { get; internal set; } public string Name { get; internal set; } = string.E..."
|
||||||
|
- File: Models\WikipediaResult.cs
|
||||||
|
Symbols: [WikipediaResult]
|
||||||
|
Preview: "namespace AuthorBuddy.Web.Models; public class WikipediaResult { public string Title { get; set; } = string.Empty; public string Snippet { get; se..."
|
||||||
- File: Properties\launchSettings.json
|
- File: Properties\launchSettings.json
|
||||||
Preview: "{ '$schema': 'https://json.schemastore.org/launchsettings.json', 'profiles': { 'http': { 'commandName': 'Project', 'dotnetRunMessages': ..."
|
Preview: "{ '$schema': 'https://json.schemastore.org/launchsettings.json', 'profiles': { 'http': { 'commandName': 'Project', 'dotnetRunMessages': ..."
|
||||||
- File: Services\FileScannerService.cs
|
- File: Services\FileScannerService.cs
|
||||||
Symbols: [FileScannerService]
|
Symbols: [FileScannerService]
|
||||||
Preview: "using AuthorBuddy.Web.Data; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; namespace AuthorBuddy.Web.Services; public class FileSca..."
|
Preview: "using AuthorBuddy.Web.Data; using LiteDB; namespace AuthorBuddy.Web.Services; public class FileScannerService : IFileScannerService { private readon..."
|
||||||
- File: Services\IFileScannerService.cs
|
- File: Services\IFileScannerService.cs
|
||||||
Symbols: [IFileScannerService]
|
Symbols: [IFileScannerService]
|
||||||
Preview: "namespace AuthorBuddy.Web.Services; public interface IFileScannerService { Task ScanProjectFolderAsync(int projectId, string rootPath, IProgress<str..."
|
Preview: "namespace AuthorBuddy.Web.Services; public interface IFileScannerService { Task ScanProjectFolderAsync(int projectId, string rootPath, IProgress<str..."
|
||||||
- File: Services\IOllamaService.cs
|
- File: Services\IOllamaService.cs
|
||||||
Symbols: [IOllamaService, IOllamaService]
|
Symbols: [IOllamaService]
|
||||||
Preview: " using AuthorBuddy.Web.Models; namespace AuthorBuddy.Web.Services; public interface IOllamaService { Task<IEnumerable<LLM_Model>> GetLocalModelsAsyn..."
|
Preview: " using AuthorBuddy.Web.Models; namespace AuthorBuddy.Web.Services; public interface IOllamaService { Task<IEnumerable<LLM_Model>> GetLocalModelsAsyn..."
|
||||||
- File: Services\IProjectService.cs
|
- File: Services\IProjectService.cs
|
||||||
Symbols: [IProjectService]
|
Symbols: [IProjectService]
|
||||||
Preview: "using AuthorBuddy.Web.Models; namespace AuthorBuddy.Web.Services; public interface IProjectService { Task<int> CreateNewProjectAsync(string projectN..."
|
Preview: "using AuthorBuddy.Web.Models; namespace AuthorBuddy.Web.Services; public interface IProjectService { Task<int> CreateNewProjectAsync(string projectN..."
|
||||||
|
- File: Services\IRagService.cs
|
||||||
|
Symbols: [IRagServi, RagSearchResult]
|
||||||
|
Preview: "namespace AuthorBuddy.Web.Services; public class RagSearchResult { public string Text { get; set; } = string.Empty; public string FilePath { get; ..."
|
||||||
- File: Services\ISettingsService.cs
|
- File: Services\ISettingsService.cs
|
||||||
Symbols: [ISettingsService]
|
Symbols: [ISettingsService]
|
||||||
Preview: "namespace AuthorBuddy.Web.Services; public interface ISettingsService { Task<string?> GetAsync(string key); Task SaveAsync(Dictionary<string, stri..."
|
Preview: "using AuthorBuddy.Web.Data; namespace AuthorBuddy.Web.Services; public interface ISettingsService { Task<string?> GetOllamaUrlAsync(); Task<string..."
|
||||||
|
- File: Services\IThemeService.cs
|
||||||
|
Symbols: [IThemeService]
|
||||||
|
Preview: "namespace AuthorBuddy.Web.Services; public interface IThemeService { Task ApplyTheme(string theme); } "
|
||||||
|
- File: Services\IWikipediaService.cs
|
||||||
|
Symbols: [IWikipediaService]
|
||||||
|
Preview: "using AuthorBuddy.Web.Models; namespace AuthorBuddy.Web.Services; public interface IWikipediaService { Task<List<WikipediaResult>> SearchAsync(strin..."
|
||||||
- File: Services\OllamaService.cs
|
- File: Services\OllamaService.cs
|
||||||
Symbols: [ChatStream, OllamaService, OllamaService, OllamaService, GetLocalModelsAsync, DeleteModel, ExtractResponseText, PullModelAsync, catch, catch, catch, catch, Chat, Reconfigure]
|
Symbols: [OllamaService]
|
||||||
Preview: "using AuthorBuddy.Web.Models; using System.Net.Http.Json; using System.Text.Json; namespace AuthorBuddy.Web.Services; public class OllamaService : IOl..."
|
Preview: "using AuthorBuddy.Web.Models; using System.Text.Json; using static System.Net.Mime.MediaTypeNames; namespace AuthorBuddy.Web.Services; public class Ol..."
|
||||||
- File: Services\ProjectService.cs
|
- File: Services\ProjectService.cs
|
||||||
Symbols: [ProjectService]
|
Symbols: [ProjectService]
|
||||||
Preview: "using AuthorBuddy.Web.Data; using AuthorBuddy.Web.Models; using Microsoft.EntityFrameworkCore; namespace AuthorBuddy.Web.Services; public class Projec..."
|
Preview: "using AuthorBuddy.Web.Data; using AuthorBuddy.Web.Models; using LiteDB; namespace AuthorBuddy.Web.Services; public class ProjectService : IProjectServ..."
|
||||||
|
- File: Services\RagService.cs
|
||||||
|
Symbols: [RagService]
|
||||||
|
Preview: "using AuthorBuddy.Web.Data; using LiteDB; using System.Security.Cryptography; using System.Text; namespace AuthorBuddy.Web.Services; public class RagS..."
|
||||||
- File: Services\SettingsService.cs
|
- File: Services\SettingsService.cs
|
||||||
Symbols: [SettingsService]
|
Symbols: [SettingsService]
|
||||||
Preview: "using AuthorBuddy.Web.Data; using AuthorBuddy.Web.Models; using Microsoft.EntityFrameworkCore; using Microsoft.JSInterop; using static System.Runtime...."
|
Preview: "using AuthorBuddy.Web.Data; using AuthorBuddy.Web.Models; using LiteDB; namespace AuthorBuddy.Web.Services; public class SettingsService : ISettingsSe..."
|
||||||
|
- File: Services\ThemeService.cs
|
||||||
|
Symbols: [ThemeService, ThemeService]
|
||||||
|
Preview: "using Microsoft.JSInterop; namespace AuthorBuddy.Web.Services; public class ThemeService : IThemeService { private readonly IJSRuntime _js; public..."
|
||||||
|
- File: Services\WikipediaService.cs
|
||||||
|
Symbols: [WikipediaService]
|
||||||
|
Preview: "using AuthorBuddy.Web.Models; using System.Text.Json; using System.Web; namespace AuthorBuddy.Web.Services; public class WikipediaService : IWikipedia..."
|
||||||
- File: Components\Layout\ReconnectModal.razor.js
|
- File: Components\Layout\ReconnectModal.razor.js
|
||||||
Preview: "// Set up event handlers const reconnectModal = document.getElementById('components-reconnect-modal'); reconnectModal.addEventListener('components-rec..."
|
Preview: "// Set up event handlers const reconnectModal = document.getElementById('components-reconnect-modal'); reconnectModal.addEventListener('components-rec..."
|
||||||
|
|
|
||||||
|
|
@ -3,48 +3,68 @@
|
||||||
"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\\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\\components\\layout\\mainlayout.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:data\\appdbcontext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
"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\\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\\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\\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\\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\\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}"
|
"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\\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\\program.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}"
|
"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\\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:models\\ollamasettings.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\\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\\projectservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:components\\pages\\settings.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
"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\\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\\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\\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}"
|
"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}",
|
"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:program.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\\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\\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\\services\\ragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\ragservice.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\\iragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\iragservice.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\\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:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|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\\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\\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\\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\\services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
|
@ -74,26 +94,14 @@
|
||||||
"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}",
|
"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}"
|
"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}",
|
"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}"
|
"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}",
|
"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}"
|
"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}",
|
"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}"
|
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:data\\projectentity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
|
@ -114,7 +122,7 @@
|
||||||
"DocumentGroups": [
|
"DocumentGroups": [
|
||||||
{
|
{
|
||||||
"DockedWidth": 200,
|
"DockedWidth": 200,
|
||||||
"SelectedChildIndex": 9,
|
"SelectedChildIndex": 7,
|
||||||
"Children": [
|
"Children": [
|
||||||
{
|
{
|
||||||
"$type": "Bookmark",
|
"$type": "Bookmark",
|
||||||
|
|
@ -122,15 +130,32 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 1,
|
"DocumentIndex": 2,
|
||||||
"Title": "OllamaService.cs",
|
"Title": "Program.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
|
||||||
"RelativeDocumentMoniker": "Services\\OllamaService.cs",
|
"RelativeDocumentMoniker": "Program.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs*",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
|
||||||
"RelativeToolTip": "Services\\OllamaService.cs*",
|
"RelativeToolTip": "Program.cs",
|
||||||
"ViewState": "AgIAADQAAAAAAAAAAAAQwEUAAABDAAAAAAAAAA==",
|
"ViewState": "AgIAAAMAAAAAAAAAAAApwBoAAAANAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-16T06:43:46.404Z",
|
"WhenOpened": "2026-05-20T04:07:21.54Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Bookmark",
|
||||||
|
"Name": "RST:0:0:{b3f9f954-0ca5-0091-76b4-34a47f44c954}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$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": "AgIAABoAAAAAAAAAAAA8wCYAAAAPAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2026-05-16T13:21:26.951Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -141,46 +166,44 @@
|
||||||
"RelativeDocumentMoniker": "Services\\SettingsService.cs",
|
"RelativeDocumentMoniker": "Services\\SettingsService.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\SettingsService.cs",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\SettingsService.cs",
|
||||||
"RelativeToolTip": "Services\\SettingsService.cs",
|
"RelativeToolTip": "Services\\SettingsService.cs",
|
||||||
"ViewState": "AgIAAMAAAAAAAAAAAAAQwMgAAAAMAAAAAAAAAA==",
|
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAYAAAAmAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-16T06:05:12.928Z",
|
"WhenOpened": "2026-05-16T06:05:12.928Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 11,
|
"DocumentIndex": 9,
|
||||||
"Title": "ThemeService.cs",
|
"Title": "RagService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\RagService.cs",
|
||||||
"RelativeDocumentMoniker": "Services\\ThemeService.cs",
|
"RelativeDocumentMoniker": "Services\\RagService.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ThemeService.cs",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\RagService.cs",
|
||||||
"RelativeToolTip": "Services\\ThemeService.cs",
|
"RelativeToolTip": "Services\\RagService.cs",
|
||||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
"ViewState": "AgIAABIAAAAAAAAAAAAxwBoAAAAIAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-16T13:35:33.991Z",
|
"WhenOpened": "2026-05-18T15:40:05.413Z"
|
||||||
"EditorCaption": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$type": "Document",
|
|
||||||
"DocumentIndex": 4,
|
|
||||||
"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": "AgIAAAsAAAAAAAAAAAA8wCEAAAAAAAAAAAAAAA==",
|
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
|
||||||
"WhenOpened": "2026-05-16T13:21:26.951Z",
|
|
||||||
"EditorCaption": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 8,
|
"DocumentIndex": 8,
|
||||||
|
"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": 0,
|
||||||
"Title": "MainLayout.razor",
|
"Title": "MainLayout.razor",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
||||||
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor",
|
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor*",
|
||||||
"RelativeToolTip": "Components\\Layout\\MainLayout.razor",
|
"RelativeToolTip": "Components\\Layout\\MainLayout.razor*",
|
||||||
"ViewState": "AgIAAG8AAAAAAAAAAAAAAH0AAAAtAAAAAAAAAA==",
|
"ViewState": "AgIAALUAAAAAAAAAAAApwM4AAABAAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||||
"WhenOpened": "2026-05-15T16:04:36.444Z",
|
"WhenOpened": "2026-05-15T16:04:36.444Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
|
|
@ -193,160 +216,75 @@
|
||||||
"RelativeDocumentMoniker": "Models\\OllamaSettings.cs",
|
"RelativeDocumentMoniker": "Models\\OllamaSettings.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
|
||||||
"RelativeToolTip": "Models\\OllamaSettings.cs",
|
"RelativeToolTip": "Models\\OllamaSettings.cs",
|
||||||
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAYAAAA6AAAAAAAAAA==",
|
"ViewState": "AgIAAAIAAAAAAAAAAAAxwAUAAAA+AAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-16T13:39:46.179Z",
|
"WhenOpened": "2026-05-16T13:39:46.179Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 9,
|
"DocumentIndex": 13,
|
||||||
|
"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",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2026-05-14T10:50:13.284Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 5,
|
||||||
"Title": "FileScannerService.cs",
|
"Title": "FileScannerService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
||||||
"RelativeDocumentMoniker": "Services\\FileScannerService.cs",
|
"RelativeDocumentMoniker": "Services\\FileScannerService.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
||||||
"RelativeToolTip": "Services\\FileScannerService.cs",
|
"RelativeToolTip": "Services\\FileScannerService.cs",
|
||||||
"ViewState": "AgIAACkAAAAAAAAAAIAwwEsAAAAfAAAAAAAAAA==",
|
"ViewState": "AgIAABIAAAAAAAAAAAAQwCUAAAAWAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-16T06:02:53.46Z",
|
"WhenOpened": "2026-05-16T06:02:53.46Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 2,
|
"DocumentIndex": 10,
|
||||||
"Title": "Editor.razor",
|
"Title": "IRagService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Editor.razor",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IRagService.cs",
|
||||||
"RelativeDocumentMoniker": "Components\\Pages\\Editor.razor",
|
"RelativeDocumentMoniker": "Services\\IRagService.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Editor.razor",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IRagService.cs",
|
||||||
"RelativeToolTip": "Components\\Pages\\Editor.razor",
|
"RelativeToolTip": "Services\\IRagService.cs",
|
||||||
"ViewState": "AgIAAFgAAAAAAAAAAAApwGsAAAAwAAAAAAAAAA==",
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAsAAAAVAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-16T13:01:59.743Z",
|
"WhenOpened": "2026-05-18T15:37:44.565Z"
|
||||||
"EditorCaption": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 0,
|
"DocumentIndex": 4,
|
||||||
"Title": "AppDbContext.cs",
|
"Title": "ProjectService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ProjectService.cs",
|
||||||
"RelativeDocumentMoniker": "Data\\AppDbContext.cs",
|
"RelativeDocumentMoniker": "Services\\ProjectService.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ProjectService.cs",
|
||||||
"RelativeToolTip": "Data\\AppDbContext.cs",
|
"RelativeToolTip": "Services\\ProjectService.cs",
|
||||||
"ViewState": "AgIAADgAAAAAAAAAAAAuwEsAAAAAAAAAAAAAAA==",
|
"ViewState": "AgIAADQAAAAAAAAAAAAqwEYAAAAWAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-14T10:50:13.284Z",
|
"WhenOpened": "2026-05-15T15:56:55.229Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 7,
|
"DocumentIndex": 7,
|
||||||
"Title": "Settings.razor",
|
"Title": "OllamaService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
||||||
"RelativeDocumentMoniker": "Components\\Pages\\Settings.razor",
|
"RelativeDocumentMoniker": "Services\\OllamaService.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
||||||
"RelativeToolTip": "Components\\Pages\\Settings.razor",
|
"RelativeToolTip": "Services\\OllamaService.cs",
|
||||||
"ViewState": "AgIAAHMAAAAAAAAAAADwv4UAAAAAAAAAAAAAAA==",
|
"ViewState": "AgIAAHoAAAAAAAAAAAAcwCoAAAAJAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
|
||||||
"WhenOpened": "2026-05-15T16:43:26.6Z",
|
|
||||||
"EditorCaption": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$type": "Bookmark",
|
|
||||||
"Name": "RST:0:0:{b3f9f954-0ca5-0091-76b4-34a47f44c954}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$type": "Document",
|
|
||||||
"DocumentIndex": 5,
|
|
||||||
"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|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-16T07:20:19.212Z",
|
"WhenOpened": "2026-05-16T06:43:46.404Z"
|
||||||
"EditorCaption": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$type": "Document",
|
|
||||||
"DocumentIndex": 10,
|
|
||||||
"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",
|
"$type": "Document",
|
||||||
"DocumentIndex": 12,
|
"DocumentIndex": 12,
|
||||||
"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": 15,
|
|
||||||
"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": 13,
|
|
||||||
"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": 14,
|
|
||||||
"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": 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",
|
"Title": "NavMenu.razor",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\NavMenu.razor",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\NavMenu.razor",
|
||||||
"RelativeDocumentMoniker": "Components\\Layout\\NavMenu.razor",
|
"RelativeDocumentMoniker": "Components\\Layout\\NavMenu.razor",
|
||||||
|
|
@ -356,9 +294,118 @@
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||||
"WhenOpened": "2026-05-15T16:04:37.739Z"
|
"WhenOpened": "2026-05-15T16:04:37.739Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"$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": "AgIAAAoAAACA6NuCpTYvwJkAAAAcAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||||
|
"WhenOpened": "2026-05-16T13:01:59.743Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 16,
|
"DocumentIndex": 16,
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 15,
|
||||||
|
"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": "AgIAAHMAAAAAAAAAAADwv4UAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||||
|
"WhenOpened": "2026-05-15T16:43:26.6Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 17,
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 20,
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 18,
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 19,
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 23,
|
||||||
|
"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": 21,
|
||||||
"Title": "IFileScannerService.cs",
|
"Title": "IFileScannerService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IFileScannerService.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IFileScannerService.cs",
|
||||||
"RelativeDocumentMoniker": "Services\\IFileScannerService.cs",
|
"RelativeDocumentMoniker": "Services\\IFileScannerService.cs",
|
||||||
|
|
@ -371,18 +418,6 @@
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 22,
|
"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": 17,
|
|
||||||
"Title": "bootstrap-utilities.css",
|
"Title": "bootstrap-utilities.css",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\wwwroot\\lib\\bootstrap\\dist\\css\\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",
|
"RelativeDocumentMoniker": "wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
|
||||||
|
|
@ -394,19 +429,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 20,
|
"DocumentIndex": 25,
|
||||||
"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",
|
"Title": "ProjectEntity.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\ProjectEntity.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\ProjectEntity.cs",
|
||||||
"RelativeDocumentMoniker": "Data\\ProjectEntity.cs",
|
"RelativeDocumentMoniker": "Data\\ProjectEntity.cs",
|
||||||
|
|
@ -418,7 +441,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 21,
|
"DocumentIndex": 24,
|
||||||
"Title": "IProjectService.cs",
|
"Title": "IProjectService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IProjectService.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IProjectService.cs",
|
||||||
"RelativeDocumentMoniker": "Services\\IProjectService.cs",
|
"RelativeDocumentMoniker": "Services\\IProjectService.cs",
|
||||||
|
|
@ -430,7 +453,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 24,
|
"DocumentIndex": 26,
|
||||||
"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",
|
||||||
|
|
@ -442,7 +465,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 25,
|
"DocumentIndex": 27,
|
||||||
"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",
|
||||||
|
|
|
||||||
|
|
@ -2,50 +2,70 @@
|
||||||
"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\\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\\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\\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\\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\\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}"
|
"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\\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\\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\\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\\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}",
|
"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}"
|
"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\\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\\services\\isettingsservice.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}"
|
"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\\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\\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}"
|
"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\\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\\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\\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\\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\\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\\services\\ragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\ragservice.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\\iragservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\iragservice.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\\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:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|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\\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\\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\\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\\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}"
|
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:services\\themeservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
|
@ -74,26 +94,14 @@
|
||||||
"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}",
|
"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}"
|
"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}",
|
"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}"
|
"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}",
|
"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}"
|
"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}",
|
"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}"
|
"RelativeMoniker": "D:0:0:{4F4697EF-EFFA-26AC-C8A1-C9859805D247}|AuthorBuddy.Web.csproj|solutionrelative:data\\projectentity.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
|
@ -114,7 +122,7 @@
|
||||||
"DocumentGroups": [
|
"DocumentGroups": [
|
||||||
{
|
{
|
||||||
"DockedWidth": 200,
|
"DockedWidth": 200,
|
||||||
"SelectedChildIndex": 8,
|
"SelectedChildIndex": 4,
|
||||||
"Children": [
|
"Children": [
|
||||||
{
|
{
|
||||||
"$type": "Bookmark",
|
"$type": "Bookmark",
|
||||||
|
|
@ -127,51 +135,75 @@
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 3,
|
"DocumentIndex": 3,
|
||||||
"Title": "SettingsService.cs",
|
"Title": "Program.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\SettingsService.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
|
||||||
"RelativeDocumentMoniker": "Services\\SettingsService.cs",
|
"RelativeDocumentMoniker": "Program.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\SettingsService.cs",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Program.cs",
|
||||||
"RelativeToolTip": "Services\\SettingsService.cs",
|
"RelativeToolTip": "Program.cs",
|
||||||
"ViewState": "AgIAAMAAAAAAAAAAAAAQwMgAAAAMAAAAAAAAAA==",
|
"ViewState": "AgIAAAMAAAAAAAAAAAApwBoAAAANAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-16T06:05:12.928Z",
|
"WhenOpened": "2026-05-20T04:07:21.54Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 11,
|
"DocumentIndex": 2,
|
||||||
"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": 4,
|
|
||||||
"Title": "ISettingsService.cs",
|
"Title": "ISettingsService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ISettingsService.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ISettingsService.cs",
|
||||||
"RelativeDocumentMoniker": "Services\\ISettingsService.cs",
|
"RelativeDocumentMoniker": "Services\\ISettingsService.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ISettingsService.cs",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ISettingsService.cs",
|
||||||
"RelativeToolTip": "Services\\ISettingsService.cs",
|
"RelativeToolTip": "Services\\ISettingsService.cs",
|
||||||
"ViewState": "AgIAAAsAAAAAAAAAAAA8wCEAAAAAAAAAAAAAAA==",
|
"ViewState": "AgIAABoAAAAAAAAAAAA8wCYAAAAPAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-16T13:21:26.951Z",
|
"WhenOpened": "2026-05-16T13:21:26.951Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 0,
|
||||||
|
"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": "AgIAADcBAAAAAAAAAAAQwEoBAAAIAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2026-05-16T06:05:12.928Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 9,
|
||||||
|
"Title": "RagService.cs",
|
||||||
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\RagService.cs",
|
||||||
|
"RelativeDocumentMoniker": "Services\\RagService.cs",
|
||||||
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\RagService.cs",
|
||||||
|
"RelativeToolTip": "Services\\RagService.cs",
|
||||||
|
"ViewState": "AgIAABIAAAAAAAAAAAAxwBoAAAAIAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2026-05-18T15:40:05.413Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 8,
|
"DocumentIndex": 8,
|
||||||
|
"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": 1,
|
||||||
"Title": "MainLayout.razor",
|
"Title": "MainLayout.razor",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
||||||
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor",
|
"RelativeDocumentMoniker": "Components\\Layout\\MainLayout.razor",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\MainLayout.razor",
|
||||||
"RelativeToolTip": "Components\\Layout\\MainLayout.razor",
|
"RelativeToolTip": "Components\\Layout\\MainLayout.razor",
|
||||||
"ViewState": "AgIAAG8AAAAAAAAAAAAAAH0AAAAtAAAAAAAAAA==",
|
"ViewState": "AgIAALUAAAAAAAAAAAApwM4AAABAAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||||
"WhenOpened": "2026-05-15T16:04:36.444Z",
|
"WhenOpened": "2026-05-15T16:04:36.444Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
|
|
@ -184,169 +216,75 @@
|
||||||
"RelativeDocumentMoniker": "Models\\OllamaSettings.cs",
|
"RelativeDocumentMoniker": "Models\\OllamaSettings.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Models\\OllamaSettings.cs",
|
||||||
"RelativeToolTip": "Models\\OllamaSettings.cs",
|
"RelativeToolTip": "Models\\OllamaSettings.cs",
|
||||||
"ViewState": "AgIAAAAAAAAAAAAAAAAqwAYAAAA6AAAAAAAAAA==",
|
"ViewState": "AgIAAAIAAAAAAAAAAAAxwAUAAAA+AAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-16T13:39:46.179Z",
|
"WhenOpened": "2026-05-16T13:39:46.179Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 9,
|
"DocumentIndex": 13,
|
||||||
|
"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",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2026-05-14T10:50:13.284Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 5,
|
||||||
"Title": "FileScannerService.cs",
|
"Title": "FileScannerService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
||||||
"RelativeDocumentMoniker": "Services\\FileScannerService.cs",
|
"RelativeDocumentMoniker": "Services\\FileScannerService.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\FileScannerService.cs",
|
||||||
"RelativeToolTip": "Services\\FileScannerService.cs",
|
"RelativeToolTip": "Services\\FileScannerService.cs",
|
||||||
"ViewState": "AgIAACkAAAAAAAAAAIAwwEsAAAAfAAAAAAAAAA==",
|
"ViewState": "AgIAABIAAAAAAAAAAAAQwCUAAAAWAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-16T06:02:53.46Z",
|
"WhenOpened": "2026-05-16T06:02:53.46Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 0,
|
"DocumentIndex": 10,
|
||||||
"Title": "AppDbContext.cs",
|
"Title": "IRagService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IRagService.cs",
|
||||||
"RelativeDocumentMoniker": "Data\\AppDbContext.cs",
|
"RelativeDocumentMoniker": "Services\\IRagService.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\AppDbContext.cs",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IRagService.cs",
|
||||||
"RelativeToolTip": "Data\\AppDbContext.cs",
|
"RelativeToolTip": "Services\\IRagService.cs",
|
||||||
"ViewState": "AgIAADgAAAAAAAAAAAAuwEsAAAAAAAAAAAAAAA==",
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAsAAAAVAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-14T10:50:13.284Z",
|
"WhenOpened": "2026-05-18T15:37:44.565Z"
|
||||||
"EditorCaption": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 1,
|
"DocumentIndex": 4,
|
||||||
"Title": "OllamaService.cs",
|
"Title": "ProjectService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ProjectService.cs",
|
||||||
"RelativeDocumentMoniker": "Services\\OllamaService.cs",
|
"RelativeDocumentMoniker": "Services\\ProjectService.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\ProjectService.cs",
|
||||||
"RelativeToolTip": "Services\\OllamaService.cs",
|
"RelativeToolTip": "Services\\ProjectService.cs",
|
||||||
"ViewState": "AgIAADQAAAAAAAAAAAAQwEUAAABDAAAAAAAAAA==",
|
"ViewState": "AgIAADQAAAAAAAAAAAAqwEYAAAAWAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-16T06:43:46.404Z",
|
"WhenOpened": "2026-05-15T15:56:55.229Z",
|
||||||
"EditorCaption": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$type": "Document",
|
|
||||||
"DocumentIndex": 2,
|
|
||||||
"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": "AgIAAFgAAAAAAAAAAAApwGsAAAAwAAAAAAAAAA==",
|
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
|
||||||
"WhenOpened": "2026-05-16T13:01:59.743Z",
|
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 7,
|
"DocumentIndex": 7,
|
||||||
"Title": "Settings.razor",
|
"Title": "OllamaService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
||||||
"RelativeDocumentMoniker": "Components\\Pages\\Settings.razor",
|
"RelativeDocumentMoniker": "Services\\OllamaService.cs",
|
||||||
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Pages\\Settings.razor",
|
"ToolTip": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\OllamaService.cs",
|
||||||
"RelativeToolTip": "Components\\Pages\\Settings.razor",
|
"RelativeToolTip": "Services\\OllamaService.cs",
|
||||||
"ViewState": "AgIAAHMAAAAAAAAAAADwv4UAAAAAAAAAAAAAAA==",
|
"ViewState": "AgIAAHoAAAAAAAAAAAAcwCoAAAAJAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
|
||||||
"WhenOpened": "2026-05-15T16:43:26.6Z",
|
|
||||||
"EditorCaption": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$type": "Document",
|
|
||||||
"DocumentIndex": 5,
|
|
||||||
"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|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-05-16T07:20:19.212Z",
|
"WhenOpened": "2026-05-16T06:43:46.404Z"
|
||||||
"EditorCaption": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$type": "Document",
|
|
||||||
"DocumentIndex": 10,
|
|
||||||
"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",
|
"$type": "Document",
|
||||||
"DocumentIndex": 12,
|
"DocumentIndex": 12,
|
||||||
"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": 15,
|
|
||||||
"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": 13,
|
|
||||||
"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": 14,
|
|
||||||
"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": 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",
|
"Title": "NavMenu.razor",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\NavMenu.razor",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Components\\Layout\\NavMenu.razor",
|
||||||
"RelativeDocumentMoniker": "Components\\Layout\\NavMenu.razor",
|
"RelativeDocumentMoniker": "Components\\Layout\\NavMenu.razor",
|
||||||
|
|
@ -356,9 +294,118 @@
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||||
"WhenOpened": "2026-05-15T16:04:37.739Z"
|
"WhenOpened": "2026-05-15T16:04:37.739Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"$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": "AgIAAAoAAACA6NuCpTYvwJkAAAAcAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||||
|
"WhenOpened": "2026-05-16T13:01:59.743Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 16,
|
"DocumentIndex": 16,
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 15,
|
||||||
|
"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": "AgIAAHMAAAAAAAAAAADwv4UAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||||
|
"WhenOpened": "2026-05-15T16:43:26.6Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 17,
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 20,
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 18,
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 19,
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 23,
|
||||||
|
"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": 21,
|
||||||
"Title": "IFileScannerService.cs",
|
"Title": "IFileScannerService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IFileScannerService.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IFileScannerService.cs",
|
||||||
"RelativeDocumentMoniker": "Services\\IFileScannerService.cs",
|
"RelativeDocumentMoniker": "Services\\IFileScannerService.cs",
|
||||||
|
|
@ -371,18 +418,6 @@
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 22,
|
"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": 17,
|
|
||||||
"Title": "bootstrap-utilities.css",
|
"Title": "bootstrap-utilities.css",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\wwwroot\\lib\\bootstrap\\dist\\css\\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",
|
"RelativeDocumentMoniker": "wwwroot\\lib\\bootstrap\\dist\\css\\bootstrap-utilities.css",
|
||||||
|
|
@ -394,19 +429,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 20,
|
"DocumentIndex": 25,
|
||||||
"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",
|
"Title": "ProjectEntity.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\ProjectEntity.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Data\\ProjectEntity.cs",
|
||||||
"RelativeDocumentMoniker": "Data\\ProjectEntity.cs",
|
"RelativeDocumentMoniker": "Data\\ProjectEntity.cs",
|
||||||
|
|
@ -418,7 +441,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 21,
|
"DocumentIndex": 24,
|
||||||
"Title": "IProjectService.cs",
|
"Title": "IProjectService.cs",
|
||||||
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IProjectService.cs",
|
"DocumentMoniker": "E:\\ollama_net\\ollama\\AuthorBuddy.Web\\Services\\IProjectService.cs",
|
||||||
"RelativeDocumentMoniker": "Services\\IProjectService.cs",
|
"RelativeDocumentMoniker": "Services\\IProjectService.cs",
|
||||||
|
|
@ -430,7 +453,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 24,
|
"DocumentIndex": 26,
|
||||||
"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",
|
||||||
|
|
@ -442,7 +465,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 25,
|
"DocumentIndex": 27,
|
||||||
"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",
|
||||||
|
|
|
||||||
|
|
@ -9,18 +9,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DiffPlex" Version="1.9.0" />
|
<PackageReference Include="DiffPlex" Version="1.9.0" />
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.5" />
|
<PackageReference Include="LiteDB" Version="5.0.21" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.8">
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.8" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Update="vec0.dll">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
|
@implements IDisposable
|
||||||
@inject IProjectService ProjectService
|
@inject IProjectService ProjectService
|
||||||
@inject ISettingsService SettingsService
|
@inject ISettingsService SettingsService
|
||||||
@inject IThemeService ThemeService
|
@inject IThemeService ThemeService
|
||||||
|
|
@ -16,24 +17,12 @@
|
||||||
{
|
{
|
||||||
<div class="nav-section-body">
|
<div class="nav-section-body">
|
||||||
<button class="nav-item" @onclick="CreateNewProject">Neues Projekt</button>
|
<button class="nav-item" @onclick="CreateNewProject">Neues Projekt</button>
|
||||||
<button class="nav-item" @onclick="OpenProject">Öffnen</button>
|
<button class="nav-item" @onclick="OpenEditor">Editor öffnen</button>
|
||||||
<div class="nav-separator"></div>
|
<div class="nav-separator"></div>
|
||||||
<button class="nav-item" @onclick="ExitApp">Beenden</button>
|
<button class="nav-item" @onclick="ExitApp">Beenden</button>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-section">
|
|
||||||
<button class="nav-section-header" @onclick='() => ToggleSection("view")'>
|
|
||||||
<span class="nav-icon">@(activeSection == "view" ? "▼" : "▶")</span>
|
|
||||||
Ansicht
|
|
||||||
</button>
|
|
||||||
@if (activeSection == "view")
|
|
||||||
{
|
|
||||||
<div class="nav-section-body">
|
|
||||||
<button class="nav-item" @onclick="OpenEditor">Editor öffnen</button>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div class="nav-section">
|
<div class="nav-section">
|
||||||
<button class="nav-section-header" @onclick='() => ToggleSection("extras")'>
|
<button class="nav-section-header" @onclick='() => ToggleSection("extras")'>
|
||||||
<span class="nav-icon">@(activeSection == "extras" ? "▼" : "▶")</span>
|
<span class="nav-icon">@(activeSection == "extras" ? "▼" : "▶")</span>
|
||||||
|
|
@ -44,6 +33,7 @@
|
||||||
<div class="nav-section-body">
|
<div class="nav-section-body">
|
||||||
<button class="nav-item" @onclick='() => NavigateTo("/settings")'>Einstellungen</button>
|
<button class="nav-item" @onclick='() => NavigateTo("/settings")'>Einstellungen</button>
|
||||||
<button class="nav-item" @onclick='() => NavigateTo("/models")'>Modelle verwalten</button>
|
<button class="nav-item" @onclick='() => NavigateTo("/models")'>Modelle verwalten</button>
|
||||||
|
<button class="nav-item" @onclick='() => NavigateTo("/assistant")'>Assistent</button>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -74,17 +64,92 @@
|
||||||
{
|
{
|
||||||
@foreach (var p in projects)
|
@foreach (var p in projects)
|
||||||
{
|
{
|
||||||
<button class="nav-item nav-item-sub" @onclick='() => SelectProject(p)'>@p.Name</button>
|
<button class="nav-item nav-item-sub @(p.Id == currentProjectId ? "active" : "")" @onclick='() => SelectProject(p)'>@p.Name</button>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div class="nav-separator"></div>
|
<div class="nav-separator"></div>
|
||||||
<button class="nav-item" @onclick="CreateNewProject">Projekt erstellen</button>
|
<button class="nav-item" @onclick="CreateNewProject">Projekt erstellen</button>
|
||||||
<button class="nav-item" @onclick="OpenProject">Projekt laden</button>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@if (currentProjectId > 0 && fileTree != null)
|
||||||
|
{
|
||||||
|
<div class="nav-section nav-section-open">
|
||||||
|
<div class="nav-section-header">
|
||||||
|
<span>Projektdateien</span>
|
||||||
|
<span class="nav-header-actions">
|
||||||
|
<button class="nav-item-icon" @onclick="RefreshFileTree" title="Dateibaum aktualisieren">↻</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="nav-section-body">
|
||||||
|
@foreach (var item in fileTree)
|
||||||
|
{
|
||||||
|
<div class="tree-item @(item.IsDirectory ? "dir" : "file") @(item.FullPath == currentFilePath ? "active" : "")"
|
||||||
|
@onclick="() => OpenFile(item)">
|
||||||
|
<span class="tree-icon">@(item.IsDirectory ? "📁" : "📄")</span>
|
||||||
|
<span class="tree-name">@item.Name</span>
|
||||||
|
@if (item.IsDirectory)
|
||||||
|
{
|
||||||
|
<button class="tree-rename" @onclick="() => BeginNewFile(item)" @onclick:stopPropagation title="Neue Datei">+</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button class="tree-rename" @onclick="() => BeginRename(item)" @onclick:stopPropagation title="Umbenennen">✎</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
@foreach (var child in item.Children)
|
||||||
|
{
|
||||||
|
<div class="tree-item file tree-child @(child.FullPath == currentFilePath ? "active" : "")"
|
||||||
|
@onclick="() => OpenFile(child)">
|
||||||
|
<span class="tree-icon">📄</span>
|
||||||
|
<span class="tree-name">@child.Name</span>
|
||||||
|
<button class="tree-rename" @onclick="() => BeginRename(child)" @onclick:stopPropagation title="Umbenennen">✎</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (showRenameDialog)
|
||||||
|
{
|
||||||
|
<div class="modal-overlay">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-title">Datei umbenennen</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Neuer Name</label>
|
||||||
|
<input @bind="renameNewName" placeholder="neuer_name.md" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-actions">
|
||||||
|
<button @onclick="CancelRename">Abbrechen</button>
|
||||||
|
<button @onclick="ConfirmRename" disabled="@(string.IsNullOrWhiteSpace(renameNewName))" class="primary">Umbenennen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (showNewFileDialog)
|
||||||
|
{
|
||||||
|
<div class="modal-overlay">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-title">Neue Datei</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Dateiname</label>
|
||||||
|
<input @bind="newFileName" placeholder="meine_datei.md" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-actions">
|
||||||
|
<button @onclick="CancelNewFile">Abbrechen</button>
|
||||||
|
<button @onclick="ConfirmNewFile" disabled="@(string.IsNullOrWhiteSpace(newFileName))" class="primary">Erstellen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<main class="detail-panel">
|
<main class="detail-panel">
|
||||||
|
|
@ -106,29 +171,93 @@
|
||||||
private string? activeSection;
|
private string? activeSection;
|
||||||
private bool showProjectList;
|
private bool showProjectList;
|
||||||
private List<Project>? projects;
|
private List<Project>? projects;
|
||||||
|
private List<FileTreeItem>? fileTree;
|
||||||
|
private int currentProjectId;
|
||||||
|
private string? currentFilePath;
|
||||||
private string statusText = "Bereit";
|
private string statusText = "Bereit";
|
||||||
private bool isBusy;
|
private bool isBusy;
|
||||||
private double operationProgress;
|
private double operationProgress;
|
||||||
|
private bool showRenameDialog;
|
||||||
|
private string renameNewName = string.Empty;
|
||||||
|
private FileTreeItem? renameTarget;
|
||||||
|
private bool showNewFileDialog;
|
||||||
|
private string newFileName = string.Empty;
|
||||||
|
private FileTreeItem? newFileParentDir;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private NavigationManager Navigation { get; set; } = default!;
|
private NavigationManager Navigation { get; set; } = default!;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
await SettingsService.InitializeAsync();
|
||||||
|
Navigation.LocationChanged += OnLocationChanged;
|
||||||
await LoadProjects();
|
await LoadProjects();
|
||||||
|
await LoadProjectContext();
|
||||||
|
await AutoLoadLastProject();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AutoLoadLastProject()
|
||||||
|
{
|
||||||
|
if (currentProjectId > 0) return;
|
||||||
|
var lastId = await SettingsService.GetLastProjectIdAsync();
|
||||||
|
if (lastId == null) return;
|
||||||
|
var project = projects?.FirstOrDefault(p => p.Id == lastId.Value);
|
||||||
|
if (project != null)
|
||||||
|
{
|
||||||
|
await SettingsService.InitializeAsync(lastId.Value);
|
||||||
|
await SelectProject(project);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
await SettingsService.InitializeAsync();
|
|
||||||
var theme = OllamaSettings.Theme;
|
var theme = OllamaSettings.Theme;
|
||||||
if (!string.IsNullOrEmpty(theme))
|
if (!string.IsNullOrEmpty(theme))
|
||||||
await ThemeService.ApplyTheme(theme);
|
await ThemeService.ApplyTheme(theme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Navigation.LocationChanged -= OnLocationChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void OnLocationChanged(object? sender, Microsoft.AspNetCore.Components.Routing.LocationChangedEventArgs e)
|
||||||
|
{
|
||||||
|
await LoadProjects();
|
||||||
|
await LoadProjectContext();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadProjectContext()
|
||||||
|
{
|
||||||
|
currentProjectId = SettingsService.CurrentProjectId ?? 0;
|
||||||
|
currentFilePath = SettingsService.CurrentFilePath;
|
||||||
|
|
||||||
|
if (currentProjectId > 0)
|
||||||
|
{
|
||||||
|
await LoadFileTree();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileTree = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadFileTree()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fileTree = await ProjectService.GetProjectFileTreeAsync(currentProjectId);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
fileTree = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task LoadProjects()
|
private async Task LoadProjects()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
@ -155,13 +284,7 @@
|
||||||
private void CreateNewProject()
|
private void CreateNewProject()
|
||||||
{
|
{
|
||||||
activeSection = null;
|
activeSection = null;
|
||||||
Navigation.NavigateTo("/editor?action=newproject");
|
Navigation.NavigateTo("/editor/newproject");
|
||||||
}
|
|
||||||
|
|
||||||
private void OpenProject()
|
|
||||||
{
|
|
||||||
activeSection = null;
|
|
||||||
Navigation.NavigateTo("/editor?action=open");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenEditor()
|
private void OpenEditor()
|
||||||
|
|
@ -176,10 +299,123 @@
|
||||||
Navigation.NavigateTo(path);
|
Navigation.NavigateTo(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SelectProject(Project project)
|
private async Task SelectProject(Project project)
|
||||||
{
|
{
|
||||||
|
activeSection = "files";
|
||||||
|
SettingsService.CurrentProjectId = project.Id;
|
||||||
|
currentProjectId = project.Id;
|
||||||
|
SettingsService.CurrentFilePath = null;
|
||||||
|
await SettingsService.SaveLastProjectIdAsync(project.Id);
|
||||||
|
await SettingsService.LoadProjectSettingsAsync();
|
||||||
|
await LoadFileTree();
|
||||||
|
Navigation.NavigateTo($"/editor/index/{project.Id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RefreshFileTree()
|
||||||
|
{
|
||||||
|
await LoadFileTree();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BeginRename(FileTreeItem item)
|
||||||
|
{
|
||||||
|
renameTarget = item;
|
||||||
|
renameNewName = item.Name;
|
||||||
|
showRenameDialog = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CancelRename()
|
||||||
|
{
|
||||||
|
showRenameDialog = false;
|
||||||
|
renameTarget = null;
|
||||||
|
renameNewName = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ConfirmRename()
|
||||||
|
{
|
||||||
|
if (renameTarget == null || string.IsNullOrWhiteSpace(renameNewName)) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dir = Path.GetDirectoryName(renameTarget.FullPath)!;
|
||||||
|
var newPath = Path.Combine(dir, renameNewName);
|
||||||
|
if (File.Exists(newPath))
|
||||||
|
{
|
||||||
|
statusText = "Datei existiert bereits.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File.Move(renameTarget.FullPath, newPath);
|
||||||
|
|
||||||
|
if (currentFilePath == renameTarget.FullPath)
|
||||||
|
SettingsService.CurrentFilePath = newPath;
|
||||||
|
|
||||||
|
statusText = $"Umbenannt zu: {renameNewName}";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
statusText = $"Fehler: {ex.Message}";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
showRenameDialog = false;
|
||||||
|
renameTarget = null;
|
||||||
|
renameNewName = string.Empty;
|
||||||
|
await LoadFileTree();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BeginNewFile(FileTreeItem dir)
|
||||||
|
{
|
||||||
|
newFileParentDir = dir;
|
||||||
|
newFileName = string.Empty;
|
||||||
|
showNewFileDialog = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CancelNewFile()
|
||||||
|
{
|
||||||
|
showNewFileDialog = false;
|
||||||
|
newFileParentDir = null;
|
||||||
|
newFileName = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ConfirmNewFile()
|
||||||
|
{
|
||||||
|
if (newFileParentDir == null || string.IsNullOrWhiteSpace(newFileName)) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var path = Path.Combine(newFileParentDir.FullPath, newFileName);
|
||||||
|
if (!path.EndsWith(".md", StringComparison.OrdinalIgnoreCase))
|
||||||
|
path += ".md";
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
statusText = "Datei existiert bereits.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File.WriteAllText(path, $"# {Path.GetFileNameWithoutExtension(path)}\n\n");
|
||||||
|
statusText = $"Erstellt: {Path.GetFileName(path)}";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
statusText = $"Fehler: {ex.Message}";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
showNewFileDialog = false;
|
||||||
|
newFileParentDir = null;
|
||||||
|
newFileName = string.Empty;
|
||||||
|
await LoadFileTree();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenFile(FileTreeItem item)
|
||||||
|
{
|
||||||
|
if (item.IsDirectory) return;
|
||||||
activeSection = null;
|
activeSection = null;
|
||||||
Navigation.NavigateTo($"/editor?projectId={project.Id}");
|
SettingsService.CurrentFilePath = item.FullPath;
|
||||||
|
Navigation.NavigateTo($"/editor/file/{currentProjectId}?t={DateTime.Now.Ticks}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetStatus(string text, bool busy = false, double progress = 0)
|
public void SetStatus(string text, bool busy = false, double progress = 0)
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,19 @@
|
||||||
@page "/editor/{action}/{projectId:int}"
|
@page "/editor/{action}/{projectId:int}"
|
||||||
@inject IOllamaService OllamaService
|
@inject IOllamaService OllamaService
|
||||||
@inject IProjectService ProjectService
|
@inject IProjectService ProjectService
|
||||||
|
@inject IRagService RagService
|
||||||
|
@inject ISettingsService SettingsService
|
||||||
|
@inject IWikipediaService WikipediaService
|
||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
|
|
||||||
|
@implements IDisposable
|
||||||
|
@rendermode InteractiveServer
|
||||||
|
|
||||||
<PageTitle>Editor - Author Buddy</PageTitle>
|
<PageTitle>Editor - Author Buddy</PageTitle>
|
||||||
|
|
||||||
<div class="editor-container">
|
<div class="editor-page">
|
||||||
<textarea @bind="editorContent" placeholder="Schreibe hier deinen Text..."></textarea>
|
<textarea class="editor-area" @bind="editorContent" placeholder="Schreibe hier deinen Text..."></textarea>
|
||||||
|
|
||||||
<div class="editor-toolbar">
|
<div class="editor-toolbar">
|
||||||
<span style="flex: 1; font-size: 12px; color: var(--border-color);">
|
<span style="flex: 1; font-size: 12px; color: var(--border-color);">
|
||||||
@statusText
|
@statusText
|
||||||
|
|
@ -17,31 +24,121 @@
|
||||||
{
|
{
|
||||||
<progress value="@checkProgress" max="100"></progress>
|
<progress value="@checkProgress" max="100"></progress>
|
||||||
}
|
}
|
||||||
<button @onclick="CheckStyle" disabled="@isChecking">
|
<button @onclick="CheckStyle" disabled="@isChecking">Stil prüfen</button>
|
||||||
Stil prüfen
|
<button @onclick="SpellCheck" disabled="@isChecking">Rechtschreibung prüfen</button>
|
||||||
</button>
|
<button @onclick="SaveCurrentFile" disabled="@(string.IsNullOrEmpty(currentFile))">Speichern</button>
|
||||||
<button @onclick="SpellCheck" disabled="@isChecking">
|
<button @onclick="ShowVersionDialog" disabled="@(string.IsNullOrEmpty(currentFile))">Version</button>
|
||||||
Rechtschreibung prüfen
|
<button @onclick="IndexProject" disabled="@isChecking">Projekt indexieren</button>
|
||||||
</button>
|
|
||||||
<button @onclick="RagSearch">
|
|
||||||
Fakten suchen (RAG)
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
@if (showVersionDialog)
|
||||||
|
{
|
||||||
|
<div class="modal-overlay">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-title">Version speichern</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Kommentar (optional)</label>
|
||||||
|
<input @bind="versionComment" placeholder="Was hat sich geandert?" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-actions">
|
||||||
|
<button @onclick="() => showVersionDialog = false">Abbrechen</button>
|
||||||
|
<button @onclick="SaveVersioned" class="primary">Version speichern</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
@if (showSpellDiff && !string.IsNullOrEmpty(correctedText))
|
<div class="search-section">
|
||||||
{
|
<input value="@searchQuery" @oninput="HandleSearchInput" placeholder="Suchbegriff für Fakten-/Wikipedia-Recherche..."
|
||||||
|
disabled="@isChecking" />
|
||||||
|
|
||||||
|
<button @onclick="RagSearch" disabled=@buttonDisabled>Fakten suchen (RAG)</button>
|
||||||
|
<button @onclick="SearchWikipedia" disabled=@buttonDisabled>Wikipedia-Recherche</button>
|
||||||
|
</div>
|
||||||
|
<div style="display:none">@searchQuery</div>
|
||||||
|
|
||||||
|
@if (showSpellDiff && !string.IsNullOrEmpty(correctedText))
|
||||||
|
{
|
||||||
|
<div class="results-area">
|
||||||
<div class="diff-panel">
|
<div class="diff-panel">
|
||||||
<h4>Rechtschreibprüfung - Änderungen:</h4>
|
<h4>Rechtschreibprüfung - Änderungen:</h4>
|
||||||
<DiffView Original="@originalText" Corrected="@correctedText" />
|
<DiffView Original="@originalText" Corrected="@correctedText" />
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
else if (!string.IsNullOrEmpty(analysisResult))
|
}
|
||||||
{
|
else if (ragResults != null && ragResults.Count > 0)
|
||||||
<div class="result-panel">
|
{
|
||||||
|
<div class="results-area">
|
||||||
|
<h4>Gefundene Fakten (RAG):</h4>
|
||||||
|
@foreach (var r in ragResults)
|
||||||
|
{
|
||||||
|
<div class="fact-card">
|
||||||
|
<div class="fact-similarity">Ähnlichkeit: @r.Similarity.ToString("P1")</div>
|
||||||
|
<div class="fact-path">@r.FilePath</div>
|
||||||
|
<div class="fact-text">@r.Text</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else if (wikipediaResults != null && wikipediaResults.Count > 0)
|
||||||
|
{
|
||||||
|
<div class="results-area">
|
||||||
|
<h4>Wikipedia-Recherche:</h4>
|
||||||
|
@foreach (var r in wikipediaResults)
|
||||||
|
{
|
||||||
|
<div class="fact-card">
|
||||||
|
<div class="fact-similarity">@(r.Language == "de" ? "🇩🇪" : "🇬🇧") @r.Language.ToUpper()</div>
|
||||||
|
<div class="fact-path">
|
||||||
|
<a href="@r.Url" target="_blank">@r.Title</a>
|
||||||
|
</div>
|
||||||
|
<div class="fact-text">@r.Snippet</div>
|
||||||
|
@if (!string.IsNullOrEmpty(r.Extract))
|
||||||
|
{
|
||||||
|
<div class="fact-extract">@r.Extract</div>
|
||||||
|
}
|
||||||
|
<div class="fact-actions">
|
||||||
|
<button @onclick="() => LoadFullArticle(r)" disabled="@(loadedArticles.ContainsKey(r.Url))">
|
||||||
|
@(loadedArticles.ContainsKey(r.Url) ? "✓ Geladen" : "Vollständigen Artikel laden")
|
||||||
|
</button>
|
||||||
|
<button @onclick="() => SaveAsFact(r)" disabled="@(string.IsNullOrWhiteSpace(r.Extract) || currentProjectId == 0)">
|
||||||
|
Als Fakt speichern
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(analysisResult))
|
||||||
|
{
|
||||||
|
<div class="results-area">
|
||||||
<h4>Ergebnis:</h4>
|
<h4>Ergebnis:</h4>
|
||||||
<div class="result-text">@analysisResult</div>
|
<div class="result-text">@analysisResult</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (showCreateDialog)
|
||||||
|
{
|
||||||
|
<div class="modal-overlay">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-title">Neues Projekt erstellen</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Projektname</label>
|
||||||
|
<input @bind="newProjectName" placeholder="z.B. Mein Roman" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Projektpfad</label>
|
||||||
|
<input @bind="newProjectPath" placeholder="z.B. C:\Projekte\MeinRoman" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-actions">
|
||||||
|
<button @onclick="CancelCreateProject">Abbrechen</button>
|
||||||
|
<button @onclick="CreateProject" disabled="@(() => string.IsNullOrWhiteSpace(newProjectName) || string.IsNullOrWhiteSpace(newProjectPath))" class="primary">Erstellen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
|
@ -52,19 +149,81 @@ else if (!string.IsNullOrEmpty(analysisResult))
|
||||||
public int? ProjectId { get; set; }
|
public int? ProjectId { get; set; }
|
||||||
|
|
||||||
private string editorContent = string.Empty;
|
private string editorContent = string.Empty;
|
||||||
|
private string searchQuery = string.Empty;
|
||||||
private string statusText = "Bereit";
|
private string statusText = "Bereit";
|
||||||
private bool isChecking;
|
private bool isChecking;
|
||||||
|
private bool buttonDisabled;
|
||||||
private double checkProgress;
|
private double checkProgress;
|
||||||
private string analysisResult = string.Empty;
|
private string analysisResult = string.Empty;
|
||||||
private string originalText = string.Empty;
|
private string originalText = string.Empty;
|
||||||
private string correctedText = string.Empty;
|
private string correctedText = string.Empty;
|
||||||
private bool showSpellDiff;
|
private bool showSpellDiff;
|
||||||
|
private List<RagSearchResult>? ragResults;
|
||||||
|
private List<WikipediaResult>? wikipediaResults;
|
||||||
|
|
||||||
|
private int currentProjectId;
|
||||||
|
private string? currentFile;
|
||||||
|
private bool showCreateDialog;
|
||||||
|
private string newProjectName = string.Empty;
|
||||||
|
private string newProjectPath = string.Empty;
|
||||||
|
private Dictionary<string, bool> loadedArticles = new();
|
||||||
|
private bool showVersionDialog;
|
||||||
|
private string versionComment = string.Empty;
|
||||||
|
private VersionEntry? latestVersion;
|
||||||
|
|
||||||
|
private record VersionEntry(string FilePath, DateTime Timestamp, string? Comment);
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
if (Action == "newproject")
|
Navigation.LocationChanged += OnLocationChanged;
|
||||||
|
await LoadProjectContext();
|
||||||
|
|
||||||
|
if (string.Equals(Action, "newproject", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
statusText = "Bitte nutze die Einstellungen zum Erstellen eines neuen Projekts.";
|
showCreateDialog = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void OnLocationChanged(object? sender, LocationChangedEventArgs e)
|
||||||
|
{
|
||||||
|
await LoadProjectContext();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Navigation.LocationChanged -= OnLocationChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleSearchInput(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
searchQuery = e.Value?.ToString() ?? string.Empty;
|
||||||
|
buttonDisabled = isChecking || string.IsNullOrWhiteSpace(searchQuery);
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadProjectContext()
|
||||||
|
{
|
||||||
|
if (ProjectId.HasValue)
|
||||||
|
{
|
||||||
|
currentProjectId = ProjectId.Value;
|
||||||
|
SettingsService.CurrentProjectId = currentProjectId;
|
||||||
|
}
|
||||||
|
else if (SettingsService.CurrentProjectId.HasValue)
|
||||||
|
{
|
||||||
|
currentProjectId = SettingsService.CurrentProjectId.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentProjectId > 0)
|
||||||
|
await SettingsService.LoadProjectSettingsAsync();
|
||||||
|
|
||||||
|
var filePath = SettingsService.CurrentFilePath;
|
||||||
|
if (!string.IsNullOrEmpty(filePath) && File.Exists(filePath))
|
||||||
|
{
|
||||||
|
currentFile = filePath;
|
||||||
|
editorContent = await File.ReadAllTextAsync(filePath);
|
||||||
|
statusText = $"Geladen: {Path.GetFileName(filePath)}";
|
||||||
|
RefreshLatestVersion();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,6 +235,8 @@ else if (!string.IsNullOrEmpty(analysisResult))
|
||||||
statusText = "Ollama analysiert Stil...";
|
statusText = "Ollama analysiert Stil...";
|
||||||
checkProgress = 50;
|
checkProgress = 50;
|
||||||
showSpellDiff = false;
|
showSpellDiff = false;
|
||||||
|
ragResults = null;
|
||||||
|
wikipediaResults = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -101,6 +262,8 @@ else if (!string.IsNullOrEmpty(analysisResult))
|
||||||
statusText = "Ollama prüft Rechtschreibung...";
|
statusText = "Ollama prüft Rechtschreibung...";
|
||||||
checkProgress = 50;
|
checkProgress = 50;
|
||||||
showSpellDiff = false;
|
showSpellDiff = false;
|
||||||
|
ragResults = null;
|
||||||
|
wikipediaResults = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -122,15 +285,314 @@ else if (!string.IsNullOrEmpty(analysisResult))
|
||||||
|
|
||||||
private async Task RagSearch()
|
private async Task RagSearch()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(editorContent)) return;
|
if (string.IsNullOrWhiteSpace(searchQuery)) return;
|
||||||
|
|
||||||
isChecking = true;
|
isChecking = true;
|
||||||
statusText = "Suche verwandte Fakten...";
|
statusText = "Suche verwandte Fakten...";
|
||||||
showSpellDiff = false;
|
showSpellDiff = false;
|
||||||
|
analysisResult = string.Empty;
|
||||||
|
ragResults = null;
|
||||||
|
wikipediaResults = null;
|
||||||
|
|
||||||
await Task.Delay(500);
|
try
|
||||||
analysisResult = "RAG-Suche: Stelle sicher, dass ein Projekt geladen und indexiert wurde.";
|
{
|
||||||
|
if (currentProjectId == 0)
|
||||||
|
{
|
||||||
|
analysisResult = "Kein Projekt geladen. Öffne zuerst ein Projekt über die Sidebar.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ragResults = await RagService.SearchAsync(currentProjectId, searchQuery, 5);
|
||||||
|
|
||||||
|
if (ragResults.Count == 0)
|
||||||
|
{
|
||||||
|
analysisResult = "Keine relevanten Fakten gefunden. Indexiere das Projekt ggf. über 'Projekt indexieren'.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
analysisResult = $"RAG-Fehler: {ex.Message}";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
statusText = "Bereit";
|
statusText = "Bereit";
|
||||||
isChecking = false;
|
isChecking = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SearchWikipedia()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(searchQuery)) return;
|
||||||
|
|
||||||
|
isChecking = true;
|
||||||
|
statusText = "Suche auf Wikipedia...";
|
||||||
|
showSpellDiff = false;
|
||||||
|
analysisResult = string.Empty;
|
||||||
|
ragResults = null;
|
||||||
|
wikipediaResults = null;
|
||||||
|
loadedArticles.Clear();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var request = new WikipediaSearchRequest
|
||||||
|
{
|
||||||
|
Query = searchQuery,
|
||||||
|
SearchGerman = true,
|
||||||
|
SearchEnglish = true,
|
||||||
|
MaxResults = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
wikipediaResults = await WikipediaService.SearchAsync(request);
|
||||||
|
|
||||||
|
foreach (var result in wikipediaResults)
|
||||||
|
{
|
||||||
|
var extract = await WikipediaService.GetExtractAsync(result.Title, result.Language);
|
||||||
|
if (extract != null)
|
||||||
|
result.Extract = extract.Length > 800 ? extract[..800] + "..." : extract;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wikipediaResults.Count == 0)
|
||||||
|
analysisResult = "Keine Wikipedia-Artikel gefunden.";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
analysisResult = $"Wikipedia-Fehler: {ex.Message}";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
statusText = "Bereit";
|
||||||
|
isChecking = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadFullArticle(WikipediaResult result)
|
||||||
|
{
|
||||||
|
statusText = $"Lade Artikel: {result.Title}...";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fullText = await WikipediaService.GetFullArticleAsync(result.Title, result.Language);
|
||||||
|
if (fullText != null)
|
||||||
|
{
|
||||||
|
result.Extract = fullText;
|
||||||
|
loadedArticles[result.Url] = true;
|
||||||
|
statusText = "Artikel geladen.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statusText = "Konnte Artikel nicht laden.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
statusText = $"Fehler: {ex.Message}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveAsFact(WikipediaResult result)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(result.Extract) || currentProjectId == 0) return;
|
||||||
|
|
||||||
|
statusText = "Speichere als Fakt...";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var projects = await ProjectService.GetAllProjectsAsync();
|
||||||
|
var project = projects.FirstOrDefault(p => p.Id == currentProjectId);
|
||||||
|
if (project == null)
|
||||||
|
{
|
||||||
|
statusText = "Projekt nicht gefunden.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var factsDir = Path.Combine(project.RootPath, "01_Fakten");
|
||||||
|
Directory.CreateDirectory(factsDir);
|
||||||
|
|
||||||
|
var safeName = SanitizeFilename(searchQuery);
|
||||||
|
var filePath = Path.Combine(factsDir, $"{safeName}.md");
|
||||||
|
|
||||||
|
var content = $"# {result.Title}\n" +
|
||||||
|
$"- Quelle: [{result.Title}]({result.Url})\n" +
|
||||||
|
$"- Sprache: {result.Language.ToUpper()}\n" +
|
||||||
|
$"- Abgerufen: {DateTime.Now:dd.MM.yyyy HH:mm}\n\n" +
|
||||||
|
result.Extract;
|
||||||
|
|
||||||
|
await File.WriteAllTextAsync(filePath, content);
|
||||||
|
statusText = $"Gespeichert als: {safeName}.md";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
statusText = $"Fehler beim Speichern: {ex.Message}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string SanitizeFilename(string name)
|
||||||
|
{
|
||||||
|
var invalid = Path.GetInvalidFileNameChars();
|
||||||
|
var sanitized = new string(name.Where(c => !invalid.Contains(c)).ToArray());
|
||||||
|
return string.IsNullOrWhiteSpace(sanitized) ? "fakt" : sanitized.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CancelCreateProject()
|
||||||
|
{
|
||||||
|
showCreateDialog = false;
|
||||||
|
Navigation.NavigateTo("/editor");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CreateProject()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(newProjectName) || string.IsNullOrWhiteSpace(newProjectPath)) return;
|
||||||
|
|
||||||
|
isChecking = true;
|
||||||
|
statusText = "Erstelle Projekt...";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(newProjectPath);
|
||||||
|
var id = await ProjectService.CreateNewProjectAsync(newProjectName, newProjectPath);
|
||||||
|
SettingsService.CurrentProjectId = id;
|
||||||
|
await SettingsService.LoadProjectSettingsAsync();
|
||||||
|
showCreateDialog = false;
|
||||||
|
Navigation.NavigateTo($"/editor/index/{id}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
analysisResult = $"Fehler beim Erstellen: {ex.Message}";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
isChecking = false;
|
||||||
|
statusText = "Bereit";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task IndexProject()
|
||||||
|
{
|
||||||
|
if (currentProjectId == 0)
|
||||||
|
{
|
||||||
|
analysisResult = "Kein Projekt geladen. Offne zuerst ein Projekt uber die Sidebar.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isChecking = true;
|
||||||
|
statusText = "Indexiere Projekt...";
|
||||||
|
analysisResult = string.Empty;
|
||||||
|
ragResults = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var projects = await ProjectService.GetAllProjectsAsync();
|
||||||
|
var project = projects.FirstOrDefault(p => p.Id == currentProjectId);
|
||||||
|
if (project == null)
|
||||||
|
{
|
||||||
|
analysisResult = "Projekt nicht gefunden.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var p = new Progress<string>(msg =>
|
||||||
|
{
|
||||||
|
statusText = msg;
|
||||||
|
InvokeAsync(StateHasChanged);
|
||||||
|
});
|
||||||
|
|
||||||
|
await RagService.IndexProjectAsync(currentProjectId, project.RootPath, p);
|
||||||
|
analysisResult = "Projekt erfolgreich indexiert.";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
analysisResult = $"Indexierungsfehler: {ex.Message}";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
statusText = "Bereit";
|
||||||
|
isChecking = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveCurrentFile()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(currentFile)) return;
|
||||||
|
await File.WriteAllTextAsync(currentFile, editorContent);
|
||||||
|
statusText = $"Gespeichert: {Path.GetFileName(currentFile)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowVersionDialog()
|
||||||
|
{
|
||||||
|
showVersionDialog = true;
|
||||||
|
versionComment = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveVersioned()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(currentFile)) return;
|
||||||
|
|
||||||
|
var dir = Path.GetDirectoryName(currentFile)!;
|
||||||
|
var name = Path.GetFileNameWithoutExtension(currentFile);
|
||||||
|
var ext = Path.GetExtension(currentFile);
|
||||||
|
var versionsDir = Path.Combine(dir, "_versions");
|
||||||
|
Directory.CreateDirectory(versionsDir);
|
||||||
|
|
||||||
|
var stamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
||||||
|
var versionPath = Path.Combine(versionsDir, $"{name}_{stamp}{ext}");
|
||||||
|
|
||||||
|
await File.WriteAllTextAsync(currentFile, editorContent);
|
||||||
|
await File.WriteAllTextAsync(versionPath, editorContent);
|
||||||
|
var meta = $"Kommentar: {versionComment}";
|
||||||
|
await File.WriteAllTextAsync(versionPath + ".meta", meta);
|
||||||
|
|
||||||
|
statusText = $"Version gespeichert: {name}_{stamp}{ext}";
|
||||||
|
showVersionDialog = false;
|
||||||
|
versionComment = string.Empty;
|
||||||
|
RefreshLatestVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshLatestVersion()
|
||||||
|
{
|
||||||
|
latestVersion = null;
|
||||||
|
if (string.IsNullOrEmpty(currentFile)) return;
|
||||||
|
|
||||||
|
var dir = Path.GetDirectoryName(currentFile)!;
|
||||||
|
var name = Path.GetFileNameWithoutExtension(currentFile);
|
||||||
|
var ext = Path.GetExtension(currentFile);
|
||||||
|
var versionsDir = Path.Combine(dir, "_versions");
|
||||||
|
if (!Directory.Exists(versionsDir)) return;
|
||||||
|
|
||||||
|
var pattern = $"{name}_*{ext}";
|
||||||
|
var files = Directory.GetFiles(versionsDir, pattern).OrderByDescending(f => f).ToList();
|
||||||
|
if (files.Count == 0) return;
|
||||||
|
|
||||||
|
var latest = files.First();
|
||||||
|
var metaFile = latest + ".meta";
|
||||||
|
string? comment = null;
|
||||||
|
if (File.Exists(metaFile))
|
||||||
|
{
|
||||||
|
var lines = File.ReadAllLines(metaFile);
|
||||||
|
if (lines.Length > 0 && lines[0].StartsWith("Kommentar: "))
|
||||||
|
comment = lines[0]["Kommentar: ".Length..];
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileName = Path.GetFileNameWithoutExtension(latest);
|
||||||
|
var stamp = fileName[(name.Length + 1)..];
|
||||||
|
var parsed = DateTime.TryParseExact(stamp, "yyyyMMdd_HHmmss", null,
|
||||||
|
System.Globalization.DateTimeStyles.None, out var dt);
|
||||||
|
latestVersion = new VersionEntry(
|
||||||
|
latest,
|
||||||
|
parsed ? dt : File.GetLastWriteTime(latest),
|
||||||
|
comment
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadLatestVersion()
|
||||||
|
{
|
||||||
|
if (latestVersion == null) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
editorContent = await File.ReadAllTextAsync(latestVersion.FilePath);
|
||||||
|
statusText = $"Version vom {latestVersion.Timestamp:dd.MM.yyyy HH:mm} geladen.";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
statusText = $"Fehler: {ex.Message}";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
105
Components/Pages/OllamaAssistant.razor
Normal file
105
Components/Pages/OllamaAssistant.razor
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
@page "/assistant"
|
||||||
|
@inject IOllamaService OllamaService
|
||||||
|
@inject ISettingsService SettingsService
|
||||||
|
@inject NavigationManager Navigation
|
||||||
|
|
||||||
|
@rendermode InteractiveServer
|
||||||
|
|
||||||
|
<PageTitle>Assistent - Author Buddy</PageTitle>
|
||||||
|
|
||||||
|
<div class="assistant-page">
|
||||||
|
<div class="assistant-toolbar">
|
||||||
|
<select @bind="selectedMode">
|
||||||
|
<option value="advocatus">Advocatus Diaboli</option>
|
||||||
|
<option value="hookfinder">Hook-Finder</option>
|
||||||
|
<option value="eli5">ELI5-Vereinfachung</option>
|
||||||
|
</select>
|
||||||
|
<button @onclick="RunAssistant" disabled="@isRunning || string.IsNullOrWhiteSpace(inputText)">Ausführen</button>
|
||||||
|
<span style="flex:1;font-size:12px;color:var(--border-color);text-align:right;">@statusText</span>
|
||||||
|
@if (isRunning)
|
||||||
|
{
|
||||||
|
<progress value="@progress" max="100"></progress>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="assistant-panels">
|
||||||
|
<div class="assistant-input-panel">
|
||||||
|
<h4>Eingabetext</h4>
|
||||||
|
<textarea class="assistant-textarea" @bind="inputText" placeholder="Füge hier deinen Text ein..."></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="assistant-output-panel">
|
||||||
|
<h4>Ergebnis</h4>
|
||||||
|
<div class="assistant-output">
|
||||||
|
@if (!string.IsNullOrEmpty(outputText))
|
||||||
|
{
|
||||||
|
<pre>@outputText</pre>
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(errorMessage))
|
||||||
|
{
|
||||||
|
<div class="assistant-error">@errorMessage</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<span class="assistant-hint">Ergebnis erscheint hier nach der Ausführung.</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private string selectedMode = "advocatus";
|
||||||
|
private string inputText = string.Empty;
|
||||||
|
private string outputText = string.Empty;
|
||||||
|
private string errorMessage = string.Empty;
|
||||||
|
private string statusText = "Bereit";
|
||||||
|
private bool isRunning;
|
||||||
|
private double progress;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RunAssistant()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(inputText)) return;
|
||||||
|
|
||||||
|
isRunning = true;
|
||||||
|
progress = 50;
|
||||||
|
outputText = string.Empty;
|
||||||
|
errorMessage = string.Empty;
|
||||||
|
statusText = "Verarbeite...";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var systemPrompt = selectedMode switch
|
||||||
|
{
|
||||||
|
"advocatus" => await SettingsService.GetAdvocatusDiaboliPromptAsync() ?? string.Empty,
|
||||||
|
"hookfinder" => await SettingsService.GetHookFinderPromptAsync() ?? string.Empty,
|
||||||
|
"eli5" => await SettingsService.GetEli5PromptAsync() ?? string.Empty,
|
||||||
|
_ => string.Empty
|
||||||
|
};
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(systemPrompt))
|
||||||
|
{
|
||||||
|
errorMessage = "Kein System-Prompt für diesen Modus konfiguriert. Bitte in den Einstellungen hinterlegen.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var model = await SettingsService.GetStyleModelAsync() ?? "llama3.2";
|
||||||
|
outputText = await OllamaService.Chat(model, inputText, systemPrompt);
|
||||||
|
statusText = "Fertig.";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
errorMessage = $"Fehler: {ex.Message}";
|
||||||
|
statusText = "Fehler";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
isRunning = false;
|
||||||
|
progress = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
<div class="settings-layout">
|
<div class="settings-layout">
|
||||||
|
|
||||||
<div class="settings-layout-left">
|
<div class="settings-column">
|
||||||
<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">
|
||||||
|
|
@ -81,7 +81,7 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="ollamaUrl">Server-URL:</label>
|
<label for="ollamaUrl">Server-URL:</label>
|
||||||
<input id="ollamaUrl" @bind="ollamaUrl" placeholder="http://localhost:11434" />
|
<input id="ollamaUrl" @bind="ollamaUrl" placeholder="http://localhost:11434" />
|
||||||
<div class="form-hint">Adresse des Ollama-Servers (z. B. http://192.168.1.100:11434)</div>
|
<div class="form-hint">Adresse des Ollama-Servers</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -98,7 +98,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="settings-layout-right">
|
<div class="settings-column">
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<h3 class="settings-section-title">Lektor-System-Prompt</h3>
|
<h3 class="settings-section-title">Lektor-System-Prompt</h3>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
@ -121,6 +121,29 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-column">
|
||||||
|
<div class="settings-section">
|
||||||
|
<h3 class="settings-section-title">Advocatus Diaboli</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<textarea id="advocatusDiaboliPrompt" @bind="advocatusDiaboliPrompt" rows="6"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-section">
|
||||||
|
<h3 class="settings-section-title">Hook-Finder</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<textarea id="hookFinderPrompt" @bind="hookFinderPrompt" rows="6"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-section">
|
||||||
|
<h3 class="settings-section-title">ELI5-Vereinfachung</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<textarea id="eli5Prompt" @bind="eli5Prompt" rows="6"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="settings-actions">
|
<div class="settings-actions">
|
||||||
|
|
@ -142,6 +165,9 @@
|
||||||
private string lektorPrompt = string.Empty;
|
private string lektorPrompt = string.Empty;
|
||||||
private string factCheckTemplate = string.Empty;
|
private string factCheckTemplate = string.Empty;
|
||||||
private string spellingPrompt = string.Empty;
|
private string spellingPrompt = string.Empty;
|
||||||
|
private string advocatusDiaboliPrompt = string.Empty;
|
||||||
|
private string hookFinderPrompt = string.Empty;
|
||||||
|
private string eli5Prompt = string.Empty;
|
||||||
private string newProjectName = string.Empty;
|
private string newProjectName = string.Empty;
|
||||||
private string newUserName = string.Empty;
|
private string newUserName = string.Empty;
|
||||||
private string statusMessage = string.Empty;
|
private string statusMessage = string.Empty;
|
||||||
|
|
@ -155,16 +181,7 @@
|
||||||
var current = await SettingsService.GetCurrentUserAsync();
|
var current = await SettingsService.GetCurrentUserAsync();
|
||||||
selectedUserId = current.Id;
|
selectedUserId = current.Id;
|
||||||
|
|
||||||
var userSettings = await LoadUserSettingsAsync();
|
await LoadUserSettings();
|
||||||
|
|
||||||
ragModel = userSettings.ragModel;
|
|
||||||
styleModel = userSettings.styleModel;
|
|
||||||
spellingModel = userSettings.spellingModel;
|
|
||||||
selectedTheme = userSettings.selectedTheme;
|
|
||||||
ollamaUrl = userSettings.ollamaUrl;
|
|
||||||
lektorPrompt = userSettings.lektorPrompt;
|
|
||||||
factCheckTemplate = userSettings.factCheckTemplate;
|
|
||||||
spellingPrompt = userSettings.spellingPrompt;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -177,18 +194,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<(string ragModel, string styleModel, string spellingModel, string selectedTheme, string ollamaUrl, string lektorPrompt, string factCheckTemplate, string spellingPrompt)> LoadUserSettingsAsync()
|
private async Task LoadUserSettings()
|
||||||
{
|
{
|
||||||
return (
|
ragModel = await SettingsService.GetRagModelAsync() ?? "llama3.2";
|
||||||
await SettingsService.GetRagModelAsync() ?? "llama3.2",
|
styleModel = await SettingsService.GetStyleModelAsync() ?? "llama3.2";
|
||||||
await SettingsService.GetStyleModelAsync() ?? "llama3.2",
|
spellingModel = await SettingsService.GetSpellingModelAsync() ?? "phi3:mini";
|
||||||
await SettingsService.GetSpellingModelAsync() ?? "phi3:mini",
|
selectedTheme = await SettingsService.GetThemeAsync() ?? "light";
|
||||||
await SettingsService.GetThemeAsync() ?? "light",
|
ollamaUrl = await SettingsService.GetOllamaUrlAsync() ?? "http://localhost:11434";
|
||||||
await SettingsService.GetOllamaUrlAsync() ?? "http://localhost:11434",
|
lektorPrompt = await SettingsService.GetLektorSystemPromptAsync() ?? string.Empty;
|
||||||
await SettingsService.GetLektorSystemPromptAsync() ?? string.Empty,
|
factCheckTemplate = await SettingsService.GetFactCheckTemplateAsync() ?? string.Empty;
|
||||||
await SettingsService.GetFactCheckTemplateAsync() ?? string.Empty,
|
spellingPrompt = await SettingsService.GetSpellingPromptAsync() ?? string.Empty;
|
||||||
await SettingsService.GetSpellingPromptAsync() ?? string.Empty
|
advocatusDiaboliPrompt = await SettingsService.GetAdvocatusDiaboliPromptAsync() ?? string.Empty;
|
||||||
);
|
hookFinderPrompt = await SettingsService.GetHookFinderPromptAsync() ?? string.Empty;
|
||||||
|
eli5Prompt = await SettingsService.GetEli5PromptAsync() ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SwitchUser(ChangeEventArgs e)
|
private async Task SwitchUser(ChangeEventArgs e)
|
||||||
|
|
@ -197,15 +215,7 @@
|
||||||
await SettingsService.SetCurrentUserAsync(userId);
|
await SettingsService.SetCurrentUserAsync(userId);
|
||||||
selectedUserId = userId;
|
selectedUserId = userId;
|
||||||
|
|
||||||
var userSettings = await LoadUserSettingsAsync();
|
await LoadUserSettings();
|
||||||
ragModel = userSettings.ragModel;
|
|
||||||
styleModel = userSettings.styleModel;
|
|
||||||
spellingModel = userSettings.spellingModel;
|
|
||||||
selectedTheme = userSettings.selectedTheme;
|
|
||||||
ollamaUrl = userSettings.ollamaUrl;
|
|
||||||
lektorPrompt = userSettings.lektorPrompt;
|
|
||||||
factCheckTemplate = userSettings.factCheckTemplate;
|
|
||||||
spellingPrompt = userSettings.spellingPrompt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AddUser()
|
private async Task AddUser()
|
||||||
|
|
@ -221,6 +231,17 @@
|
||||||
private async Task SaveSettings()
|
private async Task SaveSettings()
|
||||||
{
|
{
|
||||||
await SettingsService.SaveOllamaUrlAsync(ollamaUrl);
|
await SettingsService.SaveOllamaUrlAsync(ollamaUrl);
|
||||||
|
OllamaService.Reconfigure(ollamaUrl);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(ragModel))
|
||||||
|
{
|
||||||
|
var ok = await OllamaService.TestEmbeddingAsync(ragModel);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
statusMessage = $"Modell '{ragModel}' unterstützt keine Embeddings. RAG-Modell nicht gespeichert.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
await SettingsService.SaveRagModelAsync(ragModel);
|
await SettingsService.SaveRagModelAsync(ragModel);
|
||||||
await SettingsService.SaveStyleModelAsync(styleModel);
|
await SettingsService.SaveStyleModelAsync(styleModel);
|
||||||
await SettingsService.SaveSpellingModelAsync(spellingModel);
|
await SettingsService.SaveSpellingModelAsync(spellingModel);
|
||||||
|
|
@ -228,7 +249,9 @@
|
||||||
await SettingsService.SaveLektorSystemPromptAsync(lektorPrompt);
|
await SettingsService.SaveLektorSystemPromptAsync(lektorPrompt);
|
||||||
await SettingsService.SaveFactCheckTemplateAsync(factCheckTemplate);
|
await SettingsService.SaveFactCheckTemplateAsync(factCheckTemplate);
|
||||||
await SettingsService.SaveSpellingPromptAsync(spellingPrompt);
|
await SettingsService.SaveSpellingPromptAsync(spellingPrompt);
|
||||||
OllamaService.Reconfigure(ollamaUrl);
|
await SettingsService.SaveAdvocatusDiaboliPromptAsync(advocatusDiaboliPrompt);
|
||||||
|
await SettingsService.SaveHookFinderPromptAsync(hookFinderPrompt);
|
||||||
|
await SettingsService.SaveEli5PromptAsync(eli5Prompt);
|
||||||
|
|
||||||
statusMessage = "Einstellungen gespeichert.";
|
statusMessage = "Einstellungen gespeichert.";
|
||||||
await ThemeService.ApplyTheme(selectedTheme);
|
await ThemeService.ApplyTheme(selectedTheme);
|
||||||
|
|
|
||||||
|
|
@ -12,4 +12,3 @@
|
||||||
@using AuthorBuddy.Web.Models
|
@using AuthorBuddy.Web.Models
|
||||||
@using AuthorBuddy.Web.Services
|
@using AuthorBuddy.Web.Services
|
||||||
@using AuthorBuddy.Web.Data
|
@using AuthorBuddy.Web.Data
|
||||||
@using Microsoft.EntityFrameworkCore
|
|
||||||
|
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
using Microsoft.Data.Sqlite;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace AuthorBuddy.Web.Data;
|
|
||||||
|
|
||||||
public class AppDbContext : DbContext
|
|
||||||
{
|
|
||||||
public DbSet<ProjectEntity> Projects => Set<ProjectEntity>();
|
|
||||||
public DbSet<SettingEntity> Settings => Set<SettingEntity>();
|
|
||||||
public DbSet<DocumentMetaEntity> DocumentMeta => Set<DocumentMetaEntity>();
|
|
||||||
public DbSet<UserEntity> Users => Set<UserEntity>();
|
|
||||||
|
|
||||||
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
modelBuilder.Entity<ProjectEntity>(entity =>
|
|
||||||
{
|
|
||||||
entity.ToTable("Projects");
|
|
||||||
entity.HasKey(e => e.Id);
|
|
||||||
entity.Property(e => e.Name).IsRequired();
|
|
||||||
entity.Property(e => e.RootPath).IsRequired();
|
|
||||||
entity.Property(e => e.LastOpened);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity<SettingEntity>(entity =>
|
|
||||||
{
|
|
||||||
entity.ToTable("Settings");
|
|
||||||
entity.HasKey(e => e.Id);
|
|
||||||
entity.Property(e => e.Key).HasColumnName("key").IsRequired();
|
|
||||||
entity.Property(e => e.Value).HasColumnName("value").IsRequired();
|
|
||||||
entity.Property(e => e.UserId).HasColumnName("user_id");
|
|
||||||
entity.Property(e => e.ProjectId).HasColumnName("project_id");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity<UserEntity>(entity =>
|
|
||||||
{
|
|
||||||
entity.ToTable("Users");
|
|
||||||
entity.HasKey(e => e.Id);
|
|
||||||
entity.Property(e => e.Name).HasColumnName("name").IsRequired();
|
|
||||||
entity.Property(e => e.IsCurrent).HasColumnName("is_current");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity<DocumentMetaEntity>(entity =>
|
|
||||||
{
|
|
||||||
entity.ToTable("DocumentMeta");
|
|
||||||
entity.HasKey(e => e.Id);
|
|
||||||
entity.Property(e => e.FilePath).HasColumnName("file_path").IsRequired();
|
|
||||||
entity.Property(e => e.LastModified).HasColumnName("last_modified");
|
|
||||||
entity.Property(e => e.FileType).HasColumnName("file_type");
|
|
||||||
entity.Property(e => e.ProjectId).HasColumnName("project_id");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetupVecExtension(string connectionString)
|
|
||||||
{
|
|
||||||
using var connection = new SqliteConnection(connectionString);
|
|
||||||
connection.Open();
|
|
||||||
connection.EnableExtensions(true);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
connection.LoadExtension("vec0");
|
|
||||||
using var testCmd = connection.CreateCommand();
|
|
||||||
testCmd.CommandText = "SELECT vec_version();";
|
|
||||||
var version = testCmd.ExecuteScalar();
|
|
||||||
Console.WriteLine($"sqlite-vec Version: {version}");
|
|
||||||
}
|
|
||||||
catch (SqliteException ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Fehler beim Laden von vec0: {ex.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
using var createVecCmd = connection.CreateCommand();
|
|
||||||
createVecCmd.CommandText = @"
|
|
||||||
CREATE VIRTUAL TABLE IF NOT EXISTS vec_documents USING vec0(
|
|
||||||
embedding float[1024]
|
|
||||||
);";
|
|
||||||
createVecCmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +1,11 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace AuthorBuddy.Web.Data;
|
namespace AuthorBuddy.Web.Data;
|
||||||
|
|
||||||
[Table("DocumentMeta")]
|
|
||||||
public class DocumentMetaEntity
|
public class DocumentMetaEntity
|
||||||
{
|
{
|
||||||
[Key]
|
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
public int? ProjectId { get; set; }
|
public int? ProjectId { get; set; }
|
||||||
|
|
||||||
[Required]
|
|
||||||
public string FilePath { get; set; } = string.Empty;
|
public string FilePath { get; set; } = string.Empty;
|
||||||
|
|
||||||
public DateTime? LastModified { get; set; }
|
public DateTime? LastModified { get; set; }
|
||||||
|
|
||||||
public string? Hash { get; set; }
|
public string? Hash { get; set; }
|
||||||
|
|
||||||
public string? FileType { get; set; }
|
public string? FileType { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
Data/DocumentVector.cs
Normal file
11
Data/DocumentVector.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
namespace AuthorBuddy.Web.Data;
|
||||||
|
|
||||||
|
public class DocumentVector
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int DocumentMetaId { get; set; }
|
||||||
|
public int ProjectId { get; set; }
|
||||||
|
public string Text { get; set; } = string.Empty;
|
||||||
|
public string Hash { get; set; } = string.Empty;
|
||||||
|
public float[] Embedding { get; set; } = Array.Empty<float>();
|
||||||
|
}
|
||||||
|
|
@ -1,20 +1,9 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace AuthorBuddy.Web.Data;
|
namespace AuthorBuddy.Web.Data;
|
||||||
|
|
||||||
[Table("Projects")]
|
|
||||||
public class ProjectEntity
|
public class ProjectEntity
|
||||||
{
|
{
|
||||||
[Key]
|
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
[Required]
|
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
[Required]
|
|
||||||
public string RootPath { get; set; } = string.Empty;
|
public string RootPath { get; set; } = string.Empty;
|
||||||
|
|
||||||
public DateTime? LastOpened { get; set; }
|
public DateTime? LastOpened { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,12 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using LiteDB;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace AuthorBuddy.Web.Data;
|
namespace AuthorBuddy.Web.Data;
|
||||||
|
|
||||||
[Table("Settings")]
|
|
||||||
public class SettingEntity
|
public class SettingEntity
|
||||||
{
|
{
|
||||||
[Key]
|
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
[Required]
|
|
||||||
public string Key { get; set; } = string.Empty;
|
public string Key { get; set; } = string.Empty;
|
||||||
|
|
||||||
[Required]
|
|
||||||
public string Value { get; set; } = string.Empty;
|
public string Value { get; set; } = string.Empty;
|
||||||
|
|
||||||
public int? UserId { get; set; }
|
public int? UserId { get; set; }
|
||||||
|
|
||||||
public int? ProjectId { get; set; }
|
public int? ProjectId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,8 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace AuthorBuddy.Web.Data;
|
namespace AuthorBuddy.Web.Data;
|
||||||
|
|
||||||
[Table("Users")]
|
|
||||||
public class UserEntity
|
public class UserEntity
|
||||||
{
|
{
|
||||||
[Key]
|
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
[Required]
|
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
public bool IsCurrent { get; set; }
|
public bool IsCurrent { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
127
Migrations/20260516151053_InitialCreate.Designer.cs
generated
127
Migrations/20260516151053_InitialCreate.Designer.cs
generated
|
|
@ -1,127 +0,0 @@
|
||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using AuthorBuddy.Web.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace AuthorBuddy.Web.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(AppDbContext))]
|
|
||||||
[Migration("20260516151053_InitialCreate")]
|
|
||||||
partial class InitialCreate
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.8");
|
|
||||||
|
|
||||||
modelBuilder.Entity("AuthorBuddy.Web.Data.DocumentMetaEntity", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("FilePath")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("file_path");
|
|
||||||
|
|
||||||
b.Property<string>("FileType")
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("file_type");
|
|
||||||
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("LastModified")
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("last_modified");
|
|
||||||
|
|
||||||
b.Property<int?>("ProjectId")
|
|
||||||
.HasColumnType("INTEGER")
|
|
||||||
.HasColumnName("project_id");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("DocumentMeta", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("AuthorBuddy.Web.Data.ProjectEntity", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("LastOpened")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("RootPath")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("Projects", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("AuthorBuddy.Web.Data.SettingEntity", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Key")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("key");
|
|
||||||
|
|
||||||
b.Property<int?>("ProjectId")
|
|
||||||
.HasColumnType("INTEGER")
|
|
||||||
.HasColumnName("project_id");
|
|
||||||
|
|
||||||
b.Property<int?>("UserId")
|
|
||||||
.HasColumnType("INTEGER")
|
|
||||||
.HasColumnName("user_id");
|
|
||||||
|
|
||||||
b.Property<string>("Value")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("value");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("Settings", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("AuthorBuddy.Web.Data.UserEntity", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<bool>("IsCurrent")
|
|
||||||
.HasColumnType("INTEGER")
|
|
||||||
.HasColumnName("is_current");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("name");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("Users", (string)null);
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
using System;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace AuthorBuddy.Web.Migrations
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public partial class InitialCreate : Migration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "DocumentMeta",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
|
||||||
project_id = table.Column<int>(type: "INTEGER", nullable: true),
|
|
||||||
file_path = table.Column<string>(type: "TEXT", nullable: false),
|
|
||||||
last_modified = table.Column<DateTime>(type: "TEXT", nullable: true),
|
|
||||||
Hash = table.Column<string>(type: "TEXT", nullable: true),
|
|
||||||
file_type = table.Column<string>(type: "TEXT", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_DocumentMeta", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Projects",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
|
||||||
Name = table.Column<string>(type: "TEXT", nullable: false),
|
|
||||||
RootPath = table.Column<string>(type: "TEXT", nullable: false),
|
|
||||||
LastOpened = table.Column<DateTime>(type: "TEXT", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Projects", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Settings",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
|
||||||
key = table.Column<string>(type: "TEXT", nullable: false),
|
|
||||||
value = table.Column<string>(type: "TEXT", nullable: false),
|
|
||||||
user_id = table.Column<int>(type: "INTEGER", nullable: true),
|
|
||||||
project_id = table.Column<int>(type: "INTEGER", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Settings", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Users",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
|
||||||
name = table.Column<string>(type: "TEXT", nullable: false),
|
|
||||||
is_current = table.Column<bool>(type: "INTEGER", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Users", x => x.Id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "DocumentMeta");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Projects");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Settings");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Users");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,124 +0,0 @@
|
||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using AuthorBuddy.Web.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace AuthorBuddy.Web.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(AppDbContext))]
|
|
||||||
partial class AppDbContextModelSnapshot : ModelSnapshot
|
|
||||||
{
|
|
||||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.8");
|
|
||||||
|
|
||||||
modelBuilder.Entity("AuthorBuddy.Web.Data.DocumentMetaEntity", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("FilePath")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("file_path");
|
|
||||||
|
|
||||||
b.Property<string>("FileType")
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("file_type");
|
|
||||||
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("LastModified")
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("last_modified");
|
|
||||||
|
|
||||||
b.Property<int?>("ProjectId")
|
|
||||||
.HasColumnType("INTEGER")
|
|
||||||
.HasColumnName("project_id");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("DocumentMeta", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("AuthorBuddy.Web.Data.ProjectEntity", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("LastOpened")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("RootPath")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("Projects", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("AuthorBuddy.Web.Data.SettingEntity", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Key")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("key");
|
|
||||||
|
|
||||||
b.Property<int?>("ProjectId")
|
|
||||||
.HasColumnType("INTEGER")
|
|
||||||
.HasColumnName("project_id");
|
|
||||||
|
|
||||||
b.Property<int?>("UserId")
|
|
||||||
.HasColumnType("INTEGER")
|
|
||||||
.HasColumnName("user_id");
|
|
||||||
|
|
||||||
b.Property<string>("Value")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("value");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("Settings", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("AuthorBuddy.Web.Data.UserEntity", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<bool>("IsCurrent")
|
|
||||||
.HasColumnType("INTEGER")
|
|
||||||
.HasColumnName("is_current");
|
|
||||||
|
|
||||||
b.Property<string>("Name")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT")
|
|
||||||
.HasColumnName("name");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.ToTable("Users", (string)null);
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -10,5 +10,5 @@ public static class Constants
|
||||||
"Exports"
|
"Exports"
|
||||||
};
|
};
|
||||||
|
|
||||||
public const string SQLiteConnection = "Data Source=author_brain.db";
|
public const string DbFile = "author_brain.db";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
9
Models/FileTreeItem.cs
Normal file
9
Models/FileTreeItem.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace AuthorBuddy.Web.Models;
|
||||||
|
|
||||||
|
public class FileTreeItem
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string FullPath { get; set; } = string.Empty;
|
||||||
|
public bool IsDirectory { get; set; }
|
||||||
|
public List<FileTreeItem> Children { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
@ -2,8 +2,8 @@ namespace AuthorBuddy.Web.Models;
|
||||||
|
|
||||||
public class OllamaSettings
|
public class OllamaSettings
|
||||||
{
|
{
|
||||||
public string StyleModel { get; set; } = "llama3.2";
|
public string StyleModel { get; set; } = "gemma4:e4b";
|
||||||
public string EmbedModel { get; set; } = "mxbai-embed-large";
|
public string EmbedModel { get; set; } = "nomic-embed-text";
|
||||||
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";
|
||||||
|
|
@ -20,6 +20,12 @@ public class OllamaSettings
|
||||||
public string SpellingPrompt { get; set; } = "Du bist ein Rechtschreibprüfer. Korrigiere NUR Fehler (Rechtschreibung/Grammatik). " +
|
public string SpellingPrompt { get; set; } = "Du bist ein Rechtschreibprüfer. Korrigiere NUR Fehler (Rechtschreibung/Grammatik). " +
|
||||||
"Ändere den Stil nicht. Gib nur den korrigierten Text zurück.";
|
"Ändere den Stil nicht. Gib nur den korrigierten Text zurück.";
|
||||||
|
|
||||||
|
public string AdvocatusDiaboliPrompt { get; set; } = "Nimm eine radikale Gegenposition zu meinem Text ein. Welche Schwachstellen in meiner Argumentation fallen dir auf?";
|
||||||
|
|
||||||
|
public string HookFinderPrompt { get; set; } = "Generiere mir 5 emotionale, packende Einstiegssätze (Hooks) für diesen Text, die den Leser sofort fesseln.";
|
||||||
|
|
||||||
|
public string Eli5Prompt { get; set; } = "Wo ist der Text zu kompliziert geschrieben? Liefere mir konkrete Vorschläge, wie ich komplexe Absätze einfacher formulieren kann, ohne den Kern zu verlieren.";
|
||||||
|
|
||||||
public string GetFactCheckPrompt(string question, string facts)
|
public string GetFactCheckPrompt(string question, string facts)
|
||||||
{
|
{
|
||||||
return string.Format(FactCheckTemplate, question, facts);
|
return string.Format(FactCheckTemplate, question, facts);
|
||||||
|
|
|
||||||
18
Models/WikipediaResult.cs
Normal file
18
Models/WikipediaResult.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
namespace AuthorBuddy.Web.Models;
|
||||||
|
|
||||||
|
public class WikipediaResult
|
||||||
|
{
|
||||||
|
public string Title { get; set; } = string.Empty;
|
||||||
|
public string Snippet { get; set; } = string.Empty;
|
||||||
|
public string Url { get; set; } = string.Empty;
|
||||||
|
public string Language { get; set; } = "de";
|
||||||
|
public string? Extract { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class WikipediaSearchRequest
|
||||||
|
{
|
||||||
|
public string Query { get; set; } = string.Empty;
|
||||||
|
public bool SearchGerman { get; set; } = true;
|
||||||
|
public bool SearchEnglish { get; set; } = true;
|
||||||
|
public int MaxResults { get; set; } = 3;
|
||||||
|
}
|
||||||
17
Program.cs
17
Program.cs
|
|
@ -2,32 +2,29 @@ using AuthorBuddy.Web.Components;
|
||||||
using AuthorBuddy.Web.Data;
|
using AuthorBuddy.Web.Data;
|
||||||
using AuthorBuddy.Web.Models;
|
using AuthorBuddy.Web.Models;
|
||||||
using AuthorBuddy.Web.Services;
|
using AuthorBuddy.Web.Services;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using LiteDB;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
builder.Services.AddRazorComponents()
|
builder.Services.AddRazorComponents()
|
||||||
.AddInteractiveServerComponents();
|
.AddInteractiveServerComponents();
|
||||||
|
|
||||||
|
var dbPath = Path.Combine(AppContext.BaseDirectory, Constants.DbFile);
|
||||||
|
builder.Services.AddSingleton<ILiteDatabase>(new LiteDatabase($"Filename={dbPath};Connection=direct"));
|
||||||
|
|
||||||
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.AddSingleton<ISettingsService, SettingsService>();
|
||||||
builder.Services.AddScoped<IThemeService, ThemeService>();
|
builder.Services.AddScoped<IThemeService, ThemeService>();
|
||||||
builder.Services.AddSingleton<IProjectService, ProjectService>();
|
builder.Services.AddSingleton<IProjectService, ProjectService>();
|
||||||
|
builder.Services.AddSingleton<IRagService, RagService>();
|
||||||
builder.Services.AddDbContextFactory<AppDbContext>(options =>
|
builder.Services.AddSingleton<IWikipediaService, WikipediaService>();
|
||||||
options.UseSqlite(Constants.SQLiteConnection));
|
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
AppDbContext.SetupVecExtension(Constants.SQLiteConnection);
|
|
||||||
|
|
||||||
await using var db = await app.Services.GetRequiredService<IDbContextFactory<AppDbContext>>().CreateDbContextAsync();
|
|
||||||
await db.Database.MigrateAsync();
|
|
||||||
|
|
||||||
var settingsInit = app.Services.GetRequiredService<ISettingsService>();
|
var settingsInit = app.Services.GetRequiredService<ISettingsService>();
|
||||||
await settingsInit.InitializeAsync();
|
settingsInit.InitializeAsync().GetAwaiter().GetResult();
|
||||||
|
|
||||||
if (!app.Environment.IsDevelopment())
|
if (!app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,17 @@
|
||||||
using AuthorBuddy.Web.Data;
|
using AuthorBuddy.Web.Data;
|
||||||
using Microsoft.Data.Sqlite;
|
using LiteDB;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace AuthorBuddy.Web.Services;
|
namespace AuthorBuddy.Web.Services;
|
||||||
|
|
||||||
public class FileScannerService : IFileScannerService
|
public class FileScannerService : IFileScannerService
|
||||||
{
|
{
|
||||||
private readonly IOllamaService _ollama;
|
private readonly IOllamaService _ollama;
|
||||||
private readonly IDbContextFactory<AppDbContext> _contextFactory;
|
private readonly ILiteDatabase _db;
|
||||||
private readonly string _connectionString;
|
|
||||||
|
|
||||||
public FileScannerService(IOllamaService ollama, IDbContextFactory<AppDbContext> contextFactory)
|
public FileScannerService(IOllamaService ollama, ILiteDatabase db)
|
||||||
{
|
{
|
||||||
_ollama = ollama;
|
_ollama = ollama;
|
||||||
_contextFactory = contextFactory;
|
_db = db;
|
||||||
_connectionString = Models.Constants.SQLiteConnection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ScanProjectFolderAsync(int projectId, string rootPath, IProgress<string> progress)
|
public async Task ScanProjectFolderAsync(int projectId, string rootPath, IProgress<string> progress)
|
||||||
|
|
@ -25,77 +22,55 @@ public class FileScannerService : IFileScannerService
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
var fileInfo = new FileInfo(file);
|
var fileInfo = new FileInfo(file);
|
||||||
bool needsUpdate = await CheckIfUpdateRequired(projectId, file, fileInfo.LastWriteTimeUtc);
|
bool needsUpdate = CheckIfUpdateRequired(projectId, file, fileInfo.LastWriteTimeUtc);
|
||||||
|
|
||||||
if (needsUpdate)
|
if (needsUpdate)
|
||||||
{
|
{
|
||||||
progress?.Report($"Verarbeite: {fileInfo.Name}...");
|
progress?.Report($"Verarbeite: {fileInfo.Name}...");
|
||||||
await ProcessAndVectorizeFile(projectId, file, fileInfo.LastWriteTimeUtc);
|
await ProcessFile(projectId, file, fileInfo.LastWriteTimeUtc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
progress?.Report("Scan abgeschlossen.");
|
progress?.Report("Scan abgeschlossen.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> CheckIfUpdateRequired(int projectId, string file, DateTime lastWriteTimeUtc)
|
private bool CheckIfUpdateRequired(int projectId, string file, DateTime lastWriteTimeUtc)
|
||||||
{
|
{
|
||||||
await using var context = await _contextFactory.CreateDbContextAsync();
|
var col = _db.GetCollection<DocumentMetaEntity>("documentMeta");
|
||||||
|
var meta = col.FindOne(m => m.ProjectId == projectId && m.FilePath == file);
|
||||||
var meta = await context.DocumentMeta
|
|
||||||
.Where(m => m.ProjectId == projectId && m.FilePath == file)
|
|
||||||
.Select(m => m.LastModified)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
if (meta == null) return true;
|
if (meta == null) return true;
|
||||||
return meta.Value < lastWriteTimeUtc;
|
return meta.LastModified < lastWriteTimeUtc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> ProcessAndVectorizeFile(int projectId, string path, DateTime lastModified)
|
private async Task<bool> ProcessFile(int projectId, string path, DateTime lastModified)
|
||||||
{
|
{
|
||||||
string content = await File.ReadAllTextAsync(path);
|
string content = await File.ReadAllTextAsync(path);
|
||||||
|
|
||||||
//var vector = await _ollama.GetEmbeddingAsync(content);
|
|
||||||
|
|
||||||
using var connection = new SqliteConnection(_connectionString);
|
|
||||||
connection.Open();
|
|
||||||
using var transaction = connection.BeginTransaction();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var cmdMeta = connection.CreateCommand();
|
var col = _db.GetCollection<DocumentMetaEntity>("documentMeta");
|
||||||
cmdMeta.CommandText = @"
|
var existing = col.FindOne(m => m.ProjectId == projectId && m.FilePath == path);
|
||||||
INSERT INTO DocumentMeta (project_id, file_path, last_modified)
|
|
||||||
VALUES (@pid, @path, @mod)
|
|
||||||
ON CONFLICT(file_path) DO UPDATE SET last_modified = @mod
|
|
||||||
RETURNING id;";
|
|
||||||
cmdMeta.Parameters.AddWithValue("@pid", projectId);
|
|
||||||
cmdMeta.Parameters.AddWithValue("@path", path);
|
|
||||||
cmdMeta.Parameters.AddWithValue("@mod", lastModified);
|
|
||||||
|
|
||||||
var docId = await cmdMeta.ExecuteScalarAsync();
|
if (existing != null)
|
||||||
|
{
|
||||||
|
existing.LastModified = lastModified;
|
||||||
|
col.Update(existing);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
col.Insert(new DocumentMetaEntity
|
||||||
|
{
|
||||||
|
ProjectId = projectId,
|
||||||
|
FilePath = path,
|
||||||
|
LastModified = lastModified,
|
||||||
|
FileType = ".md"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
byte[] blob = [];// ConvertVectorToBytes(vector);
|
|
||||||
var cmdVec = connection.CreateCommand();
|
|
||||||
cmdVec.CommandText = "INSERT INTO vec_documents(rowid, embedding) VALUES (@id, @vec) " +
|
|
||||||
"ON CONFLICT(rowid) DO UPDATE SET embedding = @vec;";
|
|
||||||
cmdVec.Parameters.AddWithValue("@id", docId);
|
|
||||||
cmdVec.Parameters.AddWithValue("@vec", blob);
|
|
||||||
await cmdVec.ExecuteNonQueryAsync();
|
|
||||||
|
|
||||||
transaction.Commit();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
transaction.Rollback();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] ConvertVectorToBytes(IList<double> vector)
|
|
||||||
{
|
|
||||||
float[] floatVector = vector.Select(d => (float)d).ToArray();
|
|
||||||
byte[] bytes = new byte[floatVector.Length * sizeof(float)];
|
|
||||||
Buffer.BlockCopy(floatVector, 0, bytes, 0, bytes.Length);
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,5 +9,8 @@ public interface IOllamaService
|
||||||
Task<IEnumerable<LLM_Model>> GetLocalModelsAsync();
|
Task<IEnumerable<LLM_Model>> GetLocalModelsAsync();
|
||||||
Task<bool> PullModelAsync(string modelName, IProgress<string> progress);
|
Task<bool> PullModelAsync(string modelName, IProgress<string> progress);
|
||||||
Task<string> QuickSpellCheckAsync(string text);
|
Task<string> QuickSpellCheckAsync(string text);
|
||||||
|
Task<float[]> GetEmbeddingAsync(string text);
|
||||||
|
Task<bool> TestEmbeddingAsync(string model);
|
||||||
|
Task<string> Chat(string model, string userMessage, string? systemPrompt = null);
|
||||||
void Reconfigure(string ollamaUrl);
|
void Reconfigure(string ollamaUrl);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,7 @@ public interface IProjectService
|
||||||
{
|
{
|
||||||
Task<int> CreateNewProjectAsync(string projectName, string rootPath);
|
Task<int> CreateNewProjectAsync(string projectName, string rootPath);
|
||||||
Task<List<Project>> GetAllProjectsAsync();
|
Task<List<Project>> GetAllProjectsAsync();
|
||||||
|
Task<Project?> GetProjectAsync(int projectId);
|
||||||
|
Task<List<FileTreeItem>> GetProjectFileTreeAsync(int projectId);
|
||||||
Task SyncProjectFilesAsync(int projectId, string directoryPath, IProgress<string> progress);
|
Task SyncProjectFilesAsync(int projectId, string directoryPath, IProgress<string> progress);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
Services/IRagService.cs
Normal file
14
Services/IRagService.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
namespace AuthorBuddy.Web.Services;
|
||||||
|
|
||||||
|
public class RagSearchResult
|
||||||
|
{
|
||||||
|
public string Text { get; set; } = string.Empty;
|
||||||
|
public string FilePath { get; set; } = string.Empty;
|
||||||
|
public double Similarity { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IRagService
|
||||||
|
{
|
||||||
|
Task IndexProjectAsync(int projectId, string rootPath, IProgress<string> progress);
|
||||||
|
Task<List<RagSearchResult>> SearchAsync(int projectId, string query, int topN = 5);
|
||||||
|
}
|
||||||
|
|
@ -18,10 +18,16 @@ public interface ISettingsService
|
||||||
Task<string?> GetLektorSystemPromptAsync();
|
Task<string?> GetLektorSystemPromptAsync();
|
||||||
Task<string?> GetFactCheckTemplateAsync();
|
Task<string?> GetFactCheckTemplateAsync();
|
||||||
Task<string?> GetSpellingPromptAsync();
|
Task<string?> GetSpellingPromptAsync();
|
||||||
|
Task<string?> GetAdvocatusDiaboliPromptAsync();
|
||||||
|
Task<string?> GetHookFinderPromptAsync();
|
||||||
|
Task<string?> GetEli5PromptAsync();
|
||||||
|
|
||||||
Task SaveLektorSystemPromptAsync(string prompt);
|
Task SaveLektorSystemPromptAsync(string prompt);
|
||||||
Task SaveFactCheckTemplateAsync(string prompt);
|
Task SaveFactCheckTemplateAsync(string prompt);
|
||||||
Task SaveSpellingPromptAsync(string prompt);
|
Task SaveSpellingPromptAsync(string prompt);
|
||||||
|
Task SaveAdvocatusDiaboliPromptAsync(string prompt);
|
||||||
|
Task SaveHookFinderPromptAsync(string prompt);
|
||||||
|
Task SaveEli5PromptAsync(string prompt);
|
||||||
|
|
||||||
Task<List<UserEntity>> GetUsersAsync();
|
Task<List<UserEntity>> GetUsersAsync();
|
||||||
Task<UserEntity> GetCurrentUserAsync();
|
Task<UserEntity> GetCurrentUserAsync();
|
||||||
|
|
@ -29,6 +35,10 @@ public interface ISettingsService
|
||||||
Task<UserEntity> CreateUserAsync(string name);
|
Task<UserEntity> CreateUserAsync(string name);
|
||||||
|
|
||||||
int? CurrentProjectId { get; set; }
|
int? CurrentProjectId { get; set; }
|
||||||
|
string? CurrentFilePath { get; set; }
|
||||||
|
Task<int?> GetLastProjectIdAsync();
|
||||||
|
Task SaveLastProjectIdAsync(int projectId);
|
||||||
|
Task LoadProjectSettingsAsync();
|
||||||
|
|
||||||
Task InitializeAsync();
|
Task InitializeAsync(int projectId = -1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
Services/IWikipediaService.cs
Normal file
11
Services/IWikipediaService.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
using AuthorBuddy.Web.Models;
|
||||||
|
|
||||||
|
namespace AuthorBuddy.Web.Services;
|
||||||
|
|
||||||
|
public interface IWikipediaService
|
||||||
|
{
|
||||||
|
Task<List<WikipediaResult>> SearchAsync(string query, int maxResults = 3);
|
||||||
|
Task<List<WikipediaResult>> SearchAsync(WikipediaSearchRequest request);
|
||||||
|
Task<string?> GetExtractAsync(string title, string language = "de");
|
||||||
|
Task<string?> GetFullArticleAsync(string title, string language = "de");
|
||||||
|
}
|
||||||
|
|
@ -22,6 +22,53 @@ public class OllamaService : IOllamaService
|
||||||
_baseUrl = url;
|
_baseUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> TestEmbeddingAsync(string model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var request = new { model = model, prompt = "test" };
|
||||||
|
var response = await _httpClient.PostAsJsonAsync($"{_baseUrl}/api/embeddings", request);
|
||||||
|
if (!response.IsSuccessStatusCode) return false;
|
||||||
|
|
||||||
|
var content = await response.Content.ReadAsStringAsync();
|
||||||
|
using var doc = JsonDocument.Parse(content);
|
||||||
|
if (doc.RootElement.TryGetProperty("embedding", out var embedding))
|
||||||
|
return embedding.EnumerateArray().Any();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<float[]> GetEmbeddingAsync(string text)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var request = new { model = _settings.EmbedModel, prompt = text };
|
||||||
|
var response = await _httpClient.PostAsJsonAsync($"{_baseUrl}/api/embeddings", request);
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var content = await response.Content.ReadAsStringAsync();
|
||||||
|
using var doc = JsonDocument.Parse(content);
|
||||||
|
if (doc.RootElement.TryGetProperty("embedding", out var embedding))
|
||||||
|
{
|
||||||
|
var list = new List<float>();
|
||||||
|
foreach (var val in embedding.EnumerateArray())
|
||||||
|
list.Add(val.GetSingle());
|
||||||
|
return list.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Array.Empty<float>();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return Array.Empty<float>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<LLM_Model>> GetLocalModelsAsync()
|
public async Task<IEnumerable<LLM_Model>> GetLocalModelsAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
using AuthorBuddy.Web.Data;
|
using AuthorBuddy.Web.Data;
|
||||||
using AuthorBuddy.Web.Models;
|
using AuthorBuddy.Web.Models;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using LiteDB;
|
||||||
|
|
||||||
namespace AuthorBuddy.Web.Services;
|
namespace AuthorBuddy.Web.Services;
|
||||||
|
|
||||||
public class ProjectService : IProjectService
|
public class ProjectService : IProjectService
|
||||||
{
|
{
|
||||||
private readonly IDbContextFactory<AppDbContext> _contextFactory;
|
private readonly ILiteDatabase _db;
|
||||||
private readonly IFileScannerService _fileScannerService;
|
private readonly IFileScannerService _fileScannerService;
|
||||||
|
|
||||||
public ProjectService(IDbContextFactory<AppDbContext> contextFactory, IFileScannerService fileScannerService)
|
public ProjectService(ILiteDatabase db, IFileScannerService fileScannerService)
|
||||||
{
|
{
|
||||||
_contextFactory = contextFactory;
|
_db = db;
|
||||||
_fileScannerService = fileScannerService;
|
_fileScannerService = fileScannerService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> CreateNewProjectAsync(string projectName, string rootPath)
|
public Task<int> CreateNewProjectAsync(string projectName, string rootPath)
|
||||||
{
|
{
|
||||||
string[] subFolders = { "00_Drafts", "01_Fakten", "02_Characters", "03_Archive" };
|
string[] subFolders = { "00_Drafts", "01_Fakten", "02_Characters", "03_Archive" };
|
||||||
foreach (var subFolder in subFolders)
|
foreach (var subFolder in subFolders)
|
||||||
|
|
@ -24,10 +24,9 @@ public class ProjectService : IProjectService
|
||||||
}
|
}
|
||||||
|
|
||||||
string readmePath = Path.Combine(rootPath, "00_Projekt_Info.md");
|
string readmePath = Path.Combine(rootPath, "00_Projekt_Info.md");
|
||||||
await File.WriteAllTextAsync(readmePath, $"# Projekt: {projectName}\nErstellt am: {DateTime.Now}");
|
File.WriteAllText(readmePath, $"# Projekt: {projectName}\nErstellt am: {DateTime.Now}");
|
||||||
|
|
||||||
await using var context = await _contextFactory.CreateDbContextAsync();
|
|
||||||
|
|
||||||
|
var col = _db.GetCollection<ProjectEntity>("projects");
|
||||||
var entity = new ProjectEntity
|
var entity = new ProjectEntity
|
||||||
{
|
{
|
||||||
Name = projectName,
|
Name = projectName,
|
||||||
|
|
@ -35,17 +34,14 @@ public class ProjectService : IProjectService
|
||||||
LastOpened = DateTime.Now
|
LastOpened = DateTime.Now
|
||||||
};
|
};
|
||||||
|
|
||||||
context.Projects.Add(entity);
|
col.Insert(entity);
|
||||||
await context.SaveChangesAsync();
|
return Task.FromResult(entity.Id);
|
||||||
|
|
||||||
return entity.Id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<Project>> GetAllProjectsAsync()
|
public Task<List<Project>> GetAllProjectsAsync()
|
||||||
{
|
{
|
||||||
await using var context = await _contextFactory.CreateDbContextAsync();
|
var col = _db.GetCollection<ProjectEntity>("projects");
|
||||||
|
var list = col.FindAll()
|
||||||
return await context.Projects
|
|
||||||
.OrderByDescending(p => p.LastOpened)
|
.OrderByDescending(p => p.LastOpened)
|
||||||
.Select(p => new Project
|
.Select(p => new Project
|
||||||
{
|
{
|
||||||
|
|
@ -53,7 +49,64 @@ public class ProjectService : IProjectService
|
||||||
Name = p.Name,
|
Name = p.Name,
|
||||||
RootPath = p.RootPath
|
RootPath = p.RootPath
|
||||||
})
|
})
|
||||||
.ToListAsync();
|
.ToList();
|
||||||
|
return Task.FromResult(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Project?> GetProjectAsync(int projectId)
|
||||||
|
{
|
||||||
|
var col = _db.GetCollection<ProjectEntity>("projects");
|
||||||
|
var entity = col.FindById(projectId);
|
||||||
|
if (entity == null) return Task.FromResult<Project?>(null);
|
||||||
|
return Task.FromResult<Project?>(new Project
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
Name = entity.Name,
|
||||||
|
RootPath = entity.RootPath
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<List<FileTreeItem>> GetProjectFileTreeAsync(int projectId)
|
||||||
|
{
|
||||||
|
var col = _db.GetCollection<ProjectEntity>("projects");
|
||||||
|
var entity = col.FindById(projectId);
|
||||||
|
if (entity == null || !Directory.Exists(entity.RootPath))
|
||||||
|
return Task.FromResult(new List<FileTreeItem>());
|
||||||
|
|
||||||
|
var result = new List<FileTreeItem>();
|
||||||
|
BuildTree(entity.RootPath, result, 0);
|
||||||
|
return Task.FromResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BuildTree(string directory, List<FileTreeItem> items, int depth)
|
||||||
|
{
|
||||||
|
if (depth > 4) return;
|
||||||
|
|
||||||
|
var dirInfo = new DirectoryInfo(directory);
|
||||||
|
if (!dirInfo.Exists) return;
|
||||||
|
|
||||||
|
foreach (var dir in dirInfo.GetDirectories().OrderBy(d => d.Name))
|
||||||
|
{
|
||||||
|
var node = new FileTreeItem
|
||||||
|
{
|
||||||
|
Name = dir.Name,
|
||||||
|
FullPath = dir.FullName,
|
||||||
|
IsDirectory = true
|
||||||
|
};
|
||||||
|
BuildTree(dir.FullName, node.Children, depth + 1);
|
||||||
|
if (node.Children.Count > 0 || dir.Name.StartsWith("00_") || dir.Name.StartsWith("01_") || dir.Name.StartsWith("02_"))
|
||||||
|
items.Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var file in dirInfo.GetFiles("*.md").OrderBy(f => f.Name))
|
||||||
|
{
|
||||||
|
items.Add(new FileTreeItem
|
||||||
|
{
|
||||||
|
Name = file.Name,
|
||||||
|
FullPath = file.FullName,
|
||||||
|
IsDirectory = false
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SyncProjectFilesAsync(int projectId, string directoryPath, IProgress<string> progress)
|
public async Task SyncProjectFilesAsync(int projectId, string directoryPath, IProgress<string> progress)
|
||||||
|
|
|
||||||
145
Services/RagService.cs
Normal file
145
Services/RagService.cs
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
using AuthorBuddy.Web.Data;
|
||||||
|
using LiteDB;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AuthorBuddy.Web.Services;
|
||||||
|
|
||||||
|
public class RagService : IRagService
|
||||||
|
{
|
||||||
|
private readonly ILiteDatabase _db;
|
||||||
|
private readonly IOllamaService _ollama;
|
||||||
|
|
||||||
|
public RagService(ILiteDatabase db, IOllamaService ollama)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
_ollama = ollama;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task IndexProjectAsync(int projectId, string rootPath, IProgress<string> progress)
|
||||||
|
{
|
||||||
|
var files = Directory.GetFiles(rootPath, "*.md", SearchOption.AllDirectories)
|
||||||
|
.Where(f => f.Contains("00_Drafts") || f.Contains("01_Fakten"));
|
||||||
|
|
||||||
|
var metaCol = _db.GetCollection<DocumentMetaEntity>("documentMeta");
|
||||||
|
var vecCol = _db.GetCollection<DocumentVector>("vectors");
|
||||||
|
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
progress?.Report($"Indexiere: {Path.GetFileName(file)}...");
|
||||||
|
|
||||||
|
string content = await File.ReadAllTextAsync(file);
|
||||||
|
string hash = ComputeHash(content);
|
||||||
|
|
||||||
|
var meta = metaCol.FindOne(m => m.ProjectId == projectId && m.FilePath == file);
|
||||||
|
|
||||||
|
if (meta != null && meta.Hash == hash)
|
||||||
|
{
|
||||||
|
var existingVec = vecCol.FindOne(v => v.DocumentMetaId == meta.Id);
|
||||||
|
if (existingVec != null)
|
||||||
|
{
|
||||||
|
progress?.Report($" ↳ unverändert, übersprungen");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var embedding = await _ollama.GetEmbeddingAsync(content);
|
||||||
|
if (embedding.Length == 0)
|
||||||
|
{
|
||||||
|
progress?.Report($" ↳ Fehler beim Embedding, übersprungen");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta == null)
|
||||||
|
{
|
||||||
|
meta = new DocumentMetaEntity
|
||||||
|
{
|
||||||
|
ProjectId = projectId,
|
||||||
|
FilePath = file,
|
||||||
|
LastModified = File.GetLastWriteTimeUtc(file),
|
||||||
|
Hash = hash,
|
||||||
|
FileType = ".md"
|
||||||
|
};
|
||||||
|
metaCol.Insert(meta);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
meta.LastModified = File.GetLastWriteTimeUtc(file);
|
||||||
|
meta.Hash = hash;
|
||||||
|
metaCol.Update(meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
var vec = vecCol.FindOne(v => v.DocumentMetaId == meta.Id);
|
||||||
|
if (vec != null)
|
||||||
|
{
|
||||||
|
vec.Text = content;
|
||||||
|
vec.Hash = hash;
|
||||||
|
vec.Embedding = embedding;
|
||||||
|
vecCol.Update(vec);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vecCol.Insert(new DocumentVector
|
||||||
|
{
|
||||||
|
DocumentMetaId = meta.Id,
|
||||||
|
ProjectId = projectId,
|
||||||
|
Text = content,
|
||||||
|
Hash = hash,
|
||||||
|
Embedding = embedding
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
progress?.Report($" ↳ ✓ {embedding.Length} Dimensionen");
|
||||||
|
}
|
||||||
|
|
||||||
|
progress?.Report("Indexierung abgeschlossen.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<RagSearchResult>> SearchAsync(int projectId, string query, int topN = 5)
|
||||||
|
{
|
||||||
|
var queryVec = await _ollama.GetEmbeddingAsync(query);
|
||||||
|
if (queryVec.Length == 0)
|
||||||
|
return new List<RagSearchResult>();
|
||||||
|
|
||||||
|
var vecCol = _db.GetCollection<DocumentVector>("vectors");
|
||||||
|
var metaCol = _db.GetCollection<DocumentMetaEntity>("documentMeta");
|
||||||
|
|
||||||
|
var vectors = vecCol.Find(v => v.ProjectId == projectId).ToList();
|
||||||
|
var results = new List<RagSearchResult>();
|
||||||
|
|
||||||
|
foreach (var vec in vectors)
|
||||||
|
{
|
||||||
|
var sim = CosineSimilarity(queryVec, vec.Embedding);
|
||||||
|
if (sim > 0)
|
||||||
|
{
|
||||||
|
var meta = metaCol.FindById(vec.DocumentMetaId);
|
||||||
|
results.Add(new RagSearchResult
|
||||||
|
{
|
||||||
|
Text = vec.Text.Length > 500 ? vec.Text[..500] + "..." : vec.Text,
|
||||||
|
FilePath = meta?.FilePath ?? "",
|
||||||
|
Similarity = sim
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results.OrderByDescending(r => r.Similarity).Take(topN).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ComputeHash(string content)
|
||||||
|
{
|
||||||
|
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(content));
|
||||||
|
return Convert.ToHexStringLower(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double CosineSimilarity(float[] a, float[] b)
|
||||||
|
{
|
||||||
|
double dotProduct = 0.0, l2A = 0.0, l2B = 0.0;
|
||||||
|
for (int i = 0; i < a.Length; i++)
|
||||||
|
{
|
||||||
|
dotProduct += a[i] * b[i];
|
||||||
|
l2A += Math.Pow(a[i], 2);
|
||||||
|
l2B += Math.Pow(b[i], 2);
|
||||||
|
}
|
||||||
|
return dotProduct / (Math.Sqrt(l2A) * Math.Sqrt(l2B));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using AuthorBuddy.Web.Data;
|
using AuthorBuddy.Web.Data;
|
||||||
using AuthorBuddy.Web.Models;
|
using AuthorBuddy.Web.Models;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using LiteDB;
|
||||||
|
|
||||||
namespace AuthorBuddy.Web.Services;
|
namespace AuthorBuddy.Web.Services;
|
||||||
|
|
||||||
|
|
@ -14,15 +14,18 @@ public class SettingsService : ISettingsService
|
||||||
private const string KeyLektorPrompt = "ollama_lektor_prompt";
|
private const string KeyLektorPrompt = "ollama_lektor_prompt";
|
||||||
private const string KeyFactCheckTemplate = "ollama_fact_check";
|
private const string KeyFactCheckTemplate = "ollama_fact_check";
|
||||||
private const string KeySpellingPrompt = "ollama_spelling_prompt";
|
private const string KeySpellingPrompt = "ollama_spelling_prompt";
|
||||||
|
private const string KeyAdvocatusDiaboli = "ollama_advocatus_diaboli";
|
||||||
|
private const string KeyHookFinder = "ollama_hook_finder";
|
||||||
|
private const string KeyEli5 = "ollama_eli5";
|
||||||
|
|
||||||
private readonly IDbContextFactory<AppDbContext> _contextFactory;
|
private readonly ILiteDatabase _db;
|
||||||
private readonly OllamaSettings _ollamaConfig;
|
private readonly OllamaSettings _ollamaConfig;
|
||||||
private int? _currentUserId;
|
private int? _currentUserId;
|
||||||
private int? _currentProjectId;
|
private int? _currentProjectId;
|
||||||
|
|
||||||
public SettingsService(IDbContextFactory<AppDbContext> contextFactory, OllamaSettings ollamaConfig)
|
public SettingsService(ILiteDatabase db, OllamaSettings ollamaConfig)
|
||||||
{
|
{
|
||||||
_contextFactory = contextFactory;
|
_db = db;
|
||||||
_ollamaConfig = ollamaConfig;
|
_ollamaConfig = ollamaConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,156 +35,250 @@ public class SettingsService : ISettingsService
|
||||||
set => _currentProjectId = value;
|
set => _currentProjectId = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string?> GetSettingAsync(string key, int? userId, int? projectId)
|
public string? CurrentFilePath { get; set; }
|
||||||
{
|
|
||||||
await using var context = await _contextFactory.CreateDbContextAsync();
|
|
||||||
|
|
||||||
var matches = context.Settings.Where(s =>
|
private const string KeyLastProjectId = "last_project_id";
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
var col = _db.GetCollection<SettingEntity>("settings");
|
||||||
|
|
||||||
|
var matches = col.Find(s =>
|
||||||
s.Key == key &&
|
s.Key == key &&
|
||||||
(s.UserId == userId || s.UserId == null) &&
|
(s.UserId == userId || s.UserId == null) &&
|
||||||
(s.ProjectId == projectId || s.ProjectId == null));
|
(s.ProjectId == projectId || s.ProjectId == null));
|
||||||
|
|
||||||
var setting = await matches
|
return matches
|
||||||
.OrderByDescending(s => s.UserId != null)
|
.OrderByDescending(s => s.UserId != null)
|
||||||
.ThenByDescending(s => s.ProjectId != null)
|
.ThenByDescending(s => s.ProjectId != null)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefault()?.Value;
|
||||||
|
|
||||||
return setting?.Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string?> GetAsync(string key)
|
private string? Get(string key)
|
||||||
{
|
{
|
||||||
return await GetSettingAsync(key, _currentUserId, _currentProjectId);
|
return GetSetting(key, _currentUserId, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetAsync(string key, string value)
|
private void Set(string key, string value)
|
||||||
{
|
{
|
||||||
await using var context = await _contextFactory.CreateDbContextAsync();
|
var col = _db.GetCollection<SettingEntity>("settings");
|
||||||
|
|
||||||
var existing = await context.Settings
|
var existing = col.FindOne(s =>
|
||||||
.Where(s => s.Key == key && s.UserId == _currentUserId && s.ProjectId == _currentProjectId)
|
s.Key == key && s.UserId == _currentUserId && s.ProjectId == null);
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
if (existing != null)
|
if (existing != null)
|
||||||
{
|
{
|
||||||
existing.Value = value;
|
existing.Value = value;
|
||||||
|
col.Update(existing);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
context.Settings.Add(new SettingEntity
|
col.Insert(new SettingEntity
|
||||||
{
|
{
|
||||||
Key = key,
|
Key = key,
|
||||||
Value = value,
|
Value = value,
|
||||||
UserId = _currentUserId,
|
UserId = _currentUserId,
|
||||||
ProjectId = _currentProjectId
|
ProjectId = null
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<string?> GetOllamaUrlAsync() => GetAsync(KeyOllamaUrl);
|
public Task<string?> GetOllamaUrlAsync() => Task.FromResult(Get(KeyOllamaUrl));
|
||||||
public Task<string?> GetRagModelAsync() => GetAsync(KeyRagModel);
|
public Task<string?> GetRagModelAsync() => Task.FromResult(Get(KeyRagModel));
|
||||||
public Task<string?> GetStyleModelAsync() => GetAsync(KeyStyleModel);
|
public Task<string?> GetStyleModelAsync() => Task.FromResult(Get(KeyStyleModel));
|
||||||
public Task<string?> GetLektorSystemPromptAsync() => GetAsync(KeyLektorPrompt);
|
public Task<string?> GetLektorSystemPromptAsync() => Task.FromResult(Get(KeyLektorPrompt));
|
||||||
public Task<string?> GetFactCheckTemplateAsync() => GetAsync(KeyFactCheckTemplate);
|
public Task<string?> GetFactCheckTemplateAsync() => Task.FromResult(Get(KeyFactCheckTemplate));
|
||||||
public Task<string?> GetSpellingPromptAsync() => GetAsync(KeySpellingPrompt);
|
public Task<string?> GetSpellingPromptAsync() => Task.FromResult(Get(KeySpellingPrompt));
|
||||||
public Task<string?> GetSpellingModelAsync() => GetAsync(KeySpellingModel);
|
public Task<string?> GetSpellingModelAsync() => Task.FromResult(Get(KeySpellingModel));
|
||||||
public Task<string?> GetThemeAsync() => GetAsync(KeyTheme);
|
public Task<string?> GetAdvocatusDiaboliPromptAsync() => Task.FromResult(Get(KeyAdvocatusDiaboli));
|
||||||
|
public Task<string?> GetHookFinderPromptAsync() => Task.FromResult(Get(KeyHookFinder));
|
||||||
|
public Task<string?> GetEli5PromptAsync() => Task.FromResult(Get(KeyEli5));
|
||||||
|
public Task<string?> GetThemeAsync() => Task.FromResult(Get(KeyTheme));
|
||||||
|
|
||||||
public async Task SaveOllamaUrlAsync(string url)
|
public Task SaveOllamaUrlAsync(string url)
|
||||||
{
|
{
|
||||||
await SetAsync(KeyOllamaUrl, url);
|
Set(KeyOllamaUrl, url);
|
||||||
_ollamaConfig.OllamaUrl = url;
|
_ollamaConfig.OllamaUrl = url;
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveRagModelAsync(string model)
|
public Task SaveRagModelAsync(string model)
|
||||||
{
|
{
|
||||||
await SetAsync(KeyRagModel, model);
|
Set(KeyRagModel, model);
|
||||||
|
_ollamaConfig.EmbedModel = model;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SaveStyleModelAsync(string model)
|
||||||
|
{
|
||||||
|
Set(KeyStyleModel, model);
|
||||||
_ollamaConfig.StyleModel = model;
|
_ollamaConfig.StyleModel = model;
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveStyleModelAsync(string model)
|
public Task SaveLektorSystemPromptAsync(string prompt)
|
||||||
{
|
{
|
||||||
await SetAsync(KeyStyleModel, model);
|
Set(KeyLektorPrompt, prompt);
|
||||||
_ollamaConfig.StyleModel = model;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SaveLektorSystemPromptAsync(string prompt)
|
|
||||||
{
|
|
||||||
await SetAsync(KeyLektorPrompt, prompt);
|
|
||||||
_ollamaConfig.LektorSystemPrompt = prompt;
|
_ollamaConfig.LektorSystemPrompt = prompt;
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveFactCheckTemplateAsync(string prompt)
|
public Task SaveFactCheckTemplateAsync(string prompt)
|
||||||
{
|
{
|
||||||
await SetAsync(KeyFactCheckTemplate, prompt);
|
Set(KeyFactCheckTemplate, prompt);
|
||||||
_ollamaConfig.FactCheckTemplate = prompt;
|
_ollamaConfig.FactCheckTemplate = prompt;
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveSpellingPromptAsync(string prompt)
|
public Task SaveSpellingPromptAsync(string prompt)
|
||||||
{
|
{
|
||||||
await SetAsync(KeySpellingPrompt, prompt);
|
Set(KeySpellingPrompt, prompt);
|
||||||
_ollamaConfig.SpellingPrompt = prompt;
|
_ollamaConfig.SpellingPrompt = prompt;
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveSpellingModelAsync(string model)
|
public Task SaveSpellingModelAsync(string model)
|
||||||
{
|
{
|
||||||
await SetAsync(KeySpellingModel, model);
|
Set(KeySpellingModel, model);
|
||||||
_ollamaConfig.SpellingModel = model;
|
_ollamaConfig.SpellingModel = model;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SaveAdvocatusDiaboliPromptAsync(string prompt)
|
||||||
|
{
|
||||||
|
Set(KeyAdvocatusDiaboli, prompt);
|
||||||
|
_ollamaConfig.AdvocatusDiaboliPrompt = prompt;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SaveHookFinderPromptAsync(string prompt)
|
||||||
|
{
|
||||||
|
Set(KeyHookFinder, prompt);
|
||||||
|
_ollamaConfig.HookFinderPrompt = prompt;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SaveEli5PromptAsync(string prompt)
|
||||||
|
{
|
||||||
|
Set(KeyEli5, prompt);
|
||||||
|
_ollamaConfig.Eli5Prompt = prompt;
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SaveThemeAsync(string theme)
|
public Task SaveThemeAsync(string theme)
|
||||||
=> SetAsync(KeyTheme, theme);
|
|
||||||
|
|
||||||
public async Task<List<UserEntity>> GetUsersAsync()
|
|
||||||
{
|
{
|
||||||
await using var context = await _contextFactory.CreateDbContextAsync();
|
Set(KeyTheme, theme);
|
||||||
return await context.Users.ToListAsync();
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<UserEntity> GetCurrentUserAsync()
|
public Task<List<UserEntity>> GetUsersAsync()
|
||||||
{
|
{
|
||||||
await using var context = await _contextFactory.CreateDbContextAsync();
|
var col = _db.GetCollection<UserEntity>("users");
|
||||||
var user = await context.Users.FirstOrDefaultAsync(u => u.IsCurrent);
|
return Task.FromResult(col.FindAll().ToList());
|
||||||
return user ?? await context.Users.FirstAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SetCurrentUserAsync(int userId)
|
public Task<UserEntity> GetCurrentUserAsync()
|
||||||
{
|
{
|
||||||
await using var context = await _contextFactory.CreateDbContextAsync();
|
var col = _db.GetCollection<UserEntity>("users");
|
||||||
var users = await context.Users.ToListAsync();
|
var user = col.FindOne(u => u.IsCurrent);
|
||||||
|
return Task.FromResult(user ?? col.FindAll().First());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SetCurrentUserAsync(int userId)
|
||||||
|
{
|
||||||
|
var col = _db.GetCollection<UserEntity>("users");
|
||||||
|
var users = col.FindAll().ToList();
|
||||||
foreach (var u in users)
|
foreach (var u in users)
|
||||||
|
{
|
||||||
u.IsCurrent = u.Id == userId;
|
u.IsCurrent = u.Id == userId;
|
||||||
await context.SaveChangesAsync();
|
col.Update(u);
|
||||||
|
}
|
||||||
_currentUserId = userId;
|
_currentUserId = userId;
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<UserEntity> CreateUserAsync(string name)
|
public Task<UserEntity> CreateUserAsync(string name)
|
||||||
{
|
{
|
||||||
await using var context = await _contextFactory.CreateDbContextAsync();
|
var col = _db.GetCollection<UserEntity>("users");
|
||||||
var user = new UserEntity { Name = name };
|
var user = new UserEntity { Name = name };
|
||||||
context.Users.Add(user);
|
col.Insert(user);
|
||||||
await context.SaveChangesAsync();
|
return Task.FromResult(user);
|
||||||
return user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InitializeAsync()
|
public Task LoadProjectSettingsAsync()
|
||||||
{
|
{
|
||||||
await using var context = await _contextFactory.CreateDbContextAsync();
|
var settings = _db.GetCollection<SettingEntity>("settings");
|
||||||
|
var entries = new (string Key, Action<string> Setter)[]
|
||||||
|
{
|
||||||
|
(KeyOllamaUrl, val => _ollamaConfig.OllamaUrl = val),
|
||||||
|
(KeyRagModel, val => _ollamaConfig.EmbedModel = val),
|
||||||
|
(KeyStyleModel, val => _ollamaConfig.StyleModel = val),
|
||||||
|
(KeySpellingModel, val => _ollamaConfig.SpellingModel = val),
|
||||||
|
(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),
|
||||||
|
};
|
||||||
|
|
||||||
var userExists = await context.Users.AnyAsync();
|
foreach (var entry in entries)
|
||||||
|
{
|
||||||
|
var val = Get(entry.Key);
|
||||||
|
if (val != null) entry.Setter(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task InitializeAsync(int projectId = -1)
|
||||||
|
{
|
||||||
|
var users = _db.GetCollection<UserEntity>("users");
|
||||||
|
var settings = _db.GetCollection<SettingEntity>("settings");
|
||||||
|
|
||||||
|
var userExists = users.FindAll().Any();
|
||||||
if (!userExists)
|
if (!userExists)
|
||||||
{
|
{
|
||||||
var defaultUser = new UserEntity { Name = "Standardbenutzer", IsCurrent = true };
|
var defaultUser = new UserEntity { Name = "Standardbenutzer", IsCurrent = true };
|
||||||
context.Users.Add(defaultUser);
|
users.Insert(defaultUser);
|
||||||
await context.SaveChangesAsync();
|
|
||||||
_currentUserId = defaultUser.Id;
|
_currentUserId = defaultUser.Id;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var current = await context.Users.FirstOrDefaultAsync(u => u.IsCurrent);
|
var current = users.FindOne(u => u.IsCurrent);
|
||||||
_currentUserId = current?.Id ?? (await context.Users.FirstAsync()).Id;
|
_currentUserId = current?.Id ?? users.FindAll().First().Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
var entries = new (string Key, string Default)[]
|
var entries = new (string Key, string Default)[]
|
||||||
|
|
@ -194,29 +291,34 @@ public class SettingsService : ISettingsService
|
||||||
(KeyLektorPrompt, _ollamaConfig.LektorSystemPrompt),
|
(KeyLektorPrompt, _ollamaConfig.LektorSystemPrompt),
|
||||||
(KeyFactCheckTemplate, _ollamaConfig.FactCheckTemplate),
|
(KeyFactCheckTemplate, _ollamaConfig.FactCheckTemplate),
|
||||||
(KeySpellingPrompt, _ollamaConfig.SpellingPrompt),
|
(KeySpellingPrompt, _ollamaConfig.SpellingPrompt),
|
||||||
|
(KeyAdvocatusDiaboli, _ollamaConfig.AdvocatusDiaboliPrompt),
|
||||||
|
(KeyHookFinder, _ollamaConfig.HookFinderPrompt),
|
||||||
|
(KeyEli5, _ollamaConfig.Eli5Prompt),
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var entry in entries)
|
foreach (var entry in entries)
|
||||||
{
|
{
|
||||||
var existing = await context.Settings
|
var existing = settings.FindOne(s =>
|
||||||
.Where(s => s.Key == entry.Key && s.UserId == _currentUserId && s.ProjectId == null)
|
s.Key == entry.Key && s.UserId == _currentUserId && s.ProjectId == projectId);
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
if (existing != null)
|
if (existing != null)
|
||||||
{
|
{
|
||||||
var val = existing.Value;
|
var val = existing.Value;
|
||||||
if (entry.Key == KeyOllamaUrl) _ollamaConfig.OllamaUrl = val;
|
if (entry.Key == KeyOllamaUrl) _ollamaConfig.OllamaUrl = val;
|
||||||
else if (entry.Key == KeyRagModel) _ollamaConfig.StyleModel = val;
|
else if (entry.Key == KeyRagModel) _ollamaConfig.EmbedModel = val;
|
||||||
else if (entry.Key == KeyStyleModel) _ollamaConfig.StyleModel = val;
|
else if (entry.Key == KeyStyleModel) _ollamaConfig.StyleModel = val;
|
||||||
else if (entry.Key == KeySpellingModel) _ollamaConfig.SpellingModel = val;
|
else if (entry.Key == KeySpellingModel) _ollamaConfig.SpellingModel = val;
|
||||||
else if (entry.Key == KeyTheme) _ollamaConfig.Theme = val;
|
else if (entry.Key == KeyTheme) _ollamaConfig.Theme = val;
|
||||||
else if (entry.Key == KeyLektorPrompt) _ollamaConfig.LektorSystemPrompt = val;
|
else if (entry.Key == KeyLektorPrompt) _ollamaConfig.LektorSystemPrompt = val;
|
||||||
else if (entry.Key == KeyFactCheckTemplate) _ollamaConfig.FactCheckTemplate = val;
|
else if (entry.Key == KeyFactCheckTemplate) _ollamaConfig.FactCheckTemplate = val;
|
||||||
else if (entry.Key == KeySpellingPrompt) _ollamaConfig.SpellingPrompt = val;
|
else if (entry.Key == KeySpellingPrompt) _ollamaConfig.SpellingPrompt = val;
|
||||||
|
else if (entry.Key == KeyAdvocatusDiaboli) _ollamaConfig.AdvocatusDiaboliPrompt = val;
|
||||||
|
else if (entry.Key == KeyHookFinder) _ollamaConfig.HookFinderPrompt = val;
|
||||||
|
else if (entry.Key == KeyEli5) _ollamaConfig.Eli5Prompt = val;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
context.Settings.Add(new SettingEntity
|
settings.Insert(new SettingEntity
|
||||||
{
|
{
|
||||||
Key = entry.Key,
|
Key = entry.Key,
|
||||||
Value = entry.Default,
|
Value = entry.Default,
|
||||||
|
|
@ -226,6 +328,6 @@ public class SettingsService : ISettingsService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await context.SaveChangesAsync();
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
136
Services/WikipediaService.cs
Normal file
136
Services/WikipediaService.cs
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
using AuthorBuddy.Web.Models;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Web;
|
||||||
|
|
||||||
|
namespace AuthorBuddy.Web.Services;
|
||||||
|
|
||||||
|
public class WikipediaService : IWikipediaService
|
||||||
|
{
|
||||||
|
private readonly HttpClient _http;
|
||||||
|
private readonly string[] _languages = { "de", "en" };
|
||||||
|
|
||||||
|
public WikipediaService()
|
||||||
|
{
|
||||||
|
_http = new HttpClient { Timeout = TimeSpan.FromSeconds(15) };
|
||||||
|
_http.DefaultRequestHeaders.UserAgent.ParseAdd("AuthorBuddy/1.0 (writing-assistant)");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<WikipediaResult>> SearchAsync(string query, int maxResults = 3)
|
||||||
|
{
|
||||||
|
return await SearchAsync(new WikipediaSearchRequest
|
||||||
|
{
|
||||||
|
Query = query,
|
||||||
|
MaxResults = maxResults
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<WikipediaResult>> SearchAsync(WikipediaSearchRequest request)
|
||||||
|
{
|
||||||
|
var results = new List<WikipediaResult>();
|
||||||
|
|
||||||
|
foreach (var lang in _languages)
|
||||||
|
{
|
||||||
|
if (lang == "de" && !request.SearchGerman) continue;
|
||||||
|
if (lang == "en" && !request.SearchEnglish) continue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var langResults = await SearchLanguageAsync(lang, request.Query, request.MaxResults);
|
||||||
|
results.AddRange(langResults);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Sprache überspringen bei Fehler
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string?> GetExtractAsync(string title, string language = "de")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"https://{language}.wikipedia.org/w/api.php" +
|
||||||
|
"?action=query" +
|
||||||
|
"&prop=extracts" +
|
||||||
|
"&exintro&explaintext" +
|
||||||
|
$"&titles={HttpUtility.UrlEncode(title)}" +
|
||||||
|
"&format=json&utf8=1";
|
||||||
|
|
||||||
|
var response = await _http.GetStringAsync(url);
|
||||||
|
using var doc = JsonDocument.Parse(response);
|
||||||
|
var pages = doc.RootElement.GetProperty("query").GetProperty("pages");
|
||||||
|
|
||||||
|
foreach (var page in pages.EnumerateObject())
|
||||||
|
{
|
||||||
|
if (page.Value.TryGetProperty("extract", out var extract))
|
||||||
|
return extract.GetString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string?> GetFullArticleAsync(string title, string language = "de")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"https://{language}.wikipedia.org/w/api.php" +
|
||||||
|
"?action=query" +
|
||||||
|
"&prop=extracts" +
|
||||||
|
"&explaintext" +
|
||||||
|
$"&titles={HttpUtility.UrlEncode(title)}" +
|
||||||
|
"&format=json&utf8=1";
|
||||||
|
|
||||||
|
var response = await _http.GetStringAsync(url);
|
||||||
|
using var doc = JsonDocument.Parse(response);
|
||||||
|
var pages = doc.RootElement.GetProperty("query").GetProperty("pages");
|
||||||
|
|
||||||
|
foreach (var page in pages.EnumerateObject())
|
||||||
|
{
|
||||||
|
if (page.Value.TryGetProperty("extract", out var extract))
|
||||||
|
return extract.GetString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<WikipediaResult>> SearchLanguageAsync(string lang, string query, int maxResults)
|
||||||
|
{
|
||||||
|
var results = new List<WikipediaResult>();
|
||||||
|
|
||||||
|
var url = $"https://{lang}.wikipedia.org/w/api.php" +
|
||||||
|
"?action=query" +
|
||||||
|
"&list=search" +
|
||||||
|
$"&srsearch={HttpUtility.UrlEncode(query)}" +
|
||||||
|
$"&srlimit={maxResults}" +
|
||||||
|
"&format=json&utf8=1";
|
||||||
|
|
||||||
|
var response = await _http.GetStringAsync(url);
|
||||||
|
using var doc = JsonDocument.Parse(response);
|
||||||
|
var search = doc.RootElement.GetProperty("query").GetProperty("search");
|
||||||
|
|
||||||
|
foreach (var item in search.EnumerateArray())
|
||||||
|
{
|
||||||
|
var title = item.GetProperty("title").GetString() ?? "";
|
||||||
|
results.Add(new WikipediaResult
|
||||||
|
{
|
||||||
|
Title = title,
|
||||||
|
Snippet = StripHtml(item.GetProperty("snippet").GetString() ?? ""),
|
||||||
|
Url = $"https://{lang}.wikipedia.org/wiki/{HttpUtility.UrlEncode(title)}",
|
||||||
|
Language = lang
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string StripHtml(string html)
|
||||||
|
{
|
||||||
|
return System.Text.RegularExpressions.Regex.Replace(html, "<[^>]*>", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
author_brain.db
BIN
author_brain.db
Binary file not shown.
BIN
vec0.dll
BIN
vec0.dll
Binary file not shown.
386
wwwroot/app.css
386
wwwroot/app.css
|
|
@ -193,15 +193,68 @@ body {
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Editor */
|
.fact-similarity {
|
||||||
.editor-container {
|
font-size: 11px;
|
||||||
|
color: var(--accent-color);
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fact-path {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--border-color);
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fact-text {
|
||||||
|
font-size: 13px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fact-extract {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 6px;
|
||||||
|
padding-top: 6px;
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fact-card a {
|
||||||
|
color: var(--accent-color);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fact-card a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fact-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 8px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fact-actions button {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Editor page - no scroll */
|
||||||
|
.editor-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-container textarea {
|
.editor-area {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
font-family: 'Consolas', 'Courier New', monospace;
|
font-family: 'Consolas', 'Courier New', monospace;
|
||||||
font-size: 14pt;
|
font-size: 14pt;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
|
@ -213,13 +266,55 @@ body {
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-container .editor-toolbar {
|
.editor-toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
border-top: 1px solid var(--border-color);
|
border-top: 1px solid var(--border-color);
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
background: var(--menu-bg);
|
background: var(--menu-bg);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Results area - scrollable box */
|
||||||
|
.results-area {
|
||||||
|
max-height: 140px;
|
||||||
|
overflow-y: auto;
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
background: var(--window-bg);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Version list */
|
||||||
|
.version-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-date {
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--accent-color);
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-comment {
|
||||||
|
color: var(--border-color);
|
||||||
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Buttons */
|
/* Buttons */
|
||||||
|
|
@ -237,6 +332,18 @@ button:hover {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
background: var(--disabled-bg);
|
||||||
|
color: var(--disabled-text);
|
||||||
|
cursor: default;
|
||||||
|
border-color: var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled:hover {
|
||||||
|
background: var(--disabled-bg);
|
||||||
|
color: var(--disabled-text);
|
||||||
|
}
|
||||||
|
|
||||||
button.primary {
|
button.primary {
|
||||||
background: var(--accent-color);
|
background: var(--accent-color);
|
||||||
color: white;
|
color: white;
|
||||||
|
|
@ -295,6 +402,176 @@ button.primary {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Search section below editor */
|
||||||
|
.search-section {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 6px 12px;
|
||||||
|
background: var(--menu-bg);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-section input {
|
||||||
|
flex: 1;
|
||||||
|
padding: 6px 10px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
background: var(--editor-bg);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-section input::placeholder {
|
||||||
|
color: var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Modal overlay */
|
||||||
|
.modal-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0; left: 0; right: 0; bottom: 0;
|
||||||
|
background: rgba(0,0,0,0.4);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog {
|
||||||
|
background: var(--window-bg);
|
||||||
|
border: 2px solid var(--border-color);
|
||||||
|
min-width: 400px;
|
||||||
|
box-shadow: 4px 4px 8px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
background: var(--accent-color);
|
||||||
|
color: white;
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog .form-group {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog .form-group:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog .form-group label {
|
||||||
|
display: block;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog .form-group input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
background: var(--editor-bg);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* File tree in sidebar */
|
||||||
|
.tree-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 3px 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-item:hover {
|
||||||
|
background: var(--accent-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-item.active {
|
||||||
|
background: var(--accent-color);
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-item.file {
|
||||||
|
padding-left: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-item.tree-child {
|
||||||
|
padding-left: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-name {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-rename {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 0 4px;
|
||||||
|
opacity: 0.4;
|
||||||
|
color: inherit;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-rename:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-header-actions {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item-icon {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 0 4px;
|
||||||
|
opacity: 0.5;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item-icon:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item-sub.active {
|
||||||
|
background: var(--accent-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
/* Progress */
|
/* Progress */
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -340,21 +617,16 @@ button.primary {
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-layout {
|
.settings-layout {
|
||||||
display: flex;
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-layout-left {
|
.settings-column {
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-layout-right {
|
.settings-column .form-group textarea {
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-layout-right .form-group textarea {
|
|
||||||
min-height: 120px;
|
min-height: 120px;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
@ -450,7 +722,7 @@ button.primary {
|
||||||
.result-panel {
|
.result-panel {
|
||||||
border-top: 2px solid var(--border-color);
|
border-top: 2px solid var(--border-color);
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
max-height: 300px;
|
max-height: 400px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -465,6 +737,92 @@ button.primary {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Assistant page */
|
||||||
|
.assistant-page {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assistant-toolbar {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assistant-toolbar select {
|
||||||
|
padding: 4px 8px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
background: var(--input-bg);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assistant-panels {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assistant-input-panel,
|
||||||
|
.assistant-output-panel {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assistant-input-panel h4,
|
||||||
|
.assistant-output-panel h4 {
|
||||||
|
margin: 0 0 6px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assistant-textarea {
|
||||||
|
flex: 1;
|
||||||
|
resize: none;
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
background: var(--input-bg);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 13px;
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assistant-output {
|
||||||
|
flex: 1;
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
background: var(--card-bg);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 13px;
|
||||||
|
overflow-y: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assistant-output pre {
|
||||||
|
margin: 0;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assistant-error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assistant-hint {
|
||||||
|
color: var(--border-color);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
::-webkit-scrollbar-track {
|
||||||
background: var(--window-bg);
|
background: var(--window-bg);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,6 @@
|
||||||
--menu-bg: #252526;
|
--menu-bg: #252526;
|
||||||
--card-bg: #2d2d2d;
|
--card-bg: #2d2d2d;
|
||||||
--status-bar-bg: #007acc;
|
--status-bar-bg: #007acc;
|
||||||
|
--disabled-bg: #2a2a2a;
|
||||||
|
--disabled-text: #606060;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,6 @@
|
||||||
--menu-bg: #e0e0e0;
|
--menu-bg: #e0e0e0;
|
||||||
--card-bg: #ffffff;
|
--card-bg: #ffffff;
|
||||||
--status-bar-bg: #dcdcdc;
|
--status-bar-bg: #dcdcdc;
|
||||||
|
--disabled-bg: #e8e8e8;
|
||||||
|
--disabled-text: #a0a0a0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,6 @@
|
||||||
--menu-bg: #c0c0c0;
|
--menu-bg: #c0c0c0;
|
||||||
--card-bg: #ffffff;
|
--card-bg: #ffffff;
|
||||||
--status-bar-bg: #c0c0c0;
|
--status-bar-bg: #c0c0c0;
|
||||||
|
--disabled-bg: #c0c0c0;
|
||||||
|
--disabled-text: #808080;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue