Author Topic: Listen to VA_Log/Executed commands  (Read 4201 times)

PsiQss

  • Guest
Listen to VA_Log/Executed commands
« on: February 07, 2017, 06:10:00 AM »
Essentially, I just want to keep track of last spoken commands. Is it possible to execute a function every time a command is executed? I think it would be some sort of event handler (which I'm not too familiar with) but I have no idea if it's even possible currently. So I thought it might be possible to just read the VA log every time something appears in it.
I know I can just do that from within the profile and have every command call a function that would do stuff with last spoken command. But that will not work with external profiles, and I'd like to keep track of those as well.


Is that even possible somehow?

EDIT:

Oh and just remembered! If I decide to do this from within each command, in that each commands from within the profile will let the plugin know that it just got executed.. is it possible to pass some sort of command ID or something like that? Let me explain the problem:

This is our command: [Hey; ][Computer; ][Start up; Start; Load up; Engage] the engines [please; ]


Now, I could either pass all this as the entire command string and store it in a stack-type array or check the segments that were actually used to call the function ("Hey, load up the engines"). And here's an example of what I want to achieve. Let's say engines are already started up and VA reads that from variable (there's no real-time game state log in Star Citizen, afaik).

VA responds: "Already running, sir"
User: "No, they're not. Start them up!"

And that last command would make the plugin check recent commands to figure out what the hell is the thing that user wants to start up. In this case, its reaction would be to execute the command again, just this time ignoring the "bool enginesRunning" variable. So first, how do I do this. Do I use ExecuteCommand("<insert entire string from stack here>") or do I have to manually parse the segments?

Another question, for doing things the other way - checking if the user is calling the same command again. How do I compare what the user just said to what is stored in the "recentCommands" array if we have many concatenations? To get, for example, this:

user: hey, computer!
VA: yes, sir?
user: hello!
VA: Hello, commander
user: Umm, computer?
VA: Yes? What can I do for you, sir?
user: hello, computer!
VA: Error! Suspicious activity detected.. Possible internal failure.. Examining the user for brain damage.. Reporting to local medical station.. Please stand by and wait for help. Emergency system shutdown in 5..4..3..2..1


Just a silly example, but you get the gist ;) Is it possible to identify the commands and compare them later regardless of what the user just said or do I have to create my own command ID and pass it manually to the plugin with each execution of the command?
« Last Edit: February 07, 2017, 04:48:34 PM by PsiQss »

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4747
  • RTFM
Re: Listen to VA_Log/Executed commands
« Reply #1 on: February 07, 2017, 04:37:07 PM »
If it's specifically last spoken commands, you can use the "{LASTSPOKENCMD}" token(VoiceAttackHelp.pdf page 102), and monitor it for changes with a loop in a separate command:
Code: [Select]
Set Text [PREVCMD] to '{LASTSPOKENCMD}'
Start Loop While : [{EXP:1=1}] Equals '1'
    Begin Text Compare : [{LASTSPOKENCMD}] Does Not Equal [PREVCMD]
        Write '[Purple] Doing something with {LASTSPOKENCMD}' to log
        Set Text [PREVCMD] to '{LASTSPOKENCMD}'
    End Condition
End Loop
This commands should be started once(when loading the profile, for example), and it keeps running until the profile is changed, or VoiceAttack shuts down.
Because it has to run in the background, it should have the "Allow other commands to be executed while this one is running" option checked.

PsiQss

  • Guest
Re: Listen to VA_Log/Executed commands
« Reply #2 on: February 07, 2017, 05:06:45 PM »
Well, I did take a look at {LASTSPOKENCMD} token but I don't think that will work for this case? I have no idea how exactly that token works, from a technical perspective. Is it actually a reference to the last used command or an exact copy of what was said to call the command? If it's the former, then it would totally work for storing this token each time a command is executed. But still, testing it in a loop wouldn't work in a case where the same command was called twice in a row. And that's something I want to be aware of as well.

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4747
  • RTFM
Re: Listen to VA_Log/Executed commands
« Reply #3 on: February 07, 2017, 05:23:16 PM »
testing it in a loop wouldn't work in a case where the same command was called twice in a row. And that's something I want to be aware of as well.
Fair point.

However, it doesn't really matter, does it? Here's what you just did: Stated a clear requirement, made someone put in time to attempt to fulfill that requirement, then posted additional information which makes it very clear your initial requirement was in fact never going to be the correct solution for your problem.


Quote from: http://www.catb.org/~esr/faqs/smart-questions.html#goal
Describe the goal, not the step

If you are trying to find out how to do something (as opposed to reporting a bug), begin by describing the goal. Only then describe the particular step towards it that you are blocked on.

Often, people who need technical help have a high-level goal in mind and get stuck on what they think is one particular path towards the goal. They come for help with the step, but don't realize that the path is wrong. It can take substantial effort to get past this.

Stupid:

    How do I get the color-picker on the FooDraw program to take a hexadecimal RGB value?
Smart:

    I'm trying to replace the color table on an image with values of my choosing. Right now the only way I can see to do this is by editing each table slot, but I can't get FooDraw's color picker to take a hexadecimal RGB value.

The second version of the question is smart. It allows an answer that suggests a tool better suited to the task.

If you want to keep track of states, use variables and set them according to the state. This is how computer programs work.

PsiQss

  • Guest
Re: Listen to VA_Log/Executed commands
« Reply #4 on: February 08, 2017, 04:49:48 AM »

Fair point.

However, it doesn't really matter, does it? Here's what you just did: Stated a clear requirement, made someone put in time to attempt to fulfill that requirement, then posted additional information which makes it very clear your initial requirement was in fact never going to be the correct solution for your problem.

I know, I'm sorry :( When I ran into this problem I was basically going to work soon, so I just wanted to quickly post it on the forums so that maybe someone would answer by the time I was back. Later I realized that it's not very clear about what I actually want to achieve, so I added the EDIT to state it better. I was actually already in the edit mode when you replied. Again, sorry for that.

If you want to keep track of states, use variables and set them according to the state. This is how computer programs work.

Yes, variables would be an obvious solution. I could set an int to keep track of how many times in a row a cmd was used, bool to check if a cmd requires confirmation, txt value to specify the type of a command, and so on.

Well, l'll try to describe my way of thinking and why I wanted to go with a buffer of last used commands. On an example, but let's put user's insanity and repeating the "Hello" aside and get to a functional command:

Command: "[Turn them; ] Back on"
Expected outcome: Execute last used On/Off-type cmd - "{TXT:Action} + On"
where:
(string Action) is a cmd ID, changed with each action-type command, so that we know what was the last executed action
(bool OnOff) is changed with each action to tell if it was an on/off type cmd

Procedure with variables:

Code: [Select]
if(OnOff)
{
   switch(Action)
   {
      case "Lights":
         if (!LightsOn)
            ExecuteCMD("Lights On");
         else say "Already on, sir";
         break;
      [...] //list of cases for every single On/Off cmd
          default: break;
   }
}

Now let's say this was the recent cmd input:

Turn off the lights (Action = "Lights"; OnOff=true)
(Random chatter)
Full stop               (Action = "FwdThrust"; OnOff=false)
(Random chatter)
Turn them back on

Random chatter is purely immersive thing, it doesn't have to alter the Action and OnOff variable. But the "Full stop" is indeed an action, although not an On/Off one. So in this case, it won't work. The workaround would be to have different versions of Action variable, for example OnOffAction would keep track of last used OnOff cmd. The problem is if I wanted to call the last used action command regardless of its type.
The other problem is that every single command would have to set those variables correctly. With that in mind, if I wanted to add something fancy in the future, I'd have to go through all the commands and add another variable.

Procedure with command stack:

String LastCMD = {LastSpokenCMD}
// by the way, I've tested it in the meantime and this token stores the exact command, and the way it was spoken,
// which has its pros and cons, but more on that later ;)

Now I run some analysis of the LastCMD, check it for keywords and apply tags to it (OnOff, Movement, RandomChatter...)
then store it in a database table with, let's say, 10 entries. I could also do something with the {Category} token. If I want, I can blacklist some commands which for some reason I don't want to remember they were used.

Now, the (Turn them Back On) command would look kind of like this:
Code: [Select]
string cmd[] = cmdDB.Select( "[Type] = '" + "OnOff'");
if(cmd[0]["[ON]"]
{
     // here some code to ask the user if he wants to use the previous command instead, because "Lights" are already on
}
else
 string cmdToRun = cmd[0]["[Command]"] + " On";
 ExecuteCMD(cmdToRun);

So, we have some obvious advantages with this approach. First, if I want to add something, I just add it to the command analysis and modify the DataTable a little bit - no need to edit the profile at all. Secondly, I could handle all the commands from other profiles without users having to adhere to some specific command template that my plugin will be using.

And YES, for the life of me, I didn't use the word PLUGIN even once in my initial post (before edit). That's bad.. really bad..
Well, I think it will actually be best to explain what I'm working on, this might shed some light on why I need all this crazy stuff. I wanted to keep that a secret until closer to release, but whatever. So I'm making an immersive AI plugin. On it's own it would not have much functionality, but it will make using VA profiles more natural. The idea was inspired by A.N.N.A for Star Citizen, she had that "personality" feature that made her responses different depending on her current "mood". The higher the value, the nicer she was to you, basically.

Now, what I'm programming now, is sort of a Master Profile that would interact with other profiles and alter the responses a little bit (provided the external profile is calling a plugin variable to respond, and not a hard-coded value). The AI has few personality traits, that change depending on how a user interacts with her. For example if you are polite (you use "please" and "thank you" a lot) this will make her "kindness" value go up. Most of her responses and the way she adresses you will depend on her personality value.

This is one of the reasons I need to keep track of each spoken command - to catch all the "pleases" and "thankyous" and alter the personality. This is also a reason, aside from aforementioned functional value, why I need to keep track of a number of recent commands, regardless of the profile they were called from - to prevent users from "spamming" one command just to "farm" her personality. And I just realized, for that I need the spoken phrase (LastSpokenCMD will do) as well as the full command identifier, so that I have a way of telling if it was the same command but with different initialization phrase.
So I actually DO need this command ID somehow. If not possible, I think I'll just go with your suggestion to check the {LASTSPOKENCMD} token in a loop, and just pass it to plugin whenever it changes. I already have the personality handling down, the functions to select correct phrases from database based on personality (a method to let the users add their own response phrases with personality requirements is in the works). The only thing I need now is a way of tracking the used commands.

Wow that ended up much longer than planned o.O

TL;DR:
- IT"S FOR A PLUGIN (should've mentioned that earlier, I know)
- variables won't work
- I do need the command ID to store in the DataTable
- That {LastSpokenCMD} loop helps

Unless I've overlooked some important detail, in which case please point this out or suggest a better way of achieving my goal.

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4747
  • RTFM
Re: Listen to VA_Log/Executed commands
« Reply #5 on: February 08, 2017, 06:47:10 AM »
Your idea is ambitious, but the basic building blocks to make it possible are certainly possible to implement.

The simplest solution to getting an indication of command execution would be a "{CMDCOUNT}" token that increments every time a command is recognized(the value would reset either on application start or profile change, depending on what's deemed more logical by Gary).

You could potentially do without the command ID if you use find and replace on the output from "{LASTSPOKENCMD}" to swap "on" with "off" and such.
Otherwise, you could ask for a straight-up "{LASTCMD}" token that outputs the full "When I say" command string.

I'd recommend making explicit feature requests for these or whichever implementation seems useful but also flexible(Every request must be evaluated as a time versus utility equation).


If you do end up using tokens, you may find this function useful:
Quote
ParseTokens(String Value) – This is just a shortcut to getting values from any of the available tokens.
Code: [Select]
String s = vaProxy.ParseTokens(“{ACTIVEWINDOWTITLE}”);
Using it with "{LASTSPOKENCMD}", for example, you can set up your monitoring loop inside the plugin. This has the advantage of surviving a "Stop Processing All Commands" action, which a normal command-based loop cannot.

PsiQss

  • Guest
Re: Listen to VA_Log/Executed commands
« Reply #6 on: February 08, 2017, 02:56:17 PM »
{CMDCount}! Where was it hiding all this time?! This is just perfect :D Now just take this, and that, and stuff it into an infinite loop.. Voila!

Oh wait.. it doesn't exist yet. Well, time to write the feature request.

And yes, I will probably make a request for the {LASTCMD} token too, but first I'll have to think all this through a bit more than my OP here. I learned my lesson :P The real reason why {LASTSPOKENCMD} won't work is that I can't think of any other way to tell that "Start her up, please" and "Engines on" is actually the same command. With some simple linguistic rules it would be possible to evaluate "start up the engines" and "Engines on" as the same thing (Engines being the keyword and "start up/ on" in some confirmation dictionary), but there are things that you just can't keep track of.

I know there's also a way for users to have "Engines [On; off]" in a single "when I say" with different actions depending on what was actually said to invoke the command, but the plugin could automatically tag those commands as "complex", "unknown" type or whatever, for example when it encounters opposite keywords in one segment.
But I'm getting a bit off track here. I'm gonna contemplate on those new tokens that you suggested. Again, thank you a lot Pfeil! Especially for the patience and staying here despite my utter failure at describing my problem ;)