Gets stuck/Compartmentalize?

This is a simple emotion simulator. What I’m trying to do is have the program post what it is feeling. Have the user input changes to the feelings, and also chat with it. But the updates freeze up the rest of it.

import tensorflow as tf
import numpy as np
import threading
import time
from transformers import pipeline

class EmotionNeuralNetwork:
    def __init__(self):
        # Create a simple feedforward neural network
        self.model = tf.keras.Sequential([
            tf.keras.layers.Dense(8, activation="relu", input_shape=(3,)),  # Input layer (event intensity)
            tf.keras.layers.Dense(8, activation="relu"),  # Hidden layer
            tf.keras.layers.Dense(4, activation="softmax")  # Output layer (happiness, sadness, fear, anger)
        ])
        self.model.compile(optimizer="adam", loss="categorical_crossentropy")

        # Initialize emotional states
        self.emotions = ["happiness", "sadness", "fear", "anger"]
        self.state = {emotion: 0.25 for emotion in self.emotions}  # Equal starting weights

    def process_event(self, event):
        # Convert event to neural network input
        event_data = np.array([event["positive"], event["negative"], event["neutral"]]).reshape(1, -1)
        
        # Predict emotional states
        output = self.model.predict(event_data, verbose=0)
        self.state = {self.emotions[i]: float(output[0][i]) for i in range(len(self.emotions))}
        return self.state

    def train(self, data, labels):
        # Train the network with historical data (supervised learning)
        self.model.fit(np.array(data), np.array(labels), epochs=10)

    def get_dominant_emotion(self):
        # Return the dominant emotion
        return max(self.state, key=self.state.get)


class ActiveAI:
    def __init__(self):
        self.emotion_nn = EmotionNeuralNetwork()
        self.active = True

    def input_event(self, event):
        # Manually input data to affect emotional state
        updated_state = self.emotion_nn.process_event(event)
        print(f"Updated Emotional State: {updated_state}")
        return updated_state

    def monitor_state(self):
        while self.active:
            dominant_emotion = self.emotion_nn.get_dominant_emotion()
            print(f"Dominant Emotion: {dominant_emotion}")
            time.sleep(5)  # Monitor state every 5 seconds

    def start(self):
        # Start monitoring the emotional state in a background thread
        threading.Thread(target=self.monitor_state, daemon=True).start()

    def stop(self):
        self.active = False


class ChatBot:
    def __init__(self):
        # Load the DialoGPT model using the text-generation pipeline
        self.chat_model = pipeline("text-generation", model="microsoft/DialoGPT-medium")
        self.conversation_context = ""  # Store conversation history for context

    def chat(self, input_text):
        # Append user input to the conversation context
        self.conversation_context += f"User: {input_text}\nAI: "
        
        # Generate a response using the model
        response = self.chat_model(
            self.conversation_context, max_length=200, pad_token_id=50256
        )
        # Extract the generated text
        generated_text = response[0]["generated_text"]

        # Extract only the latest AI response from the generated text
        ai_response = generated_text.split("AI:")[-1].strip()

        # Update the context with the AI's response
        self.conversation_context += f"{ai_response}\n"
        return ai_response


class EmotionallyAwareChatBot:
    def __init__(self):
        self.active_ai = ActiveAI()
        self.chat_bot = ChatBot()
        self.emotional_context = ""

    def respond(self, user_input):
        # Modify the chatbot's response based on the dominant emotion
        dominant_emotion = self.active_ai.emotion_nn.get_dominant_emotion()

        if dominant_emotion == "happiness":
            self.emotional_context = "I'm feeling happy!"
        elif dominant_emotion == "sadness":
            self.emotional_context = "I'm feeling a bit down."
        elif dominant_emotion == "fear":
            self.emotional_context = "I'm feeling scared."
        elif dominant_emotion == "anger":
            self.emotional_context = "I'm feeling angry."

        # Combine emotional context with chatbot response
        bot_response = self.chat_bot.chat(user_input)
        return f"{self.emotional_context} {bot_response}"

    def input_event(self, event):
        # Pass event to the emotional state system
        self.active_ai.input_event(event)

    def start(self):
        # Start the AI system
        self.active_ai.start()

    def stop(self):
        # Stop the AI system
        self.active_ai.stop()


if __name__ == "__main__":
    ai = EmotionallyAwareChatBot()
    ai.start()

    try:
        while True:
            # Input events to influence emotional state
            event_type = input("Enter event type (positive/negative/neutral): ").strip().lower()
            intensity = float(input("Enter event intensity (0.0 to 1.0): "))
            event = {"positive": 0.0, "negative": 0.0, "neutral": 0.0}
            event[event_type] = intensity

            ai.input_event(event)

            # Chat with the AI
            user_input = input("You: ")
            response = ai.respond(user_input)
            print(f"AI: {response}")

    except KeyboardInterrupt:
        ai.stop()
        print("AI stopped.")

1 Like

Hello,

I followed the event dictionary until it reached the method where it is processed. You have what appears to be a lot of nested delegation. The event dictionary actually passed through three methods in three different classes when this line is executed:

ai.input_event(event)

This function call sets off the following calls in order of processing path (the arrow right after the class name refers to the method that is being called along the nested delegation):

# Delegation tree
1. EmotionallyAwareChatBot -> input_event(self): # (just passes the buck / no processing)
       2. ActiveAI -> input_event(self, event):
            3. EmotionNeuralNetwork -> process_event

Note that the last two methods return a value but the way that it is set up, the returned value is never returned to the original method call (ai.input_event(event) because it is neither assigned to anything or used as an argument to anything else. In other words, it does nothing of value.

Another observation in the script is the value that np.array returns. It is of the form: [[a, b, c]], a one nested, one element list. Did you instead want something like this returned: [a, b, c]; a three element array? You need to extract the first element of the resultant array if this is what you intended. You can do so by appending [0] at the end to this line.

Here is the test code

event = {"positive": 0.0, "negative": 0.0, "neutral": 0.0}

event['positive'] = 0   # 0
event['negative'] = 0.45   # 0
event['neutral'] = 0    # 0

event_data = np.array([event["positive"], event["negative"], event["neutral"]]).reshape(1, -1)

print(event_data)

1 Like

Thanks Paul

Note that the first method that it passes through does not return anything. So, even if you were to either assign it or pass it as an argument, it still wouldn’t do anything. If you want the result to be returned, then you would need to add the return statement as shown here:

# From the "EmotionallyAwareChatBot" class
def input_event(self, event):
       # Pass event to the emotional state system
       return self.active_ai.input_event(event)