dariusk / NaNoGenMo-2015

National Novel Generation Month, 2015 edition.
340 stars 21 forks source link

The Psychotherapy Of Racter Or The Descent Into Madness Of Dr. Eliza #184

Open spc476 opened 8 years ago

spc476 commented 8 years ago

What happens when you have a plodding, rather unimaginative psychiatrist talking to an extroverted, manic and possibly dangerous patient? An insane project of a lot of work for a lot of nothing.

What I did was take Racter, the AI (Artificial Insanity) program from the mid 80s that supposedly wrote The Policeman's Beard Is Half Constructed, and have it talk to Eliza, a program from the mid 60s that is the first "chatterbot" to have been written. You would think this would be an easy task. You would be wrong.

I did not finish. I came close. Around 16,000 words. And given another couple of hours, I might have even gotten 50,000 words. But it wasn't easy. It's not easy. And I want to stop my own descent into madness over this project.

The code: https://github.com/spc476/NaNoGenMo-2015 The "novel" (or rather, what I have of it): https://github.com/spc476/NaNoGenMo-2015/tree/master/novel And some additional notes about the project during the month: http://boston.conman.org/2015/11/11.1 http://boston.conman.org/2015/11/16-19

Somehow, it's always the "easy" projects that wipe you out ...

tra38 commented 8 years ago

It is weird reading Eliza itself being driven into insanity by a chatter bot that seems surprisingly intelligent (even if it is just the templates talking).

MichaelPaulukonis commented 8 years ago

Nothing like some good ol' fashioned applied digital archaeology to finish things off.

spc476 commented 8 years ago

The issue I have, I'm sure, is that, under Unix, I'm ... well, it's kind of like

% eliza | racter | eliza

Only the two eliza programs are the same program, so it's more like:

% eliza >< racter

If that makes any sense with a made up symbol to pipe eliza:stdout to racter:stdin and racter:stdout to eliza:stdin. The issue that makes this hard---I mean, it's not that difficult to to set this up, but you have to have a third program to create the pipes and execute the two programs, and each program has to be mindful of any buffering that, say, the standard C library imposes. And the MS-DOS version of Racter I have uses INT 21h, function 6, which is the MS-DOS version of direct console I/O (so not only does it not handle redirection that well, it's constantly polling for Ctrl-C because this is a compiled BASIC program). You can see the tortuous logic I had to go through starting here: https://github.com/spc476/NaNoGenMo-2015/blob/master/C/msdos.c#L447

I may not even have the proper use of CR and LF down right (MS-DOS uses both, but my MS-DOS development system is fifteen years in storage ... ). So that leaves Eliza looking for the Racter prompt to know when to stop reading, parse the input, and send more output. I wouldn't be surprised if there's some bizarre race condition lurking in this.

spc476 commented 8 years ago

Oh, another thing I forgot to take into account by Eliza (which frankly, probably helped the output)---Racter echos what it receives. So each statement by Racter actually starts with what Eliza already said (the reason you don't see that is I'm using the output that Racter itself saves).

hugovk commented 8 years ago

Here's a couple of couple of chatbots "chatting": https://www.youtube.com/watch?v=WnzlbyTZsQY https://www.youtube.com/watch?v=X_tvm6Eoa3g

cpressey commented 8 years ago

the MS-DOS version of Racter I have uses INT 21h, function 6 [...] it not handle redirection that well

Holy crap. OK...

My main thought about the race condition or whatever it is that is preventing this thing from getting to 50,000 words is, instead of thinking of the problem as "piping eliza:stdout to racter:stdin and racter:stdout to eliza:stdin", what if you think of it as introducing a third program which opens two pipes, one to eliza and one to racter, and which "brokers" the responses between the two?

That seems like it ought to be a bit cleaner; the lovely weird ugly I/O experience with racter could be isolated instead of trying to make eliza deal with it. For instance, giving it a timeout, and/or detect if it's not responding and just restart it.

It would mean using select() on the two pipes I guess, but for someone who just wrote their own baling-wire-and-chewing-gum MS-DOS emulator for NaNoGenMo(!!!), I don't expect that to be an advanced topic :)

(EDIT: I guess it's more fair to call it an MS-DOS emulator than an x86 emulator.)

enkiv2 commented 8 years ago

Sean, You could just do:

mkfifo .tmp tail -f .tmp | eliza | tee -a eliza_out.txt | racter | tee -a racter_out.txt > .tmp join <(sed 's/^$/\r/g' < eliza_out.txt | tr '\n' ' '| tr '\r' \n' | sed 's/^/eliza: /') <(sed 's/^$/\r/g' < racter_out.txt | tr '\n' ' '| tr '\r' \n' | sed 's/^/racter: /') | tr '\t' '\n'

Horray for pipes!

On Tue, Dec 1, 2015 at 7:19 AM Chris Pressey notifications@github.com wrote:

the MS-DOS version of Racter I have uses INT 21h, function 6 [...] it not handle redirection that well

Holy crap. OK...

My main thought about the race condition or whatever it is that is preventing this thing from getting to 50,000 words is, instead of thinking of the problem as "piping eliza:stdout to racter:stdin and racter:stdout to eliza:stdin", what if you think of it as introducing a third program which opens two pipes, one to eliza and one to racter, and which "brokers" the responses between the two?

That seems like it ought to be a bit cleaner; the lovely weird ugly I/O experience with racter could be isolated instead of trying to make eliza deal with it. For instance, giving it a timeout, and/or detect if it's not responding and just restart it.

It would mean using select() on the two pipes I guess, but for someone who just wrote their own baling-wire-and-chewing-gum x86 emulator for NaNoGenMo(!!!), I don't expect that to be an advanced topic :)

— Reply to this email directly or view it on GitHub https://github.com/dariusk/NaNoGenMo-2015/issues/184#issuecomment-160951628 .

greg-kennedy commented 8 years ago

To me, the easiest solution was to write enough of a MS-DOS emulator to run Racter and to allow me to pipe data into and out of it.

It does appear Racter has succeeded in his goal to drive you certifiably insane.

enkiv2 commented 8 years ago

This is the int 21h printing call that is unable to print dollar signs because it uses them as a string terminator, right?

On Tue, Dec 1, 2015 at 11:07 AM Greg Kennedy notifications@github.com wrote:

To me, the easiest solution was to write enough of a MS-DOS emulator to run Racter and to allow me to pipe data into and out of it.

It does appear Racter has succeeded in his goal to drive you certifiably insane.

— Reply to this email directly or view it on GitHub https://github.com/dariusk/NaNoGenMo-2015/issues/184#issuecomment-161014828 .

spc476 commented 8 years ago

@enkiv2 INT 21h, function 9 is the function that prints a string ending with '$'. The function I had to deal with is INT 21h, function 6, or "Direction Console IO". In modern parlance, this is a non-blocking read or write of one character (byte) from the console device (depending upon the parameters its called with).

Also, I tried that crazy command line you gave---nice try, but it didn't work out of the box (Eliza would need some modification to deal with Racter, who actually starts the conversation). I'm not entirely convinced it would work in any case, as the version of tee I have can't be told to not buffer anything.

@cpressey That is a thought, and had I not come down with a upper respiratory infection, I might have had time to implement such a program (in retrospect, that is probably the cleanest way to deal with this, as it mimics the "hand copy-n-paste" I did a few weeks earlier). And yes, it's more of an MS-DOS emulator as I don't have to emulate an 8088.

greg-kennedy commented 8 years ago

FYI now you've got me spending my free time today using your INRAC notes: http://boston.conman.org/2008/06/18.2

to implement Racter in a Perl module, so I can easily pit two of them against one another.