Loading...

AI-Agent

09/03/2023

Introducing AI-Agent, giving Microsoft Agents more intelligence than they ever should've had...

AI-Agent was made using WXPython and the OpenAI API, it supports most text-completion models, however, ChatGPT API support is a work-in-progress

How?

Using some WxPython wiki code for custom windows shapes, I was able to use any image as the mask, however, this was the easy part...

After getting a still image to display, I would still need to add animations, in order to do this, I had to write a custom onPaint function for the frame which would update the shape and image of the frame, then along with that I implemented a state system which would allow animations to be queued and played

In order to convert the ACS data into something else, I used a simple Python script which would convert the data into easier-to-parse JSON files, ie, an excerpt of the one used for Clippy:


"GestureLeft": [
  {
    "Duration": 100,
    "Image": "0000.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  },
  {
    "Duration": 100,
    "Image": "0001.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  },
  {
    "Duration": 100,
    "Image": "0002.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  },
  {
    "Duration": 100,
    "Image": "0003.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  },
  {
    "Duration": 100,
    "Image": "0004.bmp",
    "Sound": null,
    "Branches": {
      "-1": 13
    }
  },
  {
    "Duration": 100,
    "Image": "0005.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  },
  {
    "Duration": 100,
    "Image": "0006.bmp",
    "Sound": null,
    "Branches": {
      "-1": null,
      "5": "60"
    }
  },
  {
    "Duration": 100,
    "Image": "0007.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  },
  {
    "Duration": 100,
    "Image": "0008.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  },
  {
    "Duration": 1200,
    "Image": "0009.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  },
  {
    "Duration": 100,
    "Image": "0010.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  },
  {
    "Duration": 450,
    "Image": "0011.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  },
  {
    "Duration": 100,
    "Image": "0003.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  },
  {
    "Duration": 100,
    "Image": "0002.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  },
  {
    "Duration": 100,
    "Image": "0001.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  },
  {
    "Duration": 100,
    "Image": "0000.bmp",
    "Sound": null,
    "Branches": {
      "-1": null
    }
  }
]
        

The way MS Agent animations work is that they can "branch" to certain frames (sounds turing compue :p), this was implemented in a... somewhat hacky way but if it ain't broke...


# Handle branching in a totally not hacky way
if (len(list(animationFrame["Branches"])) > 1):
    branchableFrames = []
    for branch in list(animationFrame["Branches"]):
        branch = int(branch)
        if (branch != -1):
            for i in range(int(animationFrame["Branches"][str(branch)])):
                branchableFrames.append(branch)

    while len(branchableFrames) < 100:
        branchableFrames.append(self.currentAnimationFrame + 1)
    
    self.currentAnimationFrame = random.choice(branchableFrames)
else:
    self.currentAnimationFrame += 1

self.animationTimer.StartOnce(self.animations[self.currentAnimation][self.currentAnimationFrame-1]["Duration"])
        

yeah...

The actual animation part itself is handled by the last line of that excerpt, this causes the timer which handles animations to start, once the duration of the frame has elapsed, it will run the animation handler and either display the next frame or just not change anything (if the animation has finished)


As for the rest of the code that handles displaying the image, the custom frame shape and dragging the window, all that is shamelessly stolen from the WxPython Wiki