Pyrsona

An Affective Reasoner-like module for Python, using the PyKE module.




Source code.
Written in python 2.6, probably runs in 2.5 and maybe 2.4. Has to be on the python path, or in the site-packages directory for python.

Pre-project Power Point Presentation




My goal was to implement a simple affective reasoner-like framework for python that would be useful to me for my own gaming and interactive projects.


  • I ran into many issues that took up a lot of time, and many parts are unfinished, but the basic framework has many successful elements

  • After many changes in the design of the system which had me switching the construal rule base from forward-chaining to backward-chaining rules, I ended up with a basic python agent class Pyrsona:

class Pyrsona( object ):
    '''An emotional agent.'''
    def __init__( self, agent_name, engine_name ):
        self._personality = pyke.knowledge_engine.engine( engine_name )
        self._personality.activate( agent_name )
        self.name = agent_name
    def construe( self, event ):
        bindings = []
        with self._personality.prove_n( 'eliciting', 'bindings',
                                        (event,), 2 ) as generator:
            for answer in generator:
                bindings.append( list( answer ) )
        for answer in bindings:
            # Handle combination emotions
            pass
        # Manifest emotion
        self.emote( bindings )
    def emote( self, bindings ):
        for b in bindings:
            print b, "\n"
            print self.name, "is expressing", b[0][0], "\n"


  • Each Pysona class is basically a wrapper for a Pyke knowledge engine object at this point

  • This will allow me to separate the agents with different construal rule bases and propagate simulation events through each agent's construe method for all agents appraising an event

  • The construe method basically takes an event and asks the knowledge engine if there are any construals matching, if there's a match it returns the emotions that resulted and the related bindings

  • Each event is a nested tuple, with slots for different variables:

(1, future, (appraising_agent, andy), (action, (hugs, bob, andy), 8), (location, mcdonalds))


  • This is sent to the activated contruals for that agent and if the event is bound to the first part of the construal, pyke must figure out what emotion and eecr to return for the remaining slots we did not provide

construal_a
    use bindings( ($id, $time, (appraising_agent, $self),
                   (action, (hugs, $other, $self), $obj_desire), *$rest),
                  $emotion, ($self, None, $desire_self, None, None,
                             $status, None, None, None) )
    when              
        python
            try:
                if relationships[$other] == 'friend':
                    subj_desire = POSITIVE
                elif $relationship == 'enemy':
                    subj_desire = SCALE[-8]
            # No relationship with other
            except KeyError:
                subj_desire = SCALE[1]
               
        $desire_self = get_intensity( $obj_desire, subj_desire )    
        # Don't bind $id or $time to $event as these won't match expectation      
        $gen_event = tuple( (('appraising_agent', $self),
                         ('action', ('hugs', $other, $self))) )
        eliciting.emotion( $emotion, ($self, None, $desire_self, None, None,
                                      $status, None, None, None),
                           $gen_event, $time )


  • This causes us to have to prove the subgoal of what emotions are eliciting for the eecr bindings generated from the construal

  • First the intensity of $desire_self is computed from the intensity variables in the event and the construal:

# Intensity dictionary, values could be changed to reflect new theory
SCALE = {-10:-10, -9:-9, -8:-8, -7:-7, -6:-6, -5:-5, -4:4, -3:-3, -2:-2,
         -1:-1, 0:0, 1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8, 9:9, 10:10}
         
# Arbitrary default constants, negative emphasized
NEGATIVE = SCALE[-5]
POSITIVE = SCALE[3]
       
def get_intensity( obj_desire=0, subj_desire=0, reality=1, surprise=1 ):
    return (obj_desire + subj_desire) / 2.0 * reality * surprise


  • Then pyke finds the eliciting.emotion that binds to the eecr generated from the construal and fully binds $emotion and the eecr slots to return to the agent's construe method:

well_being  # and prospect-based / confirmation
    use emotion( $emotion, ($self, $_, $desire_self, $_, $_, $status,
                            $_, $_, $_),
                 $gen_event, $time )
    when
        check $desire_self
        python
            status = get_status( $time )            
            if not status:
                # Check expectations database for the event
                try:
                    if expectations[$gen_event] == 'hope':
                        (status, emotion) = get_emotion(
                            $desire_self, ('confirmed', 'satisfaction'),
                            ('disconfirmed', 'disappointment') )
                    else:
                        (status, emotion) = get_emotion(
                            $desire_self, ('confirmed', 'fears_confirmed'),
                            ('disconfirmed', 'relief') )
                    del expectations[$gen_event]
                                         
                # If not expected the emotion is joy
                except KeyError:
                    emotion = get_emotion( $desire_self, 'joy', 'distress' )
            else:
                emotion = get_emotion( $desire_self, 'hope', 'fear' )
               
                # Add event / prospect emotion pair to expectations database
                expectations[$gen_event] = emotion        
               
        $emotion = emotion
        $status = status


  • And finally the emotion is expressed:
andy is expressing hope

Still a lot to do


  • Learning the pyke api, logic programming, bug tracing and multiple design changes took a lot of time and I was not able to implement all of the affective reasoner ideas that I wanted to.

  • Things that still need to be implemented or improved:
    • temperaments and emotion expression channels, intensities are in place to work with emotion expression
    • combination emotions anger, love, etc., multiple emotions can be returned from an event so it is just a matter of combining the bindings for the multiple emotions.
    • Allow for dynamic changes to the intensity variables in construals, friendships, etc
    • Incorporate time-based disconfirmation
    • Many more test construals
    • Dynamic event generation and agents involved "collision detection"



EmotionAIProjects
Valid XHTML 1.0 Transitional :: Valid CSS :: Powered by WikkaWiki
Page was generated in 0.3416 seconds