Tutorial - Creating a Receptor, the Basics

Preface

This tutorial discussing the basics of building a receptor. In the tutorial, you'll see some paragraphs where I identify tasks that would improve the HOPE user experience. These are marked with "NEED:" I hope you find this tutorial helpful -- more will be posted soon!

Introduction

When writing a receptor, there are some basic patterns that are always followed. First, consider the questions:

Does your receptor process semantic types?

Does your receptor emit semantic types?

Will your receptor need a user interface for visualizing the semantic data?

Will your receptor require or offer some user configurability?

What other receptors will your receptor interact with?

Receptors typically implement a very specific behavior. From the perspective of the user, it is the "system of receptors" that creates a rich and flexible application, therefore be careful that your receptor does not do "too much."

For example, let's write a very basic receptor that loads a text file that the user specifies in a configuration UI. All the receptor does, either when it's initialized or when the user selects the text file, is load the file into memory and emit it as a "Text" semantic type. We already have receptors for both displaying text semantic types and speaking them, so we let the user configure what he/she wants to do with the text.

Later on:

We'll look at a more advanced topic -- the idea of the user creating a base semantic type so that the text file has more semantic meaning than just "text" as this opens the door to more interesting kinds of semantic processing.

We'll write a translate receptor which will interface, probably with Google's translate API, to translate the text file.

We will also feed the text to the AlchemyAPI for NLP processing.

As you can see, starting with a very basic receptor, we can create different applets that do some interesting and meaningful things with even the most basic of semantic types, "text."

Getting Started

Creating the Basic Project

Assuming you are going to write a receptor available to the public, open Visual Studio and create the receptor project in the "Receptors" folder or in a sub-folder if you feel that is appropriate:

We'll call our receptor the "TextFileLoaderReceptor".

In the "New Project" dialog:

select Class Library

enter in the name of your receptor

make sure the location is correct ("Receptors" folder and any sub-folder you may want)

Visual Studio will create a class. Rename this class and its associated file to "TextFileLoader" (removing the word "Receptor"):

Setup References

Once the project is created, you should add some references right away:

Clifton.Receptor.Interfaces

Clifton.SemanticTypeSystem.Interfaces

lib

These are the core assemblies that every receptor should reference.

Lastly, add references to these two assemblies in your receptor's .cs file:

using Clifton.Receptor.Interfaces;
using Clifton.SemanticTypeSystem.Interfaces;

Because we'll be working with a file chooser dialog and a file reader, we'll also add the System.Windows.Forms reference and add:

using System.IO;
using System.Windows.Forms;

to the code.

We'll also add this "using" statement so we get access to the XML instantiation engine's attributes, which we use later on:

using Clifton.MycroParser;

So, all put together, we have:

using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Clifton.MycroParser;
using Clifton.Receptor.Interfaces;
using Clifton.SemanticTypeSystem.Interfaces;
namespace TextFileLoaderReceptor
{
public class TextFileLoader : BaseReceptor
{
... etc...

Setup Post-Build Event

Assuming you are building the receptor in the HOPE solution, you'll want to copy the receptor's assembly to the HOPE application's bin\debug folder.

NEED: This step would not be necessary if the HOPE application had a configuration file of folders to look into for receptors, so that it could scan the folders and know where the receptor's assembly and any optional UI configuration file lived.

In the post-build step, copy the receptor assembly the the bin\Debug folder of the HOPE application, which is called "TypeSystemExplorer".

Setup the Receptor Class

"WindowedBaseReceptor" is a useful base class for when your receptor has a "visualization" UI (as opposed to a configuration UI, which is handled by "BaseReceptor.")

For our purposes, since there's no visualization UI, we'll use BaseReceptor and create the required constructor, which takes the IReceptorSystem interface as a parameter and passes it to the base class:

Also, you must implement the Name property:

public override string Name { get { return "Text File Loader"; } }

Build your receptor, then...

Add Your Receptor to the Receptor Chooser List:

In HOPE application ("TypeSystemExplorer" for now), open the Controllers/ReceptorChooserController.cs file:

NEED: When implementing the "auto-detect receptors from specified folders" feature, the receptor chooser should be auto-populated with discovered receptors.

Configuration UI

While you can implement a receptor configuration UI as a form in the receptor itself, the preferred way to do this is by using an XML file. HOPE automatically persists designated configuration properties and it also somewhat separates the UI from the receptor implementation.

The first step is to specify the name of the configuration UI. In our case:

Next, we implement the UI. Here we'll create a UI that lets the user enter a file path or use a the built-in .NET file browser. At the moment, all configuration UI's must live in the application's bin\Debug folder.

NEED: With the receptor discovery feature, the configuration and visualization UI's should also be associated, such that they do not need to live in the bin\Debug folder. This requires reworking where the application goes to load the XML files.

We also implement clicking on the "Browse..." button. Note that the Click handler is automatically wired up, where "receptor" is the receptor instance that is associated with this configuration dialog. In other words, when you double-click on a receptor to configure it, that receptor receives UI events wired up in the XML. Because the property binding is one way, we need to auto-populate to the control in the receptor itself:

the value of this property is automatically persisted when the user saves the applet, and is restored on load. Note that the parameter to this attribute is currently ignored.

Now we can add the Text Display receptor to create a two-receptor applet that displays the Text semantic type. If we create a text file called "hi.txt" with the context "Hello HOPE!", it will now be displayed in the text display receptor:

Receptor Subtitles

One final touch is to display the filename portion as a subtitle of the Text File Loader receptor. "Subname" is a built-in property of the base class:

Text to Speech

Our receptor can also take advantage of the existing Text to Speech receptor - simply add it to the applet surface and it will receive the Text signal as well:

Separate Tabs

We can load text files into separate tabs by creating "computational islands" with membranes:

Of course, it would be great if the tab title reflected to filename -- we'll leave this for later! But the salient point here is that we can put together simple receptor combinations into different configurations depending on the user's needs.

Conclusion

This concludes the introductory tutorial on how to write a receptor. We'll explore receiving signals next.