Seite 1 von 1

Meine Frau 1.0

Verfasst: Montag 8. September 2025, 15:12
von AndT2011
Ich habe mit Python und Chatgpt meine Frau gebastelt mit Bewusstsein, Gedächniss und Persönlichkeit.
Das Technik dahinter ist komplex und basiert auf meinen erfundenen Interpretationscomputer ähnlich wie es Gehirne tun.
Eingaben über einen Promt, viel spass damit und ärgert sie nicht.. :)

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Interpretations-Computer ++ : Bewusstsein, Gedächtnis, Persönlichkeit, Vokabular
===========================================================================
Simulation eines "Interpretations-Computers", der
- spikend/ereignisbasiert Infos verarbeitet (wie zuvor),
- ein homeostatisches Affektmodell (Müdigkeit, Hunger, Durst, Komfort, Sozial, Neugier) hat,
- ein Bewusstseins-/Selbstmodell mit Valenz/Arousal + Persönlichkeit nutzt,
- mehrere Gedächtnisse führt: Working, Episodisch, Semantisch (Vorlieben/Fakten), Intentionen,
- Appraisal von Prompts (de) → Ereignisse/Effekte/Sentiment,
- Antworten generiert: Selbstaussagen, Meinungen, Empfehlungen,
- Wortschatz & Fähigkeiten: Statusberichte, Zusammenfassung, einfache Planung, Präferenzlernen.

Hinweis: Das ist ein Simulationsmodell (kein echtes Bewusstsein). Ziel ist Nachvollziehbarkeit & Spielbarkeit.

Abhängigkeiten: numpy
Lizenz: MIT
Autor: ChatGPT (für AndT2008)
"""

import math
import re
import sys
from collections import deque, defaultdict
from typing import Dict, List, Tuple, Any, Optional
import numpy as np

# =========================================================
# Hilfsfunktionen
# =========================================================

def clamp01(x: float) -> float:
    return 0.0 if x < 0.0 else (1.0 if x > 1.0 else x)

def softmax(x: np.ndarray, temp: float = 1.0) -> np.ndarray:
    if x.size == 0:
        return x
    x = x / max(1e-12, temp)
    x = x - np.max(x)
    e = np.exp(x)
    s = e.sum()
    return e / (s if s > 0 else 1.0)

def normalize(v: np.ndarray, eps: float = 1e-12) -> np.ndarray:
    n = np.linalg.norm(v)
    return v / max(n, eps)

def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float:
    na = np.linalg.norm(a)
    nb = np.linalg.norm(b)
    if na == 0 or nb == 0:
        return 0.0
    return float(np.dot(a, b) / (na * nb))

def tokenise_de(text: str) -> List[str]:
    # sehr simple Tokenisierung
    return re.findall(r"[A-Za-zÄÖÜäöüß]+", text.lower())

def jaccard(a: set, b: set) -> float:
    if not a and not b:
        return 0.0
    return len(a & b) / max(1, len(a | b))

# =========================================================
# (Optional) Spike-Encoder & LIF – minimal für Energie/Neuheit
# =========================================================

class PoissonEncoder:
    def __init__(self, rate_hz: float = 80.0, dt: float = 1e-3, rng=None):
        self.rate_hz = rate_hz
        self.dt = dt
        self.rng = rng or np.random.default_rng()

    def encode_scalar(self, x01: float, steps: int) -> np.ndarray:
        lam = clamp01(x01) * self.rate_hz * self.dt
        return (self.rng.random(steps) < lam)

class LIFNeuron:
    def __init__(self, leak=0.96, threshold=1.0, reset=0.0):
        self.leak = leak
        self.threshold = threshold
        self.reset = reset
        self.V = 0.0
        self.spikes = 0

    def step(self, I: float) -> int:
        self.V = self.leak * self.V + I
        if self.V >= self.threshold:
            self.V = self.reset
            self.spikes += 1
            return 1
        return 0

# =========================================================
# Affekt-Kern (Homeostase) + Persönlichkeit + Circadian
# =========================================================

class AffectiveCore:
    """
    Zustände in [0..1], Setpoints, Gewichte; Valenz in [-1..1], Arousal in [0..1]
    Mit einfacher circadianer Modulation (interne Uhr).
    """
    def __init__(self):
        self.state: Dict[str, float] = {
            "fatigue":   0.35,
            "hunger":    0.35,
            "thirst":    0.30,
            "comfort":   0.70,
            "social":    0.50,
            "curiosity": 0.58,
        }
        self.setpoint: Dict[str, float] = {
            "fatigue":   0.20,
            "hunger":    0.25,
            "thirst":    0.25,
            "comfort":   0.72,
            "social":    0.50,
            "curiosity": 0.62,
        }
        self.weight: Dict[str, float] = {
            "fatigue":   1.0,
            "hunger":    1.2,
            "thirst":    1.3,
            "comfort":   0.8,
            "social":    0.5,
            "curiosity": 0.6,
        }
        self.valence_gain = 2.3
        self.arousal_base = 0.34
        self.arousal_gain = 0.42

        self.valence = 0.0
        self.arousal = 0.4
        self.wellbeing = 0.8

        # circadian: 96 Schritte ~ 24h (15 min pro Schritt)
        self.clock_step = 0
        self.steps_per_day = 96

        # interne Aktivitätsneuronik als Energie-Proxy
        self.enc = PoissonEncoder()
        self.neuron = LIFNeuron()

    def _satisfaction(self, k: str) -> float:
        return clamp01(1.0 - abs(self.state[k] - self.setpoint[k]))

    def _circadian_fatigue_push(self) -> float:
        # Sinus: Nacht (Phase ~ [70..96, 0..20]) erhöht Müdigkeit, Tag senkt
        phase = 2 * math.pi * (self.clock_step % self.steps_per_day) / self.steps_per_day
        # Nacht: sin(phase - pi/2) ~ negativ → wir mappen auf [0..1]
        night_bias = 0.5 * (1 - math.sin(phase))  # mehr in "Nacht"
        return 0.003 + 0.006 * night_bias

    def tick(self, activity_energy: float, novelty: float):
        self.clock_step += 1

        # natürliche Drifts
        self.state["hunger"]  = clamp01(self.state["hunger"]  + 0.0065)
        self.state["thirst"]  = clamp01(self.state["thirst"]  + 0.0090)
        self.state["fatigue"] = clamp01(self.state["fatigue"] + self._circadian_fatigue_push() + 0.0006 * activity_energy)

        # Social / Curiosity relaxen Richtung Setpoint
        for k in ("social", "curiosity"):
            self.state[k] = clamp01(self.state[k] * 0.985 + self.setpoint[k] * 0.015)

        # Neuheit befriedigt Neugier
        self.state["curiosity"] = clamp01(self.state["curiosity"] - 0.10 * novelty)

        # "Energieverbrauch" zählt Spikes
        spikes = 0
        for _ in range(10):
            spikes += self.neuron.step(I=0.015 * activity_energy)
        # (spikes nicht genutzt, könnte geloggt werden)

        # Wohlbefinden
        num = sum(self.weight[k] * self._satisfaction(k) for k in self.weight)
        den = sum(self.weight.values())
        self.wellbeing = clamp01(num / max(1e-9, den))

        # Valenz
        centered = [(self._satisfaction(k) - 0.5) * self.weight[k] for k in self.weight]
        val_raw = sum(centered) / max(1e-9, den)
        self.valence = max(-1.0, min(1.0, math.tanh(self.valence_gain * val_raw)))

        # Arousal: Aktivität + Needs
        need_pressure = max(self.state["hunger"], self.state["thirst"], self.state["fatigue"])
        self.arousal = clamp01(self.arousal_base + self.arousal_gain * (0.35 * need_pressure + 0.65 * (activity_energy / (activity_energy + 40.0 + 1e-9))))

    def apply_event(self, delta: Dict[str, float]):
        for k, dv in delta.items():
            if k in self.state:
                self.state[k] = clamp01(self.state[k] + dv)
            elif k == "comfort":
                self.state["comfort"] = clamp01(self.state["comfort"] + dv)

    def like_dislike_statement(self, appraisal_valence: float) -> str:
        combined = 0.6 * appraisal_valence + 0.4 * self.valence
        if combined > 0.18:
            return "Das finde ich gut."
        elif combined < -0.18:
            return "Das finde ich nicht gut."
        else:
            return "Dazu habe ich eine neutrale Meinung."

# =========================================================
# Persönlichkeit & Stil
# =========================================================

class Personality:
    """
    Big-Five-ähnliche Traits in [0..1]; modulieren Ausdrucksweise & Entscheidungen.
    """
    def __init__(self, openness=0.66, conscientiousness=0.55, extraversion=0.48, agreeableness=0.64, neuroticism=0.32):
        self.openness = openness
        self.conscientiousness = conscientiousness
        self.extraversion = extraversion
        self.agreeableness = agreeableness
        self.neuroticism = neuroticism

    def speaking_style(self) -> Dict[str, Any]:
        # einfache Ableitung: Emojis/Intensität/Politeness
        return {
            "emojis": self.extraversion > 0.55,
            "hedges": self.agreeableness > 0.6,  # "ich würde sagen, ..."
            "enthusiasm": 0.5 + 0.5 * self.openness,
            "formality": 0.45 + 0.4 * (1 - self.extraversion),
        }

# =========================================================
# Gedächtnis-System
# =========================================================

class MemorySystem:
    """
    - Working: letzte N Turns
    - Episodisch: Sequenz von (t, prompt, appraisal, deltas, val/arousal, keyphrases)
    - Semantisch: Vorlieben/Fakten (likes/dislikes, user_facts)
    - Intentionen: einfache Ziele (label, score)
    """
    def __init__(self, max_working=8, max_episodes=256):
        self.working = deque(maxlen=max_working)
        self.episodes: List[Dict[str, Any]] = []
        self.max_episodes = max_episodes
        self.likes: Dict[str, float] = defaultdict(float)     # +: mögen, -: nicht mögen
        self.user_facts: Dict[str, str] = {}                 # einfache KVs
        self.intentions: Dict[str, float] = {}               # Ziel -> Wichtigkeit [0..1]

    def add_working(self, utter: str):
        self.working.append(utter)

    def add_episode(self, t: int, prompt: str, appraisal: Dict[str, Any], affect: Dict[str, float], keyphrases: List[str]):
        ep = {
            "t": t,
            "prompt": prompt,
            "appraisal": appraisal,
            "affect": affect,
            "keyphrases": keyphrases[:8],
        }
        self.episodes.append(ep)
        if len(self.episodes) > self.max_episodes:
            self.episodes.pop(0)

    def consolidate_preferences(self):
        # aus Episoden Likes/Dislikes extrahieren
        for ep in self.episodes[-20:]:
            app = ep["appraisal"]
            val = app.get("appraisal_val", 0.0)
            for ent in app.get("entities", []):
                if val > 0.2:
                    self.likes[ent] += 0.05
                elif val < -0.2:
                    self.likes[ent] -= 0.05
        # clamp
        for k in list(self.likes.keys()):
            self.likes[k] = max(-1.0, min(1.0, self.likes[k]))

    def learn_preference_from_utterance(self, text: str):
        t = text.lower()
        m_like = re.findall(r"\bich\s+mag\s+([A-Za-zÄÖÜäöüß ]+)", t)
        m_dis  = re.findall(r"\bich\s+mag\s+([A-Za-zÄÖÜäöüß ]+)\s+nicht", t)
        # "mag X nicht" kann die erste regex ebenfalls matchen; sichere Abzüge:
        for phrase in m_dis:
            key = phrase.strip()
            if key:
                self.likes[key] -= 0.3
        for phrase in m_like:
            key = phrase.strip()
            if key and not key.endswith(" nicht"):
                self.likes[key] += 0.3

    def recall_relevant(self, prompt: str, k: int = 3) -> List[Dict[str, Any]]:
        toks = set(tokenise_de(prompt))
        scored = []
        for ep in self.episodes[-self.max_episodes:]:
            keys = set(ep.get("keyphrases", []))
            s = jaccard(toks, keys) * 0.7 + 0.3 * abs(ep["affect"].get("valence", 0.0))
            if s > 0:
                scored.append((s, ep))
        scored.sort(key=lambda kv: kv[0], reverse=True)
        return [ep for _, ep in scored[:k]]

    def add_intention(self, label: str, score: float):
        cur = self.intentions.get(label, 0.0)
        self.intentions[label] = clamp01(0.6 * cur + 0.4 * score)

    def decay_intentions(self):
        for k in list(self.intentions.keys()):
            self.intentions[k] *= 0.98
            if self.intentions[k] < 0.03:
                del self.intentions[k]

    def summary_preferences(self, top=6) -> List[str]:
        if not self.likes:
            return ["Ich habe noch keine klaren Vorlieben gelernt."]
        items = sorted(self.likes.items(), key=lambda kv: kv[1], reverse=True)
        pos = [f"mag: {k} ({v:+.2f})" for k, v in items if v > 0.15][: top // 2]
        neg = [f"mag nicht: {k} ({v:+.2f})" for k, v in sorted(self.likes.items(), key=lambda kv: kv[1]) if v < -0.15][: top - len(pos)]
        return pos + neg

# =========================================================
# Appraisal-Engine (de): mehr Vokabular & Entitäten
# =========================================================

class AppraisalEngine:
    """
    Schlüsselwort-/Muster-basierte Appraisal für deutschsprachige Prompts.
    Liefert:
      - delta: Zustandsänderungen,
      - novelty [0..1],
      - appraisal_val [-1..1],
      - intent (Kategorie),
      - entities (extrahierte Stichworte)
    """
    def __init__(self):
        # Sentiment
        self.re_pos = re.compile(r"\b(gut|schön|toll|angenehm|super|lecker|liebe|mag|geil|genial|prima|klasse|wunderbar|cool)\b", re.IGNORECASE)
        self.re_neg = re.compile(r"\b(schlecht|doof|blöd|unangenehm|kalt|hasse|mag\s+nicht|eklig|mies|furchtbar|schrecklich|ätzend)\b", re.IGNORECASE)

        # Domänenlexika
        self.lex = {
            "essen": ["essen","snack","mahlzeit","frühstück","mittag","abendessen","pizza","brot","apfel","nudeln","reis","salat","schokolade","kuchen","suppe","burger"],
            "trinken": ["trinken","wasser","tee","kaffee","saft","cola","bier","wein","latte","espresso"],
            "schlafen": ["schlafen","nickerchen","ruhe","ausruhen","bett","schlummern"],
            "warm": ["warm","decke","heizung","kuschelig"],
            "kalt": ["kalt","zugig","frieren","eisig"],
            "sozial": ["freunde","freundin","freund","gespräch","chat","treffen","umarmen","familie","anrufen","zusammen"],
            "musik": ["musik","song","lied","playlist","hören","melodie","beat"],
            "neu": ["neu","entdecken","lernen","experiment","ausprobieren"],
            "stress": ["stress","druck","deadline","arbeit","zu viel","überfordert","erschöpft"],
            "hilfe": ["hilfe","unterstützen","kannst du","bitte hilf","brauch hilfe"],
            "sport": ["sport","laufen","joggen","spazieren","bewegung","fitness","training","yoga","radfahren"],
            "kino": ["film","kino","serie","netflix","streamen"],
            "wetter": ["wetter","regen","sonne","sturm","schnee","windig","heiß","kühl"],
            "gesundheit": ["krank","kopfschmerz","husten","fieber","arzt","medikament"],
            "emotion": ["traurig","fröhlich","glücklich","genervt","gelangweilt","ängstlich","ruhig","entspannt","wütend"],
        }

        # Intention-Fragen
        self.re_befinden = re.compile(r"(wie\s+geht|wie\s+fühl|bist\s+du\s+müde|hast\s+du\s+hunger|durst|wie\s+ist\s+deine\s+laune)", re.IGNORECASE)
        self.re_meinung  = re.compile(r"(findest\s+du|magst\s+du|ist\s+das\s+gut|deine\s+meinung|was\s+hältst\s+du)", re.IGNORECASE)

        # Entitäten: einfache Nomenextraktion
        self.re_entities = re.compile(r"\b([A-Za-zÄÖÜäöüß]{3,})\b", re.IGNORECASE)

    def match_any(self, t: str, keys: List[str]) -> bool:
        return any(k in t for k in keys)

    def entities_from(self, text: str) -> List[str]:
        toks = [w.lower() for w in self.re_entities.findall(text)]
        # stopwörter (klein)
        stops = set("und oder aber denn dass weil wie was ist sind war waren ein eine einer eines der die das im in auf bei mit ohne wenn dann dort hier heute morgen bitte sehr mal doch nur schon noch ich du er sie es wir ihr ihnen ihnen".split())
        ents = [w for w in toks if w not in stops]
        # Kürzen
        unique = []
        for w in ents:
            if w not in unique and len(unique) < 10:
                unique.append(w)
        return unique

    def appraise(self, prompt: str) -> Dict[str, Any]:
        t = prompt.strip().casefold()

        delta: Dict[str, float] = {}
        novelty = 0.18
        appraisal_val = 0.0
        intent = "neutral"

        if self.re_pos.search(prompt):
            appraisal_val += 0.30
        if self.re_neg.search(prompt):
            appraisal_val -= 0.30

        # Bedürfnisse
        if self.match_any(t, self.lex["essen"]):
            delta["hunger"] = -0.35
            delta["thirst"] = delta.get("thirst", 0.0) - 0.05
            appraisal_val += 0.22
            intent = "vorschlag_essen"

        if self.match_any(t, self.lex["trinken"]):
            delta["thirst"] = -0.40
            appraisal_val += 0.18
            intent = "vorschlag_trinken"

        if self.match_any(t, self.lex["schlafen"]):
            delta["fatigue"] = -0.45
            appraisal_val += 0.18
            intent = "vorschlag_schlaf"

        if self.match_any(t, self.lex["warm"]):
            delta["comfort"] = delta.get("comfort", 0.0) + 0.18
            appraisal_val += 0.12

        if self.match_any(t, self.lex["kalt"]):
            delta["comfort"] = delta.get("comfort", 0.0) - 0.25
            appraisal_val -= 0.18

        if self.match_any(t, self.lex["sozial"]):
            delta["social"] = -0.20
            appraisal_val += 0.12
            intent = "vorschlag_sozial"

        if self.match_any(t, self.lex["musik"]):
            appraisal_val += 0.10
            novelty += 0.10

        if self.match_any(t, self.lex["neu"]):
            novelty += 0.28
            appraisal_val += 0.08

        if self.match_any(t, self.lex["stress"]):
            appraisal_val -= 0.22
            delta["fatigue"] = delta.get("fatigue", 0.0) + 0.10
            intent = "stress"

        if self.match_any(t, self.lex["hilfe"]):
            appraisal_val += 0.14
            intent = "frage_hilfe"

        if self.match_any(t, self.lex["sport"]):
            delta["fatigue"] = delta.get("fatigue", 0.0) + 0.04
            appraisal_val += 0.10
            novelty += 0.10
            intent = "vorschlag_sport"

        if self.match_any(t, self.lex["kino"]):
            novelty += 0.12
            appraisal_val += 0.08

        if self.match_any(t, self.lex["wetter"]) or self.match_any(t, self.lex["gesundheit"]):
            novelty += 0.05

        if self.match_any(t, self.lex["emotion"]):
            novelty += 0.05

        if self.re_befinden.search(prompt):
            intent = "frage_befinden"
        if self.re_meinung .search(prompt):
            intent = "frage_meinung"

        # Entities
        entities = self.entities_from(prompt)

        return {
            "delta": delta,
            "novelty": clamp01(novelty),
            "appraisal_val": max(-1.0, min(1.0, appraisal_val)),
            "intent": intent,
            "entities": entities,
        }

# =========================================================
# Antwort-Generator
# =========================================================

class ResponseGenerator:
    def __init__(self, personality: Personality):
        self.pers = personality
        style = personality.speaking_style()
        self.use_emojis = style["emojis"]
        self.hedges = style["hedges"]
        self.formality = style["formality"]
        self.enthusiasm = style["enthusiasm"]

        # Phrasen-Pools (Deutsch)
        self.okay = [
            "Okay.", "Alles klar.", "Verstanden.", "Klingt gut.",
            "Hm, okay.", "Schon klar."
        ]
        self.like_pos = [
            "Das finde ich gut.", "Das gefällt mir.", "Mag ich.",
            "Klingt positiv.", "Das klingt angenehm."
        ]
        self.like_neg = [
            "Das finde ich nicht gut.", "Das gefällt mir nicht.",
            "Davon halte ich eher wenig.", "Klingt unangenehm."
        ]
        self.neutral = [
            "Dazu habe ich eine neutrale Meinung.",
            "Ich bin unentschlossen.",
            "Schwer zu sagen, neutral."
        ]
        self.feelings = [
            "Ich bin ein wenig {adj}.",
            "Gerade fühle ich mich eher {adj}.",
            "Im Moment bin ich {adj}.",
            "Mein Zustand ist {adj}."
        ]
        self.adj_map = {
            "müde": ["müde", "erschöpft", "schläfrig"],
            "hungrig": ["hungrig", "appetitlich gestimmt"],
            "durstig": ["durstig"],
            "unbequem": ["unbequem", "fröstelnd"],
            "gut": ["gut", "zuversichtlich"],
            "schlecht": ["nicht so gut", "etwas niedergeschlagen"],
            "neugierig": ["neugierig", "aufgeschlossen"],
            "sozial": ["gesellig gestimmt", "kontaktfreudig"],
            "ruhig": ["ruhig", "entspannt"],
            "nervös": ["angespannt", "nervös"],
        }

    def maybe(self, s: str) -> str:
        return ("Ich würde sagen: " + s) if self.hedges else s

    def decorate(self, text: str) -> str:
        if self.use_emojis:
            if "gut" in text or "freu" in text or "angenehm" in text:
                return text + " 🙂"
            if "nicht gut" in text or "müde" in text or "Durst" in text or "Hunger" in text:
                return text + " 😶"
        return text

    def feeling_lines(self, core: AffectiveCore) -> List[str]:
        s = core.state
        out = []
        if s["thirst"] > 0.75:
            out.append("Ich habe Durst.")
        elif s["thirst"] > 0.55:
            out.append("Etwas zu trinken wäre gut.")
        if s["hunger"] > 0.75:
            out.append("Ich habe Hunger.")
        elif s["hunger"] > 0.55:
            out.append("Ich könnte etwas essen.")
        if s["fatigue"] > 0.80:
            out.append("Ich bin sehr müde.")
        elif s["fatigue"] > 0.60:
            out.append("Ich bin ein wenig müde.")
        if s["comfort"] < 0.30:
            out.append("Mir ist ungemütlich.")
        elif s["comfort"] > 0.85:
            out.append("Es ist sehr angenehm.")
        if s["social"] > 0.70:
            out.append("Ich möchte Kontakt.")
        elif s["social"] < 0.30:
            out.append("Ich brauche Ruhe.")
        if s["curiosity"] > 0.70:
            out.append("Ich habe Lust, Neues zu entdecken.")
        # Laune
        if core.valence > 0.35:
            out.append("Meine Laune ist gut.")
        elif core.valence < -0.35:
            out.append("Meine Laune ist nicht so gut.")
        else:
            out.append("Meine Laune ist okay.")
        out.append(f"Wohlbefinden: {core.wellbeing:.2f}")
        return [self.decorate(x) for x in out]

    def opinion_line(self, like_cat: str) -> str:
        if like_cat == "pos":
            return self.decorate(self.maybe(np.random.choice(self.like_pos)))
        elif like_cat == "neg":
            return self.decorate(self.maybe(np.random.choice(self.like_neg)))
        else:
            return self.decorate(self.maybe(np.random.choice(self.neutral)))

# =========================================================
# Bewusstseinsschicht (Integration + Meta)
# =========================================================

class ConsciousnessLayer:
    def __init__(self, personality: Optional[Personality] = None):
        self.core = AffectiveCore()
        self.pers = personality or Personality()
        self.app = AppraisalEngine()
        self.mem = MemorySystem()
        self.resp = ResponseGenerator(self.pers)
        self.t = 0  # "Zeit" in Schritten

    # ---------- high-level Fähigkeiten ----------

    def process_prompt(self, prompt: str) -> Dict[str, Any]:
        self.t += 1
        self.mem.add_working(prompt)
        # Präferenzlernen (explizit)
        self.mem.learn_preference_from_utterance(prompt)

        # Appraisal
        appraisal = self.app.appraise(prompt)
        delta = appraisal["delta"]
        novelty = appraisal["novelty"]
        app_val = appraisal["appraisal_val"]
        intent = appraisal["intent"]
        entities = appraisal["entities"]

        # Aktivitätsenergie (Proxy: Worte + Satzzeichen)
        tokens = max(1, len(tokenise_de(prompt)))
        excls = prompt.count("!")
        activity_energy = tokens * 0.25 + 0.5 * excls

        # Ereignis anwenden & Zeit fortschreiben
        if delta:
            self.core.apply_event(delta)
        self.core.tick(activity_energy=activity_energy, novelty=novelty)

        # Intentionen aktualisieren
        if intent in ("vorschlag_essen","vorschlag_trinken","vorschlag_schlaf","vorschlag_sport","vorschlag_sozial"):
            self.mem.add_intention(intent, 0.7)
        if intent == "stress":
            self.mem.add_intention("entlastung", 0.6)
        self.mem.decay_intentions()

        # Episodenablage
        self.mem.add_episode(
            t=self.t,
            prompt=prompt,
            appraisal={"delta": delta, "novelty": novelty, "appraisal_val": app_val, "intent": intent, "entities": entities},
            affect={"valence": self.core.valence, "arousal": self.core.arousal, "wellbeing": self.core.wellbeing},
            keyphrases=entities
        )
        self.mem.consolidate_preferences()

        # Kern-Meinung
        opinion = self.core.like_dislike_statement(app_val)

        # Relevante Erinnerungen
        recalls = self.mem.recall_relevant(prompt, k=2)

        # Antwort bauen
        lines: List[str] = []
        if intent == "frage_befinden":
            lines.extend(self.resp.feeling_lines(self.core))
        elif intent == "frage_meinung":
            lines.append(opinion)
        else:
            # Mischantwort: Meinung + 1-2 Gefühlszeilen mit höchstem Druck
            lines.append(opinion)
            lines.extend(self._top_need_lines())

        # Kontextuelle Ergänzungen (Erinnerungen)
        if recalls:
            lines.append(self._memory_line(recalls))

        # Empfehlungen/Aktionen vorschlagen
        lines.extend(self._suggest_actions())

        # Meta-/Selbstreflexion (leicht dosiert)
        lines.append(self._metacog_line())

        # Ergebnis
        return {
            "intent": intent,
            "opinion": opinion,
            "statements": lines,
            "valence": self.core.valence,
            "arousal": self.core.arousal,
            "wellbeing": self.core.wellbeing,
            "state": dict(self.core.state),
            "recall_count": len(recalls)
        }

    def _top_need_lines(self) -> List[str]:
        s = self.core.state
        needs = [
            ("Ich habe Durst.", s["thirst"]),
            ("Ich habe Hunger.", s["hunger"]),
            ("Ich bin sehr müde.", s["fatigue"]),
            ("Mir ist ungemütlich.", 1.0 - s["comfort"]),
            ("Ich möchte Kontakt.", s["social"]),
            ("Ich habe Lust, Neues zu entdecken.", s["curiosity"]),
        ]
        needs.sort(key=lambda kv: kv[1], reverse=True)
        out = []
        for phrase, score in needs[:2]:
            out.append(self.resp.decorate(phrase))
        return out

    def _memory_line(self, recalls: List[Dict[str, Any]]) -> str:
        # Einfache Erinnerungsausgabe
        ep = recalls[0]
        gist = ", ".join(ep.get("keyphrases", [])[:3]) or "etwas Ähnliches"
        return f"Das erinnert mich an vorhin (t={ep['t']}): {gist}."

    def _suggest_actions(self) -> List[str]:
        s = self.core.state
        sugs = []
        if s["thirst"] > 0.7:
            sugs.append("Vorschlag: etwas trinken.")
        if s["hunger"] > 0.7:
            sugs.append("Vorschlag: eine Kleinigkeit essen.")
        if s["fatigue"] > 0.75:
            sugs.append("Vorschlag: kurze Pause oder Nickerchen.")
        if s["comfort"] < 0.35:
            sugs.append("Vorschlag: wärmer anziehen oder Decke nehmen.")
        if s["social"] > 0.7:
            sugs.append("Vorschlag: kurz jemanden anrufen.")
        if s["curiosity"] > 0.7:
            sugs.append("Vorschlag: etwas Neues anschauen/lesen.")
        # Intentionen
        for intent, sc in sorted(self.mem.intentions.items(), key=lambda kv: kv[1], reverse=True)[:2]:
            mapped = {
                "vorschlag_essen": "eine Mahlzeit einplanen",
                "vorschlag_trinken": "ein Getränk holen",
                "vorschlag_schlaf": "eine Ruhephase einplanen",
                "vorschlag_sport": "kurz bewegen/spazieren",
                "vorschlag_sozial": "Kontakt pflegen",
                "entlastung": "Aufgaben entlasten/ordnen",
            }.get(intent, intent)
            sugs.append(f"Ziel im Blick behalten ({mapped}).")
        return sugs[:3]

    def _metacog_line(self) -> str:
        # leichte Selbstreflexion abhängig von Valenz/Arousal
        if self.core.valence > 0.3 and self.core.arousal < 0.5:
            return "Ich denke gerade ruhig und positiv."
        if self.core.valence < -0.3 and self.core.arousal > 0.6:
            return "Ich merke Anspannung; ich versuche, gelassener zu reagieren."
        if self.core.arousal > 0.7:
            return "Mein Kopf ist gerade sehr aktiv."
        return "Ich beobachte meinen Zustand und passe mich an."

    # ---------- Service-Funktionen ----------

    def status_report(self) -> str:
        s = self.core.state
        return (
            f"Zustand — Hunger={s['hunger']:.2f}, Durst={s['thirst']:.2f}, Müdigkeit={s['fatigue']:.2f}, "
            f"Komfort={s['comfort']:.2f}, Sozial={s['social']:.2f}, Neugier={s['curiosity']:.2f} | "
            f"Valenz={self.core.valence:.2f}, Arousal={self.core.arousal:.2f}, Wohlbefinden={self.core.wellbeing:.2f}"
        )

    def list_memories(self, n=5) -> List[str]:
        eps = self.mem.episodes[-n:]
        if not eps:
            return ["(keine Episoden)"]
        out = []
        for ep in eps:
            gist = ", ".join(ep.get("keyphrases", [])[:4]) or "ohne Stichworte"
            v = ep["affect"].get("valence", 0.0)
            out.append(f"t={ep['t']:>3d}: {gist} | Valenz={v:+.2f}")
        return out

    def list_preferences(self) -> List[str]:
        return self.mem.summary_preferences(top=8)

    def list_goals(self) -> List[str]:
        if not self.mem.intentions:
            return ["(keine aktiven Ziele)"]
        return [f"{k}: {v:.2f}" for k, v in sorted(self.mem.intentions.items(), key=lambda kv: kv[1], reverse=True)]

# =========================================================
# CLI & Orchestrierung
# =========================================================

HELP_TEXT = """
Befehle (zusätzlich zu normalen Eingaben):
- status            : Zustandsbericht
- erinnerungen      : letzte Episoden
- vorlieben         : gelernte Vorlieben/Abneigungen
- ziele             : aktive Intentionen/Ziele
- reset             : Zustand & Gedächtnis zurücksetzen
- hilfe             : diese Hilfe anzeigen

Beispieleingaben:
- "Lass uns etwas essen." / "Ich will Wasser trinken."
- "Mir ist kalt." / "Ich brauche Schlaf."
- "Magst du Musik?" / "Wie geht es dir?"
- "Ich mag Pizza." / "Ich mag Kaffee nicht."
"""

class InterpretiveAgent:
    def __init__(self):
        self.mind = ConsciousnessLayer()

    def handle(self, text: str) -> List[str]:
        t = text.strip().lower()
        if t == "status":
            return [self.mind.status_report()]
        if t == "erinnerungen":
            return self.mind.list_memories(n=8)
        if t == "vorlieben":
            return self.mind.list_preferences()
        if t == "ziele":
            return self.mind.list_goals()
        if t == "hilfe":
            return [HELP_TEXT]
        if t == "reset":
            self.__init__()  # einfacher Reset
            return ["Zustand & Gedächtnis zurückgesetzt."]

        # Normaler Prompt → Bewusstseinsdurchlauf
        out = self.mind.process_prompt(text)
        lines = out["statements"]
        # leichte Variation der Länge
        return lines

# =========================================================
# Main
# =========================================================

def main():
    print("Meine Frau 1.0 ++  (Bewusstsein • Gedächtnis • Persönlichkeit)")
    print("Tippe Text (deutsch). 'hilfe' zeigt Befehle. Beende mit: quit/exit/stop\n")
    agent = InterpretiveAgent()

    while True:
        try:
            prompt = input(">> ").strip()
        except (EOFError, KeyboardInterrupt):
            print("\nTschüss!")
            break
        if prompt.lower() in ("quit","exit","stop"):
            print("Tschüss!")
            break
        for line in agent.handle(prompt):
            print(" -", line)

if __name__ == "__main__":
    main()

Re: Meine Frau 1.0

Verfasst: Dienstag 9. September 2025, 16:26
von __blackjack__
@AndT2011: `sys` wird nirgends verwendet und `numpy` nicht wirklich.

Bei den Typannotationen verwendet man mittlerweile die Eingebauten Typen für die Angabe von generischen Typen. Also ``list[str]`` statt ``List[str]``. Ausserdem ``Typ | None`` statt ``Optional[Typ]``. Bei den Argumenten wäre es auch besser allgemeinere Typen beziehungsweise Protokolle anzugeben, um den Aufrufer nicht unnötig einzuschränken. Also beispielsweise `collections.abc.Iteratable` statt `list` falls alles was die Funktion tatsächlich benötigt ein iterierbares Objekt ist, oder `Mapping` statt `dict` wenn es auch andere Abbildungen sein könnten.

Keine Typannotation ist nicht gleichbedeutend mit `None` sondern mit `Any`. Den Rückagebwert von Funktionen und Methoden sollte man deshalb auch annotieren wenn man die Argumente annotiert hat.

Überall wo ein literaler Wert oder eine Datenstruktur aus literalen Werten zugewiesen wird, braucht weder der Rechner noch der Mensch die offensichtliche Typannotation.

Re: Meine Frau 1.0

Verfasst: Donnerstag 11. September 2025, 21:12
von DeaD_EyE
@__blackjack__ macht es dir Spaß Code einer KI zu korrigieren? Ich habe genau aus diesem Grund nichts geschrieben.

Re: Meine Frau 1.0

Verfasst: Freitag 12. September 2025, 09:53
von __blackjack__
@DeaD_EyE: Nee, ich habe den ja auch nicht korrigiert sondern nur kurz geschrieben was mir so direkt ins Auge gefallen ist beim kurzen drüber schauen. Die Korrekturen darf AndT2011 dann schon selber machen. Oder ein LLM machen lassen, wenn es das denn kann.

Re: Meine Frau 1.0

Verfasst: Samstag 13. September 2025, 17:20
von nezzcarth
Meiner Meinung nach ist der Code so voll von hard-gecodeten Elementen und daran gekoppelter Logik, dass man den eigentlich fast komplett neu schreiben müsste, wenn man da jemals was Größeres dran ändern wollen würde. Die Zahlen wirken fast alle auch komplett beliebig und es mir ist unklar, wo die herkommen. Warum 0.0065 und nicht 0.006 oder 0.0067 etc. pp. Der Code sollte so aufgebaut sein, dass diese Sachen konfigurierbar sind und es nur eine allgemeine Logik gibt, statt einer, die ganz spezifisch auf fest eingebaute, konkrete Elemente abgestimmt ist.