diff --git a/aria-brain/main.py b/aria-brain/main.py index 5b4708a..bcfa680 100644 --- a/aria-brain/main.py +++ b/aria-brain/main.py @@ -398,6 +398,19 @@ def memory_delete(point_id: str): # ─── Memory-Anhaenge ────────────────────────────────────────────────── +@app.get("/attachments/limit") +def memory_attachments_limit(): + """Aktuelles Groessen-Limit fuer Memory-Anhaenge. + + Die Oberflaechen zeigen damit die ECHTE Zahl an statt eines fest + eingetippten "max 20 MB" — das stand vorher im HTML und stimmte nicht mehr, + sobald jemand das Limit anhob. + """ + import memory_attachments as mem_att + limit = mem_att.max_bytes() + return {"maxBytes": limit, "maxMb": round(limit / 1024 / 1024, 1)} + + @app.get("/memory/{point_id}/attachments") def memory_attachments_list(point_id: str): """Liste der Anhaenge zum Memory. Source-of-Truth ist das Payload diff --git a/aria-brain/memory_attachments.py b/aria-brain/memory_attachments.py index 071e382..daffcaa 100644 --- a/aria-brain/memory_attachments.py +++ b/aria-brain/memory_attachments.py @@ -16,6 +16,7 @@ selbst hat in Stufe A kein Tool zum Upload. from __future__ import annotations import base64 +import json import logging import mimetypes import os @@ -27,9 +28,41 @@ from typing import List, Optional logger = logging.getLogger(__name__) ROOT = Path(os.environ.get("MEMORY_ATTACHMENTS_DIR", "/shared/memory-attachments")) -MAX_BYTES = int(os.environ.get("MEMORY_ATTACHMENT_MAX_BYTES", str(20 * 1024 * 1024))) # 20 MB SAFE_NAME_RE = re.compile(r"[^A-Za-z0-9._\-]") +RUNTIME_CONFIG_FILE = Path("/shared/config/runtime.json") +# 64 MB: so viel holt die App auch auf ausdruecklichen Tipp noch herunter +# (TAP_DL_MAX_BYTES in ChatScreen.tsx). Ein hoeheres Limit wuerde Anhaenge +# erlauben, die das Handy anschliessend nicht mehr laden kann. +_DEFAULT_MAX_BYTES = 64 * 1024 * 1024 + + +def max_bytes() -> int: + """Aktuelles Groessen-Limit fuer Anhaenge. + + Reihenfolge: runtime.json (Diagnostic → System & Wartung) > ENV > Default. + Wird bei JEDEM Aufruf gelesen, damit eine Aenderung in der Diagnostic sofort + greift — ein Brain-Neustart nur fuers Anheben einer Zahl waere Unsinn. + """ + try: + with RUNTIME_CONFIG_FILE.open() as f: + mb = json.load(f).get("memoryAttachmentMaxMb") + if mb is not None: + val = int(float(mb) * 1024 * 1024) + if val > 0: + return val + except FileNotFoundError: + pass + except Exception as exc: + logger.warning("runtime.json lesen fehlgeschlagen: %s", exc) + env = os.environ.get("MEMORY_ATTACHMENT_MAX_BYTES") + if env: + try: + return int(env) + except ValueError: + logger.warning("MEMORY_ATTACHMENT_MAX_BYTES ist keine Zahl: %r", env) + return _DEFAULT_MAX_BYTES + def _safe_filename(name: str) -> str: """Macht aus einem User-Namen einen filesystem-sicheren String — @@ -78,8 +111,12 @@ def save_attachment(memory_id: str, filename: str, data: bytes) -> dict: Ueberschreibt eine bestehende Datei mit gleichem Namen.""" if not memory_id: raise ValueError("memory_id ist Pflicht") - if len(data) > MAX_BYTES: - raise ValueError(f"Anhang zu gross ({len(data)} > {MAX_BYTES} Byte)") + limit = max_bytes() + if len(data) > limit: + raise ValueError( + f"Anhang zu gross ({len(data) // (1024 * 1024)} MB > " + f"{limit // (1024 * 1024)} MB). Das Limit steht in der Diagnostic " + f"unter System & Wartung.") safe = _safe_filename(filename) d = memory_dir(memory_id) d.mkdir(parents=True, exist_ok=True) @@ -165,8 +202,12 @@ def attach_from_path(memory_id: str, source_path: str) -> dict: if not src.is_file(): raise ValueError(f"Datei nicht gefunden: {source_path}") size = src.stat().st_size - if size > MAX_BYTES: - raise ValueError(f"Datei zu gross ({size} > {MAX_BYTES} Byte)") + limit = max_bytes() + if size > limit: + raise ValueError( + f"Datei zu gross ({size // (1024 * 1024)} MB > " + f"{limit // (1024 * 1024)} MB). Das Limit steht in der Diagnostic " + f"unter System & Wartung.") # Reuse save_attachment damit Filename-Sanitization + Logging konsistent data = src.read_bytes() return save_attachment(memory_id, src.name, data) diff --git a/diagnostic/index.html b/diagnostic/index.html index a31cdeb..a39d25e 100644 --- a/diagnostic/index.html +++ b/diagnostic/index.html @@ -1051,6 +1051,31 @@
+ +
+

Grösse von Anhängen

+
+

+ Grösste Datei, die an einen Gedanken angehängt werden darf. + Greift sofort — kein Neustart nötig. +

+
+ + MB + +
+

+ Über 64 MB lädt die Handy-App Anhänge nicht mehr herunter — + ein Anhang muss als Base64 komplett in den Speicher, und daran ist die App + schon einmal gestorben. Er liegt dann sauber auf dem Server, ist mobil aber + nur noch über den Dateimanager erreichbar. +

+
+
+
+

Reparatur & Restart

@@ -1371,9 +1396,42 @@ + +
+