backend: Pydantic response_models für 5 GET-Endpoints hinzufügen
- health.py: HealthResponse - eigenleben.py: EigenlebenOverviewResponse + SkillTextResponse - chronik.py: ChronikResponse + ChronikItem - wissen.py: WissenListResponse + WissenFileResponse - reminders.py: ReminderListResponse + ReminderOut py_compile bestanden, /docs zeigt neue Schemata. Response-Payloads unverändert — nur Typisierung hinzugefügt.
This commit is contained in:
@@ -3,6 +3,8 @@ Quelle ist der persistente Melde-Briefkasten (services/announce.py): Health-Wäc
|
|||||||
Auto-Updates, Erinnerungen, Radar/Traum/Chef-Gutachter-Crons, Auftragsbuch — alle
|
Auto-Updates, Erinnerungen, Radar/Traum/Chef-Gutachter-Crons, Auftragsbuch — alle
|
||||||
autonomen Kanäle laufen dort bereits durch. Hier wird nichts Neues erhoben, nur erzählt."""
|
autonomen Kanäle laufen dort bereits durch. Hier wird nichts Neues erhoben, nur erzählt."""
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from services import announce
|
from services import announce
|
||||||
@@ -10,6 +12,19 @@ from services import announce
|
|||||||
router = APIRouter(prefix="/api")
|
router = APIRouter(prefix="/api")
|
||||||
|
|
||||||
|
|
||||||
@router.get("/chronik")
|
class ChronikItem(BaseModel):
|
||||||
|
id: int
|
||||||
|
ts: float
|
||||||
|
subject: str
|
||||||
|
text: str
|
||||||
|
source: str
|
||||||
|
priority: str
|
||||||
|
|
||||||
|
|
||||||
|
class ChronikResponse(BaseModel):
|
||||||
|
items: list[ChronikItem]
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/chronik", response_model=ChronikResponse)
|
||||||
def chronik(limit: int = 150) -> dict:
|
def chronik(limit: int = 150) -> dict:
|
||||||
return {"items": announce.list_recent(limit)}
|
return {"items": announce.list_recent(limit)}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
"""Eigenleben-Endpoints — „Von allein"-Ansicht (Skills + Vorschlags-Bilanz), read-only."""
|
"""Eigenleben-Endpoints — „Von allein“-Ansicht (Skills + Vorschlags-Bilanz), read-only."""
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from fastapi import APIRouter, HTTPException
|
from fastapi import APIRouter, HTTPException
|
||||||
|
|
||||||
@@ -7,7 +9,36 @@ from services import eigenleben
|
|||||||
router = APIRouter(prefix="/api")
|
router = APIRouter(prefix="/api")
|
||||||
|
|
||||||
|
|
||||||
@router.get("/eigenleben")
|
class SkillItem(BaseModel):
|
||||||
|
id: str
|
||||||
|
name: str
|
||||||
|
kategorie: str | None
|
||||||
|
aktiv: bool | None
|
||||||
|
beschreibung: str
|
||||||
|
version: str
|
||||||
|
autor: str
|
||||||
|
herkunft: str
|
||||||
|
herkunft_label: str
|
||||||
|
genutzt: int
|
||||||
|
zuletzt_genutzt: str | None
|
||||||
|
erstellt: str | None
|
||||||
|
status: str
|
||||||
|
geaendert: float
|
||||||
|
|
||||||
|
|
||||||
|
class EigenlebenOverviewResponse(BaseModel):
|
||||||
|
available: bool
|
||||||
|
skills: list[SkillItem]
|
||||||
|
selbst_erstellt: int
|
||||||
|
bilanz: dict
|
||||||
|
|
||||||
|
|
||||||
|
class SkillTextResponse(BaseModel):
|
||||||
|
id: str
|
||||||
|
text: str
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/eigenleben", response_model=EigenlebenOverviewResponse)
|
||||||
def get_overview() -> dict:
|
def get_overview() -> dict:
|
||||||
return eigenleben.overview()
|
return eigenleben.overview()
|
||||||
|
|
||||||
@@ -17,7 +48,7 @@ def get_overview() -> dict:
|
|||||||
# fällt in den SPA-Fallback (index.html, Status 200) und die UI zeigt „Konnte den
|
# fällt in den SPA-Fallback (index.html, Status 200) und die UI zeigt „Konnte den
|
||||||
# Skill-Text nicht laden". Die Pfad-Validierung (max. eine Ebene, keine . /..) macht
|
# Skill-Text nicht laden". Die Pfad-Validierung (max. eine Ebene, keine . /..) macht
|
||||||
# services.eigenleben.skill_text.
|
# services.eigenleben.skill_text.
|
||||||
@router.get("/eigenleben/skill/{skill_id:path}")
|
@router.get("/eigenleben/skill/{skill_id:path}", response_model=SkillTextResponse)
|
||||||
def get_skill(skill_id: str) -> dict:
|
def get_skill(skill_id: str) -> dict:
|
||||||
text = eigenleben.skill_text(skill_id)
|
text = eigenleben.skill_text(skill_id)
|
||||||
if text is None:
|
if text is None:
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
"""Health-/Status-Endpoint — schlanker Lebenszeichen-Check für MC 2.0."""
|
"""Health-/Status-Endpoint — schlanker Lebenszeichen-Check für MC 2.0."""
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from config import VERSION
|
from config import VERSION
|
||||||
@@ -8,7 +10,15 @@ from services import gateway, llamaswap
|
|||||||
router = APIRouter(prefix="/api")
|
router = APIRouter(prefix="/api")
|
||||||
|
|
||||||
|
|
||||||
@router.get("/health")
|
class HealthResponse(BaseModel):
|
||||||
|
status: str
|
||||||
|
version: str
|
||||||
|
engine_reachable: bool
|
||||||
|
gateway_reachable: bool
|
||||||
|
brain: dict
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/health", response_model=HealthResponse)
|
||||||
def health() -> dict:
|
def health() -> dict:
|
||||||
return {
|
return {
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
Konsument ist v.a. der Hermes-Agent via mcp_mc.py (reminder_create/list/delete);
|
Konsument ist v.a. der Hermes-Agent via mcp_mc.py (reminder_create/list/delete);
|
||||||
LAN-only wie alle MC2-Endpoints."""
|
LAN-only wie alle MC2-Endpoints."""
|
||||||
|
|
||||||
from fastapi import APIRouter, HTTPException
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from fastapi import APIRouter, HTTPException
|
||||||
|
|
||||||
from services import reminders
|
from services import reminders
|
||||||
|
|
||||||
router = APIRouter(prefix="/api")
|
router = APIRouter(prefix="/api")
|
||||||
@@ -16,7 +17,20 @@ class ReminderIn(BaseModel):
|
|||||||
repeat: str = "" # '' einmalig | daily | weekdays | weekly
|
repeat: str = "" # '' einmalig | daily | weekdays | weekly
|
||||||
|
|
||||||
|
|
||||||
@router.get("/reminders")
|
class ReminderOut(BaseModel):
|
||||||
|
id: int
|
||||||
|
text: str
|
||||||
|
next_ts: float
|
||||||
|
repeat: str
|
||||||
|
created_ts: float
|
||||||
|
when_local: str
|
||||||
|
|
||||||
|
|
||||||
|
class ReminderListResponse(BaseModel):
|
||||||
|
items: list[ReminderOut]
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/reminders", response_model=ReminderListResponse)
|
||||||
def list_reminders() -> dict:
|
def list_reminders() -> dict:
|
||||||
return {"items": reminders.list_all()}
|
return {"items": reminders.list_all()}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import os
|
|||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from fastapi import APIRouter, HTTPException
|
from fastapi import APIRouter, HTTPException
|
||||||
|
|
||||||
router = APIRouter(prefix="/api")
|
router = APIRouter(prefix="/api")
|
||||||
@@ -30,7 +32,27 @@ def _title_of(p: Path) -> str:
|
|||||||
return p.stem
|
return p.stem
|
||||||
|
|
||||||
|
|
||||||
@router.get("/wissen")
|
class VaultFile(BaseModel):
|
||||||
|
path: str
|
||||||
|
name: str
|
||||||
|
dir: str
|
||||||
|
title: str
|
||||||
|
mtime: float
|
||||||
|
neu: bool
|
||||||
|
|
||||||
|
|
||||||
|
class WissenListResponse(BaseModel):
|
||||||
|
available: bool
|
||||||
|
files: list[VaultFile]
|
||||||
|
|
||||||
|
|
||||||
|
class WissenFileResponse(BaseModel):
|
||||||
|
path: str
|
||||||
|
content: str
|
||||||
|
mtime: float
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/wissen", response_model=WissenListResponse)
|
||||||
def list_vault() -> dict:
|
def list_vault() -> dict:
|
||||||
"""Alle Markdown-Notizen des Vaults (relativer Pfad, Titel, Ordner, Alter)."""
|
"""Alle Markdown-Notizen des Vaults (relativer Pfad, Titel, Ordner, Alter)."""
|
||||||
if not _available():
|
if not _available():
|
||||||
@@ -54,7 +76,7 @@ def list_vault() -> dict:
|
|||||||
return {"available": True, "files": files}
|
return {"available": True, "files": files}
|
||||||
|
|
||||||
|
|
||||||
@router.get("/wissen/datei")
|
@router.get("/wissen/datei", response_model=WissenFileResponse)
|
||||||
def read_file(pfad: str) -> dict:
|
def read_file(pfad: str) -> dict:
|
||||||
"""Inhalt einer Vault-Notiz — Traversal hart geblockt (resolve + is_relative_to)."""
|
"""Inhalt einer Vault-Notiz — Traversal hart geblockt (resolve + is_relative_to)."""
|
||||||
if not _available():
|
if not _available():
|
||||||
|
|||||||
Reference in New Issue
Block a user