using System; using System.IO; using System.Net; using System.Net.Http; using System.Runtime.InteropServices; using Gott.Endpoints; using Gott.Middleware; using Gott.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Hosting; var builder = WebApplication.CreateBuilder(args); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) builder.Services.AddWindowsService(); var dataDir = Path.Combine(AppContext.BaseDirectory, "data"); Directory.CreateDirectory(dataDir); var dbPath = Path.Combine(dataDir, "gott.db"); // ServerSettingsService – zentrale Settings aus DB var serverSettings = new ServerSettingsService(dbPath); serverSettings.MigrateFromAppSettings(builder.Environment.ContentRootPath); builder.Services.AddSingleton(serverSettings); // Proxy (erfordert Neustart – wird nur beim Start gelesen) var proxyUrl = serverSettings.Get("ProxyUrl"); if (!string.IsNullOrWhiteSpace(proxyUrl)) { builder.Services.AddHttpClient().ConfigureHttpClientDefaults(b => b.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { Proxy = new WebProxy(proxyUrl), UseProxy = true })); } else { builder.Services.AddHttpClient(); } var authService = new AuthService(dbPath); var dbService = new DatabaseService(dbPath); dbService.EnsureDefaultUser(authService); builder.Services.AddSingleton(authService); builder.Services.AddSingleton(dbService); builder.Services.AddSingleton(new ImageService()); builder.Services.AddSingleton(new StreamingTracker()); builder.Services.AddSingleton(new RemoteConnectionManager()); var memoryService = new MemoryService(dataDir); var skillService = new SkillService(dataDir); builder.Services.AddSingleton(memoryService); builder.Services.AddSingleton(skillService); // Shared Services var toolService = new ToolService(serverSettings); builder.Services.AddSingleton(toolService); var chatService = new ChatService(dbService, toolService, memoryService, skillService, serverSettings); builder.Services.AddSingleton(chatService); // Embedding-Services (lokal, ONNX) var embeddingModelDir = serverSettings.Get("EmbeddingModelDir"); var embeddingMaxSeq = serverSettings.GetInt("EmbeddingMaxSeqLen", 256); var embeddingService = new Gott.Services.EmbeddingService( string.IsNullOrEmpty(embeddingModelDir) ? null : Path.Combine(dataDir, "models", embeddingModelDir), embeddingMaxSeq ); builder.Services.AddSingleton(embeddingService); var vectorSearchService = new Gott.Services.VectorSearchService(dbPath, embeddingService); builder.Services.AddSingleton(vectorSearchService); var embeddingBgService = new Gott.Services.EmbeddingBackgroundService(vectorSearchService, embeddingService, dbPath); builder.Services.AddSingleton(embeddingBgService); builder.Services.AddHostedService(sp => sp.GetRequiredService()); // AnthropicService (Singleton – Token wird pro Request vom User aufgelöst) builder.Services.AddSingleton(sp => { var svc = new AnthropicService( sp.GetRequiredService(), toolService, dbService, memoryService, serverSettings, vectorSearch: vectorSearchService, embeddingBg: embeddingBgService); svc.SetChatService(chatService); return svc; }); // OpenAI-kompatibler Service (Nvidia etc.) builder.Services.AddSingleton(sp => new OpenAiService(sp.GetRequiredService(), dbService, sp.GetRequiredService(), serverSettings, dataDir)); // Telegram Bot (pro Session – Token aus Session-Config) builder.Services.AddSingleton(sp => new TelegramService( sp.GetRequiredService(), dbService, chatService, sp.GetRequiredService(), sp.GetRequiredService(), serverSettings)); // Krea Image Generation builder.Services.AddSingleton(sp => new KreaService(sp.GetRequiredService(), serverSettings, dataDir)); // Cronjob-Service (BackgroundService) builder.Services.AddSingleton(); builder.Services.AddHostedService(sp => sp.GetRequiredService()); // Key-Scanner-Service (BackgroundService mit Timer) builder.Services.AddSingleton(); builder.Services.AddHostedService(sp => sp.GetRequiredService()); // GitHub Event Scanner (Echtzeit-Monitoring öffentlicher Pushes) builder.Services.AddSingleton(); builder.Services.AddHostedService(sp => sp.GetRequiredService()); // Claude CLI Service (für OAuth-basierte Chats via CLI) builder.Services.AddSingleton(); var app = builder.Build(); // No-cache for static files (mobile browsers love caching too much) app.Use(async (context, next) => { var path = context.Request.Path.Value ?? ""; if (path.EndsWith(".html") || path.EndsWith(".js") || path.EndsWith(".css") || path == "/") { var headers = context.Response.Headers; headers["Cache-Control"] = "no-cache, no-store, must-revalidate"; headers["Pragma"] = "no-cache"; headers["Expires"] = "0"; } await next(); }); toolService.SetHttpClientFactory(app.Services.GetRequiredService()); app.Services.GetRequiredService().SetTelegramService(app.Services.GetRequiredService()); app.Services.GetRequiredService().SetOpenAiService(app.Services.GetRequiredService()); app.Services.GetRequiredService().SetCliService(app.Services.GetRequiredService()); await app.Services.GetRequiredService().LoadModelsAsync(); app.UseWebSockets(); // wwwroot: Quell-Verzeichnis bevorzugen (Live-Änderungen ohne Publish) AppPaths.Initialize(); if (AppPaths.WwwRoot != Path.Combine(AppContext.BaseDirectory, "wwwroot")) { var fileProvider = new PhysicalFileProvider(AppPaths.WwwRoot); app.UseDefaultFiles(new DefaultFilesOptions { FileProvider = fileProvider }); app.UseStaticFiles(new StaticFileOptions { FileProvider = fileProvider }); } else { app.UseDefaultFiles(); app.UseStaticFiles(); } app.UseMiddleware(); app.MapAuthEndpoints(); app.MapChatEndpoint(); app.MapHistoryEndpoint(); app.MapSessionEndpoints(); app.MapAgentEndpoints(); app.MapWorkspaceEndpoint(); app.MapInfoEndpoint(); app.MapModelsEndpoint(); app.MapBackupEndpoint(); app.MapSkillEndpoints(); app.MapProfileEndpoints(); app.MapSettingsEndpoints(); app.MapTelegramEndpoints(); app.MapCronjobEndpoints(); app.MapKreaEndpoints(); app.MapSharedEndpoints(); app.MapAdminEndpoints(); app.MapServerSettingsEndpoints(); app.MapApiKeysEndpoints(); app.MapOpenClawEndpoints(); app.MapRemoteEndpoints(); app.MapDatabaseExplorerEndpoints(); app.MapEmbeddingDebugEndpoints(); app.MapInternalEndpoints(); var port = app.Configuration.GetValue("Port", 19000); app.Run($"http://0.0.0.0:{port}");