add JSDoc comments because yes
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Verbindet Express, Sitzungen, Datenbank und Routen und verwaltet den Server-Lebenszyklus.
|
||||
*/
|
||||
import fs from "fs";
|
||||
import {randomUUID} from "crypto";
|
||||
import {performance} from "perf_hooks";
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Erstellt die Anwendungskonfiguration aus Umgebungsvariablen, Standardwerten und expliziten Vorgaben.
|
||||
*/
|
||||
import path from "path";
|
||||
|
||||
const bool = (value, fallback = false) => {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Definiert Tabellen für Bildanhänge und Analyse-Caches und bereitet Anhangsmetadaten auf.
|
||||
*/
|
||||
export function initializeAttachments(db) {
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS attachments (
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Öffnet die SQLite-Datenbank und initialisiert Tabellen sowie Migrationen.
|
||||
*/
|
||||
import fs from "fs";
|
||||
import Database from "better-sqlite3";
|
||||
import {initializeSchema, runMigrations} from "./schema.js";
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Bündelt Datenbankzugriffe auf Konten, Chats, Nachrichten, Personas und den Marktplatz.
|
||||
*/
|
||||
import {attachmentMetadata} from "./attachments.js";
|
||||
|
||||
const parseJsonArray = (value) => {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Definiert das Datenbankschema und migriert bestehende Daten auf die benötigte Struktur.
|
||||
*/
|
||||
export function initializeSchema(db) {
|
||||
db.pragma("journal_mode = WAL");
|
||||
db.pragma("foreign_keys = ON");
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Schützt Routen vor Zugriffen ohne angemeldete Sitzung.
|
||||
*/
|
||||
export function requireLogin(req, res, next) {
|
||||
if (!req.session.user) {
|
||||
return res.status(403).json({error: "Not logged in"});
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Begrenzt Anfragen je Schlüssel in einem gleitenden Zeitfenster und entfernt abgelaufene Einträge.
|
||||
*/
|
||||
function pruneBucket(bucket, windowMs, now) {
|
||||
const cutoff = now - windowMs;
|
||||
while (bucket.length && bucket[0] <= cutoff) {
|
||||
@@ -21,6 +24,7 @@ export function createRateLimiter({windowMs, max, keyGenerator, message, cleanup
|
||||
|
||||
if (cleanupIntervalMs > 0) {
|
||||
cleanupTimer = setInterval(cleanup, cleanupIntervalMs);
|
||||
// Der Aufräumtimer allein soll den Node-Prozess beim Herunterfahren nicht offen halten.
|
||||
cleanupTimer.unref();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Erstellt die konfigurierten Anfragebegrenzungen für Anmeldung und Chat-Nutzung.
|
||||
*/
|
||||
import {createRateLimiter} from "./rateLimit.js";
|
||||
|
||||
export function createAuthRateLimiters(config) {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Prüft Anfrageinhalte mit einem übergebenen Validator und stellt die validierten Daten für Routen bereit.
|
||||
*/
|
||||
export function validateBody(validator) {
|
||||
return (req, res, next) => {
|
||||
const result = validator(req.body || {}, req);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Erzeugt den gemeinsamen HTML-Seitenkopf mit Navigation und Kontosteuerung.
|
||||
*/
|
||||
const escapeHtml = (value) => String(value).replace(/[&<>"']/g, (character) => ({
|
||||
"&": "&", "<": "<", ">": ">", '"': """, "'": "'"
|
||||
})[character]);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Verarbeitet Registrierung, Anmeldung, Abmeldung und die Abfrage der aktuellen Sitzung.
|
||||
*/
|
||||
import express from "express";
|
||||
import bcrypt from "bcrypt";
|
||||
import {validateBody} from "../middleware/validate.js";
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Stellt Chat-Routen für Nachrichten, Streaming, Antwortvarianten, Verzweigungen und Einstellungen bereit.
|
||||
*/
|
||||
import express from "express";
|
||||
import {requireLogin} from "../middleware/auth.js";
|
||||
import {validateBody} from "../middleware/validate.js";
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Liefert öffentliche Seiten und geschützte Ansichten des Arbeitsbereichs aus.
|
||||
*/
|
||||
import express from "express";
|
||||
import {readFile} from "node:fs/promises";
|
||||
import {renderSiteHeader} from "../pageLayout.js";
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Verwaltet eigene Personas sowie Veröffentlichung, Suche und Interaktionen auf dem Persona-Marktplatz.
|
||||
*/
|
||||
import express from "express";
|
||||
import {requireLogin} from "../middleware/auth.js";
|
||||
import {validateBody} from "../middleware/validate.js";
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Verarbeitet Benutzer- und Kontoeinstellungen sowie Export und Import des Arbeitsbereichs.
|
||||
*/
|
||||
import express from "express";
|
||||
import bcrypt from "bcrypt";
|
||||
import {requireLogin} from "../middleware/auth.js";
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Stellt Modellinformationen und administrative Diagnosedaten bereit.
|
||||
*/
|
||||
import express from "express";
|
||||
import {requireLogin} from "../middleware/auth.js";
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Verarbeitet das Hochladen, Abrufen und Entfernen von Bildanhängen mit Zugriffskontrolle.
|
||||
*/
|
||||
import express from "express";
|
||||
import multer from "multer";
|
||||
import {requireLogin} from "../middleware/auth.js";
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Liefert angemeldeten Benutzern die für sie zugänglichen Diagnosen der Bildverarbeitung.
|
||||
*/
|
||||
import express from "express";
|
||||
import {requireLogin} from "../middleware/auth.js";
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Validiert und speichert Bildanhänge und bereitet zwischengespeicherte Bildanalysen für den Chat vor.
|
||||
*/
|
||||
import sharp from "sharp";
|
||||
import {createHash, randomUUID} from "node:crypto";
|
||||
import {attachmentMetadata} from "../db/attachments.js";
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Normalisiert Nachrichten und erstellt Kontexttexte für Erinnerungen, Zusammenfassungen und Personas.
|
||||
*/
|
||||
import {normalizeSources} from "./webSearchService.js";
|
||||
|
||||
export function parseSources(value) {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Koordiniert Chat-Antworten, Modellkontext, Websuche, Anhänge, Antwortvarianten und Gesprächsverzweigungen.
|
||||
*/
|
||||
import {
|
||||
buildPersonaPrompt,
|
||||
buildRoleplayDirectionPrompt,
|
||||
@@ -95,15 +98,18 @@ export function createChatService(repositories, modelService, config, webSearchP
|
||||
|
||||
const withChatGenerationLock = (chatId, operation) => {
|
||||
const previous = chatGenerationQueues.get(chatId) || Promise.resolve();
|
||||
// Ein fehlgeschlagener Vorgänger darf die Warteschlange dieses Chats nicht blockieren.
|
||||
const current = previous.catch(() => undefined).then(operation);
|
||||
chatGenerationQueues.set(chatId, current);
|
||||
return current.finally(() => {
|
||||
// Nur den eigenen Eintrag entfernen: Inzwischen könnte bereits ein Folgeauftrag warten.
|
||||
if (chatGenerationQueues.get(chatId) === current) chatGenerationQueues.delete(chatId);
|
||||
});
|
||||
};
|
||||
|
||||
const withActiveGeneration = async (chatId, externalSignal, operation) => {
|
||||
const controller = new AbortController();
|
||||
// Verbindungsabbruch und manuelles Stoppen wirken auf denselben Generierungsauftrag.
|
||||
const abortFromCaller = () => controller.abort(externalSignal?.reason);
|
||||
if (externalSignal?.aborted) abortFromCaller();
|
||||
else externalSignal?.addEventListener("abort", abortFromCaller, { once: true });
|
||||
@@ -157,6 +163,7 @@ export function createChatService(repositories, modelService, config, webSearchP
|
||||
const allMessages = repositories.listActiveBranchMessages(chatId)
|
||||
.filter((message) => !message.delivery_status || message.delivery_status === "complete");
|
||||
const keepRecent = Math.max(0, config.chatHistoryLimit);
|
||||
// Die neuesten Nachrichten bleiben vollständig im Kontext; nur ältere werden zusammengefasst.
|
||||
const cutoffIndex = allMessages.length - keepRecent - 1;
|
||||
if (cutoffIndex < 0) return;
|
||||
const cutoffMessage = allMessages[cutoffIndex];
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Speichert, liest und löscht hochgeladene Dateien in einem lokalen Speicherverzeichnis.
|
||||
*/
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import {randomUUID} from "node:crypto";
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Kommuniziert mit Ollama und verwaltet Antwortstreams, Zeitlimits, Modellstatus und Modell-Caches.
|
||||
*/
|
||||
import { supportsReasoning } from "../../public/js/modelCapabilities.js";
|
||||
import { AttachmentError } from "./attachmentService.js";
|
||||
|
||||
@@ -147,6 +150,7 @@ export function createModelService(config, overrides = {}) {
|
||||
touch();
|
||||
buffer += decoder.decode(value, { stream: true });
|
||||
const lines = buffer.split("\n");
|
||||
// Netzwerkblöcke können mitten in einer JSON-Zeile enden; den Rest für den nächsten Block behalten.
|
||||
buffer = lines.pop() || "";
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
@@ -160,6 +164,7 @@ export function createModelService(config, overrides = {}) {
|
||||
if (!completed && buffer.trim()) {
|
||||
consume(buffer.trim());
|
||||
}
|
||||
// Erst das Abschlussereignis bestätigt eine vollständige Antwort; ein Stream-Ende allein genügt nicht.
|
||||
if (!completed) throw new ModelServiceError("MODEL_INTERRUPTED", "Model response was interrupted.", 502);
|
||||
onRawReply?.(fullReply);
|
||||
return fullReply.trim();
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Validiert Persona-Daten und erstellt Rollenspielanweisungen sowie Prüfungen für die Rollenverteilung.
|
||||
*/
|
||||
const PERSONA_FIELD_LIMITS = {
|
||||
name: 200,
|
||||
pronouns: 40,
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Definiert Anweisungen, Antwortschema und Normalisierung für Bildanalysen und deren Nutzung im Chat.
|
||||
*/
|
||||
// Bump whenever the perception prompt, schema, or interpretation contract changes.
|
||||
export const VISION_PROMPT_VERSION = 4;
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Sammelt begrenzte Diagnosedaten zur Bildverarbeitung und kontrolliert deren benutzerbezogenen Zugriff.
|
||||
*/
|
||||
const RAW_VISION_LIMIT = 12000;
|
||||
const EVIDENCE_LIMIT = 100000;
|
||||
const ANSWER_LIMIT = 30000;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Entscheidet über Websuchen, fragt SearXNG ab und bereitet relevante Quellen als Modellkontext auf.
|
||||
*/
|
||||
/** @typedef {{title: string, url: string, snippet: string, score?: number, engine?: string, category?: string, publishedDate?: string}} RawSearchResult */
|
||||
/** @typedef {{title: string, url: string, snippet: string}} SearchResult */
|
||||
/** @typedef {{signal?: AbortSignal, limit?: number, category?: string}} SearchOptions */
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* @file Prüft und normalisiert importierte Arbeitsbereiche mit Personas, Chats und Nachrichtenbeziehungen.
|
||||
*/
|
||||
import {parseSources} from "./chatMessageHelpers.js";
|
||||
|
||||
const VALID_PERSONA_TYPES = new Set(["assistant", "user"]);
|
||||
|
||||
Reference in New Issue
Block a user