I have been coding my own version of Jarvis in Applescript for a few days now, I have been using iMessages as my input and output as I love the way its portable, yet I now want to get a bit more advanced and start making it feel like it has a use.
Currently I just use simple lines of code to recognise when I send something and then run the appropriate script to send a reply. Such as, If I say "hello", it says "hello sir" back to me.
An example being:
using terms from application "Messages"
on message received theMessage from theBuddy for theChat
if theMessage is "hello" then
run script ("/Users/Alex/Desktop/JarvisScripts/hello.scpt" as POSIX file)
end if
end message received
end using terms from
All good, but I as I said before I want to go further, I need a way it can ask me a question such as "how are you", and then depending on what I say back such as "good" it will run the right scripts to respond to "good".
My current attempts go along the lines of:
if theMessage contains "Are you ok" then
run script ("/Users/Alex/Desktop/JarvisScripts/areyouok.scpt" as POSIX file)
if theMessage is "I'm fine" then
run script ("/Users/Alex/Desktop/JarvisScripts/happy.scpt" as POSIX file)
else
if theMessage is "No I'm not" then
run script ("/Users/Alex/Desktop/JarvisScripts/unhappy.scpt" as POSIX file)
end if
end if
end if
But I know this is far from correct. So, can anybody help me with some code? Thanks
Instead of storing your 'responses' in separate script files. Try using a handler instead.
For example:
if theMessage contains "Are you ok" then
run script ("/Users/Alex/Desktop/JarvisScripts/areyouok.scpt" as POSIX file)
if theMessage is "I'm fine" then
happyResponse()
else
if theMessage is "No I'm not" then
unhappyResponse()
end if
end if
end if
--HANDLERS--
on unhappyResponse()
--<<whatever you want to happen (the code inside your .scpt file)>>
end unhappyResponse
on happyResponse()
--<<put the contents of happy.scpt here>>
end happyResponse
As you can see, the 'handlers' are listed at the bottom of your code and whenever one of the functions are called, code is evaluated for them. Now I don't know what is inside of your .scpt files but this should work in most uses.
Related
PreNote: I am open and hungry for any information, advice, tip etc.
Hello Everyone!
I am trying to create automation with applescript. This is my first personal applescript task but I have some valuable questions. Basically I am trying to catch live notifications from a website and display them in mac os notification.
I am trying to build process for a few days but I don't want to give a mess to you :) so I have roughly explained my process below.
(* Variables used in whole process
set $webToCheck > This is Safari webpage which I want to run my script on it. It won't be front window, script should be run with its name or other property.
set $theClass > This is class name of DOM element to check if it is exist or not. This class is not always exist on DOM of $webpage. It comes with notifications so when use it in "do Javascript" I got error "variable is not defined"
set $num > number of class to use in "do Javascript"
set $input > variable to assign HTML text
set $modifiedInput > Text of input seperated from HTML tags
*)
-- Step 1
tell application "Safari"
work on $webToCheck
-- Step 2
repeat until $input is not empty
set input do Javascript
document.getElementsByClassName > $theClass, $num of $webToCheck
end repeat
-- Step 3
modify text of $input to seperate from RAW HTML -- For example: <a class="" value=""> TEXT to be seperated </a>
Display notification $modifiedInput
-- Step 4
Go back to step 1 or 2 to check and display notification again
First of all, here are some general tips though:
Applescript won't accept $ at the start of variable names.
The variable assignment you are looking for is set {variable} to {value}. You can optionally at the end of it clarify the variable's class using as {class} at the end of the assignment.
Focusing a certain website does not happen with work on {URL} but as with most object oriented things in Applescript with the tell-statement. It will be shown in the full solution.
Text concatenation in Applescript happens with &. So something like "Hello " & "World" is the standard way to do it.
Modification of most things in Applescript happens with set.
It is easier to use innerText instead of innerHTML as splitting text in Applescript is a bit of a pain.
There is no goto but you could wrap the first few steps into a function, which are declared with on or to in Applescript.
Here is the full code with some documentation sprinkled in there:
global webToCheck, theClass, num, input --This says that all variables can be used even in functions.
set webToCheck to "youtube.com" --Strings can only use double quotes.
set theClass to "style-scope yt-alert-with-actions-renderer" --I will use an actual demo to prove that it is working
set num to 0 as integer -- This is the type declaration I was talking about. For numbers we have integer, real(float) and number.
set input to "" -- You don't have define everything at the top, but I will do so for this.
on displayNotification()
tell application "Safari"
tell window 1 -- This will target only the first window. For multiple windows you would have to write a repeat with-loop(for-loop), which I'm not going to do, for the sake of simplicity.
tell (first tab whose URL contains webToCheck) -- This targets just the first tab which contains the webToCheck variable.
set input to do JavaScript "document.getElementsByClassName('" & theClass & "')[" & num & "].innerText" -- This is the way I would go about writing the Javascript. I think you had something different in mind, but this works for my example.
display notification (paragraph 1 of input) with title webToCheck -- This displays the first line of my input since that is the relevant part. I also set a title so I doesn't just say "Script Editor"
end tell
end tell
end tell
end displayNotification
repeat 4 times -- I think this is quite obvious. Adjust this to your needs.
displayNotification()
delay 4
end repeat
Running this while having not used youtube on Safari in a while it displays this:
Note that this isn't the most elegant solution, but I think it is readable and it (hopefully) works for your needs.
I have written a little AppleScript which returns "missing value" and I have no idea why this happens. The script is doing what it should do, but the output is not nice in my application where I use it.
The principle of this script is just to take the argument and run the file (with "VLC Media Player") which is provided through the argument.
So for example a use would be osascript open_video.scpt ~/Path/To/File/File.mp3
on run argv
tell application "VLC"
activate
open argv
end tell
end run
This question is old but brought to the top of the questions by a new answer before I added this answer.
The recently posted answer suggests this issue might be caused if there isn't an ending newline character, and this is not at all true in this case as I've tested both with and without an ending newline character and get the exact same results, both with compiled and plain text AppleScript scripts.
You do not need to have an ending newline character and it has nothing to do with why your code is returning missing value.
Looking in the AppleScript Dictionary for the open command, it shows the following:
open v : Open an object.
open alias : The file(s) to be opened.
→ document
Where the → represents returns as in it returns info about the documents, e.g. its name.
In this case VLC is returning missing value instead, and probably because VLC does not integrate AppleScript as nice as e.g. Apple's own apps.
If you do not want to see missing value then add a return "" to the code and it will return a blank line. Or you could add e.g., return "VLC is now playing: & (argv as string); however, because VLC's AppleScript integration is not the best, I'd just go with return "" as VLC does not respond to standard AppleScript error handling well. Again, an observation by testing error handling code that works with other apps but not VLC.
Or just simply directly use the command line open command, e.g:
open "/Applications/VLC.app" "/path/to/media_file.ext"
Which will open the VLC app, start the media_file.ext file, and return the prompt.
In my testing, you have to coerce the passed variable to a string.
osascript open_video.scpt '~/Path/To/File/File.mp3'
with a script as such:
on run argv
tell application "VLC"
activate
open (argv as string)
end tell
end run
Did you make sure that you have a newline on the end of the last line? For me I got this error when I had a script that ended abruptly at the last character of the script, instead of having a newline at the end.
AFAIK this doesn't affect the functionality of your script, just what it returns. In my case I got some other output instead after I made this change, but the output appeared to be merely informational.
This is a example of a simple code I'm using for my virtual assistant:
tell application "SpeechRecognitionServer"
set theResponse to listen for {"good", "bad"} with prompt "How are you?"
if theResponse is "good" then
say "Wonderful sir… Is there anything you want me to do for you?"
else
say "Cheer up chap! Is there anything you want me to do for you?"
end if
end tell
Can anyone develop this even more, so it can understand more than 2 words and understand certain keywords?
You could, I assume, use two lists, one that stands for "Good", and another that stands for "Bad":
set good_list to {"Good", "Fine", "I'm fine", "OK", "Okay"} --List of words, meaning "Good"
set bad_list to {"Bad", "Irritated", "Fustrated", "Depressed"} --List of words, meaning "Bad"
set complete_list to good_list & bad_list
tell application "SpeechRecognitionServer"
set theResponse to listen for complete_list with prompt "How are you?"
if (good_list contains theResponse) then
say "Wonderful sir… Is there anything you want me to do?"
else if (bad_list contains theResponse) then
say "Clear up, chap! Is there anything you want me to do?"
end if
end tell
Remember, the more words or group words you include in the list, the more your script can understand!
If you want to, you could make it look more intelligent, by using the spoken answer (of the user), in the sentence the computer would say.
It would look like this:
set good_list to {"Good", "Fine", "I'm fine", "OK", "Okay"} --List of words, meaning "Good"
set bad_list to {"Bad", "Irritated", "Fustrated", "Depressed"} --List of words, meaning "Bad"
set complete_list to good_list & bad_list
tell application "SpeechRecognitionServer"
set theResponse to listen for complete_list with prompt "How are you?"
if (good_list contains theResponse) then
if theResponse = "I'm fine" then
set theResponse to "Fine" --Otherwise you would get a very weird sentence
end if
say theResponse & " is good sir! Is there anything you want me to do?"
else if (bad_list contains theResponse) then
if theResponse = "Bad" then
set theResponse to "feeling bad" --Otherwise you would get a very weird sentence
end if
say "Oh, are you " & theResponse & "? Well, clear up chap! Is there anything you want me to do?"
end if
end tell
Sorry, but I just had to correct your text mistakes (:
I am trying to write a script that does the following job: it goes through all of the emails in the mailbox, finds the ones that have the word "French" in their subject line and then copies all the subject lines of those emails in a text file. Here is what I came up with
tell application "TextEdit"
make new document
end tell
tell application "Mail"
tell the mailbox "Inbox" of account "tigeresque#gmail.com"
set numm to count of messages
repeat with kk from 1 to numm
set wordsub to subject of the message kk
tell application "TextEdit"
if "French" is in wordsub then
set paragraph kk of front document to wordsub & return
end if
end tell
end repeat
end tell
end tell
Unfortunately, I keep receiving the error
"TextEdit got an error: The index of the event is too large to be valid."
and I have already spent a couple of hours trying to fix it without much success. Could you please take a look at my code and see what is wrong with it?
Your main problem is that the number of paragraphs in TextEdit and the number of email messages have nothing to do with each other, so if you're counting on the number of messages then TextEdit will not understand it. For example you may have 50 messages but TextEdit does not have 50 paragraphs so it errors. As such we just use a separate counter for TextEdit.
I made other changes too. I often see errors happen by having one "tell application" block of code inside another... so I separated them. Also notice that the only code inside of any "tell application" block is only what is necessary for that application to handle. This too avoids errors. These are good habits to have when programming.
Therefore give this a try...
set searchWord to "French"
set emailAddress to "tigeresque#gmail.com"
tell application "Mail"
set theSubjects to subject of messages of mailbox "INBOX" of account emailAddress
end tell
set paraCounter to 1
repeat with i from 1 to count of theSubjects
set thisSubject to item i of theSubjects
if thisSubject contains searchWord then
tell application "TextEdit"
set paragraph paraCounter of front document to thisSubject & return
end tell
set paraCounter to paraCounter + 1
end if
end repeat
I wrote two applescripts so that my wife could launch mt-daapd and shut it down easily. They work fine in the Script Editor app but when I compile them into stand-alone apps, the apps work the first time I test them. Then they embarrass me as I proudly show them off to my wife. I see the "open" animation and then they just sit there. I've created other stand-alone apps before and this hasn't happened.
I tried changing the app type to a bundle (same problem). I even tried attaching to the executable via gdb to see if I could break on something magic to tell me what was going on. I looked in the Console for some information. Nothing was ther The scripts laughed in my face.
How do I fix this problem?
I've included one of the scripts below; the second is pretty much the same. I'm running 10.5.8.
property userpassword : ""
if userpassword is "" then
display dialog "Please enter your user password:" default answer "" with hidden answer
set userpassword to text returned of result
set the_password to "Undefined"
repeat until the_password is "Correct"
try
do shell script "/opt/local/sbin/mt-daapd -c /etc/mt-daapd.conf" password userpassword with administrator privileges
set the_password to "Correct"
on error
display dialog "Sorry, the password entered was not correct. Please try again:" default answer "" with hidden answer
set userpassword to text returned of result
end try
end repeat
if the_password is "Correct" then
display dialog "Your music is being shared!" buttons {"Done"} default button "Done"
end if
end if
I'm not sure how this is happening but the script is saving the value of userpassword between calls so once it has been set to whatever value, it retains that value and just exits the program. I discovered this after looking at how I created my other stand alone apps.
properties in applescripts are not fixed, they're like the properties of any other object. You can change them at run time, or evn from another script. so if your script1 was
property potato: "potayto"
say potato
and you ran another script
set potato of script1 to "potahto"
then running script1 again would make your computer say "potahto".
Properties can be useful ways of storing preferences in scripts.
Just delete the first if statement, it's redundant anyway. Check if the password is correct, rather than if it is empty.
thus:
property userpassword :""
set the_password to "Undefined"
repeat until the_password is "Correct"
try
do shell script "/opt/local/sbin/mt-daapd -c /etc/mt-daapd.conf" password userpassword with administrator privileges
set the_password to "Correct"
on error
display dialog "Sorry, the password was not correct. Please try again:" default answer "" with hidden answer
set userpassword to text returned of result
end try
end repeat
if the_password is "Correct" then
display dialog "Your music is being shared!" buttons {"Done"} default button "Done"
end if